rtic/macros/src/codegen.rs

219 lines
5.8 KiB
Rust
Raw Normal View History

use proc_macro2::TokenStream as TokenStream2;
2018-11-03 17:02:41 +01:00
use quote::quote;
2020-06-11 19:18:29 +02:00
use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra};
mod assertions;
mod dispatchers;
mod hardware_tasks;
mod idle;
mod init;
mod locals;
mod module;
mod post_init;
mod pre_init;
mod resources;
mod resources_struct;
mod software_tasks;
mod timer_queue;
mod util;
2020-06-11 19:18:29 +02:00
// TODO document the syntax here or in `rtic-syntax`
pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
2020-10-01 18:17:15 +02:00
let mut mod_app = vec![];
let mut mains = vec![];
let mut root = vec![];
let mut user = vec![];
2018-11-03 17:02:41 +01:00
2020-09-01 19:04:55 +02:00
// Generate the `main` function
2020-12-10 20:33:13 +01:00
let assertion_stmts = assertions::codegen(app, analysis);
2018-11-03 17:02:41 +01:00
2020-12-10 20:33:13 +01:00
let pre_init_stmts = pre_init::codegen(app, analysis, extra);
2018-11-03 17:02:41 +01:00
2020-10-15 18:50:17 +02:00
let (mod_app_init, root_init, user_init, call_init) = init::codegen(app, analysis, extra);
2018-11-03 17:02:41 +01:00
2020-12-10 20:33:13 +01:00
let post_init_stmts = post_init::codegen(app, analysis);
2018-11-03 17:02:41 +01:00
2020-10-15 18:50:17 +02:00
let (mod_app_idle, root_idle, user_idle, call_idle) = idle::codegen(app, analysis, extra);
2020-08-27 13:21:56 +02:00
user.push(quote!(
#user_init
2018-11-03 17:02:41 +01:00
2020-08-27 13:21:56 +02:00
#user_idle
));
2018-11-03 17:02:41 +01:00
2020-08-27 13:21:56 +02:00
root.push(quote!(
#(#root_init)*
2018-11-03 17:02:41 +01:00
2020-08-27 13:21:56 +02:00
#(#root_idle)*
));
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
mod_app.push(quote!(
#mod_app_init
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
#mod_app_idle
2020-08-27 13:21:56 +02:00
));
2020-08-27 13:21:56 +02:00
let main = util::suffixed("main");
mains.push(quote!(
#[doc(hidden)]
2020-11-15 18:40:14 +01:00
mod rtic_ext {
use super::*;
#[no_mangle]
unsafe extern "C" fn #main() -> ! {
#(#assertion_stmts)*
2020-05-26 22:21:32 +02:00
#(#pre_init_stmts)*
2021-04-18 23:35:11 +02:00
#[inline(never)]
fn __rtic_init_resources<F>(f: F) where F: FnOnce() {
f();
}
2021-04-18 23:35:11 +02:00
// Wrap late_init_stmts in a function to ensure that stack space is reclaimed.
__rtic_init_resources(||{
#call_init
#(#post_init_stmts)*
});
#call_idle
}
2020-08-27 13:21:56 +02:00
}
));
2020-10-21 20:20:26 +02:00
let (mod_app_resources, mod_resources) = resources::codegen(app, analysis, extra);
2018-11-03 17:02:41 +01:00
2020-10-21 20:20:26 +02:00
let (mod_app_hardware_tasks, root_hardware_tasks, user_hardware_tasks) =
hardware_tasks::codegen(app, analysis, extra);
2018-11-03 17:02:41 +01:00
2020-10-15 18:50:17 +02:00
let (mod_app_software_tasks, root_software_tasks, user_software_tasks) =
software_tasks::codegen(app, analysis, extra);
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
let mod_app_dispatchers = dispatchers::codegen(app, analysis, extra);
let mod_app_timer_queue = timer_queue::codegen(app, analysis, extra);
let user_imports = &app.user_imports;
let user_code = &app.user_code;
let name = &app.name;
2020-10-23 10:35:56 +02:00
let device = &extra.device;
2021-02-18 19:30:59 +01:00
let app_name = &app.name;
let app_path = quote! {crate::#app_name};
2021-02-20 18:32:05 +01:00
let monotonic_parts: Vec<_> = app
2020-12-12 23:31:05 +01:00
.monotonics
.iter()
.map(|(_, monotonic)| {
let name = &monotonic.ident;
let name_str = &name.to_string();
2020-12-12 23:31:05 +01:00
let ty = &monotonic.ty;
let ident = util::monotonic_ident(&name_str);
let ident = util::mark_internal_ident(&ident);
let panic_str = &format!(
"Use of monotonic '{}' before it was passed to the runtime",
name_str
);
let doc = &format!(
"This module holds the static implementation for `{}::now()`",
name_str
);
let user_imports = &app.user_imports;
let default_monotonic = if monotonic.args.default {
quote!(pub use #name::now;)
} else {
quote!()
};
2021-02-18 19:30:59 +01:00
quote! {
#default_monotonic
#[doc = #doc]
2021-02-20 18:32:05 +01:00
#[allow(non_snake_case)]
2021-02-18 19:30:59 +01:00
pub mod #name {
#(
#[allow(unused_imports)]
#user_imports
)*
/// Read the current time from this monotonic
pub fn now() -> rtic::time::Instant<#ty> {
2021-02-18 19:30:59 +01:00
rtic::export::interrupt::free(|_| {
use rtic::Monotonic as _;
use rtic::time::Clock as _;
if let Some(m) = unsafe{ #app_path::#ident.as_ref() } {
if let Ok(v) = m.try_now() {
v
} else {
unreachable!("Your monotonic is not infallible!")
}
2021-02-18 19:30:59 +01:00
} else {
panic!(#panic_str);
2021-02-18 19:30:59 +01:00
}
})
}
}
}
2020-12-12 23:31:05 +01:00
})
.collect();
2020-12-10 20:33:13 +01:00
let monotonics = if !monotonic_parts.is_empty() {
quote!(
pub use rtic::Monotonic as _;
/// Holds static methods for each monotonic.
pub mod monotonics {
#(#monotonic_parts)*
}
)
} else {
quote!()
};
2020-12-13 14:52:16 +01:00
let rt_err = util::rt_err_ident();
quote!(
2021-02-25 17:32:12 +01:00
/// The RTIC application module
2020-10-21 20:20:26 +02:00
pub mod #name {
/// Always include the device crate which contains the vector table
2020-12-13 14:52:16 +01:00
use #device as #rt_err;
2020-10-15 18:50:17 +02:00
#monotonics
2020-12-10 20:33:13 +01:00
#(#user_imports)*
2019-02-15 19:52:25 +01:00
/// User code from within the module
#(#user_code)*
/// User code end
2020-10-15 18:50:17 +02:00
#(#user)*
#(#user_hardware_tasks)*
#(#user_software_tasks)*
#(#root)*
#mod_resources
#(#root_hardware_tasks)*
2020-10-15 18:50:17 +02:00
#(#root_software_tasks)*
2020-10-01 18:17:15 +02:00
/// app module
#(#mod_app)*
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
#(#mod_app_resources)*
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
#(#mod_app_hardware_tasks)*
2020-10-01 18:17:15 +02:00
#(#mod_app_software_tasks)*
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
#(#mod_app_dispatchers)*
2018-11-03 17:02:41 +01:00
2020-10-01 18:17:15 +02:00
#(#mod_app_timer_queue)*
#(#mains)*
}
2018-11-03 17:02:41 +01:00
)
}