aboutsummaryrefslogtreecommitdiff
path: root/macros/src/syntax/parse/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'macros/src/syntax/parse/app.rs')
-rw-r--r--macros/src/syntax/parse/app.rs480
1 files changed, 0 insertions, 480 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,
- })
- }
-}