aboutsummaryrefslogtreecommitdiff
path: root/macros/src/syntax.rs
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src/syntax.rs')
-rw-r--r--macros/src/syntax.rs1394
1 files changed, 0 insertions, 1394 deletions
diff --git a/macros/src/syntax.rs b/macros/src/syntax.rs
deleted file mode 100644
index 228d9588..00000000
--- a/macros/src/syntax.rs
+++ /dev/null
@@ -1,1394 +0,0 @@
-use std::{
- collections::{BTreeMap, BTreeSet},
- iter, u8,
-};
-
-use proc_macro2::Span;
-use syn::{
- braced, bracketed, parenthesized,
- parse::{self, Parse, ParseStream},
- punctuated::Punctuated,
- spanned::Spanned,
- token::Brace,
- ArgCaptured, AttrStyle, Attribute, Expr, FnArg, ForeignItem, Ident, IntSuffix, Item, ItemFn,
- ItemForeignMod, ItemStatic, LitInt, Path, PathArguments, PathSegment, ReturnType, Stmt, Token,
- Type, TypeTuple, Visibility,
-};
-
-pub struct AppArgs {
- pub device: Path,
-}
-
-impl Parse for AppArgs {
- fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
- let mut device = None;
- loop {
- if input.is_empty() {
- break;
- }
-
- // #ident = ..
- let ident: Ident = input.parse()?;
- let _eq_token: Token![=] = input.parse()?;
-
- let ident_s = ident.to_string();
- match &*ident_s {
- "device" => {
- if device.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- device = Some(input.parse()?);
- }
- _ => {
- return Err(parse::Error::new(
- ident.span(),
- "expected `device`; other keys are not accepted",
- ));
- }
- }
-
- if input.is_empty() {
- break;
- }
-
- // ,
- let _: Token![,] = input.parse()?;
- }
-
- Ok(AppArgs {
- device: device.ok_or(parse::Error::new(
- Span::call_site(),
- "`device` argument is required",
- ))?,
- })
- }
-}
-
-pub struct Input {
- _const_token: Token![const],
- _ident: Ident,
- _colon_token: Token![:],
- _ty: TypeTuple,
- _eq_token: Token![=],
- _brace_token: Brace,
- pub items: Vec<Item>,
- _semi_token: Token![;],
-}
-
-impl Parse for Input {
- fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
- fn parse_items(input: ParseStream<'_>) -> parse::Result<Vec<Item>> {
- let mut items = vec![];
-
- while !input.is_empty() {
- items.push(input.parse()?);
- }
-
- Ok(items)
- }
-
- let content;
- Ok(Input {
- _const_token: input.parse()?,
- _ident: input.parse()?,
- _colon_token: input.parse()?,
- _ty: input.parse()?,
- _eq_token: input.parse()?,
- _brace_token: braced!(content in input),
- items: content.call(parse_items)?,
- _semi_token: input.parse()?,
- })
- }
-}
-
-pub struct App {
- pub args: AppArgs,
- pub idle: Option<Idle>,
- pub init: Init,
- pub exceptions: Exceptions,
- pub interrupts: Interrupts,
- pub resources: Resources,
- pub tasks: Tasks,
- pub free_interrupts: FreeInterrupts,
-}
-
-impl App {
- pub fn parse(items: Vec<Item>, args: AppArgs) -> parse::Result<Self> {
- let mut idle = None;
- let mut init = None;
- let mut exceptions = BTreeMap::new();
- let mut interrupts = BTreeMap::new();
- let mut resources = BTreeMap::new();
- let mut tasks = BTreeMap::new();
- let mut free_interrupts = None;
-
- for item in items {
- match item {
- Item::Fn(mut item) => {
- if let Some(pos) = item.attrs.iter().position(|attr| eq(attr, "idle")) {
- if idle.is_some() {
- return Err(parse::Error::new(
- item.span(),
- "`#[idle]` function must appear at most once",
- ));
- }
-
- let args = syn::parse2(item.attrs.swap_remove(pos).tts)?;
-
- idle = Some(Idle::check(args, item)?);
- } else if let Some(pos) = item.attrs.iter().position(|attr| eq(attr, "init")) {
- if init.is_some() {
- return Err(parse::Error::new(
- item.span(),
- "`#[init]` function must appear exactly once",
- ));
- }
-
- let args = syn::parse2(item.attrs.swap_remove(pos).tts)?;
-
- init = Some(Init::check(args, item)?);
- } else if let Some(pos) =
- item.attrs.iter().position(|attr| eq(attr, "exception"))
- {
- if exceptions.contains_key(&item.ident)
- || interrupts.contains_key(&item.ident)
- || tasks.contains_key(&item.ident)
- {
- return Err(parse::Error::new(
- item.ident.span(),
- "this task is defined multiple times",
- ));
- }
-
- let args = syn::parse2(item.attrs.swap_remove(pos).tts)?;
-
- exceptions.insert(item.ident.clone(), Exception::check(args, item)?);
- } else if let Some(pos) =
- item.attrs.iter().position(|attr| eq(attr, "interrupt"))
- {
- if exceptions.contains_key(&item.ident)
- || interrupts.contains_key(&item.ident)
- || tasks.contains_key(&item.ident)
- {
- return Err(parse::Error::new(
- item.ident.span(),
- "this task is defined multiple times",
- ));
- }
-
- let args = syn::parse2(item.attrs.swap_remove(pos).tts)?;
-
- interrupts.insert(item.ident.clone(), Interrupt::check(args, item)?);
- } else if let Some(pos) = item.attrs.iter().position(|attr| eq(attr, "task")) {
- if exceptions.contains_key(&item.ident)
- || interrupts.contains_key(&item.ident)
- || tasks.contains_key(&item.ident)
- {
- return Err(parse::Error::new(
- item.ident.span(),
- "this task is defined multiple times",
- ));
- }
-
- let args = syn::parse2(item.attrs.swap_remove(pos).tts)?;
-
- tasks.insert(item.ident.clone(), Task::check(args, item)?);
- } else {
- return Err(parse::Error::new(
- item.span(),
- "this item must live outside the `#[app]` module",
- ));
- }
- }
- Item::Static(item) => {
- if resources.contains_key(&item.ident) {
- return Err(parse::Error::new(
- item.ident.span(),
- "this resource is listed twice",
- ));
- }
-
- resources.insert(item.ident.clone(), Resource::check(item)?);
- }
- Item::ForeignMod(item) => {
- if free_interrupts.is_some() {
- return Err(parse::Error::new(
- item.abi.extern_token.span(),
- "`extern` block can only appear at most once",
- ));
- }
-
- free_interrupts = Some(FreeInterrupt::parse(item)?);
- }
- _ => {
- return Err(parse::Error::new(
- item.span(),
- "this item must live outside the `#[app]` module",
- ));
- }
- }
- }
-
- Ok(App {
- args,
- idle,
- init: init.ok_or_else(|| {
- parse::Error::new(Span::call_site(), "`#[init]` function is missing")
- })?,
- exceptions,
- interrupts,
- resources,
- tasks,
- free_interrupts: free_interrupts.unwrap_or_else(|| FreeInterrupts::new()),
- })
- }
-
- /// Returns an iterator over all resource accesses.
- ///
- /// Each resource access include the priority it's accessed at (`u8`) and the name of the
- /// resource (`Ident`). A resource may appear more than once in this iterator
- pub fn resource_accesses(&self) -> impl Iterator<Item = (u8, &Ident)> {
- self.idle
- .as_ref()
- .map(|idle| -> Box<dyn Iterator<Item = _>> {
- Box::new(idle.args.resources.iter().map(|res| (0, res)))
- })
- .unwrap_or_else(|| Box::new(iter::empty()))
- .chain(self.exceptions.values().flat_map(|e| {
- e.args
- .resources
- .iter()
- .map(move |res| (e.args.priority, res))
- }))
- .chain(self.interrupts.values().flat_map(|i| {
- i.args
- .resources
- .iter()
- .map(move |res| (i.args.priority, res))
- }))
- .chain(self.tasks.values().flat_map(|t| {
- t.args
- .resources
- .iter()
- .map(move |res| (t.args.priority, res))
- }))
- }
-
- /// Returns an iterator over all `spawn` calls
- ///
- /// Each spawn call includes the priority of the task from which it's issued and the name of the
- /// task that's spawned. A task may appear more that once in this iterator.
- ///
- /// A priority of `None` means that this being called from `init`
- pub fn spawn_calls(&self) -> impl Iterator<Item = (Option<u8>, &Ident)> {
- self.init
- .args
- .spawn
- .iter()
- .map(|s| (None, s))
- .chain(
- self.idle
- .as_ref()
- .map(|idle| -> Box<dyn Iterator<Item = _>> {
- Box::new(idle.args.spawn.iter().map(|s| (Some(0), s)))
- })
- .unwrap_or_else(|| Box::new(iter::empty())),
- )
- .chain(
- self.exceptions
- .values()
- .flat_map(|e| e.args.spawn.iter().map(move |s| (Some(e.args.priority), s))),
- )
- .chain(
- self.interrupts
- .values()
- .flat_map(|i| i.args.spawn.iter().map(move |s| (Some(i.args.priority), s))),
- )
- .chain(
- self.tasks
- .values()
- .flat_map(|t| t.args.spawn.iter().map(move |s| (Some(t.args.priority), s))),
- )
- }
-
- /// Returns an iterator over all `schedule` calls
- ///
- /// Each spawn call includes the priority of the task from which it's issued and the name of the
- /// task that's spawned. A task may appear more that once in this iterator.
- #[allow(dead_code)]
- pub fn schedule_calls(&self) -> impl Iterator<Item = (Option<u8>, &Ident)> {
- self.init
- .args
- .schedule
- .iter()
- .map(|s| (None, s))
- .chain(
- self.idle
- .as_ref()
- .map(|idle| -> Box<dyn Iterator<Item = _>> {
- Box::new(idle.args.schedule.iter().map(|s| (Some(0), s)))
- })
- .unwrap_or_else(|| Box::new(iter::empty())),
- )
- .chain(self.exceptions.values().flat_map(|e| {
- e.args
- .schedule
- .iter()
- .map(move |s| (Some(e.args.priority), s))
- }))
- .chain(self.interrupts.values().flat_map(|i| {
- i.args
- .schedule
- .iter()
- .map(move |s| (Some(i.args.priority), s))
- }))
- .chain(self.tasks.values().flat_map(|t| {
- t.args
- .schedule
- .iter()
- .map(move |s| (Some(t.args.priority), s))
- }))
- }
-
- #[allow(dead_code)]
- pub fn schedule_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> {
- self.idle
- .as_ref()
- .map(|idle| -> Box<dyn Iterator<Item = _>> {
- Box::new(iter::once((
- Ident::new("idle", Span::call_site()),
- &idle.args.schedule,
- )))
- })
- .unwrap_or_else(|| Box::new(iter::empty()))
- .chain(iter::once((
- Ident::new("init", Span::call_site()),
- &self.init.args.schedule,
- )))
- .chain(
- self.exceptions
- .iter()
- .map(|(name, exception)| (name.clone(), &exception.args.schedule)),
- )
- .chain(
- self.interrupts
- .iter()
- .map(|(name, interrupt)| (name.clone(), &interrupt.args.schedule)),
- )
- .chain(
- self.tasks
- .iter()
- .map(|(name, task)| (name.clone(), &task.args.schedule)),
- )
- }
-
- pub fn spawn_callers(&self) -> impl Iterator<Item = (Ident, &Idents)> {
- self.idle
- .as_ref()
- .map(|idle| -> Box<dyn Iterator<Item = _>> {
- Box::new(iter::once((
- Ident::new("idle", Span::call_site()),
- &idle.args.spawn,
- )))
- })
- .unwrap_or_else(|| Box::new(iter::empty()))
- .chain(iter::once((
- Ident::new("init", Span::call_site()),
- &self.init.args.spawn,
- )))
- .chain(
- self.exceptions
- .iter()
- .map(|(name, exception)| (name.clone(), &exception.args.spawn)),
- )
- .chain(
- self.interrupts
- .iter()
- .map(|(name, interrupt)| (name.clone(), &interrupt.args.spawn)),
- )
- .chain(
- self.tasks
- .iter()
- .map(|(name, task)| (name.clone(), &task.args.spawn)),
- )
- }
-}
-
-pub type Idents = BTreeSet<Ident>;
-
-pub type Exceptions = BTreeMap<Ident, Exception>;
-
-pub type Interrupts = BTreeMap<Ident, Interrupt>;
-
-pub type Resources = BTreeMap<Ident, Resource>;
-
-pub type Statics = Vec<ItemStatic>;
-
-pub type Tasks = BTreeMap<Ident, Task>;
-
-pub type FreeInterrupts = BTreeMap<Ident, FreeInterrupt>;
-
-pub struct Idle {
- pub args: IdleArgs,
- pub attrs: Vec<Attribute>,
- pub unsafety: Option<Token![unsafe]>,
- pub statics: BTreeMap<Ident, Static>,
- pub stmts: Vec<Stmt>,
-}
-
-pub type IdleArgs = InitArgs;
-
-impl Idle {
- fn check(args: IdleArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = item.vis == Visibility::Inherited
- && item.constness.is_none()
- && item.asyncness.is_none()
- && item.abi.is_none()
- && item.decl.generics.params.is_empty()
- && item.decl.generics.where_clause.is_none()
- && item.decl.inputs.is_empty()
- && item.decl.variadic.is_none()
- && is_bottom(&item.decl.output);
-
- let span = item.span();
-
- if !valid_signature {
- return Err(parse::Error::new(
- span,
- "`idle` must have type signature `[unsafe] fn() -> !`",
- ));
- }
-
- let (statics, stmts) = extract_statics(item.block.stmts);
-
- Ok(Idle {
- args,
- attrs: item.attrs,
- unsafety: item.unsafety,
- statics: Static::parse(statics)?,
- stmts,
- })
- }
-}
-
-pub struct InitArgs {
- pub resources: Idents,
- pub schedule: Idents,
- pub spawn: Idents,
-}
-
-impl Default for InitArgs {
- fn default() -> Self {
- InitArgs {
- resources: Idents::new(),
- schedule: Idents::new(),
- spawn: Idents::new(),
- }
- }
-}
-
-impl Parse for InitArgs {
- fn parse(input: ParseStream<'_>) -> parse::Result<InitArgs> {
- if input.is_empty() {
- return Ok(InitArgs::default());
- }
-
- let mut resources = None;
- let mut schedule = None;
- let mut spawn = None;
-
- let content;
- parenthesized!(content in input);
- loop {
- if content.is_empty() {
- break;
- }
-
- // #ident = ..
- let ident: Ident = content.parse()?;
- let _: Token![=] = content.parse()?;
-
- let ident_s = ident.to_string();
- match &*ident_s {
- "schedule" if cfg!(not(feature = "timer-queue")) => {
- return Err(parse::Error::new(
- ident.span(),
- "The `schedule` API requires that the `timer-queue` feature is \
- enabled in the `cortex-m-rtfm` crate",
- ));
- }
- "resources" | "schedule" | "spawn" => {} // OK
- _ => {
- return Err(parse::Error::new(
- ident.span(),
- "expected one of: resources, schedule or spawn",
- ));
- }
- }
-
- // .. [#(#idents)*]
- let inner;
- bracketed!(inner in content);
- let mut idents = Idents::new();
- for ident in inner.call(Punctuated::<_, Token![,]>::parse_terminated)? {
- if idents.contains(&ident) {
- return Err(parse::Error::new(
- ident.span(),
- "element appears more than once in list",
- ));
- }
-
- idents.insert(ident);
- }
-
- let ident_s = ident.to_string();
- match &*ident_s {
- "resources" => {
- if resources.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- resources = Some(idents);
- }
- "schedule" => {
- if schedule.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- schedule = Some(idents);
- }
- "spawn" => {
- if spawn.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- spawn = Some(idents);
- }
- _ => unreachable!(),
- }
-
- if content.is_empty() {
- break;
- }
-
- // ,
- let _: Token![,] = content.parse()?;
- }
-
- Ok(InitArgs {
- resources: resources.unwrap_or(Idents::new()),
- schedule: schedule.unwrap_or(Idents::new()),
- spawn: spawn.unwrap_or(Idents::new()),
- })
- }
-}
-
-// TODO remove in v0.5.x
-pub struct Assign {
- pub attrs: Vec<Attribute>,
- pub left: Ident,
- pub right: Box<Expr>,
-}
-
-pub struct Init {
- pub args: InitArgs,
- pub attrs: Vec<Attribute>,
- pub unsafety: Option<Token![unsafe]>,
- pub statics: BTreeMap<Ident, Static>,
- pub stmts: Vec<Stmt>,
- // TODO remove in v0.5.x
- pub assigns: Vec<Assign>,
- pub returns_late_resources: bool,
-}
-
-impl Init {
- fn check(args: InitArgs, item: ItemFn) -> parse::Result<Self> {
- let mut valid_signature = item.vis == Visibility::Inherited
- && item.constness.is_none()
- && item.asyncness.is_none()
- && item.abi.is_none()
- && item.decl.generics.params.is_empty()
- && item.decl.generics.where_clause.is_none()
- && item.decl.inputs.is_empty()
- && item.decl.variadic.is_none();
-
- let returns_late_resources = match &item.decl.output {
- ReturnType::Default => false,
- ReturnType::Type(_, ty) => {
- match &**ty {
- Type::Tuple(t) => {
- if t.elems.is_empty() {
- // -> ()
- true
- } else {
- valid_signature = false;
-
- false // don't care
- }
- }
-
- Type::Path(p) => {
- let mut segments = p.path.segments.iter();
- if p.qself.is_none()
- && p.path.leading_colon.is_none()
- && p.path.segments.len() == 2
- && segments.next().map(|s| {
- s.arguments == PathArguments::None && s.ident.to_string() == "init"
- }) == Some(true)
- && segments.next().map(|s| {
- s.arguments == PathArguments::None
- && s.ident.to_string() == "LateResources"
- }) == Some(true)
- {
- // -> init::LateResources
- true
- } else {
- valid_signature = false;
-
- false // don't care
- }
- }
-
- _ => {
- valid_signature = false;
-
- false // don't care
- }
- }
- }
- };
-
- let span = item.span();
-
- if !valid_signature {
- return Err(parse::Error::new(
- span,
- "`init` must have type signature `[unsafe] fn() [-> init::LateResources]`",
- ));
- }
-
- let (statics, stmts) = extract_statics(item.block.stmts);
- let (stmts, assigns) = if returns_late_resources {
- (stmts, vec![])
- } else {
- extract_assignments(stmts)
- };
-
- Ok(Init {
- args,
- attrs: item.attrs,
- unsafety: item.unsafety,
- statics: Static::parse(statics)?,
- stmts,
- assigns,
- returns_late_resources,
- })
- }
-}
-
-/// Union of `TaskArgs`, `ExceptionArgs` and `InterruptArgs`
-pub struct Args {
- pub binds: Option<Ident>,
- pub capacity: Option<u8>,
- pub priority: u8,
- pub resources: Idents,
- pub schedule: Idents,
- pub spawn: Idents,
-}
-
-impl Default for Args {
- fn default() -> Self {
- Args {
- binds: None,
- capacity: None,
- priority: 1,
- resources: Idents::new(),
- schedule: Idents::new(),
- spawn: Idents::new(),
- }
- }
-}
-
-pub struct Exception {
- pub args: ExceptionArgs,
- pub attrs: Vec<Attribute>,
- pub unsafety: Option<Token![unsafe]>,
- pub statics: BTreeMap<Ident, Static>,
- pub stmts: Vec<Stmt>,
-}
-
-pub struct ExceptionArgs {
- binds: Option<Ident>,
- pub priority: u8,
- pub resources: Idents,
- pub schedule: Idents,
- pub spawn: Idents,
-}
-
-impl ExceptionArgs {
- /// Returns the name of the exception / interrupt this handler binds to
- pub fn binds<'a>(&'a self, handler: &'a Ident) -> &'a Ident {
- self.binds.as_ref().unwrap_or(handler)
- }
-}
-
-impl Parse for ExceptionArgs {
- fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
- parse_args(input, /* binds */ true, /* capacity */ false).map(
- |Args {
- binds,
- priority,
- resources,
- schedule,
- spawn,
- ..
- }| {
- ExceptionArgs {
- binds,
- priority,
- resources,
- schedule,
- spawn,
- }
- },
- )
- }
-}
-
-impl Exception {
- fn check(args: ExceptionArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = item.vis == Visibility::Inherited
- && item.constness.is_none()
- && item.asyncness.is_none()
- && item.abi.is_none()
- && item.decl.generics.params.is_empty()
- && item.decl.generics.where_clause.is_none()
- && item.decl.inputs.is_empty()
- && item.decl.variadic.is_none()
- && is_unit(&item.decl.output);
-
- if !valid_signature {
- return Err(parse::Error::new(
- item.span(),
- "`exception` handlers must have type signature `[unsafe] fn()`",
- ));
- }
-
- let span = item.ident.span();
- match &*args.binds.as_ref().unwrap_or(&item.ident).to_string() {
- "MemoryManagement" | "BusFault" | "UsageFault" | "SecureFault" | "SVCall"
- | "DebugMonitor" | "PendSV" => {} // OK
- "SysTick" => {
- if cfg!(feature = "timer-queue") {
- return Err(parse::Error::new(
- span,
- "the `SysTick` exception can't be used because it's used by \
- the runtime when the `timer-queue` feature is enabled",
- ));
- }
- }
- _ => {
- return Err(parse::Error::new(
- span,
- "only exceptions with configurable priority can be used as hardware tasks",
- ));
- }
- }
-
- let (statics, stmts) = extract_statics(item.block.stmts);
-
- Ok(Exception {
- args,
- attrs: item.attrs,
- unsafety: item.unsafety,
- statics: Static::parse(statics)?,
- stmts,
- })
- }
-}
-
-pub struct Interrupt {
- pub args: InterruptArgs,
- pub attrs: Vec<Attribute>,
- pub unsafety: Option<Token![unsafe]>,
- pub statics: BTreeMap<Ident, Static>,
- pub stmts: Vec<Stmt>,
-}
-
-pub type InterruptArgs = ExceptionArgs;
-
-impl Interrupt {
- fn check(args: InterruptArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = item.vis == Visibility::Inherited
- && item.constness.is_none()
- && item.asyncness.is_none()
- && item.abi.is_none()
- && item.decl.generics.params.is_empty()
- && item.decl.generics.where_clause.is_none()
- && item.decl.inputs.is_empty()
- && item.decl.variadic.is_none()
- && is_unit(&item.decl.output);
-
- let span = item.span();
-
- if !valid_signature {
- return Err(parse::Error::new(
- span,
- "`interrupt` handlers must have type signature `[unsafe] fn()`",
- ));
- }
-
- match &*item.ident.to_string() {
- "init" | "idle" | "resources" => {
- return Err(parse::Error::new(
- span,
- "`interrupt` handlers can NOT be named `idle`, `init` or `resources`",
- ));
- }
- _ => {}
- }
-
- let (statics, stmts) = extract_statics(item.block.stmts);
-
- Ok(Interrupt {
- args,
- attrs: item.attrs,
- unsafety: item.unsafety,
- statics: Static::parse(statics)?,
- stmts,
- })
- }
-}
-
-pub struct Resource {
- pub singleton: bool,
- pub cfgs: Vec<Attribute>,
- pub attrs: Vec<Attribute>,
- pub mutability: Option<Token![mut]>,
- pub ty: Box<Type>,
- pub expr: Option<Box<Expr>>,
-}
-
-impl Resource {
- fn check(mut item: ItemStatic) -> parse::Result<Resource> {
- if item.vis != Visibility::Inherited {
- return Err(parse::Error::new(
- item.span(),
- "resources must have inherited / private visibility",
- ));
- }
-
- let uninitialized = match *item.expr {
- Expr::Tuple(ref tuple) => tuple.elems.is_empty(),
- _ => false,
- };
-
- let pos = item.attrs.iter().position(|attr| eq(attr, "Singleton"));
-
- if let Some(pos) = pos {
- item.attrs[pos].path.segments.insert(
- 0,
- PathSegment::from(Ident::new("owned_singleton", Span::call_site())),
- );
- }
-
- let (cfgs, attrs) = extract_cfgs(item.attrs);
-
- Ok(Resource {
- singleton: pos.is_some(),
- cfgs,
- attrs,
- mutability: item.mutability,
- ty: item.ty,
- expr: if uninitialized { None } else { Some(item.expr) },
- })
- }
-}
-
-pub struct TaskArgs {
- pub capacity: Option<u8>,
- pub priority: u8,
- pub resources: Idents,
- pub spawn: Idents,
- pub schedule: Idents,
-}
-
-impl Parse for TaskArgs {
- fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
- parse_args(input, /* binds */ false, /* capacity */ true).map(
- |Args {
- capacity,
- priority,
- resources,
- schedule,
- spawn,
- ..
- }| {
- TaskArgs {
- capacity,
- priority,
- resources,
- schedule,
- spawn,
- }
- },
- )
- }
-}
-
-// Parser shared by ExceptionArgs, InterruptArgs and TaskArgs
-fn parse_args(
- input: ParseStream<'_>,
- accepts_binds: bool,
- accepts_capacity: bool,
-) -> parse::Result<Args> {
- if input.is_empty() {
- return Ok(Args::default());
- }
-
- let mut binds = None;
- let mut capacity = None;
- let mut priority = None;
- let mut resources = None;
- let mut schedule = None;
- let mut spawn = None;
-
- let content;
- parenthesized!(content in input);
- loop {
- if content.is_empty() {
- break;
- }
-
- // #ident = ..
- let ident: Ident = content.parse()?;
- let _: Token![=] = content.parse()?;
-
- let ident_s = ident.to_string();
- match &*ident_s {
- "binds" if accepts_binds => {
- if binds.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- // #ident
- let ident = content.parse()?;
-
- binds = Some(ident);
- }
- "capacity" if accepts_capacity => {
- if capacity.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- // #lit
- let lit: LitInt = content.parse()?;
-
- if lit.suffix() != IntSuffix::None {
- return Err(parse::Error::new(
- lit.span(),
- "this literal must be unsuffixed",
- ));
- }
-
- let value = lit.value();
- if value > u64::from(u8::MAX) || value == 0 {
- return Err(parse::Error::new(
- lit.span(),
- "this literal must be in the range 1...255",
- ));
- }
-
- capacity = Some(value as u8);
- }
- "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() != IntSuffix::None {
- return Err(parse::Error::new(
- lit.span(),
- "this literal must be unsuffixed",
- ));
- }
-
- let value = lit.value();
- if value > u64::from(u8::MAX) || value == 0 {
- return Err(parse::Error::new(
- lit.span(),
- "this literal must be in the range 1...255",
- ));
- }
-
- priority = Some(value as u8);
- }
- "schedule" if cfg!(not(feature = "timer-queue")) => {
- return Err(parse::Error::new(
- ident.span(),
- "The `schedule` API requires that the `timer-queue` feature is \
- enabled in the `cortex-m-rtfm` crate",
- ));
- }
- "resources" | "schedule" | "spawn" => {
- // .. [#(#idents)*]
- let inner;
- bracketed!(inner in content);
- let mut idents = Idents::new();
- for ident in inner.call(Punctuated::<_, Token![,]>::parse_terminated)? {
- if idents.contains(&ident) {
- return Err(parse::Error::new(
- ident.span(),
- "element appears more than once in list",
- ));
- }
-
- idents.insert(ident);
- }
-
- match &*ident_s {
- "resources" => {
- if resources.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- resources = Some(idents);
- }
- "schedule" => {
- if schedule.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- schedule = Some(idents);
- }
- "spawn" => {
- if spawn.is_some() {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- spawn = Some(idents);
- }
- _ => unreachable!(),
- }
- }
- _ => {
- return Err(parse::Error::new(
- ident.span(),
- format!(
- "expected one of: {}{}priority, resources, schedule or spawn",
- if accepts_binds { "binds, " } else { "" },
- if accepts_capacity { "capacity, " } else { "" },
- ),
- ));
- }
- }
-
- if content.is_empty() {
- break;
- }
-
- // ,
- let _: Token![,] = content.parse()?;
- }
-
- Ok(Args {
- binds,
- capacity,
- priority: priority.unwrap_or(1),
- resources: resources.unwrap_or(Idents::new()),
- schedule: schedule.unwrap_or(Idents::new()),
- spawn: spawn.unwrap_or(Idents::new()),
- })
-}
-
-pub struct Static {
- /// `#[cfg]` attributes
- pub cfgs: Vec<Attribute>,
- /// Attributes that are not `#[cfg]`
- pub attrs: Vec<Attribute>,
- pub ty: Box<Type>,
- pub expr: Box<Expr>,
-}
-
-impl Static {
- fn parse(items: Vec<ItemStatic>) -> parse::Result<BTreeMap<Ident, Static>> {
- let mut statics = BTreeMap::new();
-
- for item in items {
- if statics.contains_key(&item.ident) {
- return Err(parse::Error::new(
- item.ident.span(),
- "this `static` is listed twice",
- ));
- }
-
- let (cfgs, attrs) = extract_cfgs(item.attrs);
-
- statics.insert(
- item.ident,
- Static {
- cfgs,
- attrs,
- ty: item.ty,
- expr: item.expr,
- },
- );
- }
-
- Ok(statics)
- }
-}
-
-pub struct Task {
- pub args: TaskArgs,
- pub cfgs: Vec<Attribute>,
- pub attrs: Vec<Attribute>,
- pub unsafety: Option<Token![unsafe]>,
- pub inputs: Vec<ArgCaptured>,
- pub statics: BTreeMap<Ident, Static>,
- pub stmts: Vec<Stmt>,
-}
-
-impl Task {
- fn check(args: TaskArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = item.vis == Visibility::Inherited
- && item.constness.is_none()
- && item.asyncness.is_none()
- && item.abi.is_none()
- && item.decl.generics.params.is_empty()
- && item.decl.generics.where_clause.is_none()
- && item.decl.variadic.is_none()
- && is_unit(&item.decl.output);
-
- let span = item.span();
-
- if !valid_signature {
- return Err(parse::Error::new(
- span,
- "`task` handlers must have type signature `[unsafe] fn(..)`",
- ));
- }
-
- let (statics, stmts) = extract_statics(item.block.stmts);
-
- let mut inputs = vec![];
- for input in item.decl.inputs {
- if let FnArg::Captured(capture) = input {
- inputs.push(capture);
- } else {
- return Err(parse::Error::new(
- span,
- "inputs must be named arguments (e.f. `foo: u32`) and not include `self`",
- ));
- }
- }
-
- match &*item.ident.to_string() {
- "init" | "idle" | "resources" => {
- return Err(parse::Error::new(
- span,
- "`task` handlers can NOT be named `idle`, `init` or `resources`",
- ));
- }
- _ => {}
- }
-
- let (cfgs, attrs) = extract_cfgs(item.attrs);
- Ok(Task {
- args,
- cfgs,
- attrs,
- unsafety: item.unsafety,
- inputs,
- statics: Static::parse(statics)?,
- stmts,
- })
- }
-}
-
-pub struct FreeInterrupt {
- pub attrs: Vec<Attribute>,
-}
-
-impl FreeInterrupt {
- fn parse(mod_: ItemForeignMod) -> parse::Result<FreeInterrupts> {
- let mut free_interrupts = FreeInterrupts::new();
-
- for item in mod_.items {
- if let ForeignItem::Fn(f) = item {
- let valid_signature = f.vis == Visibility::Inherited
- && f.decl.generics.params.is_empty()
- && f.decl.generics.where_clause.is_none()
- && f.decl.inputs.is_empty()
- && f.decl.variadic.is_none()
- && is_unit(&f.decl.output);
-
- if !valid_signature {
- return Err(parse::Error::new(
- f.span(),
- "free interrupts must have type signature `fn()`",
- ));
- }
-
- if free_interrupts.contains_key(&f.ident) {
- return Err(parse::Error::new(
- f.ident.span(),
- "this interrupt appears twice",
- ));
- }
-
- free_interrupts.insert(f.ident, FreeInterrupt { attrs: f.attrs });
- } else {
- return Err(parse::Error::new(
- mod_.abi.extern_token.span(),
- "`extern` block should only contains functions",
- ));
- }
- }
-
- Ok(free_interrupts)
- }
-}
-
-fn eq(attr: &Attribute, name: &str) -> bool {
- attr.style == AttrStyle::Outer && attr.path.segments.len() == 1 && {
- let pair = attr.path.segments.first().unwrap();
- let segment = pair.value();
- segment.arguments == PathArguments::None && segment.ident.to_string() == name
- }
-}
-
-fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
- let mut cfgs = vec![];
- let mut not_cfgs = vec![];
-
- for attr in attrs {
- if eq(&attr, "cfg") {
- cfgs.push(attr);
- } else {
- not_cfgs.push(attr);
- }
- }
-
- (cfgs, not_cfgs)
-}
-
-/// Extracts `static mut` vars from the beginning of the given statements
-fn extract_statics(stmts: Vec<Stmt>) -> (Statics, Vec<Stmt>) {
- let mut istmts = stmts.into_iter();
-
- let mut statics = Statics::new();
- let mut stmts = vec![];
- while let Some(stmt) = istmts.next() {
- match stmt {
- Stmt::Item(Item::Static(var)) => {
- if var.mutability.is_some() {
- statics.push(var);
- } else {
- stmts.push(Stmt::Item(Item::Static(var)));
- break;
- }
- }
- _ => {
- stmts.push(stmt);
- break;
- }
- }
- }
-
- stmts.extend(istmts);
-
- (statics, stmts)
-}
-
-// TODO remove in v0.5.x
-fn extract_assignments(stmts: Vec<Stmt>) -> (Vec<Stmt>, Vec<Assign>) {
- let mut istmts = stmts.into_iter().rev();
-
- let mut assigns = vec![];
- let mut stmts = vec![];
- while let Some(stmt) = istmts.next() {
- match stmt {
- Stmt::Semi(Expr::Assign(assign), semi) => {
- if let Expr::Path(ref expr) = *assign.left {
- if expr.path.segments.len() == 1 {
- assigns.push(Assign {
- attrs: assign.attrs,
- left: expr.path.segments[0].ident.clone(),
- right: assign.right,
- });
- continue;
- }
- }
-
- stmts.push(Stmt::Semi(Expr::Assign(assign), semi));
- }
- _ => {
- stmts.push(stmt);
- break;
- }
- }
- }
-
- stmts.extend(istmts);
-
- (stmts.into_iter().rev().collect(), assigns)
-}
-
-fn is_bottom(ty: &ReturnType) -> bool {
- if let ReturnType::Type(_, ty) = ty {
- if let Type::Never(_) = **ty {
- true
- } else {
- false
- }
- } else {
- false
- }
-}
-
-fn is_unit(ty: &ReturnType) -> bool {
- if let ReturnType::Type(_, ty) = ty {
- if let Type::Tuple(ref tuple) = **ty {
- tuple.elems.is_empty()
- } else {
- false
- }
- } else {
- true
- }
-}