diff --git a/src/check.rs b/src/check.rs index f143c90b01c76f413866d78752e8278ac87a2f5d..0608df1b611d79c9acd6f8945559519845721d82 100644 --- a/src/check.rs +++ b/src/check.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use syn::{Ident, Path}; use error::*; -use {util, Resources, Statics}; +use {util, Resources, Statics, Crcs}; /// `$($Ident: { .. },)*` pub type Tasks = HashMap<Ident, Task>; @@ -65,8 +65,9 @@ pub fn app(app: ::App) -> Result<App> { device: app.device, idle: ::check::idle(app.idle).chain_err(|| "checking `idle`")?, init: ::check::init(app.init).chain_err(|| "checking `init`")?, - resources: ::check::statics("resources", app.resources) - .chain_err(|| "checking `resources`")?, + resources: ::check::statics("resources", app.resources).chain_err( + || "checking `resources`", + )?, tasks: ::check::tasks(app.tasks).chain_err(|| "checking `tasks`")?, }) } @@ -80,8 +81,9 @@ fn idle(idle: Option<::Idle>) -> Result<Idle> { Idle { _extensible: (), - path: ::check::path("idle", idle.path) - .chain_err(|| "checking `path`")?, + path: ::check::path("idle", idle.path).chain_err( + || "checking `path`", + )?, resources: ::check::resources("resources", idle.resources)?, } } else { @@ -98,8 +100,9 @@ fn init(init: Option<::Init>) -> Result<Init> { if let Some(path) = init.path { Init { _extensible: (), - path: ::check::path("init", Some(path)) - .chain_err(|| "checking `path`")?, + path: ::check::path("init", Some(path)).chain_err( + || "checking `path`", + )?, } } else { bail!("empty `init` field. It should be removed."); @@ -115,8 +118,7 @@ fn init(init: Option<::Init>) -> Result<Init> { fn path(default: &str, path: Option<Path>) -> Result<Path> { Ok(if let Some(path) = path { ensure!( - path.segments.len() != 1 || - path.segments[0].ident.as_ref() != default, + path.segments.len() != 1 || path.segments[0].ident.as_ref() != default, "this is the default value. It should be omitted." ); @@ -186,3 +188,15 @@ fn tasks(tasks: Option<::Tasks>) -> Result<Tasks> { Tasks::new() }) } + +/// `crc! { .. }` +#[derive(Debug)] +pub struct Crc { + /// `crcs: Crcs` + pub crcs: Option<Crcs>, +} + +/// Checks the syntax of the parsed `app!` macro +pub fn crc(crc: ::Crc) -> Result<Crc> { + Ok(Crc { crcs: crc.crcs }) +} diff --git a/src/lib.rs b/src/lib.rs index 72efece8e9672f4207635e26e881141a52458f6e..4ec8db5144c1b76e3d85bb63d74f1ab7f5917b8b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ //! framework #![deny(missing_debug_implementations)] #![deny(missing_docs)] -#![deny(warnings)] +// #![deny(warnings)] #[macro_use] extern crate error_chain; @@ -99,3 +99,37 @@ impl App { parse::app(input) } } + +/// Crc related + +/// `$($Ident: $Path,)*` +pub type Crcs = HashMap<Ident, Path>; + +pub enum IpTo { + Crc(Path), + Method(Ident), +} + +pub struct Ip { + ty: Ty, + to: IpBind, +} + +/// `$($Ident: $Ty,)*` +pub type Ips = HashMap<Ident, Ty>; + +/// `crc! { .. }` +#[derive(Debug)] +pub struct Crc { + /// Inner Crcs (can be None) + pub crcs: Option<Crcs>, + /// Input ports (should not be None) + pub ips: Option<Ips>, +} + +impl Crc { + /// Parses the contents of the `sys! { .. }` macro + pub fn parse(input: &str) -> Result<Self> { + parse::crc(input) + } +} diff --git a/src/parse.rs b/src/parse.rs index ab832ad001c047024a15026899e09a141c52452f..cdb2bd506a7ec95c3c0f5ce935a2c52eeee5a523 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -2,11 +2,11 @@ use std::collections::{HashMap, HashSet}; use std::iter::Peekable; use std::slice::Iter; -use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, TokenTree}; +use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, TokenTree, Ty}; use error::*; -use {App, Idle, Init, Resources, Static, Statics, Task, Tasks}; +use {Crc, Crcs, Ips, App, Idle, Init, Resources, Static, Statics, Task, Tasks}; /// Parses the contents of `app! { $App }` pub fn app(input: &str) -> Result<App> { @@ -39,9 +39,9 @@ pub fn app(input: &str) -> Result<App> { "resources" => { ensure!(resources.is_none(), "duplicated `resources` field"); - resources = Some( - ::parse::statics(tts).chain_err(|| "parsing `resources`")?, - ); + resources = Some(::parse::statics(tts).chain_err( + || "parsing `resources`", + )?); } "tasks" => { ensure!(tasks.is_none(), "duplicated `tasks` field"); @@ -122,7 +122,8 @@ where let tt = tts.next(); match tt { - None | Some(&TokenTree::Token(Token::Comma)) => {} + None | + Some(&TokenTree::Token(Token::Comma)) => {} _ => bail!("expected Comma, found {:?}", tt), } } @@ -149,8 +150,9 @@ fn idle(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Idle> { "duplicated `resources` field" ); - resources = Some(::parse::resources(tts) - .chain_err(|| "parsing `resources`")?); + resources = Some(::parse::resources(tts).chain_err( + || "parsing `resources`", + )?); } _ => bail!("unknown field: `{}`", key), } @@ -305,8 +307,9 @@ fn statics(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Statics> { statics.insert( ident.clone(), - ::parse::static_(&mut tts) - .chain_err(|| format!("parsing `{}`", ident))?, + ::parse::static_(&mut tts).chain_err( + || format!("parsing `{}`", ident), + )?, ); } @@ -331,6 +334,7 @@ fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Path> { tts.next(); } + // bail!("in path fragments, {:? }===== {:?}", fragments, tts); Ok(syn::parse_path(&format!("{}", quote!(#(#fragments)*)))?) } @@ -348,8 +352,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { "enabled" => { ensure!(enabled.is_none(), "duplicated `enabled` field"); - enabled = Some(::parse::bool(tts.next()) - .chain_err(|| "parsing `enabled`")?); + enabled = Some(::parse::bool(tts.next()).chain_err( + || "parsing `enabled`", + )?); } "path" => { ensure!(path.is_none(), "duplicated `path` field"); @@ -361,8 +366,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { "priority" => { ensure!(priority.is_none(), "duplicated `priority` field"); - priority = Some(::parse::u8(tts.next()) - .chain_err(|| "parsing `priority`")?); + priority = Some(::parse::u8(tts.next()).chain_err( + || "parsing `priority`", + )?); } "resources" => { ensure!( @@ -370,8 +376,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { "duplicated `resources` field" ); - resources = Some(::parse::resources(tts) - .chain_err(|| "parsing `resources`")?); + resources = Some(::parse::resources(tts).chain_err( + || "parsing `resources`", + )?); } _ => bail!("unknown field: `{}`", key), } @@ -403,8 +410,9 @@ fn tasks(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Tasks> { tasks.insert( key.clone(), - ::parse::task(tts) - .chain_err(|| format!("parsing task `{}`", key))?, + ::parse::task(tts).chain_err( + || format!("parsing task `{}`", key), + )?, ); Ok(()) @@ -429,3 +437,121 @@ fn u8(tt: Option<&TokenTree>) -> Result<u8> { bail!("expected integer, found {:?}", tt); } } + +/// Parses the contents of `crc! { $Crc }` +pub fn crc(input: &str) -> Result<Crc> { + let tts = syn::parse_token_trees(input)?; + + let mut crcs = None; + let mut ips = None; + + fields(&tts, |key, tts| { + match key.as_ref() { + "crcs" => { + ensure!(crcs.is_none(), "duplicated `crcs` field"); + + crcs = Some(::parse::crcs(tts).chain_err(|| "parsing `crcs`")?); + } + "ips" => { + ensure!(ips.is_none(), "duplicated `ips` field"); + + ips = Some(::parse::ip(tts).chain_err(|| "parsing `ips`")?); + } + + _ => bail!("unknown field: `{}`", key), + + } + + Ok(()) + })?; + + Ok(Crc { crcs, ips }) +} + + + +/// Parses `$($Ident: $Path,)*` +fn crcs(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Crcs> { + ::parse::delimited(tts, DelimToken::Brace, |tts| { + let mut crcs = HashMap::new(); + let mut tts = tts.iter().peekable(); + while let Some(tt) = tts.next() { + let ident = if let &TokenTree::Token(Token::Ident(ref id)) = tt { + id + } else { + bail!("expected Ident, found {:?}", tt); + }; + + ensure!( + !crcs.contains_key(ident), + "crc {} listed more than once", + ident + ); + + let tt = tts.next(); + if let Some(&TokenTree::Token(Token::Colon)) = tt { + } else { + bail!("expected Colon, found {:?}", tt); + } + + let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?; + tts.next(); + crcs.insert(ident.clone(), path); + } + Ok(crcs) + + }) +} + +/// Parses `$($Ident: $Path,)*` +fn ip(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> { + ::parse::delimited(tts, DelimToken::Brace, |tts| { + let mut ips = HashMap::new(); + let mut tts = tts.iter(); + while let Some(tt) = tts.next() { + let ident = if let &TokenTree::Token(Token::Ident(ref id)) = tt { + id + } else { + bail!("expected Ident, found {:?}", tt); + }; + + ensure!( + !ips.contains_key(ident), + "ip {} listed more than once", + ident + ); + + let tt = tts.next(); + if let Some(&TokenTree::Token(Token::Colon)) = tt { + } else { + bail!("expected Colon, found {:?}", tt); + } + + let ty = ::parse::ty(&mut tts).chain_err(|| { + format!("parsing `type` for {:?}", ident) + })?; + ips.insert(ident.clone(), ty); + } + Ok(ips) + + }) +} + +/// Parses `$Ty ` +fn ty(tts: &mut Iter<TokenTree>) -> Result<Ty> { + let mut fragments = vec![]; + loop { + if let Some(tt) = tts.next() { + if tt == &TokenTree::Token(Token::Comma) { + break; + } else { + fragments.push(tt); + } + } else { + bail!("expected comma, found end of macro"); + } + } + + Ok(syn::parse_type(&format!("{}", quote!(#(#fragments)*)))?) + +}