diff --git a/examples/single.rs b/examples/single.rs index 5249b5d..dfb7f3b 100644 --- a/examples/single.rs +++ b/examples/single.rs @@ -1,6 +1,6 @@ //! Full syntax -#[mock::app] +#[mock::app(parse_extern_interrupt, parse_binds)] mod app { #[resources] struct Resources { @@ -27,6 +27,7 @@ mod app { resources = [&a, d], spawn = [foo], )] + fn idle(_: idle::Context) -> ! { static mut X: u32 = 0; @@ -34,9 +35,9 @@ mod app { } #[task( - resources = [b, &c], - spawn = [bar], - )] + resources = [b, &c], + spawn = [bar], + )] fn foo(_: foo::Context) { static mut X: u32 = 0; @@ -44,14 +45,33 @@ mod app { } #[task( - capacity = 2, - priority = 2, - resources = [d], - spawn = [foo], - )] + capacity = 2, + priority = 2, + resources = [d], + spawn = [foo], + )] + fn bar(_: bar::Context, _: u32) { static mut X: u32 = 0; *X += 1; } + + extern "C" { + // #[init()] + // fn init(_: init::Context); + + // #[task()] + // fn task_decl(_: task_decl::Context); + + // mod x { + fn SSIO(); + // #[dispatcher] + // fn SSIO(); + // } + + } + + // #[task()] + // extern "C" fn task_decl2(_: task_decl2::Context); } diff --git a/src/ast.rs b/src/ast.rs index 0aacda6..8ad5a83 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -205,9 +205,13 @@ pub struct SoftwareTask { /// Static variables local to this context pub locals: Map, + /// The statements that make up the task handler pub stmts: Vec, + /// Set if the function is external + pub is_extern: bool, + pub(crate) _extensible: (), } @@ -259,9 +263,13 @@ pub struct HardwareTask { /// Static variables local to this context pub locals: Map, + /// The statements that make up the task handler pub stmts: Vec, + /// Set if the function is external + pub is_extern: bool, + pub(crate) _extensible: (), } diff --git a/src/lib.rs b/src/lib.rs index 35535bc..9a9d762 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #![deny(missing_docs)] #![deny(rust_2018_compatibility)] #![deny(rust_2018_idioms)] -#![deny(warnings)] +// #![deny(warnings)] #[allow(unused_extern_crates)] extern crate proc_macro; diff --git a/src/parse/app.rs b/src/parse/app.rs index c46089e..2ae41aa 100644 --- a/src/parse/app.rs +++ b/src/parse/app.rs @@ -5,7 +5,7 @@ use proc_macro2::TokenStream as TokenStream2; use syn::{ parse::{self, ParseStream, Parser}, spanned::Spanned, - ExprParen, Fields, ForeignItem, Ident, Item, Lit, Path, Token, Visibility, + Attribute, ExprParen, Fields, ForeignItem, Ident, Item, Lit, Path, Token, Visibility, }; use super::Input; @@ -89,6 +89,56 @@ impl AppArgs { } } +enum AppAttribute { + Resources, + Init, + Idle, + Task, + Dispatch, +} + +fn check_attr(attr: &Attribute) -> Option { + if util::attr_eq(attr, "resources") { + Some(AppAttribute::Resources) + } else if util::attr_eq(attr, "init") { + Some(AppAttribute::Init) + } else if util::attr_eq(attr, "idle") { + Some(AppAttribute::Idle) + } else if util::attr_eq(attr, "task") { + Some(AppAttribute::Task) + } else if util::attr_eq(attr, "dispatch") { + Some(AppAttribute::Dispatch) + } else { + None + } +} + +fn parse_attr( + attrs: &mut Vec, +) -> Result<(Option, Option), parse::Error> { + let mut r = (None, None); + loop { + if attrs + .iter() + .position(|attr| match check_attr(attr) { + Some(app_attr) => match r { + (None, _) => { + r.0 = Some(app_attr); + true + } + (Some(_), _) => unimplemented!(), + }, + None => false, + }) + .map(|e| r.1 = Some(attrs.remove(e))) + .is_none() + { + break; + } + } + Ok(r) +} + impl App { pub(crate) fn parse(args: AppArgs, input: Input, settings: &Settings) -> parse::Result { let mut inits = Vec::new(); @@ -106,6 +156,7 @@ impl App { let mut seen_idents = HashSet::::new(); let mut bindings = HashSet::::new(); + let mut check_binding = |ident: &Ident| { if bindings.contains(ident) { return Err(parse::Error::new( @@ -118,6 +169,7 @@ impl App { Ok(()) }; + let mut check_ident = |ident: &Ident| { if seen_idents.contains(ident) { return Err(parse::Error::new( @@ -130,171 +182,165 @@ impl App { Ok(()) }; + for mut item in input.items { match item { Item::Fn(mut item) => { let span = item.sig.ident.span(); - if let Some(pos) = item - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "init")) - { - let args = InitArgs::parse(item.attrs.remove(pos).tokens, settings)?; - - // If an init function already exists, error - if !inits.is_empty() { - return Err(parse::Error::new( - span, - "`#[init]` function must appear at most once", - )); - } - - check_ident(&item.sig.ident)?; + match parse_attr(&mut item.attrs)? { + (Some(AppAttribute::Init), Some(init)) => { + // If an init function already exists, error + if !inits.is_empty() { + return Err(parse::Error::new( + span, + "`#[init]` function must appear at most once", + )); + } - inits.push(Init::parse(args, item)?); - } else if let Some(pos) = item - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "idle")) - { - let args = IdleArgs::parse(item.attrs.remove(pos).tokens, settings)?; + check_ident(&item.sig.ident)?; + let args = InitArgs::parse(init.tokens, settings)?; - // If an idle function already exists, error - if !idles.is_empty() { - return Err(parse::Error::new( - span, - "`#[idle]` function must appear at most once", - )); + inits.push(Init::parse(args, item)?); } + (Some(AppAttribute::Idle), Some(idle)) => { + // If an idle function already exists, error + if !idles.is_empty() { + return Err(parse::Error::new( + span, + "`#[idle]` function must appear at most once", + )); + } - check_ident(&item.sig.ident)?; - - idles.push(Idle::parse(args, item)?); - } else if let Some(pos) = item - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "task")) - { - if hardware_tasks.contains_key(&item.sig.ident) - || software_tasks.contains_key(&item.sig.ident) - { - return Err(parse::Error::new( - span, - "this task is defined multiple times", - )); + check_ident(&item.sig.ident)?; + let args = IdleArgs::parse(idle.tokens, settings)?; + + idles.push(Idle::parse(args, item)?); } + (Some(AppAttribute::Task), Some(task)) => { + eprintln!("--- task ---"); + if hardware_tasks.contains_key(&item.sig.ident) + || software_tasks.contains_key(&item.sig.ident) + { + return Err(parse::Error::new( + span, + "this task is defined multiple times", + )); + } - match crate::parse::task_args(item.attrs.remove(pos).tokens, settings)? { - Either::Left(args) => { - check_binding(&args.binds)?; - check_ident(&item.sig.ident)?; + match crate::parse::task_args(task.tokens, settings)? { + Either::Left(args) => { + check_binding(&args.binds)?; + check_ident(&item.sig.ident)?; - hardware_tasks.insert( - item.sig.ident.clone(), - HardwareTask::parse(args, item)?, - ); - } + hardware_tasks.insert( + item.sig.ident.clone(), + HardwareTask::parse(args, item)?, + ); + } - Either::Right(args) => { - check_ident(&item.sig.ident)?; + Either::Right(args) => { + eprintln!("--- software task aaueaeu ---"); + check_ident(&item.sig.ident)?; - software_tasks.insert( - item.sig.ident.clone(), - SoftwareTask::parse(args, item)?, - ); + software_tasks.insert( + item.sig.ident.clone(), + SoftwareTask::parse(args, item)?, + ); + } } } - } else { - return Err(parse::Error::new( - span, - "this item must live outside the `#[app]` module", - )); + _ => { + return Err(parse::Error::new( + span, + "this item must live outside the `#[app]` module", + )); + } } } Item::Struct(ref mut struct_item) => { // Match structures with the attribute #[resources], name of structure is not // important - if let Some(_pos) = struct_item - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "resources")) - { - let span = struct_item.ident.span(); - - if resource_struct.contains_key(&struct_item.ident) { - return Err(parse::Error::new( - span, - "`#[resources]` struct must appear at most once", - )); - } + let span = struct_item.ident.span(); + match parse_attr(&mut struct_item.attrs)? { + (Some(AppAttribute::Resources), _) => { + if resource_struct.contains_key(&struct_item.ident) { + return Err(parse::Error::new( + span, + "`#[resources]` struct must appear at most once", + )); + } - if struct_item.vis != Visibility::Inherited { - return Err(parse::Error::new( - struct_item.span(), - "this item must have inherited / private visibility", - )); - } + if struct_item.vis != Visibility::Inherited { + return Err(parse::Error::new( + struct_item.span(), + "this item must have inherited / private visibility", + )); + } - if let Fields::Named(fields) = &mut struct_item.fields { - for field in &mut fields.named { - let ident = field.ident.as_ref().expect("UNREACHABLE"); + if let Fields::Named(fields) = &mut struct_item.fields { + for field in &mut fields.named { + let ident = field.ident.as_ref().expect("UNREACHABLE"); - if late_resources.contains_key(ident) - || resources.contains_key(ident) - { - return Err(parse::Error::new( - ident.span(), - "this resource is listed more than once", - )); - } + if late_resources.contains_key(ident) + || resources.contains_key(ident) + { + return Err(parse::Error::new( + ident.span(), + "this resource is listed more than once", + )); + } - if let Some(pos) = field - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "init")) - { - let attr = field.attrs.remove(pos); - - let late = LateResource::parse(field, ident.span())?; - - resources.insert( - ident.clone(), - Resource { - late, - expr: syn::parse2::(attr.tokens)?.expr, - }, - ); - } else { - let late = LateResource::parse(field, ident.span())?; + if let Some(pos) = field + .attrs + .iter() + .position(|attr| util::attr_eq(attr, "init")) + { + let attr = field.attrs.remove(pos); + + let late = LateResource::parse(field, ident.span())?; + + resources.insert( + ident.clone(), + Resource { + late, + expr: syn::parse2::(attr.tokens)?.expr, + }, + ); + } else { + let late = LateResource::parse(field, ident.span())?; - late_resources.insert(ident.clone(), late); + late_resources.insert(ident.clone(), late); + } } + } else { + return Err(parse::Error::new( + struct_item.span(), + "this `struct` must have named fields", + )); } - } else { - return Err(parse::Error::new( - struct_item.span(), - "this `struct` must have named fields", - )); + // resource_struct will be non-empty if #[resources] was encountered before + resource_struct.insert(struct_item.ident.clone(), struct_item.clone()); + } + _ => { + // Structure without the #[resources] attribute should just be passed along + user_code.push(item.clone()); } - // resource_struct will be non-empty if #[resources] was encountered before - resource_struct.insert(struct_item.ident.clone(), struct_item.clone()); - } else { - // Structure without the #[resources] attribute should just be passed along - user_code.push(item.clone()); } } Item::ForeignMod(mod_) => { - if !util::abi_is_c(&mod_.abi) { - return Err(parse::Error::new( - mod_.abi.extern_token.span(), - "this `extern` block must use the \"C\" abi", - )); - } + // if !util::abi_is_c(&mod_.abi) { + // return Err(parse::Error::new( + // mod_.abi.extern_token.span(), + // "this `extern` block must use the \"C\" abi", + // )); + // } for item in mod_.items { if let ForeignItem::Fn(item) = item { + eprintln!("--- foreign Fn -- {}", item.sig.ident); + eprintln!("attr {:?}", item.attrs); if settings.parse_extern_interrupt { let (ident, extern_interrupt) = ExternInterrupt::parse(item)?; @@ -318,10 +364,12 @@ impl App { )); } } else { - return Err(parse::Error::new( - item.span(), - "this item must live outside the `#[app]` module", - )); + panic!("not fn"); + // eprintln!("--- not fn ---"); + // return Err(parse::Error::new( + // item.span(), + // "this item must live outside the `#[app]` module", + // )); } } } @@ -329,7 +377,9 @@ impl App { // Store the user provided use-statements user_imports.push(itemuse_.clone()); } + _ => { + eprintln!("-- not recognized -- {:?}", &item); // Anything else within the module should not make any difference user_code.push(item.clone()); } diff --git a/src/parse/hardware_task.rs b/src/parse/hardware_task.rs index 9fb32d8..0924bf5 100644 --- a/src/parse/hardware_task.rs +++ b/src/parse/hardware_task.rs @@ -26,6 +26,7 @@ impl HardwareTask { if rest.is_empty() { let (locals, stmts) = util::extract_locals(item.block.stmts)?; let attrs = item.attrs; + let is_extern = item.sig.abi.is_none(); return Ok(HardwareTask { args, @@ -33,6 +34,7 @@ impl HardwareTask { context, locals: Local::parse(locals)?, stmts, + is_extern, _extensible: (), }); } diff --git a/src/parse/software_task.rs b/src/parse/software_task.rs index 73f6c9b..ff730bd 100644 --- a/src/parse/software_task.rs +++ b/src/parse/software_task.rs @@ -16,9 +16,10 @@ impl SoftwareTask { if valid_signature { if let Some((context, Ok(inputs))) = util::parse_inputs(item.sig.inputs, &name) { + eprintln!("item {:?}", &item.sig.ident); let (locals, stmts) = util::extract_locals(item.block.stmts)?; let (cfgs, attrs) = util::extract_cfgs(item.attrs); - + let is_extern = item.sig.abi.is_none(); return Ok(SoftwareTask { args, attrs, @@ -27,6 +28,7 @@ impl SoftwareTask { inputs, locals: Local::parse(locals)?, stmts, + is_extern, _extensible: (), }); } diff --git a/src/parse/util.rs b/src/parse/util.rs index c753351..c07947a 100644 --- a/src/parse/util.rs +++ b/src/parse/util.rs @@ -31,14 +31,13 @@ pub fn attr_eq(attr: &Attribute, name: &str) -> bool { /// - is not `async` /// - is not `const` /// - is not `unsafe` -/// - is not generic (has no type parametrs) +/// - is not generic (has no type parameters) /// - is not variadic -/// - uses the Rust ABI (and not e.g. "C") pub fn check_fn_signature(item: &ItemFn) -> bool { item.vis == Visibility::Inherited && item.sig.constness.is_none() && item.sig.asyncness.is_none() - && item.sig.abi.is_none() + // && item.sig.abi.is_none() && item.sig.unsafety.is_none() && item.sig.generics.params.is_empty() && item.sig.generics.where_clause.is_none()