diff options
Diffstat (limited to 'macros/src/syntax')
-rw-r--r-- | macros/src/syntax/analyze.rs | 57 | ||||
-rw-r--r-- | macros/src/syntax/ast.rs | 50 | ||||
-rw-r--r-- | macros/src/syntax/parse.rs | 121 | ||||
-rw-r--r-- | macros/src/syntax/parse/app.rs | 58 | ||||
-rw-r--r-- | macros/src/syntax/parse/hardware_task.rs | 44 | ||||
-rw-r--r-- | macros/src/syntax/parse/idle.rs | 18 | ||||
-rw-r--r-- | macros/src/syntax/parse/init.rs | 22 | ||||
-rw-r--r-- | macros/src/syntax/parse/software_task.rs | 26 | ||||
-rw-r--r-- | macros/src/syntax/parse/util.rs | 26 |
9 files changed, 75 insertions, 347 deletions
diff --git a/macros/src/syntax/analyze.rs b/macros/src/syntax/analyze.rs index 44960b9e..ff0577da 100644 --- a/macros/src/syntax/analyze.rs +++ b/macros/src/syntax/analyze.rs @@ -16,19 +16,11 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { type TaskName = String; type Priority = u8; - // The task list is a Tuple (Name, Shared Resources, Local Resources, Priority, IsAsync) - let task_resources_list: Vec<(TaskName, Vec<&Ident>, &LocalResources, Priority, bool)> = + // The task list is a Tuple (Name, Shared Resources, Local Resources, Priority) + let task_resources_list: Vec<(TaskName, Vec<&Ident>, &LocalResources, Priority)> = Some(&app.init) .iter() - .map(|ht| { - ( - "init".to_string(), - Vec::new(), - &ht.args.local_resources, - 0, - false, - ) - }) + .map(|ht| ("init".to_string(), Vec::new(), &ht.args.local_resources, 0)) .chain(app.idle.iter().map(|ht| { ( "idle".to_string(), @@ -39,7 +31,6 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { .collect::<Vec<_>>(), &ht.args.local_resources, 0, - false, ) })) .chain(app.software_tasks.iter().map(|(name, ht)| { @@ -52,7 +43,6 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { .collect::<Vec<_>>(), &ht.args.local_resources, ht.args.priority, - ht.is_async, ) })) .chain(app.hardware_tasks.iter().map(|(name, ht)| { @@ -65,7 +55,6 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { .collect::<Vec<_>>(), &ht.args.local_resources, ht.args.priority, - false, ) })) .collect(); @@ -84,21 +73,20 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { // Check that lock_free resources are correct for lf_res in lock_free.iter() { - for (task, tr, _, priority, is_async) in task_resources_list.iter() { + for (task, tr, _, priority) in task_resources_list.iter() { for r in tr { // Get all uses of resources annotated lock_free if lf_res == r { // lock_free resources are not allowed in async tasks - if *is_async { - error.push(syn::Error::new( + error.push(syn::Error::new( r.span(), format!( "Lock free shared resource {:?} is used by an async tasks, which is forbidden", r.to_string(), ), )); - } + // TODO: Should this be removed? // HashMap returns the previous existing object if old.key == new.key if let Some(lf_res) = lf_hash.insert(r.to_string(), (task, r, priority)) { // Check if priority differ, if it does, append to @@ -150,7 +138,7 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { // Check that local resources are not shared for lr in local { - for (task, _, local_resources, _, _) in task_resources_list.iter() { + for (task, _, local_resources, _) in task_resources_list.iter() { for (name, res) in local_resources.iter() { // Get all uses of resources annotated lock_free if lr == name { @@ -193,18 +181,7 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { error.push(syn::Error::new( name.span(), format!( - "Software task {:?} has priority 0, but `#[idle]` is defined. 0-priority software tasks are only allowed if there is no `#[idle]`.", - name.to_string(), - ) - )); - } - - // 0-priority tasks must be async - if !task.is_async { - error.push(syn::Error::new( - name.span(), - format!( - "Software task {:?} has priority 0, but is not `async`. 0-priority software tasks must be `async`.", + "Async task {:?} has priority 0, but `#[idle]` is defined. 0-priority async tasks are only allowed if there is no `#[idle]`.", name.to_string(), ) )); @@ -263,7 +240,7 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { // Create the list of used local resource Idents let mut used_local_resource = IndexSet::new(); - for (_, _, locals, _, _) in task_resources_list { + for (_, _, locals, _) in task_resources_list { for (local, _) in locals { used_local_resource.insert(local.clone()); } @@ -307,27 +284,11 @@ pub(crate) fn app(app: &App) -> Result<Analysis, syn::Error> { let channel = channels.entry(spawnee_prio).or_default(); channel.tasks.insert(name.clone()); - - if !spawnee.args.only_same_priority_spawn { - // Require `Send` if the task can be spawned from other priorities - spawnee.inputs.iter().for_each(|input| { - send_types.insert(input.ty.clone()); - }); - } } // No channel should ever be empty debug_assert!(channels.values().all(|channel| !channel.tasks.is_empty())); - // Compute channel capacities - for channel in channels.values_mut() { - channel.capacity = channel - .tasks - .iter() - .map(|name| app.software_tasks[name].args.capacity) - .sum(); - } - Ok(Analysis { channels, shared_resources: used_shared_resource, diff --git a/macros/src/syntax/ast.rs b/macros/src/syntax/ast.rs index 0f2e36f4..ea6e402c 100644 --- a/macros/src/syntax/ast.rs +++ b/macros/src/syntax/ast.rs @@ -1,6 +1,6 @@ //! Abstract Syntax Tree -use syn::{Attribute, Expr, Ident, Item, ItemUse, Pat, PatType, Path, Stmt, Type}; +use syn::{Attribute, Expr, Ident, Item, ItemUse, Pat, Path, Stmt, Type}; use crate::syntax::Map; @@ -20,9 +20,6 @@ pub struct App { /// The `#[idle]` function pub idle: Option<Idle>, - /// Monotonic clocks - pub monotonics: Map<Monotonic>, - /// Resources shared between tasks defined in `#[shared]` pub shared_resources: Map<SharedResource>, @@ -38,7 +35,7 @@ pub struct App { /// Hardware tasks: `#[task(binds = ..)]`s pub hardware_tasks: Map<HardwareTask>, - /// Software tasks: `#[task]` + /// Async software tasks: `#[task]` pub software_tasks: Map<SoftwareTask>, } @@ -192,38 +189,7 @@ pub struct LocalResource { pub ty: Box<Type>, } -/// Monotonic -#[derive(Debug)] -#[non_exhaustive] -pub struct Monotonic { - /// `#[cfg]` attributes like `#[cfg(debug_assertions)]` - pub cfgs: Vec<Attribute>, - - /// The identifier of the monotonic - pub ident: Ident, - - /// The type of this monotonic - pub ty: Box<Type>, - - /// Monotonic args - pub args: MonotonicArgs, -} - -/// Monotonic metadata -#[derive(Debug)] -#[non_exhaustive] -pub struct MonotonicArgs { - /// The interrupt or exception that this monotonic is bound to - pub binds: Ident, - - /// The priority of this monotonic - pub priority: Option<u8>, - - /// If this is the default monotonic - pub default: bool, -} - -/// A software task +/// An async software task #[derive(Debug)] #[non_exhaustive] pub struct SoftwareTask { @@ -239,26 +205,17 @@ pub struct SoftwareTask { /// The context argument pub context: Box<Pat>, - /// The inputs of this software task - pub inputs: Vec<PatType>, - /// The statements that make up the task handler pub stmts: Vec<Stmt>, /// The task is declared externally pub is_extern: bool, - - /// If the task is marked as `async` - pub is_async: bool, } /// Software task metadata #[derive(Debug)] #[non_exhaustive] pub struct SoftwareTaskArgs { - /// The task capacity: the maximum number of pending messages that can be queued - pub capacity: u8, - /// The priority of this task pub priority: u8, @@ -275,7 +232,6 @@ pub struct SoftwareTaskArgs { impl Default for SoftwareTaskArgs { fn default() -> Self { Self { - capacity: 1, priority: 1, local_resources: LocalResources::new(), shared_resources: SharedResources::new(), diff --git a/macros/src/syntax/parse.rs b/macros/src/syntax/parse.rs index ceedaa98..abdd677a 100644 --- a/macros/src/syntax/parse.rs +++ b/macros/src/syntax/parse.rs @@ -2,7 +2,6 @@ mod app; mod hardware_task; mod idle; mod init; -mod monotonic; mod resource; mod software_task; mod util; @@ -11,15 +10,12 @@ use proc_macro2::TokenStream as TokenStream2; use syn::{ braced, parenthesized, parse::{self, Parse, ParseStream, Parser}, - token::{self, Brace}, - Ident, Item, LitBool, LitInt, Path, Token, + token::Brace, + Ident, Item, LitInt, Token, }; use crate::syntax::{ - ast::{ - App, AppArgs, HardwareTaskArgs, IdleArgs, InitArgs, MonotonicArgs, SoftwareTaskArgs, - TaskLocal, - }, + ast::{App, AppArgs, HardwareTaskArgs, IdleArgs, InitArgs, SoftwareTaskArgs, TaskLocal}, Either, }; @@ -388,7 +384,6 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof }) } else { Either::Right(SoftwareTaskArgs { - capacity: capacity.unwrap_or(1), priority, shared_resources, local_resources, @@ -398,113 +393,3 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof }) .parse2(tokens) } - -fn monotonic_args(path: Path, tokens: TokenStream2) -> parse::Result<MonotonicArgs> { - (|input: ParseStream<'_>| -> parse::Result<MonotonicArgs> { - let mut binds = None; - let mut priority = None; - let mut default = None; - - if !input.peek(token::Paren) { - return Err(parse::Error::new( - path.segments.first().unwrap().ident.span(), - "expected opening ( in #[monotonic( ... )]", - )); - } - - let content; - parenthesized!(content in input); - - if !content.is_empty() { - loop { - // Parse identifier name - let ident: Ident = content.parse()?; - // Handle equal sign - let _: Token![=] = content.parse()?; - - match &*ident.to_string() { - "binds" => { - if binds.is_some() { - return Err(parse::Error::new( - ident.span(), - "argument appears more than once", - )); - } - // Parse identifier name - let ident = content.parse()?; - - binds = Some(ident); - } - - "priority" => { - if priority.is_some() { - return Err(parse::Error::new( - ident.span(), - "argument appears more than once", - )); - } - - // #lit - let lit: LitInt = content.parse()?; - - if !lit.suffix().is_empty() { - return Err(parse::Error::new( - lit.span(), - "this literal must be unsuffixed", - )); - } - - let value = lit.base10_parse::<u8>().ok(); - if value.is_none() || value == Some(0) { - return Err(parse::Error::new( - lit.span(), - "this literal must be in the range 1...255", - )); - } - - priority = Some(value.unwrap()); - } - - "default" => { - if default.is_some() { - return Err(parse::Error::new( - ident.span(), - "argument appears more than once", - )); - } - - let lit: LitBool = content.parse()?; - default = Some(lit.value); - } - - _ => { - return Err(parse::Error::new(ident.span(), "unexpected argument")); - } - } - if content.is_empty() { - break; - } - - // Handle comma: , - let _: Token![,] = content.parse()?; - } - } - - let binds = if let Some(r) = binds { - r - } else { - return Err(parse::Error::new( - content.span(), - "`binds = ...` is missing", - )); - }; - let default = default.unwrap_or(false); - - Ok(MonotonicArgs { - binds, - priority, - default, - }) - }) - .parse2(tokens) -} diff --git a/macros/src/syntax/parse/app.rs b/macros/src/syntax/parse/app.rs index dd7c3999..8a9242e9 100644 --- a/macros/src/syntax/parse/app.rs +++ b/macros/src/syntax/parse/app.rs @@ -5,14 +5,14 @@ use proc_macro2::TokenStream as TokenStream2; use syn::{ parse::{self, ParseStream, Parser}, spanned::Spanned, - Expr, ExprArray, Fields, ForeignItem, Ident, Item, LitBool, Path, Token, Type, Visibility, + Expr, ExprArray, Fields, ForeignItem, Ident, Item, LitBool, Path, Token, Visibility, }; use super::Input; use crate::syntax::{ ast::{ App, AppArgs, Dispatcher, Dispatchers, HardwareTask, Idle, IdleArgs, Init, InitArgs, - LocalResource, Monotonic, MonotonicArgs, SharedResource, SoftwareTask, + LocalResource, SharedResource, SoftwareTask, }, parse::{self as syntax_parse, util}, Either, Map, Set, @@ -150,7 +150,6 @@ impl App { let mut shared_resources = Map::new(); let mut local_resources_ident = None; let mut local_resources = Map::new(); - let mut monotonics = Map::new(); let mut hardware_tasks = Map::new(); let mut software_tasks = Map::new(); let mut user_imports = vec![]; @@ -158,7 +157,6 @@ impl App { let mut seen_idents = HashSet::<Ident>::new(); let mut bindings = HashSet::<Ident>::new(); - let mut monotonic_types = HashSet::<Type>::new(); let mut check_binding = |ident: &Ident| { if bindings.contains(ident) { @@ -186,19 +184,6 @@ impl App { Ok(()) }; - let mut check_monotonic = |ty: &Type| { - if monotonic_types.contains(ty) { - return Err(parse::Error::new( - ty.span(), - "this type is already used by another monotonic", - )); - } else { - monotonic_types.insert(ty.clone()); - } - - Ok(()) - }; - for mut item in input.items { match item { Item::Fn(mut item) => { @@ -448,44 +433,6 @@ impl App { // Store the user provided use-statements user_imports.push(itemuse_.clone()); } - Item::Type(ref mut type_item) => { - // Match types with the attribute #[monotonic] - if let Some(pos) = type_item - .attrs - .iter() - .position(|attr| util::attr_eq(attr, "monotonic")) - { - let span = type_item.ident.span(); - - if monotonics.contains_key(&type_item.ident) { - return Err(parse::Error::new( - span, - "`#[monotonic(...)]` on a specific type must appear at most once", - )); - } - - if type_item.vis != Visibility::Inherited { - return Err(parse::Error::new( - type_item.span(), - "this item must have inherited / private visibility", - )); - } - - check_monotonic(&*type_item.ty)?; - - let m = type_item.attrs.remove(pos); - let args = MonotonicArgs::parse(m)?; - - check_binding(&args.binds)?; - - let monotonic = Monotonic::parse(args, type_item, span)?; - - monotonics.insert(type_item.ident.clone(), monotonic); - } - - // All types are passed on - user_code.push(item.clone()); - } _ => { // Anything else within the module should not make any difference user_code.push(item.clone()); @@ -524,7 +471,6 @@ impl App { name: input.ident, init, idle, - monotonics, shared_resources, local_resources, user_imports, diff --git a/macros/src/syntax/parse/hardware_task.rs b/macros/src/syntax/parse/hardware_task.rs index 304bfcd3..ff94bc51 100644 --- a/macros/src/syntax/parse/hardware_task.rs +++ b/macros/src/syntax/parse/hardware_task.rs @@ -23,19 +23,17 @@ impl HardwareTask { } if valid_signature { - if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) { - if rest.is_empty() { - let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { + let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); - return Ok(HardwareTask { - args, - cfgs, - attrs, - context, - stmts: item.block.stmts, - is_extern: false, - }); - } + return Ok(HardwareTask { + args, + cfgs, + attrs, + context, + stmts: item.block.stmts, + is_extern: false, + }); } } @@ -69,19 +67,17 @@ impl HardwareTask { } if valid_signature { - if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) { - if rest.is_empty() { - let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { + let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); - return Ok(HardwareTask { - args, - cfgs, - attrs, - context, - stmts: Vec::<Stmt>::new(), - is_extern: true, - }); - } + return Ok(HardwareTask { + args, + cfgs, + attrs, + context, + stmts: Vec::<Stmt>::new(), + is_extern: true, + }); } } diff --git a/macros/src/syntax/parse/idle.rs b/macros/src/syntax/parse/idle.rs index d9f3a99e..ffec358f 100644 --- a/macros/src/syntax/parse/idle.rs +++ b/macros/src/syntax/parse/idle.rs @@ -21,16 +21,14 @@ impl Idle { let name = item.sig.ident.to_string(); if valid_signature { - if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) { - if rest.is_empty() { - return Ok(Idle { - args, - attrs: item.attrs, - context, - name: item.sig.ident, - stmts: item.block.stmts, - }); - } + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { + return Ok(Idle { + args, + attrs: item.attrs, + context, + name: item.sig.ident, + stmts: item.block.stmts, + }); } } diff --git a/macros/src/syntax/parse/init.rs b/macros/src/syntax/parse/init.rs index 727ee205..5ec1abaf 100644 --- a/macros/src/syntax/parse/init.rs +++ b/macros/src/syntax/parse/init.rs @@ -25,18 +25,16 @@ impl Init { if let Ok((user_shared_struct, user_local_struct)) = util::type_is_init_return(&item.sig.output, &name) { - if let Some((context, Ok(rest))) = util::parse_inputs(item.sig.inputs, &name) { - if rest.is_empty() { - return Ok(Init { - args, - attrs: item.attrs, - context, - name: item.sig.ident, - stmts: item.block.stmts, - user_shared_struct, - user_local_struct, - }); - } + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { + return Ok(Init { + args, + attrs: item.attrs, + context, + name: item.sig.ident, + stmts: item.block.stmts, + user_shared_struct, + user_local_struct, + }); } } } diff --git a/macros/src/syntax/parse/software_task.rs b/macros/src/syntax/parse/software_task.rs index 2b1ac4a5..6be597e8 100644 --- a/macros/src/syntax/parse/software_task.rs +++ b/macros/src/syntax/parse/software_task.rs @@ -8,17 +8,16 @@ use crate::syntax::{ impl SoftwareTask { pub(crate) fn parse(args: SoftwareTaskArgs, item: ItemFn) -> parse::Result<Self> { - let valid_signature = - util::check_fn_signature(&item, true) && util::type_is_unit(&item.sig.output); + let valid_signature = util::check_fn_signature(&item, true) + && util::type_is_unit(&item.sig.output) + && item.sig.asyncness.is_some(); let span = item.sig.ident.span(); let name = item.sig.ident.to_string(); - let is_async = item.sig.asyncness.is_some(); - if valid_signature { - if let Some((context, Ok(inputs))) = util::parse_inputs(item.sig.inputs, &name) { + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); return Ok(SoftwareTask { @@ -26,10 +25,8 @@ impl SoftwareTask { attrs, cfgs, context, - inputs, stmts: item.block.stmts, is_extern: false, - is_async, }); } } @@ -37,7 +34,7 @@ impl SoftwareTask { Err(parse::Error::new( span, &format!( - "this task handler must have type signature `(async) fn({}::Context, ..)`", + "this task handler must have type signature `async fn({}::Context)`", name ), )) @@ -49,17 +46,16 @@ impl SoftwareTask { args: SoftwareTaskArgs, item: ForeignItemFn, ) -> parse::Result<Self> { - let valid_signature = - util::check_foreign_fn_signature(&item, true) && util::type_is_unit(&item.sig.output); + let valid_signature = util::check_foreign_fn_signature(&item, true) + && util::type_is_unit(&item.sig.output) + && item.sig.asyncness.is_some(); let span = item.sig.ident.span(); let name = item.sig.ident.to_string(); - let is_async = item.sig.asyncness.is_some(); - if valid_signature { - if let Some((context, Ok(inputs))) = util::parse_inputs(item.sig.inputs, &name) { + if let Some(context) = util::parse_inputs(item.sig.inputs, &name) { let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs); return Ok(SoftwareTask { @@ -67,10 +63,8 @@ impl SoftwareTask { attrs, cfgs, context, - inputs, stmts: Vec::<Stmt>::new(), is_extern: true, - is_async, }); } } @@ -78,7 +72,7 @@ impl SoftwareTask { Err(parse::Error::new( span, &format!( - "this task handler must have type signature `(async) fn({}::Context, ..)`", + "this task handler must have type signature `async fn({}::Context)`", name ), )) diff --git a/macros/src/syntax/parse/util.rs b/macros/src/syntax/parse/util.rs index 3fa51ef8..119129c0 100644 --- a/macros/src/syntax/parse/util.rs +++ b/macros/src/syntax/parse/util.rs @@ -3,8 +3,8 @@ use syn::{ parse::{self, ParseStream}, punctuated::Punctuated, spanned::Spanned, - Abi, AttrStyle, Attribute, Expr, FnArg, ForeignItemFn, Ident, ItemFn, Pat, PatType, Path, - PathArguments, ReturnType, Token, Type, Visibility, + Abi, AttrStyle, Attribute, Expr, FnArg, ForeignItemFn, Ident, ItemFn, Pat, Path, PathArguments, + ReturnType, Token, Type, Visibility, }; use crate::syntax::{ @@ -231,29 +231,23 @@ pub fn parse_local_resources(content: ParseStream<'_>) -> parse::Result<LocalRes Ok(resources) } -type ParseInputResult = Option<(Box<Pat>, Result<Vec<PatType>, FnArg>)>; - -pub fn parse_inputs(inputs: Punctuated<FnArg, Token![,]>, name: &str) -> ParseInputResult { +pub fn parse_inputs(inputs: Punctuated<FnArg, Token![,]>, name: &str) -> Option<Box<Pat>> { let mut inputs = inputs.into_iter(); match inputs.next() { Some(FnArg::Typed(first)) => { if type_is_path(&first.ty, &[name, "Context"]) { - let rest = inputs - .map(|arg| match arg { - FnArg::Typed(arg) => Ok(arg), - _ => Err(arg), - }) - .collect::<Result<Vec<_>, _>>(); - - Some((first.pat, rest)) - } else { - None + // No more inputs + if inputs.next().is_none() { + return Some(first.pat); + } } } - _ => None, + _ => {} } + + None } pub fn type_is_bottom(ty: &ReturnType) -> bool { |