diff --git a/src/check.rs b/src/check.rs index 6e6f9d5a30e2b58f2aa2d364b2c00dcc96c20457..9793c1e13297c0afd81677c3228170dafaa7adfc 100644 --- a/src/check.rs +++ b/src/check.rs @@ -189,7 +189,7 @@ fn tasks(tasks: Option<::Tasks>) -> Result<Tasks> { }) } -/// `crc! { .. }` +/// `cro! { .. }` #[derive(Debug)] pub struct Cro { /// `crcs: Crcs` @@ -198,7 +198,7 @@ pub struct Cro { pub ops: ::Ops, } -/// Checks the syntax of the parsed `app!` macro +/// Checks the syntax of the parsed `cro!` macro pub fn cro(cro: ::Cro) -> Result<Cro> { Ok(Cro { ips: ::check::ips(cro.ips).chain_err(|| "checking `ips`")?, @@ -212,7 +212,7 @@ pub fn ips(ips: Option<::Ips>) -> Result<::Ips> { Ok(if let Some(ips) = ips { ensure!( !ips.is_empty(), - "empty `ips` field. Each Crc must have at least one input port" + "empty `ips` field. Each Cro must have at least one input port" ); ips } else { @@ -229,3 +229,32 @@ pub fn ops(ops: Option<::Ops>) -> Result<::Ops> { //Ops::new() }) } + +/// `crc! { .. }` +#[derive(Debug)] +pub struct Crc { + /// `crcs: Crcs` + pub crcs: ::Crcs, +} + + +/// Checks the syntax of the parsed `crc!` macro +pub fn crc(crc: ::Crc) -> Result<Crc> { + Ok(Crc { + crcs: ::check::crcs(crc.crcs).chain_err(|| "checking `crcs`")?, + }) + +} + +/// +pub fn crcs(crcs: Option<::Crcs>) -> Result<Crcs> { + Ok(if let Some(crcs) = crcs { + ensure!( + !crcs.is_empty(), + "empty `crcs` field. Each Crc must have at least one inner component" + ); + crcs + } else { + bail!("missing `crcs` field") + }) +} diff --git a/src/lib.rs b/src/lib.rs index 4e11b3121972292ffc354f9b46c9887dbaeb2730..21e691c76c138a1e333c7dc1972ff4fa7c3fb2a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,9 +102,6 @@ impl App { /// Crc related -/// `$($Ident: $Path,)*` -pub type Crcs = HashMap<Ident, Path>; - /// Input port binding #[derive(Debug)] pub enum IpTo { @@ -136,3 +133,28 @@ impl Cro { parse::cro(input) } } + + +// Crc related +/// `$($Ident: $Path,)*` +pub type Crcs = HashMap<Ident, (Path, OpBind)>; +/// `$($Ident: $Path,)*` +pub type OpBind = HashMap<Ident, Path>; + +/// `crc! { .. }` +#[derive(Debug)] +pub struct Crc { + /// Crcs are the inner Cro/Crcs + pub crcs: Option<Crcs>, +// /// Input ports (should not be None, given we have interrupts at top level) +// pub ips: Option<Ips>, +// /// Output ports (should not be None, given we treat peripherals as Crcs) +// pub ops: Option<Ops>, +} + +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 1b26b060513c9e9d23f05c738220e6fccf356cc2..82de7469b0604de1ff3a7d3fbff33fdf58c4d4bc 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -7,8 +7,8 @@ use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, BinOpToken, use error::*; -use {Cro, Ips, Ops, App, Idle, Init, Resources, Static, Statics, Task, Tasks, - Expr}; +use {Cro, Ips, Ops, Crc, Crcs, OpBind, App, Idle, Init, Resources, Static, + Statics, Task, Tasks, Expr}; /// Parses the contents of `app! { $App }` pub fn app(input: &str) -> Result<App> { @@ -435,7 +435,7 @@ fn u8(tt: Option<&TokenTree>) -> Result<u8> { } } -/// Parses the contents of `crc! { $Crc }` +/// Parses the contents of `cro! { $Cro }` pub fn cro(input: &str) -> Result<Cro> { let tts = syn::parse_token_trees(input)?; @@ -467,8 +467,32 @@ pub fn cro(input: &str) -> Result<Cro> { Ok(Cro { ips, ops }) } +/// Parses the contents of `crc! { $Crc }` +pub fn crc(input: &str) -> Result<Crc> { + let tts = syn::parse_token_trees(input)?; + + let mut crcs = 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`")?); + } + + _ => bail!("unknown field: `{}`", key), + + } + + Ok(()) + })?; + + Ok(Crc { crcs }) +} + -/* /// Parses `$($Ident: $Path,)*` fn crcs(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Crcs> { ::parse::delimited(tts, DelimToken::Brace, |tts| { @@ -495,13 +519,46 @@ fn crcs(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Crcs> { let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?; tts.next(); - crcs.insert(ident.clone(), path); + let op_bind = + ::parse::op_bind(&mut tts).chain_err(|| "parsing `path`")?; + tts.next(); + crcs.insert(ident.clone(), (path, op_bind)); } Ok(crcs) }) } -*/ + +fn op_bind(tts: &mut Peekable<Iter<TokenTree>>) -> Result<OpBind> { + ::parse::delimited(tts, DelimToken::Brace, |tts| { + let mut op_bind = 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!( + !op_bind.contains_key(ident), + "op {} listed more than once", + ident + ); + + let tt = tts.next(); + if let Some(&TokenTree::Token(Token::RArrow)) = tt { + } else { + bail!("expected '->' found {:?}", tt); + } + tts.next(); + let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?; + tts.next(); + op_bind.insert(ident.clone(), path); + } + Ok(op_bind) + }) +} /// Parses `$($Ident: $Ty > $Path,)*` fn ips(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> {