1#![feature(lint_reasons)]
7#![feature(proc_macro_diagnostic)]
8#![warn(
9 missing_docs,
10 unused_crate_dependencies,
11 unused_macro_rules,
12 variant_size_differences,
13 clippy::allow_attributes,
14 clippy::allow_attributes_without_reason,
15 clippy::expect_used,
16 clippy::indexing_slicing,
17 clippy::missing_docs_in_private_items,
18 clippy::multiple_inherent_impl,
19 clippy::panic,
20 clippy::pedantic,
21 clippy::str_to_string,
22 clippy::unreachable,
23 clippy::unwrap_used,
24 clippy::use_debug
25)]
26
27mod pipeline;
28
29use chandeliers_err::{self as err, EAccum, Error};
30use chandeliers_san::sp::Sp;
31use chandeliers_syn as syntax;
32
33#[cfg(test)]
35mod integration_deps {
36 use chandeliers_sem as _;
37 use chandeliers_std as _;
38 use rand as _;
39}
40
41#[proc_macro]
64pub fn decl(i: proc_macro::TokenStream) -> proc_macro::TokenStream {
65 use syn::parse_macro_input;
67 let prog = parse_macro_input!(i as Sp<syntax::Prog>);
68 let mut eaccum = EAccum::default();
69 let prog = prog_pipeline(&mut eaccum, prog);
71 let fatal = eaccum.is_fatal();
73 let (es, ws) = eaccum.fetch();
74 let Some(prog) = prog else {
75 err::consistency!(fatal, "No program generated, but no fatal error emitted");
76 for e in es {
77 emit(e, proc_macro::Level::Error);
78 }
79 return proc_macro2::TokenStream::new().into();
80 };
81 for w in ws {
82 emit(w, proc_macro::Level::Error);
84 }
85 prog
86}
87
88fn prog_pipeline(eaccum: &mut EAccum, prog: Sp<syntax::Prog>) -> Option<proc_macro::TokenStream> {
90 pipeline::CompilerPass::new(eaccum, prog)?
92 .finish()
93 .apply(eaccum)?
94 .finish()
95 .apply(eaccum)?
96 .finish()
97 .apply(eaccum)?
98 .finish()
99 .apply(eaccum)?
100 .finish()
101 .codegen()
102}
103
104macro_rules! compiling {
107 ($fun:ident with $testing:ident in $($dir:ident / )*) => {
108 #[test]
109 fn $fun() {
110 let t = trybuild::TestCases::new();
111 t.$testing(concat!("tests/", $( concat!(stringify!($dir), "/") , )* "**/*.rs"));
112 }
113 };
114}
115
116compiling!(fail_ui_causality with compile_fail in compile_fail/ui/causality/);
119compiling!(fail_ui_syn with compile_fail in compile_fail/ui/syn/);
120compiling!(fail_ui_tc with compile_fail in compile_fail/ui/tc/);
121compiling!(fail_ui_options with compile_fail in compile_fail/ui/options/);
122compiling!(fail_std with compile_fail in compile_fail/std/);
123compiling!(fail_ui_clk with compile_fail in compile_fail/ui/clk/);
124compiling!(pass_ui with pass in pass/ui/);
126compiling!(pass_syn with pass in pass/syn/);
127compiling!(pass_std with pass in pass/std/);
128compiling!(pass_fromslides with pass in pass/fromslides/);
129compiling!(pass_given with pass in pass/given/);
130compiling!(pass_options with pass in pass/options/);
131compiling!(pass_poly with pass in pass/poly/);
132compiling!(pass_registers with pass in pass/registers/);
133compiling!(warn_dead_code with compile_fail in warn/dead_code/);
136compiling!(warn_options with compile_fail in warn/options/);
137fn emit(elements: Error, level: proc_macro::Level) -> proc_macro2::TokenStream {
144 let mut elements = elements.into_iter();
145 let Some((msg, span)) = elements.next() else {
146 err::abort!("This error message is empty")
147 };
148 let Some(span) = span else {
149 err::abort!("The very first error should always have an associated span")
150 };
151 let mut d = proc_macro::Diagnostic::spanned(
152 span.unwrap().unwrap(),
153 level,
154 msg,
155 );
156 for (msg, span) in elements {
157 if let Some(span) = span {
158 d = d.span_note(
159 span.unwrap().unwrap(),
160 msg,
161 );
162 } else {
163 d = d.note(msg);
164 }
165 }
166 d.emit();
167 proc_macro2::TokenStream::new()
168}