arcis_interpreter/
module.rs1use crate::{
2 circuit_builder::CircuitBuilder,
3 error::{Error, SpanRange},
4 helper_cleaner::HelperCleaner,
5 interpreter_builder::InterpreterBuilder,
6 utils::catch_unwind,
7};
8use arcis_compiler::core::{
9 global_value::global_expr_store::with_local_expr_store_as_global,
10 ir_builder::IRBuilder,
11};
12use proc_macro2::TokenStream;
13use quote::quote;
14
15pub fn run_interpreter_on_module(module: &syn::ItemMod) -> (TokenStream, Vec<Error>) {
16 let mut expr_store = IRBuilder::new(true);
17 let res = with_local_expr_store_as_global(
18 || {
19 catch_unwind(|| {
20 let interpreter_builder = InterpreterBuilder::new(module);
21 let mut interpreter = interpreter_builder.run();
22
23 interpreter.handle_all_unhandled_items();
24 if !interpreter.errors().is_empty() {
25 let errors = interpreter.errors();
26 return (quote! {}, errors);
27 }
28 let mut circuit_launcher = CircuitBuilder::new(interpreter);
29 circuit_launcher.build_circuits();
30 circuit_launcher
31 .write_post_build(module.ident.to_string())
32 .expect("Failed to write post build (pre-profiles, types).");
33
34 let tests = circuit_launcher.tests;
35 let errors = circuit_launcher.errors;
36 (tests, errors)
37 })
38 },
39 &mut expr_store,
40 );
41
42 res.unwrap_or_else(|p| {
43 let error_msg = match &p {
44 None => "unknown error",
45 Some(s) => s.as_str(),
46 };
47
48 (
49 quote! {},
50 vec![Error::new(
51 SpanRange::call_site(),
52 format!("The `#[encrypted]` macro panicked: {:?}.", error_msg),
53 )],
54 )
55 })
56}
57
58pub fn module_macro(input: TokenStream) -> TokenStream {
59 let mut module = match syn::parse2(input.clone()) {
60 Ok(module) => module,
61 Err(e) => {
62 let mut output = input;
63 output.extend(e.to_compile_error());
64 return output;
65 }
66 };
67
68 let (tests, errors) = run_interpreter_on_module(&module);
69
70 HelperCleaner::clean(&mut module);
71 let mod_name = &module.ident;
72 let mod_visibility = &module.vis;
73 let content = module.content.unwrap();
74 let mod_content = content.1.iter();
75 quote! {
78 #[allow(clippy::new_without_default)]
79 #mod_visibility mod #mod_name {
80 #(#mod_content)*
81 #(#errors)*
82 #[cfg(test)]
83 mod tests {
84 use super::*;
85 #tests
86 }
87 }
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 #[ignore = "used for debugging only"]
95 #[test]
96 fn it_works() {
97 let token_stream = quote! {
98 mod blabla {
99 #[instruction]
100 fn gen_integers(max: u128) -> (u128, bool) {
101 ArcisRNG::gen_integer_in_range(0, max, 8)
102 }
103 }
104 };
105
106 let result = module_macro(token_stream);
107 let syntax_tree = syn::parse_file(&result.to_string()).unwrap();
108 let formatted = prettyplease::unparse(&syntax_tree);
109 print!("{}", formatted);
110 }
111}