aboutsummaryrefslogtreecommitdiff
path: root/rtic-macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'rtic-macros/src')
-rw-r--r--rtic-macros/src/codegen/local_resources.rs5
-rw-r--r--rtic-macros/src/codegen/shared_resources.rs5
-rw-r--r--rtic-macros/src/syntax/parse.rs53
-rw-r--r--rtic-macros/src/syntax/parse/app.rs25
-rw-r--r--rtic-macros/src/syntax/parse/init.rs3
-rw-r--r--rtic-macros/src/syntax/parse/util.rs193
6 files changed, 171 insertions, 113 deletions
diff --git a/rtic-macros/src/codegen/local_resources.rs b/rtic-macros/src/codegen/local_resources.rs
index e6d1553..c73ad56 100644
--- a/rtic-macros/src/codegen/local_resources.rs
+++ b/rtic-macros/src/codegen/local_resources.rs
@@ -19,7 +19,10 @@ pub fn codegen(app: &App, _analysis: &Analysis) -> TokenStream2 {
// late resources in `util::link_section_uninit`
// unless user specifies custom link section
- let section = if attrs.iter().any(|attr| attr.path.is_ident("link_section")) {
+ let section = if attrs
+ .iter()
+ .any(|attr| attr.path().is_ident("link_section"))
+ {
None
} else {
Some(util::link_section_uninit())
diff --git a/rtic-macros/src/codegen/shared_resources.rs b/rtic-macros/src/codegen/shared_resources.rs
index 686c280..d89f0c2 100644
--- a/rtic-macros/src/codegen/shared_resources.rs
+++ b/rtic-macros/src/codegen/shared_resources.rs
@@ -19,7 +19,10 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
// late resources in `util::link_section_uninit`
// unless user specifies custom link section
- let section = if attrs.iter().any(|attr| attr.path.is_ident("link_section")) {
+ let section = if attrs
+ .iter()
+ .any(|attr| attr.path().is_ident("link_section"))
+ {
None
} else {
Some(util::link_section_uninit())
diff --git a/rtic-macros/src/syntax/parse.rs b/rtic-macros/src/syntax/parse.rs
index 823bd82..aae8a50 100644
--- a/rtic-macros/src/syntax/parse.rs
+++ b/rtic-macros/src/syntax/parse.rs
@@ -8,7 +8,7 @@ mod util;
use proc_macro2::TokenStream as TokenStream2;
use syn::{
- braced, parenthesized,
+ braced,
parse::{self, Parse, ParseStream, Parser},
token::Brace,
Ident, Item, LitInt, Token,
@@ -70,15 +70,12 @@ fn init_args(tokens: TokenStream2) -> parse::Result<InitArgs> {
let mut local_resources = None;
- let content;
- parenthesized!(content in input);
-
- if !content.is_empty() {
+ if !input.is_empty() {
loop {
// Parse identifier name
- let ident: Ident = content.parse()?;
+ let ident: Ident = input.parse()?;
// Handle equal sign
- let _: Token![=] = content.parse()?;
+ let _: Token![=] = input.parse()?;
match &*ident.to_string() {
"local" => {
@@ -89,18 +86,18 @@ fn init_args(tokens: TokenStream2) -> parse::Result<InitArgs> {
));
}
- local_resources = Some(util::parse_local_resources(&content)?);
+ local_resources = Some(util::parse_local_resources(input)?);
}
_ => {
return Err(parse::Error::new(ident.span(), "unexpected argument"));
}
}
- if content.is_empty() {
+ if input.is_empty() {
break;
}
// Handle comma: ,
- let _: Token![,] = content.parse()?;
+ let _: Token![,] = input.parse()?;
}
}
@@ -131,14 +128,12 @@ fn idle_args(tokens: TokenStream2) -> parse::Result<IdleArgs> {
let mut shared_resources = None;
let mut local_resources = None;
- let content;
- parenthesized!(content in input);
- if !content.is_empty() {
+ if !input.is_empty() {
loop {
// Parse identifier name
- let ident: Ident = content.parse()?;
+ let ident: Ident = input.parse()?;
// Handle equal sign
- let _: Token![=] = content.parse()?;
+ let _: Token![=] = input.parse()?;
match &*ident.to_string() {
"shared" => {
@@ -149,7 +144,7 @@ fn idle_args(tokens: TokenStream2) -> parse::Result<IdleArgs> {
));
}
- shared_resources = Some(util::parse_shared_resources(&content)?);
+ shared_resources = Some(util::parse_shared_resources(input)?);
}
"local" => {
@@ -160,19 +155,19 @@ fn idle_args(tokens: TokenStream2) -> parse::Result<IdleArgs> {
));
}
- local_resources = Some(util::parse_local_resources(&content)?);
+ local_resources = Some(util::parse_local_resources(input)?);
}
_ => {
return Err(parse::Error::new(ident.span(), "unexpected argument"));
}
}
- if content.is_empty() {
+ if input.is_empty() {
break;
}
// Handle comma: ,
- let _: Token![,] = content.parse()?;
+ let _: Token![,] = input.parse()?;
}
}
@@ -196,19 +191,17 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
let mut local_resources = None;
let mut prio_span = None;
- let content;
- parenthesized!(content in input);
loop {
- if content.is_empty() {
+ if input.is_empty() {
break;
}
// Parse identifier name
- let ident: Ident = content.parse()?;
+ let ident: Ident = input.parse()?;
let ident_s = ident.to_string();
// Handle equal sign
- let _: Token![=] = content.parse()?;
+ let _: Token![=] = input.parse()?;
match &*ident_s {
"binds" => {
@@ -220,7 +213,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
}
// Parse identifier name
- let ident = content.parse()?;
+ let ident = input.parse()?;
binds = Some(ident);
}
@@ -234,7 +227,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
}
// #lit
- let lit: LitInt = content.parse()?;
+ let lit: LitInt = input.parse()?;
if !lit.suffix().is_empty() {
return Err(parse::Error::new(
@@ -263,7 +256,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
));
}
- shared_resources = Some(util::parse_shared_resources(&content)?);
+ shared_resources = Some(util::parse_shared_resources(input)?);
}
"local" => {
@@ -274,7 +267,7 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
));
}
- local_resources = Some(util::parse_local_resources(&content)?);
+ local_resources = Some(util::parse_local_resources(input)?);
}
_ => {
@@ -282,12 +275,12 @@ fn task_args(tokens: TokenStream2) -> parse::Result<Either<HardwareTaskArgs, Sof
}
}
- if content.is_empty() {
+ if input.is_empty() {
break;
}
// Handle comma: ,
- let _: Token![,] = content.parse()?;
+ let _: Token![,] = input.parse()?;
}
let shared_resources = shared_resources.unwrap_or_default();
let local_resources = local_resources.unwrap_or_default();
diff --git a/rtic-macros/src/syntax/parse/app.rs b/rtic-macros/src/syntax/parse/app.rs
index d75c8c6..efcafbe 100644
--- a/rtic-macros/src/syntax/parse/app.rs
+++ b/rtic-macros/src/syntax/parse/app.rs
@@ -198,7 +198,9 @@ impl App {
.iter()
.position(|attr| util::attr_eq(attr, "init"))
{
- let args = InitArgs::parse(item.attrs.remove(pos).tokens)?;
+ let args = InitArgs::parse(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )?;
// If an init function already exists, error
if init.is_some() {
@@ -216,7 +218,9 @@ impl App {
.iter()
.position(|attr| util::attr_eq(attr, "idle"))
{
- let args = IdleArgs::parse(item.attrs.remove(pos).tokens)?;
+ let args = IdleArgs::parse(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )?;
// If an idle function already exists, error
if idle.is_some() {
@@ -243,7 +247,9 @@ impl App {
));
}
- match syntax_parse::task_args(item.attrs.remove(pos).tokens)? {
+ match syntax_parse::task_args(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )? {
Either::Left(args) => {
check_binding(&args.binds)?;
check_ident(&item.sig.ident)?;
@@ -369,8 +375,9 @@ impl App {
.iter()
.position(|attr| util::attr_eq(attr, "init"))
{
- let args = InitArgs::parse(item.attrs.remove(pos).tokens)?;
-
+ let args = InitArgs::parse(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )?;
// If an init function already exists, error
if init.is_some() {
return Err(parse::Error::new(
@@ -387,7 +394,9 @@ impl App {
.iter()
.position(|attr| util::attr_eq(attr, "idle"))
{
- let args = IdleArgs::parse(item.attrs.remove(pos).tokens)?;
+ let args = IdleArgs::parse(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )?;
// If an idle function already exists, error
if idle.is_some() {
@@ -421,7 +430,9 @@ impl App {
));
}
- match syntax_parse::task_args(item.attrs.remove(pos).tokens)? {
+ match syntax_parse::task_args(
+ item.attrs.remove(pos).parse_args().unwrap_or_default(),
+ )? {
Either::Left(args) => {
check_binding(&args.binds)?;
check_ident(&item.sig.ident)?;
diff --git a/rtic-macros/src/syntax/parse/init.rs b/rtic-macros/src/syntax/parse/init.rs
index 59d0093..e96d5f9 100644
--- a/rtic-macros/src/syntax/parse/init.rs
+++ b/rtic-macros/src/syntax/parse/init.rs
@@ -1,5 +1,4 @@
-use proc_macro2::TokenStream as TokenStream2;
-
+use crate::syntax::TokenStream2;
use syn::{parse, ForeignItemFn, ItemFn, Stmt};
use crate::syntax::{
diff --git a/rtic-macros/src/syntax/parse/util.rs b/rtic-macros/src/syntax/parse/util.rs
index 5a5e0c0..44d9759 100644
--- a/rtic-macros/src/syntax/parse/util.rs
+++ b/rtic-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, ExprPath, FnArg, ForeignItemFn, Ident, ItemFn, Pat, PatType,
+ Path, PathArguments, ReturnType, Token, Type, Visibility,
};
use crate::syntax::{
@@ -20,8 +20,8 @@ pub fn abi_is_rust(abi: &Abi) -> bool {
}
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();
+ 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
}
}
@@ -143,91 +143,140 @@ fn extract_resource_name_ident(path: Path) -> parse::Result<Ident> {
}
pub fn parse_local_resources(content: ParseStream<'_>) -> parse::Result<LocalResources> {
- let inner;
- bracketed!(inner in content);
+ let input;
+ bracketed!(input 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 error_msg_no_local_resources =
+ "malformed, expected 'local = [EXPRPATH: TYPE = EXPR]', or 'local = [EXPRPATH, ...]'";
- 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",
- ));
- }
+ loop {
+ if input.is_empty() {
+ break;
+ }
+ // Type ascription is de-RFCd from Rust in
+ // https://github.com/rust-lang/rfcs/pull/3307
+ // Manually pull out the tokens
+
+ // Two acceptable variants:
+ //
+ // Task local and declared (initialized in place)
+ // local = [EXPRPATH: TYPE = EXPR, ...]
+ // ~~~~~~~~~~~~~~~~~~~~~~
+ // or
+ // Task local but not initialized
+ // local = [EXPRPATH, ...],
+ // ~~~~~~~~~
+
+ // Common: grab first identifier EXPRPATH
+ // local = [EXPRPATH: TYPE = EXPR, ...]
+ // ~~~~~~~~
+ let exprpath: ExprPath = input.parse()?;
+
+ let name = extract_resource_name_ident(exprpath.path)?;
+
+ // Extract attributes
+ let ExprPath { attrs, .. } = exprpath;
+ let (cfgs, attrs) = {
+ let FilterAttrs { cfgs, attrs, .. } = filter_attributes(attrs);
+ (cfgs, attrs)
+ };
- let ident = extract_resource_name_ident(path.path)?;
- // let (cfgs, attrs) = extract_cfgs(path.attrs);
+ let local;
- (ident, TaskLocal::External)
+ // Declared requries type ascription
+ if input.peek(Token![:]) {
+ // Handle colon
+ let _: Token![:] = input.parse()?;
+
+ // Extract the type
+ let ty: Box<Type> = input.parse()?;
+
+ if input.peek(Token![=]) {
+ // Handle equal sign
+ let _: Token![=] = input.parse()?;
+ } else {
+ return Err(parse::Error::new(
+ name.span(),
+ "malformed, expected 'IDENT: TYPE = EXPR'",
+ ));
}
- // 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,
- }),
- )
+ // Grab the final expression right of equal
+ let expr: Box<Expr> = input.parse()?;
+
+ // We got a trailing colon, remove it
+ if input.peek(Token![,]) {
+ let _: Token![,] = input.parse()?;
}
- expr => {
+ // 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",
+ ))
+ }
+ };
+
+ local = TaskLocal::Declared(Local {
+ attrs,
+ cfgs,
+ ty,
+ expr,
+ });
+ } else if input.peek(Token![=]) {
+ // Missing type ascription is not valid
+ return Err(parse::Error::new(name.span(), "malformed, expected a type"));
+ } else if input.peek(Token![,]) {
+ // Attributes not supported on non-initialized local resources!
+
+ if !attrs.is_empty() {
return Err(parse::Error::new(
- expr.span(),
- "malformed, expected 'IDENT: TYPE = EXPR'",
- ))
+ name.span(),
+ "attributes are not supported here",
+ ));
}
+
+ // Remove comma
+ let _: Token![,] = input.parse()?;
+
+ // Expected when multiple local resources
+ local = TaskLocal::External;
+ } else if input.is_empty() {
+ // There was only one single local resource
+ // Task local but not initialized
+ // local = [EXPRPATH],
+ // ~~~~~~~~
+ local = TaskLocal::External;
+ } else {
+ // Specifying local without any resources is invalid
+ return Err(parse::Error::new(name.span(), error_msg_no_local_resources));
};
+ if resources.contains_key(&name) {
+ return Err(parse::Error::new(
+ name.span(),
+ "resource appears more than once in list",
+ ));
+ }
+
resources.insert(name, local);
}
+ if resources.is_empty() {
+ return Err(parse::Error::new(
+ input.span(),
+ error_msg_no_local_resources,
+ ));
+ }
+
Ok(resources)
}