From 404a781d628f93d50a1658be64158a2fb9e3cbb3 Mon Sep 17 00:00:00 2001
From: pln <Per Lindgren>
Date: Fri, 18 Aug 2017 14:30:37 +0200
Subject: [PATCH] sketch of crc abstraction

---
 src/check.rs | 35 +++++++++++++++++++++++---
 src/lib.rs   | 28 ++++++++++++++++++---
 src/parse.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 120 insertions(+), 12 deletions(-)

diff --git a/src/check.rs b/src/check.rs
index 6e6f9d5..9793c1e 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 4e11b31..21e691c 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 1b26b06..82de746 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> {
-- 
GitLab