diff --git a/src/check.rs b/src/check.rs index 0608df1b611d79c9acd6f8945559519845721d82..6539e3e0c0712f4c0a37e192501a8f7df1bdad71 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, Crcs}; +use {util, Resources, Statics, Crcs, Ips, Ops}; /// `$($Ident: { .. },)*` pub type Tasks = HashMap<Ident, Task>; @@ -194,9 +194,41 @@ fn tasks(tasks: Option<::Tasks>) -> Result<Tasks> { pub struct Crc { /// `crcs: Crcs` pub crcs: Option<Crcs>, + /// `crcs: Crcs` + pub ips: ::Ips, + /// `crcs: Crcs` + pub ops: ::Ops, } /// Checks the syntax of the parsed `app!` macro pub fn crc(crc: ::Crc) -> Result<Crc> { - Ok(Crc { crcs: crc.crcs }) + Ok(Crc { + crcs: crc.crcs, + ips: ::check::ips(crc.ips).chain_err(|| "checking `ips`")?, + ops: ::check::ops(crc.ops).chain_err(|| "checking `ops`")?, + }) + +} + +/// +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" + ); + ips + } else { + bail!("missing input ports ") + }) +} + +/// +pub fn ops(ops: Option<::Ops>) -> Result<::Ops> { + Ok(if let Some(ops) = ops { + ops + } else { + bail!("missing input ports ") + //Ops::new() + }) } diff --git a/src/lib.rs b/src/lib.rs index 5de85110b2030c301d06eb0fd410c26dd55c40b7..495c6b3135b28405c37fe10e30c7235544507997 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,13 +117,18 @@ pub enum IpTo { /// `$($Ident: $Ty > $Path,)*` pub type Ips = HashMap<Ident, (Ty, Path)>; +/// `$($Ident: $Ty < $Path,)*` +pub type Ops = HashMap<Ident, (Ty, Path)>; + /// `crc! { .. }` #[derive(Debug)] pub struct Crc { /// Inner Crcs (can be None) pub crcs: Option<Crcs>, - /// Input ports (should not be None) + /// 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 { diff --git a/src/parse.rs b/src/parse.rs index 6e88ea2c0549dc229b43981fce0c33e5474362b5..1dab965c6b6e9688cdddc88a69789dc341734b21 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -7,7 +7,8 @@ use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, BinOpToken, use error::*; -use {Crc, Crcs, Ips, App, Idle, Init, Resources, Static, Statics, Task, Tasks}; +use {Crc, Crcs, Ips, Ops, App, Idle, Init, Resources, Static, Statics, Task, + Tasks}; /// Parses the contents of `app! { $App }` pub fn app(input: &str) -> Result<App> { @@ -445,6 +446,7 @@ pub fn crc(input: &str) -> Result<Crc> { let mut crcs = None; let mut ips = None; + let mut ops = None; fields(&tts, |key, tts| { match key.as_ref() { @@ -456,7 +458,13 @@ pub fn crc(input: &str) -> Result<Crc> { "ips" => { ensure!(ips.is_none(), "duplicated `ips` field"); - ips = Some(::parse::ip(tts).chain_err(|| "parsing `ips`")?); + ips = Some(::parse::ips(tts).chain_err(|| "parsing `ips`")?); + } + + "ops" => { + ensure!(ops.is_none(), "duplicated `ops` field"); + + ops = Some(::parse::ops(tts).chain_err(|| "parsing `ops`")?); } _ => bail!("unknown field: `{}`", key), @@ -466,7 +474,7 @@ pub fn crc(input: &str) -> Result<Crc> { Ok(()) })?; - Ok(Crc { crcs, ips }) + Ok(Crc { crcs, ips, ops }) } @@ -505,7 +513,7 @@ fn crcs(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Crcs> { } /// Parses `$($Ident: $Ty > $Path,)*` -fn ip(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> { +fn ips(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> { ::parse::delimited(tts, DelimToken::Brace, |tts| { let mut ips = HashMap::new(); let mut tts = tts.iter().peekable(); @@ -528,9 +536,9 @@ fn ip(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> { bail!("expected Colon, found {:?}", tt); } - let ty = ::parse::ty(&mut tts).chain_err(|| { - format!("parsing `type` for {:?}", ident) - })?; + let ty = + ::parse::ty(&TokenTree::Token(Token::Gt), &mut tts) + .chain_err(|| format!("parsing `type` for {:?}", ident))?; let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?; tts.next(); @@ -542,19 +550,56 @@ fn ip(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> { }) } +/// Parses `$($Ident: $Ty < $Path,)*` +fn ops(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ops> { + ::parse::delimited(tts, DelimToken::Brace, |tts| { + let mut ops = 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!( + !ops.contains_key(ident), + "op {} 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(&TokenTree::Token(Token::Lt), &mut tts) + .chain_err(|| format!("parsing `type` for {:?}", ident))?; + + let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?; + tts.next(); + + ops.insert(ident.clone(), (ty, path)); + } + Ok(ops) + }) +} + + /// Parses `$Ty ` -fn ty(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ty> { +fn ty(token: &TokenTree, tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ty> { let mut fragments = vec![]; loop { if let Some(tt) = tts.next() { - // if tt == &TokenTree::Token(Token::BinOp(BinOpToken::Minus)) { - if tt == &TokenTree::Token(Token::Gt) { + if tt == token { break; } else { fragments.push(tt); } } else { - bail!("expected `>`, found end of macro"); + bail!("expected `{:?}`, found end of macro", token); } }