diff options
author | 2018-04-08 18:23:27 +0200 | |
---|---|---|
committer | 2018-04-16 21:32:29 +0200 | |
commit | 7fdf16eab948ea04c1e56fdb5a704ed88780f5c6 (patch) | |
tree | a7438c2353382d5d46a391a1a81f7d05f9e83d65 /macros/src | |
parent | b55581dfe35040a4fdc93a1f38c1e1769d4d2535 (diff) | |
download | rtic-7fdf16eab948ea04c1e56fdb5a704ed88780f5c6.tar.gz rtic-7fdf16eab948ea04c1e56fdb5a704ed88780f5c6.tar.zst rtic-7fdf16eab948ea04c1e56fdb5a704ed88780f5c6.zip |
update parser
closes #69
this doesn't change functionality per se but improves diagnostics in some cases. Some hard errors
have becomes warnings, for example: when `resources` is empty, or when `idle.path` is set to the
default `idle` path.
Diffstat (limited to 'macros/src')
-rw-r--r-- | macros/src/analyze.rs | 2 | ||||
-rw-r--r-- | macros/src/check.rs | 91 | ||||
-rw-r--r-- | macros/src/lib.rs | 21 | ||||
-rw-r--r-- | macros/src/trans.rs | 46 |
4 files changed, 44 insertions, 116 deletions
diff --git a/macros/src/analyze.rs b/macros/src/analyze.rs index 65d98e69..666dc306 100644 --- a/macros/src/analyze.rs +++ b/macros/src/analyze.rs @@ -40,7 +40,7 @@ pub fn app(app: &App) -> Ownerships { } for task in app.tasks.values() { - for resource in &task.resources { + for resource in task.resources.iter() { if let Some(ownership) = ownerships.get_mut(resource) { match *ownership { Ownership::Owned { priority } => { diff --git a/macros/src/check.rs b/macros/src/check.rs index f6fd9cc6..4defb46d 100644 --- a/macros/src/check.rs +++ b/macros/src/check.rs @@ -1,10 +1,8 @@ use std::collections::HashMap; use syn::{Ident, Path}; -use syntax::check::{self, Idle, Init}; -use syntax::{self, Resources, Statics}; - -use syntax::error::*; +use syntax::check::{self, Idents, Idle, Init, Statics}; +use syntax::{self, Result}; pub struct App { pub device: Path, @@ -51,7 +49,7 @@ pub struct Task { pub kind: Kind, pub path: Path, pub priority: u8, - pub resources: Resources, + pub resources: Idents, } pub fn app(app: check::App) -> Result<App> { @@ -63,80 +61,16 @@ pub fn app(app: check::App) -> Result<App> { tasks: app.tasks .into_iter() .map(|(k, v)| { - let v = - ::check::task(k.as_ref(), v).chain_err(|| format!("checking task `{}`", k))?; + let v = ::check::task(k.as_ref(), v)?; Ok((k, v)) }) .collect::<Result<_>>()?, }; - ::check::resources(&app).chain_err(|| "checking `resources`")?; - Ok(app) } -fn resources(app: &App) -> Result<()> { - for name in &app.init.resources { - if let Some(resource) = app.resources.get(name) { - ensure!( - resource.expr.is_some(), - "resource `{}`, allocated to `init`, must have an initial value", - name - ); - } else { - bail!( - "resource `{}`, allocated to `init`, must be a data resource", - name - ); - } - - ensure!( - !app.idle.resources.contains(name), - "resources assigned to `init` can't be shared with `idle`" - ); - - ensure!( - app.tasks - .iter() - .all(|(_, task)| !task.resources.contains(name)), - "resources assigned to `init` can't be shared with tasks" - ) - } - - for resource in app.resources.keys() { - if app.init.resources.contains(resource) { - continue; - } - - if app.idle.resources.contains(resource) { - continue; - } - - if app.tasks - .values() - .any(|task| task.resources.contains(resource)) - { - continue; - } - - bail!("resource `{}` is unused", resource); - } - - for (name, task) in &app.tasks { - for resource in &task.resources { - ensure!( - app.resources.contains_key(&resource), - "task {} contains an undeclared resource with name {}", - name, - resource - ); - } - } - - Ok(()) -} - fn task(name: &str, task: syntax::check::Task) -> Result<Task> { let kind = match Exception::from(name) { Some(e) => { @@ -147,23 +81,14 @@ fn task(name: &str, task: syntax::check::Task) -> Result<Task> { Kind::Exception(e) } - None => { - if task.enabled == Some(true) { - bail!( - "`enabled: true` is the default value; this line can be \ - omitted" - ); - } - - Kind::Interrupt { - enabled: task.enabled.unwrap_or(true), - } - } + None => Kind::Interrupt { + enabled: task.enabled.unwrap_or(true), + }, }; Ok(Task { kind, - path: task.path.ok_or("`path` field is missing")?, + path: task.path, priority: task.priority.unwrap_or(1), resources: task.resources, }) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index c45646c2..728e6133 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,19 +1,19 @@ //! Procedural macros of the `cortex-m-rtfm` crate -#![deny(warnings)] +// #![deny(warnings)] #![feature(proc_macro)] #![recursion_limit = "128"] #[macro_use] -extern crate error_chain; +extern crate failure; extern crate proc_macro; +extern crate proc_macro2; +extern crate syn; #[macro_use] extern crate quote; extern crate rtfm_syntax as syntax; -extern crate syn; use proc_macro::TokenStream; -use syntax::App; -use syntax::error::*; +use syntax::{App, Result}; mod analyze; mod check; @@ -170,22 +170,17 @@ mod trans; #[proc_macro] pub fn app(ts: TokenStream) -> TokenStream { match run(ts) { - Err(e) => panic!("{}", error_chain::ChainedError::display(&e)), + Err(e) => panic!("error: {}", e), Ok(ts) => ts, } } fn run(ts: TokenStream) -> Result<TokenStream> { - let input = format!("{}", ts); - - let app = App::parse(&input).chain_err(|| "parsing")?; - let app = syntax::check::app(app).chain_err(|| "checking the AST")?; + let app = App::parse(ts)?.check()?; let app = check::app(app)?; let ownerships = analyze::app(&app); let tokens = trans::app(&app, &ownerships); - Ok(format!("{}", tokens) - .parse() - .map_err(|_| "BUG: error parsing the generated code")?) + Ok(tokens.into()) } diff --git a/macros/src/trans.rs b/macros/src/trans.rs index 42f7487d..964b1a30 100644 --- a/macros/src/trans.rs +++ b/macros/src/trans.rs @@ -1,5 +1,6 @@ -use quote::{Ident, Tokens}; -use syn::{Lit, StrStyle}; +use proc_macro2::Span; +use quote::Tokens; +use syn::{Ident, LitStr}; use analyze::Ownerships; use check::{App, Kind}; @@ -10,12 +11,12 @@ fn krate() -> Ident { pub fn app(app: &App, ownerships: &Ownerships) -> Tokens { let mut root = vec![]; - let mut main = vec![]; + let mut main = vec![quote!(#![allow(path_statements)])]; + ::trans::tasks(app, ownerships, &mut root, &mut main); ::trans::init(app, &mut main, &mut root); ::trans::idle(app, ownerships, &mut main, &mut root); ::trans::resources(app, ownerships, &mut root); - ::trans::tasks(app, ownerships, &mut root); root.push(quote! { #[allow(unsafe_code)] @@ -53,7 +54,7 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V let super_ = if needs_reexport { None } else { - Some(Ident::new("super")) + Some(Ident::from("super")) }; let mut rexprs = vec![]; let mut rfields = vec![]; @@ -69,7 +70,7 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V pub #name: &'static mut #ty, }); - let _name = Ident::new(format!("_{}", name.as_ref())); + let _name = Ident::from(format!("_{}", name.as_ref())); rexprs.push(if resource.expr.is_some() { quote! { #name: &mut #super_::#_name, @@ -132,10 +133,10 @@ fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut V // owned resource if ceiling == 0 { - continue + continue; } - let _name = Ident::new(format!("_{}", name.as_ref())); + let _name = Ident::from(format!("_{}", name.as_ref())); let resource = app.resources .get(name) .expect(&format!("BUG: resource {} has no definition", name)); @@ -262,7 +263,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { &mut #name },)); } else { - let _name = Ident::new(format!("_{}", name.as_ref())); + let _name = Ident::from(format!("_{}", name.as_ref())); lifetime = Some(quote!('a)); fields.push(quote! { @@ -309,7 +310,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { let mut fields = vec![]; for (name, resource) in late_resources { - let _name = Ident::new(format!("_{}", name.as_ref())); + let _name = Ident::from(format!("_{}", name.as_ref())); let ty = &resource.ty; @@ -373,6 +374,8 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { // Interrupt. These are enabled / disabled through the NVIC if interrupts.is_empty() { interrupts.push(quote! { + use #device::Interrupt; + let mut nvic: #device::NVIC = core::mem::transmute(()); }); } @@ -381,16 +384,16 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) { interrupts.push(quote! { let prio_bits = #device::NVIC_PRIO_BITS; let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits); - nvic.set_priority(#device::Interrupt::#name, hw); + nvic.set_priority(Interrupt::#name, hw); }); if enabled { interrupts.push(quote! { - nvic.enable(#device::Interrupt::#name); + nvic.enable(Interrupt::#name); }); } else { interrupts.push(quote! { - nvic.disable(#device::Interrupt::#name); + nvic.disable(Interrupt::#name); }); } } @@ -416,7 +419,7 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { let krate = krate(); for name in ownerships.keys() { - let _name = Ident::new(format!("_{}", name.as_ref())); + let _name = Ident::from(format!("_{}", name.as_ref())); // Declare the static that holds the resource let resource = app.resources @@ -439,7 +442,7 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { } } -fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { +fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>, main: &mut Vec<Tokens>) { let device = &app.device; let krate = krate(); @@ -453,7 +456,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { if has_resources { for rname in &task.resources { let ceiling = ownerships[rname].ceiling(); - let _rname = Ident::new(format!("_{}", rname.as_ref())); + let _rname = Ident::from(format!("_{}", rname.as_ref())); let resource = app.resources .get(rname) .expect(&format!("BUG: resource {} has no definition", rname)); @@ -591,8 +594,8 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { } let path = &task.path; - let _tname = Ident::new(format!("_{}", tname)); - let export_name = Lit::Str(tname.as_ref().to_owned(), StrStyle::Cooked); + let _tname = Ident::from(format!("_{}", tname)); + let export_name = LitStr::new(tname.as_ref(), Span::call_site()); root.push(quote! { #[allow(non_snake_case)] #[allow(unsafe_code)] @@ -608,11 +611,12 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { #[allow(non_snake_case)] #[allow(unsafe_code)] mod #tname { + #[allow(unused_imports)] use core::marker::PhantomData; #[allow(dead_code)] #[deny(const_err)] - const CHECK_PRIORITY: (u8, u8) = ( + pub const CHECK_PRIORITY: (u8, u8) = ( #priority - 1, (1 << ::#device::NVIC_PRIO_BITS) - #priority, ); @@ -620,5 +624,9 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) { #(#items)* } }); + + // after miri landed (?) rustc won't analyze `const` items unless they are used so we force + // evaluation with this path statement + main.push(quote!(#tname::CHECK_PRIORITY;)); } } |