aboutsummaryrefslogtreecommitdiff
path: root/rtic-macros/src/syntax/parse.rs
diff options
context:
space:
mode:
authorGravatar bors[bot] <26634292+bors[bot]@users.noreply.github.com> 2023-03-04 21:10:24 +0000
committerGravatar GitHub <noreply@github.com> 2023-03-04 21:10:24 +0000
commit7c7d6558f6d9c50fbb4d2487c98c9a5be15f2f7b (patch)
tree80a47f0dc40059014e9448c4c2eb34c54dff45fe /rtic-macros/src/syntax/parse.rs
parent1c5db277e4161470136dbd2a11e914ff1d383581 (diff)
parent98c5490d94950608d31cd5ad9dd260f2f853735c (diff)
downloadrtic-7c7d6558f6d9c50fbb4d2487c98c9a5be15f2f7b.tar.gz
rtic-7c7d6558f6d9c50fbb4d2487c98c9a5be15f2f7b.tar.zst
rtic-7c7d6558f6d9c50fbb4d2487c98c9a5be15f2f7b.zip
Merge #694
694: RTIC 2 r=AfoHT a=korken89 Co-authored-by: Emil Fresk <emil.fresk@gmail.com> Co-authored-by: Per Lindgren <per.lindgren@ltu.se>
Diffstat (limited to 'rtic-macros/src/syntax/parse.rs')
-rw-r--r--rtic-macros/src/syntax/parse.rs319
1 files changed, 319 insertions, 0 deletions
diff --git a/rtic-macros/src/syntax/parse.rs b/rtic-macros/src/syntax/parse.rs
new file mode 100644
index 00000000..72eeeaf6
--- /dev/null
+++ b/rtic-macros/src/syntax/parse.rs
@@ -0,0 +1,319 @@
+mod app;
+mod hardware_task;
+mod idle;
+mod init;
+mod resource;
+mod software_task;
+mod util;
+
+use proc_macro2::TokenStream as TokenStream2;
+use syn::{
+ braced, parenthesized,
+ parse::{self, Parse, ParseStream, Parser},
+ token::Brace,
+ Ident, Item, LitInt, Token,
+};
+
+use crate::syntax::{
+ ast::{App, AppArgs, HardwareTaskArgs, IdleArgs, InitArgs, SoftwareTaskArgs, TaskLocal},
+ Either,
+};
+
+// Parse the app, both app arguments and body (input)
+pub fn app(args: TokenStream2, input: TokenStream2) -> parse::Result<App> {
+ let args = AppArgs::parse(args)?;
+ let input: Input = syn::parse2(input)?;
+
+ App::parse(args, input)
+}
+
+pub(crate) struct Input {
+ _mod_token: Token![mod],
+ pub ident: Ident,
+ _brace_token: Brace,
+ pub items: Vec<Item>,
+}
+
+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;
+
+ let _mod_token = input.parse()?;
+ let ident = input.parse()?;
+ let _brace_token = braced!(content in input);
+ let items = content.call(parse_items)?;
+
+ Ok(Input {
+ _mod_token,
+ ident,
+ _brace_token,
+ items,
+ })
+ }
+}
+
+fn init_args(tokens: TokenStream2) -> parse::Result<InitArgs> {
+ (|input: ParseStream<'_>| -> parse::Result<InitArgs> {
+ if input.is_empty() {
+ return Ok(InitArgs::default());
+ }
+
+ let mut local_resources = None;
+
+ 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() {
+ "local" => {
+ if local_resources.is_some() {
+ return Err(parse::Error::new(
+ ident.span(),
+ "argument appears more than once",
+ ));
+ }
+
+ local_resources = Some(util::parse_local_resources(&content)?);
+ }
+ _ => {
+ return Err(parse::Error::new(ident.span(), "unexpected argument"));
+ }
+ }
+
+ if content.is_empty() {
+ break;
+ }
+ // Handle comma: ,
+ let _: Token![,] = content.parse()?;
+ }
+ }
+
+ if let Some(locals) = &local_resources {
+ for (ident, task_local) in locals {
+ if let TaskLocal::External = task_local {
+ return Err(parse::Error::new(
+ ident.span(),
+ "only declared local resources are allowed in init",
+ ));
+ }
+ }
+ }
+
+ Ok(InitArgs {
+ local_resources: local_resources.unwrap_or_default(),
+ })
+ })
+ .parse2(tokens)
+}
+
+fn idle_args(tokens: TokenStream2) -> parse::Result<IdleArgs> {
+ (|input: ParseStream<'_>| -> parse::Result<IdleArgs> {
+ if input.is_empty() {
+ return Ok(IdleArgs::default());
+ }
+
+ let mut shared_resources = None;
+ let mut local_resources = None;
+
+ 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() {
+ "shared" => {
+ if shared_resources.is_some() {
+ return Err(parse::Error::new(
+ ident.span(),
+ "argument appears more than once",
+ ));
+ }
+
+ shared_resources = Some(util::parse_shared_resources(&content)?);
+ }
+
+ "local" => {
+ if local_resources.is_some() {
+ return Err(parse::Error::new(
+ ident.span(),
+ "argument appears more than once",
+ ));
+ }
+
+ local_resources = Some(util::parse_local_resources(&content)?);
+ }
+
+ _ => {
+ return Err(parse::Error::new(ident.span(), "unexpected argument"));
+ }
+ }
+ if content.is_empty() {
+ break;
+ }
+
+ // Handle comma: ,
+ let _: Token![,] = content.parse()?;
+ }
+ }
+
+ Ok(IdleArgs {
+ shared_resources: shared_resources.unwrap_or_default(),
+ local_resources: local_resources.unwrap_or_default(),
+ })
+ })
+ .parse2(tokens)
+}
+
+fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, SoftwareTaskArgs>> {
+ (|input: ParseStream<'_>| -> parse::Result<Either<HardwareTaskArgs, SoftwareTaskArgs>> {
+ if input.is_empty() {
+ return Ok(Either::Right(SoftwareTaskArgs::default()));
+ }
+
+ let mut binds = None;
+ let mut priority = None;
+ let mut shared_resources = None;
+ let mut local_resources = None;
+ let mut prio_span = None;
+
+ let content;
+ parenthesized!(content in input);
+ loop {
+ if content.is_empty() {
+ break;
+ }
+
+ // Parse identifier name
+ let ident: Ident = content.parse()?;
+ let ident_s = ident.to_string();
+
+ // Handle equal sign
+ let _: Token![=] = content.parse()?;
+
+ match &*ident_s {
+ "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() {
+ return Err(parse::Error::new(
+ lit.span(),
+ "this literal must be in the range 0...255",
+ ));
+ }
+
+ prio_span = Some(lit.span());
+ priority = Some(value.unwrap());
+ }
+
+ "shared" => {
+ if shared_resources.is_some() {
+ return Err(parse::Error::new(
+ ident.span(),
+ "argument appears more than once",
+ ));
+ }
+
+ shared_resources = Some(util::parse_shared_resources(&content)?);
+ }
+
+ "local" => {
+ if local_resources.is_some() {
+ return Err(parse::Error::new(
+ ident.span(),
+ "argument appears more than once",
+ ));
+ }
+
+ local_resources = Some(util::parse_local_resources(&content)?);
+ }
+
+ _ => {
+ return Err(parse::Error::new(ident.span(), "unexpected argument"));
+ }
+ }
+
+ if content.is_empty() {
+ break;
+ }
+
+ // Handle comma: ,
+ let _: Token![,] = content.parse()?;
+ }
+ let priority = priority.unwrap_or(1);
+ let shared_resources = shared_resources.unwrap_or_default();
+ let local_resources = local_resources.unwrap_or_default();
+
+ Ok(if let Some(binds) = binds {
+ if priority == 0 {
+ return Err(parse::Error::new(
+ prio_span.unwrap(),
+ "hardware tasks are not allowed to be at priority 0",
+ ));
+ }
+
+ Either::Left(HardwareTaskArgs {
+ binds,
+ priority,
+ shared_resources,
+ local_resources,
+ })
+ } else {
+ Either::Right(SoftwareTaskArgs {
+ priority,
+ shared_resources,
+ local_resources,
+ })
+ })
+ })
+ .parse2(tokens)
+}