aboutsummaryrefslogtreecommitdiff
path: root/macros/src/syntax/parse
diff options
context:
space:
mode:
authorGravatar Emil Fresk <emil.fresk@gmail.com> 2023-01-23 20:05:47 +0100
committerGravatar Henrik Tjäder <henrik@tjaders.com> 2023-03-01 00:33:31 +0100
commit306aa47170fd59369b7a184924e287dc3706d64d (patch)
tree75a331a63a4021f078e330bf2ce4edb1228e2ecf /macros/src/syntax/parse
parentb8b881f446a226d6f3c4a7db7c9174590b47dbf6 (diff)
downloadrtic-306aa47170fd59369b7a184924e287dc3706d64d.tar.gz
rtic-306aa47170fd59369b7a184924e287dc3706d64d.tar.zst
rtic-306aa47170fd59369b7a184924e287dc3706d64d.zip
Add rtic-timer (timerqueue + monotonic) and rtic-monotonics (systick-monotonic)
Diffstat (limited to 'macros/src/syntax/parse')
-rw-r--r--macros/src/syntax/parse/app.rs480
-rw-r--r--macros/src/syntax/parse/hardware_task.rs76
-rw-r--r--macros/src/syntax/parse/idle.rs42
-rw-r--r--macros/src/syntax/parse/init.rs51
-rw-r--r--macros/src/syntax/parse/resource.rs55
-rw-r--r--macros/src/syntax/parse/software_task.rs76
-rw-r--r--macros/src/syntax/parse/util.rs338
7 files changed, 0 insertions, 1118 deletions
diff --git a/macros/src/syntax/parse/app.rs b/macros/src/syntax/parse/app.rs
deleted file mode 100644
index e797f75e..00000000
--- a/macros/src/syntax/parse/app.rs
+++ /dev/null
@@ -1,480 +0,0 @@
-use std::collections::HashSet;
-
-// use indexmap::map::Entry;
-use proc_macro2::TokenStream as TokenStream2;
-use syn::{
- parse::{self, ParseStream, Parser},
- spanned::Spanned,
- 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, SharedResource, SoftwareTask,
- },
- parse::{self as syntax_parse, util},
- Either, Map, Set,
-};
-
-impl AppArgs {
- pub(crate) fn parse(tokens: TokenStream2) -> parse::Result<Self> {
- (|input: ParseStream<'_>| -> parse::Result<Self> {
- let mut custom = Set::new();
- let mut device = None;
- let mut peripherals = true;
- let mut dispatchers = Dispatchers::new();
-
- loop {
- if input.is_empty() {
- break;
- }
-
- // #ident = ..
- let ident: Ident = input.parse()?;
- let _eq_token: Token![=] = input.parse()?;
-
- if custom.contains(&ident) {
- return Err(parse::Error::new(
- ident.span(),
- "argument appears more than once",
- ));
- }
-
- custom.insert(ident.clone());
-
- let ks = ident.to_string();
-
- match &*ks {
- "device" => {
- if let Ok(p) = input.parse::<Path>() {
- device = Some(p);
- } else {
- return Err(parse::Error::new(
- ident.span(),
- "unexpected argument value; this should be a path",
- ));
- }
- }
-
- "peripherals" => {
- if let Ok(p) = input.parse::<LitBool>() {
- peripherals = p.value;
- } else {
- return Err(parse::Error::new(
- ident.span(),
- "unexpected argument value; this should be a boolean",
- ));
- }
- }
-
- "dispatchers" => {
- if let Ok(p) = input.parse::<ExprArray>() {
- for e in p.elems {
- match e {
- Expr::Path(ep) => {
- let path = ep.path;
- let ident = if path.leading_colon.is_some()
- || path.segments.len() != 1
- {
- return Err(parse::Error::new(
- path.span(),
- "interrupt must be an identifier, not a path",
- ));
- } else {
- path.segments[0].ident.clone()
- };
- let span = ident.span();
- if dispatchers.contains_key(&ident) {
- return Err(parse::Error::new(
- span,
- "this extern interrupt is listed more than once",
- ));
- } else {
- dispatchers
- .insert(ident, Dispatcher { attrs: ep.attrs });
- }
- }
- _ => {
- return Err(parse::Error::new(
- e.span(),
- "interrupt must be an identifier",
- ));
- }
- }
- }
- } else {
- return Err(parse::Error::new(
- ident.span(),
- // increasing the length of the error message will break rustfmt
- "unexpected argument value; expected an array",
- ));
- }
- }
- _ => {
- return Err(parse::Error::new(ident.span(), "unexpected argument"));
- }
- }
-
- if input.is_empty() {
- break;
- }
-
- // ,
- let _: Token![,] = input.parse()?;
- }
-
- let device = if let Some(device) = device {
- device
- } else {
- return Err(parse::Error::new(input.span(), "missing `device = ...`"));
- };
-
- Ok(AppArgs {
- device,
- peripherals,
- dispatchers,
- })
- })
- .parse2(tokens)
- }
-}
-
-impl App {
- pub(crate) fn parse(args: AppArgs, input: Input) -> parse::Result<Self> {
- let mut init = None;
- let mut idle = None;
-
- let mut shared_resources_ident = None;
- let mut shared_resources = Map::new();
- let mut local_resources_ident = None;
- let mut local_resources = Map::new();
- let mut hardware_tasks = Map::new();
- let mut software_tasks = Map::new();
- let mut user_imports = vec![];
- let mut user_code = vec![];
-
- let mut seen_idents = HashSet::<Ident>::new();
- let mut bindings = HashSet::<Ident>::new();
-
- let mut check_binding = |ident: &Ident| {
- if bindings.contains(ident) {
- return Err(parse::Error::new(
- ident.span(),
- "this interrupt is already bound",
- ));
- } else {
- bindings.insert(ident.clone());
- }
-
- Ok(())
- };
-
- let mut check_ident = |ident: &Ident| {
- if seen_idents.contains(ident) {
- return Err(parse::Error::new(
- ident.span(),
- "this identifier has already been used",
- ));
- } else {
- seen_idents.insert(ident.clone());
- }
-
- 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)?;
-
- // If an init function already exists, error
- if init.is_some() {
- return Err(parse::Error::new(
- span,
- "`#[init]` function must appear at most once",
- ));
- }
-
- check_ident(&item.sig.ident)?;
-
- init = Some(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)?;
-
- // If an idle function already exists, error
- if idle.is_some() {
- return Err(parse::Error::new(
- span,
- "`#[idle]` function must appear at most once",
- ));
- }
-
- check_ident(&item.sig.ident)?;
-
- idle = Some(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",
- ));
- }
-
- match syntax_parse::task_args(item.attrs.remove(pos).tokens)? {
- Either::Left(args) => {
- check_binding(&args.binds)?;
- check_ident(&item.sig.ident)?;
-
- hardware_tasks.insert(
- item.sig.ident.clone(),
- HardwareTask::parse(args, item)?,
- );
- }
-
- Either::Right(args) => {
- check_ident(&item.sig.ident)?;
-
- software_tasks.insert(
- item.sig.ident.clone(),
- SoftwareTask::parse(args, item)?,
- );
- }
- }
- } else {
- // Forward normal functions
- user_code.push(Item::Fn(item.clone()));
- }
- }
-
- Item::Struct(ref mut struct_item) => {
- // Match structures with the attribute #[shared], name of structure is not
- // important
- if let Some(_pos) = struct_item
- .attrs
- .iter()
- .position(|attr| util::attr_eq(attr, "shared"))
- {
- let span = struct_item.ident.span();
-
- shared_resources_ident = Some(struct_item.ident.clone());
-
- if !shared_resources.is_empty() {
- return Err(parse::Error::new(
- span,
- "`#[shared]` 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 let Fields::Named(fields) = &mut struct_item.fields {
- for field in &mut fields.named {
- let ident = field.ident.as_ref().expect("UNREACHABLE");
-
- if shared_resources.contains_key(ident) {
- return Err(parse::Error::new(
- ident.span(),
- "this resource is listed more than once",
- ));
- }
-
- shared_resources.insert(
- ident.clone(),
- SharedResource::parse(field, ident.span())?,
- );
- }
- } else {
- return Err(parse::Error::new(
- struct_item.span(),
- "this `struct` must have named fields",
- ));
- }
- } else if let Some(_pos) = struct_item
- .attrs
- .iter()
- .position(|attr| util::attr_eq(attr, "local"))
- {
- let span = struct_item.ident.span();
-
- local_resources_ident = Some(struct_item.ident.clone());
-
- if !local_resources.is_empty() {
- return Err(parse::Error::new(
- span,
- "`#[local]` 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 let Fields::Named(fields) = &mut struct_item.fields {
- for field in &mut fields.named {
- let ident = field.ident.as_ref().expect("UNREACHABLE");
-
- if local_resources.contains_key(ident) {
- return Err(parse::Error::new(
- ident.span(),
- "this resource is listed more than once",
- ));
- }
-
- local_resources.insert(
- ident.clone(),
- LocalResource::parse(field, ident.span())?,
- );
- }
- } else {
- return Err(parse::Error::new(
- struct_item.span(),
- "this `struct` must have named fields",
- ));
- }
- } else {
- // Structure without the #[resources] attribute should just be passed along
- user_code.push(item.clone());
- }
- }
-
- Item::ForeignMod(mod_) => {
- if !util::abi_is_rust(&mod_.abi) {
- return Err(parse::Error::new(
- mod_.abi.extern_token.span(),
- "this `extern` block must use the \"Rust\" ABI",
- ));
- }
-
- for item in mod_.items {
- if let ForeignItem::Fn(mut item) = item {
- let span = item.sig.ident.span();
- 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",
- ));
- }
-
- if item.attrs.len() != 1 {
- return Err(parse::Error::new(
- span,
- "`extern` task required `#[task(..)]` attribute",
- ));
- }
-
- match syntax_parse::task_args(item.attrs.remove(pos).tokens)? {
- Either::Left(args) => {
- check_binding(&args.binds)?;
- check_ident(&item.sig.ident)?;
-
- hardware_tasks.insert(
- item.sig.ident.clone(),
- HardwareTask::parse_foreign(args, item)?,
- );
- }
-
- Either::Right(args) => {
- check_ident(&item.sig.ident)?;
-
- software_tasks.insert(
- item.sig.ident.clone(),
- SoftwareTask::parse_foreign(args, item)?,
- );
- }
- }
- } else {
- return Err(parse::Error::new(
- span,
- "`extern` task required `#[task(..)]` attribute",
- ));
- }
- } else {
- return Err(parse::Error::new(
- item.span(),
- "this item must live outside the `#[app]` module",
- ));
- }
- }
- }
- Item::Use(itemuse_) => {
- // Store the user provided use-statements
- user_imports.push(itemuse_.clone());
- }
- _ => {
- // Anything else within the module should not make any difference
- user_code.push(item.clone());
- }
- }
- }
-
- let shared_resources_ident =
- shared_resources_ident.expect("No `#[shared]` resource struct defined");
- let local_resources_ident =
- local_resources_ident.expect("No `#[local]` resource struct defined");
- let init = init.expect("No `#[init]` function defined");
-
- if shared_resources_ident != init.user_shared_struct {
- return Err(parse::Error::new(
- init.user_shared_struct.span(),
- format!(
- "This name and the one defined on `#[shared]` are not the same. Should this be `{shared_resources_ident}`?"
- ),
- ));
- }
-
- if local_resources_ident != init.user_local_struct {
- return Err(parse::Error::new(
- init.user_local_struct.span(),
- format!(
- "This name and the one defined on `#[local]` are not the same. Should this be `{local_resources_ident}`?"
- ),
- ));
- }
-
- Ok(App {
- args,
- name: input.ident,
- init,
- idle,
- shared_resources,
- local_resources,
- user_imports,
- user_code,
- hardware_tasks,
- software_tasks,
- })
- }
-}
diff --git a/macros/src/syntax/parse/hardware_task.rs b/macros/src/syntax/parse/hardware_task.rs
deleted file mode 100644
index 7f6dfbe4..00000000
--- a/macros/src/syntax/parse/hardware_task.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use syn::{parse, ForeignItemFn, ItemFn, Stmt};
-
-use crate::syntax::parse::util::FilterAttrs;
-use crate::syntax::{
- ast::{HardwareTask, HardwareTaskArgs},
- parse::util,
-};
-
-impl HardwareTask {
- pub(crate) fn parse(args: HardwareTaskArgs, item: ItemFn) -> parse::Result<Self> {
- let span = item.sig.ident.span();
- let valid_signature = util::check_fn_signature(&item, false)
- && item.sig.inputs.len() == 1
- && util::type_is_unit(&item.sig.output);
-
- 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() {
- let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs);
-
- return Ok(HardwareTask {
- args,
- cfgs,
- attrs,
- context,
- stmts: item.block.stmts,
- is_extern: false,
- });
- }
- }
- }
-
- Err(parse::Error::new(
- span,
- format!("this task handler must have type signature `fn({name}::Context)`"),
- ))
- }
-}
-
-impl HardwareTask {
- pub(crate) fn parse_foreign(
- args: HardwareTaskArgs,
- item: ForeignItemFn,
- ) -> parse::Result<Self> {
- let span = item.sig.ident.span();
- let valid_signature = util::check_foreign_fn_signature(&item, false)
- && item.sig.inputs.len() == 1
- && util::type_is_unit(&item.sig.output);
-
- 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() {
- let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs);
-
- return Ok(HardwareTask {
- args,
- cfgs,
- attrs,
- context,
- stmts: Vec::<Stmt>::new(),
- is_extern: true,
- });
- }
- }
- }
-
- Err(parse::Error::new(
- span,
- format!("this task handler must have type signature `fn({name}::Context)`"),
- ))
- }
-}
diff --git a/macros/src/syntax/parse/idle.rs b/macros/src/syntax/parse/idle.rs
deleted file mode 100644
index 124c1366..00000000
--- a/macros/src/syntax/parse/idle.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use proc_macro2::TokenStream as TokenStream2;
-use syn::{parse, ItemFn};
-
-use crate::syntax::{
- ast::{Idle, IdleArgs},
- parse::util,
-};
-
-impl IdleArgs {
- pub(crate) fn parse(tokens: TokenStream2) -> parse::Result<Self> {
- crate::syntax::parse::idle_args(tokens)
- }
-}
-
-impl Idle {
- pub(crate) fn parse(args: IdleArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = util::check_fn_signature(&item, false)
- && item.sig.inputs.len() == 1
- && util::type_is_bottom(&item.sig.output);
-
- 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,
- });
- }
- }
- }
-
- Err(parse::Error::new(
- item.sig.ident.span(),
- format!("this `#[idle]` function must have signature `fn({name}::Context) -> !`"),
- ))
- }
-}
diff --git a/macros/src/syntax/parse/init.rs b/macros/src/syntax/parse/init.rs
deleted file mode 100644
index 0aea20bd..00000000
--- a/macros/src/syntax/parse/init.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use proc_macro2::TokenStream as TokenStream2;
-
-use syn::{parse, ItemFn};
-
-use crate::syntax::{
- ast::{Init, InitArgs},
- parse::{self as syntax_parse, util},
-};
-
-impl InitArgs {
- pub(crate) fn parse(tokens: TokenStream2) -> parse::Result<Self> {
- syntax_parse::init_args(tokens)
- }
-}
-
-impl Init {
- pub(crate) fn parse(args: InitArgs, item: ItemFn) -> parse::Result<Self> {
- let valid_signature = util::check_fn_signature(&item, false) && item.sig.inputs.len() == 1;
-
- let span = item.sig.ident.span();
-
- let name = item.sig.ident.to_string();
-
- if valid_signature {
- if let Ok((user_shared_struct, user_local_struct)) =
- util::type_is_init_return(&item.sig.output)
- {
- 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,
- });
- }
- }
- }
- }
-
- Err(parse::Error::new(
- span,
- format!(
- "the `#[init]` function must have signature `fn({name}::Context) -> (Shared resources struct, Local resources struct)`"
- ),
- ))
- }
-}
diff --git a/macros/src/syntax/parse/resource.rs b/macros/src/syntax/parse/resource.rs
deleted file mode 100644
index ff100576..00000000
--- a/macros/src/syntax/parse/resource.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use proc_macro2::Span;
-use syn::{parse, Field, Visibility};
-
-use crate::syntax::parse::util::FilterAttrs;
-use crate::syntax::{
- ast::{LocalResource, SharedResource, SharedResourceProperties},
- parse::util,
-};
-
-impl SharedResource {
- pub(crate) fn parse(item: &Field, span: Span) -> parse::Result<Self> {
- if item.vis != Visibility::Inherited {
- return Err(parse::Error::new(
- span,
- "this field must have inherited / private visibility",
- ));
- }
-
- let FilterAttrs {
- cfgs,
- mut attrs,
- docs,
- } = util::filter_attributes(item.attrs.clone());
-
- let lock_free = util::extract_lock_free(&mut attrs)?;
-
- Ok(SharedResource {
- cfgs,
- attrs,
- docs,
- ty: Box::new(item.ty.clone()),
- properties: SharedResourceProperties { lock_free },
- })
- }
-}
-
-impl LocalResource {
- pub(crate) fn parse(item: &Field, span: Span) -> parse::Result<Self> {
- if item.vis != Visibility::Inherited {
- return Err(parse::Error::new(
- span,
- "this field must have inherited / private visibility",
- ));
- }
-
- let FilterAttrs { cfgs, attrs, docs } = util::filter_attributes(item.attrs.clone());
-
- Ok(LocalResource {
- cfgs,
- attrs,
- docs,
- ty: Box::new(item.ty.clone()),
- })
- }
-}
diff --git a/macros/src/syntax/parse/software_task.rs b/macros/src/syntax/parse/software_task.rs
deleted file mode 100644
index 769aa653..00000000
--- a/macros/src/syntax/parse/software_task.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-use syn::{parse, ForeignItemFn, ItemFn, Stmt};
-
-use crate::syntax::parse::util::FilterAttrs;
-use crate::syntax::{
- ast::{SoftwareTask, SoftwareTaskArgs},
- parse::util,
-};
-
-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)
- && item.sig.asyncness.is_some();
-
- let span = item.sig.ident.span();
-
- let name = item.sig.ident.to_string();
-
- if valid_signature {
- if let Some((context, Ok(inputs))) = util::parse_inputs(item.sig.inputs, &name) {
- let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs);
-
- return Ok(SoftwareTask {
- args,
- attrs,
- cfgs,
- context,
- inputs,
- stmts: item.block.stmts,
- is_extern: false,
- });
- }
- }
-
- Err(parse::Error::new(
- span,
- format!("this task handler must have type signature `async fn({name}::Context, ..)`"),
- ))
- }
-}
-
-impl SoftwareTask {
- pub(crate) fn parse_foreign(
- args: SoftwareTaskArgs,
- item: ForeignItemFn,
- ) -> parse::Result<Self> {
- 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();
-
- if valid_signature {
- if let Some((context, Ok(inputs))) = util::parse_inputs(item.sig.inputs, &name) {
- let FilterAttrs { cfgs, attrs, .. } = util::filter_attributes(item.attrs);
-
- return Ok(SoftwareTask {
- args,
- attrs,
- cfgs,
- context,
- inputs,
- stmts: Vec::<Stmt>::new(),
- is_extern: true,
- });
- }
- }
-
- Err(parse::Error::new(
- span,
- format!("this task handler must have type signature `async fn({name}::Context, ..)`"),
- ))
- }
-}
diff --git a/macros/src/syntax/parse/util.rs b/macros/src/syntax/parse/util.rs
deleted file mode 100644
index 5a5e0c0e..00000000
--- a/macros/src/syntax/parse/util.rs
+++ /dev/null
@@ -1,338 +0,0 @@
-use syn::{
- bracketed,
- parse::{self, ParseStream},
- punctuated::Punctuated,
- spanned::Spanned,
- Abi, AttrStyle, Attribute, Expr, FnArg, ForeignItemFn, Ident, ItemFn, Pat, PatType, Path,
- PathArguments, ReturnType, Token, Type, Visibility,
-};
-
-use crate::syntax::{
- ast::{Access, Local, LocalResources, SharedResources, TaskLocal},
- Map,
-};
-
-pub fn abi_is_rust(abi: &Abi) -> bool {
- match &abi.name {
- None => true,
- Some(s) => s.value() == "Rust",
- }
-}
-
-pub fn attr_eq(attr: &Attribute, name: &str) -> bool {
- attr.style == AttrStyle::Outer && attr.path.segments.len() == 1 && {
- let segment = attr.path.segments.first().unwrap();
- segment.arguments == PathArguments::None && *segment.ident.to_string() == *name
- }
-}
-
-/// checks that a function signature
-///
-/// - has no bounds (like where clauses)
-/// - is not `async`
-/// - is not `const`
-/// - is not `unsafe`
-/// - 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, allow_async: bool) -> bool {
- item.vis == Visibility::Inherited
- && item.sig.constness.is_none()
- && (item.sig.asyncness.is_none() || allow_async)
- && item.sig.abi.is_none()
- && item.sig.unsafety.is_none()
- && item.sig.generics.params.is_empty()
- && item.sig.generics.where_clause.is_none()
- && item.sig.variadic.is_none()
-}
-
-#[allow(dead_code)]
-pub fn check_foreign_fn_signature(item: &ForeignItemFn, allow_async: bool) -> bool {
- item.vis == Visibility::Inherited
- && item.sig.constness.is_none()
- && (item.sig.asyncness.is_none() || allow_async)
- && item.sig.abi.is_none()
- && item.sig.unsafety.is_none()
- && item.sig.generics.params.is_empty()
- && item.sig.generics.where_clause.is_none()
- && item.sig.variadic.is_none()
-}
-
-pub struct FilterAttrs {
- pub cfgs: Vec<Attribute>,
- pub docs: Vec<Attribute>,
- pub attrs: Vec<Attribute>,
-}
-
-pub fn filter_attributes(input_attrs: Vec<Attribute>) -> FilterAttrs {
- let mut cfgs = vec![];
- let mut docs = vec![];
- let mut attrs = vec![];
-
- for attr in input_attrs {
- if attr_eq(&attr, "cfg") {
- cfgs.push(attr);
- } else if attr_eq(&attr, "doc") {
- docs.push(attr);
- } else {
- attrs.push(attr);
- }
- }
-
- FilterAttrs { cfgs, docs, attrs }
-}
-
-pub fn extract_lock_free(attrs: &mut Vec<Attribute>) -> parse::Result<bool> {
- if let Some(pos) = attrs.iter().position(|attr| attr_eq(attr, "lock_free")) {
- attrs.remove(pos);
- Ok(true)
- } else {
- Ok(false)
- }
-}
-
-pub fn parse_shared_resources(content: ParseStream<'_>) -> parse::Result<SharedResources> {
- let inner;
- bracketed!(inner in content);
-
- let mut resources = Map::new();
- for e in inner.call(Punctuated::<Expr, Token![,]>::parse_terminated)? {
- let err = Err(parse::Error::new(
- e.span(),
- "identifier appears more than once in list",
- ));
- let (access, path) = match e {
- Expr::Path(e) => (Access::Exclusive, e.path),
-
- Expr::Reference(ref r) if r.mutability.is_none() => match &*r.expr {
- Expr::Path(e) => (Access::Shared, e.path.clone()),
-
- _ => return err,
- },
-
- _ => return err,
- };
-
- let ident = extract_resource_name_ident(path)?;
-
- if resources.contains_key(&ident) {
- return Err(parse::Error::new(
- ident.span(),
- "resource appears more than once in list",
- ));
- }
-
- resources.insert(ident, access);
- }
-
- Ok(resources)
-}
-
-fn extract_resource_name_ident(path: Path) -> parse::Result<Ident> {
- if path.leading_colon.is_some()
- || path.segments.len() != 1
- || path.segments[0].arguments != PathArguments::None
- {
- Err(parse::Error::new(
- path.span(),
- "resource must be an identifier, not a path",
- ))
- } else {
- Ok(path.segments[0].ident.clone())
- }
-}
-
-pub fn parse_local_resources(content: ParseStream<'_>) -> parse::Result<LocalResources> {
- let inner;
- bracketed!(inner in content);
-
- let mut resources = Map::new();
-
- for e in inner.call(Punctuated::<Expr, Token![,]>::parse_terminated)? {
- let err = Err(parse::Error::new(
- e.span(),
- "identifier appears more than once in list",
- ));
-
- let (name, local) = match e {
- // local = [IDENT],
- Expr::Path(path) => {
- if !path.attrs.is_empty() {
- return Err(parse::Error::new(
- path.span(),
- "attributes are not supported here",
- ));
- }
-
- let ident = extract_resource_name_ident(path.path)?;
- // let (cfgs, attrs) = extract_cfgs(path.attrs);
-
- (ident, TaskLocal::External)
- }
-
- // local = [IDENT: TYPE = EXPR]
- Expr::Assign(e) => {
- let (name, ty, cfgs, attrs) = match *e.left {
- Expr::Type(t) => {
- // Extract name and attributes
- let (name, cfgs, attrs) = match *t.expr {
- Expr::Path(path) => {
- let name = extract_resource_name_ident(path.path)?;
- let FilterAttrs { cfgs, attrs, .. } = filter_attributes(path.attrs);
-
- (name, cfgs, attrs)
- }
- _ => return err,
- };
-
- let ty = t.ty;
-
- // Error check
- match &*ty {
- Type::Array(_) => {}
- Type::Path(_) => {}
- Type::Ptr(_) => {}
- Type::Tuple(_) => {}
- _ => return Err(parse::Error::new(
- ty.span(),
- "unsupported type, must be an array, tuple, pointer or type path",
- )),
- };
-
- (name, ty, cfgs, attrs)
- }
- e => return Err(parse::Error::new(e.span(), "malformed, expected a type")),
- };
-
- let expr = e.right; // Expr
-
- (
- name,
- TaskLocal::Declared(Local {
- attrs,
- cfgs,
- ty,
- expr,
- }),
- )
- }
-
- expr => {
- return Err(parse::Error::new(
- expr.span(),
- "malformed, expected 'IDENT: TYPE = EXPR'",
- ))
- }
- };
-
- resources.insert(name, local);
- }
-
- Ok(resources)
-}
-
-type ParseInputResult = Option<(Box<Pat>, Result<Vec<PatType>, FnArg>)>;
-
-pub fn parse_inputs(inputs: Punctuated<FnArg, Token![,]>, name: &str) -> ParseInputResult {
- 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
- }
- }
-
- _ => None,
- }
-}
-
-pub fn type_is_bottom(ty: &ReturnType) -> bool {
- if let ReturnType::Type(_, ty) = ty {
- matches!(**ty, Type::Never(_))
- } else {
- false
- }
-}
-
-fn extract_init_resource_name_ident(ty: Type) -> Result<Ident, ()> {
- match ty {
- Type::Path(path) => {
- let path = path.path;
-
- if path.leading_colon.is_some()
- || path.segments.len() != 1
- || path.segments[0].arguments != PathArguments::None
- {
- Err(())
- } else {
- Ok(path.segments[0].ident.clone())
- }
- }
- _ => Err(()),
- }
-}
-
-/// Checks Init's return type, return the user provided types for analysis
-pub fn type_is_init_return(ty: &ReturnType) -> Result<(Ident, Ident), ()> {
- match ty {
- ReturnType::Default => Err(()),
-
- ReturnType::Type(_, ty) => match &**ty {
- Type::Tuple(t) => {
- // return should be:
- // fn -> (User's #[shared] struct, User's #[local] struct)
- //
- // We check the length and the last one here, analysis checks that the user
- // provided structs are correct.
- if t.elems.len() == 2 {
- return Ok((
- extract_init_resource_name_ident(t.elems[0].clone())?,
- extract_init_resource_name_ident(t.elems[1].clone())?,
- ));
- }
-
- Err(())
- }
-
- _ => Err(()),
- },
- }
-}
-
-pub fn type_is_path(ty: &Type, segments: &[&str]) -> bool {
- match ty {
- Type::Path(tpath) if tpath.qself.is_none() => {
- tpath.path.segments.len() == segments.len()
- && tpath
- .path
- .segments
- .iter()
- .zip(segments)
- .all(|(lhs, rhs)| lhs.ident == **rhs)
- }
-
- _ => false,
- }
-}
-
-pub fn type_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
- }
-}