rtic_macros/codegen/
main.rs

1use crate::{
2    analyze::Analysis,
3    codegen::{bindings, util},
4    syntax::ast::App,
5};
6use proc_macro2::TokenStream as TokenStream2;
7use quote::quote;
8
9use super::{assertions, extra_mods, post_init, pre_init};
10
11/// Generates code for `fn main`
12pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
13    let extra_mods_stmts = extra_mods::codegen(app, analysis);
14
15    let assertion_stmts = assertions::codegen(app, analysis);
16
17    let pre_init_stmts = pre_init::codegen(app, analysis);
18
19    let post_init_stmts = post_init::codegen(app, analysis);
20
21    let call_idle = if let Some(idle) = &app.idle {
22        let name = &idle.name;
23        quote!(#name(#name::Context::new()))
24    } else if analysis.channels.contains_key(&0) {
25        let dispatcher = util::zero_prio_dispatcher_ident();
26        quote!(#dispatcher();)
27    } else {
28        quote!(loop {})
29    };
30
31    let mut executor_allocations = Vec::new();
32
33    for (name, _) in app.software_tasks.iter() {
34        let exec_name = util::internal_task_ident(name, "EXEC");
35        let new_n_args = util::new_n_args_ident(app.software_tasks[name].inputs.len());
36
37        executor_allocations.push(quote!(
38            let executor = ::core::mem::ManuallyDrop::new(rtic::export::executor::AsyncTaskExecutor::#new_n_args(#name));
39            executors_size += ::core::mem::size_of_val(&executor);
40            #exec_name.set_in_main(&executor);
41        ));
42    }
43
44    let main = util::suffixed("main");
45    let init_name = &app.init.name;
46
47    let init_args = if app.args.core {
48        quote!(core.into(), executors_size)
49    } else {
50        quote!(executors_size)
51    };
52
53    let msp_check = bindings::check_stack_overflow_before_init(app, analysis);
54
55    quote!(
56        #(#extra_mods_stmts)*
57
58        #[doc(hidden)]
59        #[no_mangle]
60        unsafe extern "C" fn #main() -> ! {
61            #(#assertion_stmts)*
62
63            #(#pre_init_stmts)*
64
65            #[inline(never)]
66            fn __rtic_init_resources<F>(f: F) where F: FnOnce() {
67                f();
68            }
69
70            // Generate allocations for async executors.
71            let mut executors_size = 0;
72            #(#executor_allocations)*
73
74            #(#msp_check)*
75
76            // Wrap late_init_stmts in a function to ensure that stack space is reclaimed.
77            __rtic_init_resources(||{
78                let (shared_resources, local_resources) = #init_name(#init_name::Context::new(#init_args));
79
80                #(#post_init_stmts)*
81            });
82
83            #call_idle
84        }
85    )
86}