From 3db36b8c958644dacf4461b1d60f02b081ebd97c Mon Sep 17 00:00:00 2001
From: pln <Per Lindgren>
Date: Mon, 7 Aug 2017 00:57:35 +0200
Subject: [PATCH] syntax

---
 src/check.rs |  32 +++++++---
 src/lib.rs   |  36 +++++++++++-
 src/parse.rs | 162 +++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 202 insertions(+), 28 deletions(-)

diff --git a/src/check.rs b/src/check.rs
index f143c90..0608df1 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 72efece..4ec8db5 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 ab832ad..cdb2bd5 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)*)))?)
+
+}
-- 
GitLab