From b2c59e2a7f66495723fd53f0d70fb34470448a75 Mon Sep 17 00:00:00 2001
From: Jorge Aparicio <jorge@japaric.io>
Date: Tue, 18 Jul 2017 16:49:30 -0500
Subject: [PATCH] more typed: use Path / Ty instead of just "Tokens"

---
 src/check.rs | 25 +++++++++++++------------
 src/lib.rs   | 11 ++++++-----
 src/parse.rs | 16 ++++------------
 src/util.rs  | 14 ++++++++++++++
 4 files changed, 37 insertions(+), 29 deletions(-)
 create mode 100644 src/util.rs

diff --git a/src/check.rs b/src/check.rs
index 6988783..ea0b55f 100644
--- a/src/check.rs
+++ b/src/check.rs
@@ -1,15 +1,14 @@
 use std::collections::HashMap;
 
-use quote::Tokens;
-use syn::Ident;
+use syn::{Ident, Path};
 
 use error::*;
-use {Idents, Statics};
+use {util, Idents, Statics};
 
 pub type Tasks = HashMap<Ident, Task>;
 
 pub struct App {
-    pub device: Tokens,
+    pub device: Path,
     pub idle: Idle,
     pub init: Init,
     pub resources: Statics,
@@ -18,12 +17,12 @@ pub struct App {
 
 pub struct Idle {
     pub locals: Statics,
-    pub path: Tokens,
+    pub path: Path,
     pub resources: Idents,
 }
 
 pub struct Init {
-    pub path: Tokens,
+    pub path: Path,
 }
 
 pub struct Task {
@@ -74,7 +73,7 @@ fn idle(idle: Option<::Idle>) -> Result<Idle> {
     } else {
         Idle {
             locals: Statics::new(),
-            path: quote!(idle),
+            path: util::mk_path("idle"),
             resources: Idents::new(),
         }
     })
@@ -91,21 +90,23 @@ fn init(init: Option<::Init>) -> Result<Init> {
             bail!("empty `init` field. It should be removed.");
         }
     } else {
-        Init { path: quote!(init) }
+        Init {
+            path: util::mk_path("init"),
+        }
     })
 }
 
-fn path(default: &str, path: Option<Tokens>) -> Result<Tokens> {
+fn path(default: &str, path: Option<Path>) -> Result<Path> {
     Ok(if let Some(path) = path {
         ensure!(
-            path.as_str() != default,
+            path.segments.len() == 1 &&
+                path.segments[0].ident.as_ref() != default,
             "this is the default value. It should be omitted."
         );
 
         path
     } else {
-        let default = Ident::new(default);
-        quote!(#default)
+        util::mk_path(default)
     })
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index f010d68..4abe151 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,11 +10,12 @@ pub mod check;
 pub mod error;
 
 mod parse;
+mod util;
 
 use std::collections::{HashMap, HashSet};
 
 use quote::Tokens;
-use syn::Ident;
+use syn::{Ident, Path, Ty};
 
 use error::*;
 
@@ -26,7 +27,7 @@ pub type Tasks = HashMap<Ident, Task>;
 
 #[derive(Debug)]
 pub struct App {
-    pub device: Tokens,
+    pub device: Path,
     pub idle: Option<Idle>,
     pub init: Option<Init>,
     pub resources: Option<Statics>,
@@ -36,14 +37,14 @@ pub struct App {
 /// `init`
 #[derive(Debug)]
 pub struct Init {
-    pub path: Option<Tokens>,
+    pub path: Option<Path>,
 }
 
 /// `idle`
 #[derive(Debug)]
 pub struct Idle {
     pub locals: Option<Statics>,
-    pub path: Option<Tokens>,
+    pub path: Option<Path>,
     pub resources: Option<Idents>,
 }
 
@@ -58,7 +59,7 @@ pub struct Task {
 #[derive(Debug)]
 pub struct Static {
     pub expr: Tokens,
-    pub ty: Tokens,
+    pub ty: Ty,
 }
 
 impl App {
diff --git a/src/parse.rs b/src/parse.rs
index ebc279e..7c1a813 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -2,8 +2,7 @@ use std::collections::{HashMap, HashSet};
 use std::iter::Peekable;
 use std::slice::Iter;
 
-use quote::Tokens;
-use syn::{self, DelimToken, Ident, IntTy, Lit, Token, TokenTree};
+use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, TokenTree};
 
 use error::*;
 
@@ -234,12 +233,6 @@ fn static_(tts: &mut Iter<TokenTree>) -> Result<Static> {
         if let Some(tt) = tts.next() {
             if tt == &TokenTree::Token(Token::Eq) {
                 break;
-            } else if tt == &TokenTree::Token(Token::Semi) {
-                fragments.push(tt);
-                bail!(
-                    "expected a type, found Semicolon: `{}`",
-                    quote!(#(#fragments)*)
-                );
             } else {
                 fragments.push(tt);
             }
@@ -248,8 +241,7 @@ fn static_(tts: &mut Iter<TokenTree>) -> Result<Static> {
         }
     }
 
-    ensure!(!fragments.is_empty(), "type is missing");
-    let ty = quote!(#(#fragments)*);
+    let ty = syn::parse_type(&format!("{}", quote!(#(#fragments)*)))?;
 
     let mut fragments = vec![];
     loop {
@@ -306,7 +298,7 @@ fn statics(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Statics> {
     })
 }
 
-fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Tokens> {
+fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Path> {
     let mut fragments = vec![];
 
     loop {
@@ -323,7 +315,7 @@ fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Tokens> {
         tts.next();
     }
 
-    Ok(quote!(#(#fragments)*))
+    Ok(syn::parse_path(&format!("{}", quote!(#(#fragments)*)))?)
 }
 
 fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> {
diff --git a/src/util.rs b/src/util.rs
new file mode 100644
index 0000000..21e5447
--- /dev/null
+++ b/src/util.rs
@@ -0,0 +1,14 @@
+use syn::{Ident, Path, PathParameters, PathSegment};
+
+/// Creates a path with contents `#ident`
+pub fn mk_path(ident: &str) -> Path {
+    Path {
+        global: false,
+        segments: vec![
+            PathSegment {
+                ident: Ident::new(ident),
+                parameters: PathParameters::none(),
+            },
+        ],
+    }
+}
-- 
GitLab