Separate delimiter and tokenstream in macro ast
diff --git a/codegen/src/main.rs b/codegen/src/main.rs
index 0115cae..1c199f1 100644
--- a/codegen/src/main.rs
+++ b/codegen/src/main.rs
@@ -127,16 +127,16 @@
 
                 // Try to parse the AstItem declaration out of the item.
                 let found = if path_eq(&item.mac.path, &"ast_struct".into()) {
-                    syn::parse_tokens::<parsing::AstStruct>(item.mac.tt.clone().into_tokens())
+                    syn::parse_tokens::<parsing::AstStruct>(item.mac.tts.clone().into_tokens())
                         .map_err(|_| err_msg("failed to parse ast_struct"))?
                         .0
                 } else if path_eq(&item.mac.path, &"ast_enum".into()) {
-                    syn::parse_tokens::<parsing::AstEnum>(item.mac.tt.clone().into_tokens())
+                    syn::parse_tokens::<parsing::AstEnum>(item.mac.tts.clone().into_tokens())
                         .map_err(|_| err_msg("failed to parse ast_enum"))?
                         .0
                 } else if path_eq(&item.mac.path, &"ast_enum_of_structs".into()) {
                     syn::parse_tokens::<parsing::AstEnumOfStructs>(
-                        item.mac.tt.clone().into_tokens(),
+                        item.mac.tts.clone().into_tokens(),
                     ).map_err(|_| err_msg("failed to parse ast_enum_of_structs"))?
                         .0
                 } else {
@@ -221,21 +221,21 @@
     // ast_struct! parsing
     pub struct AstStruct(pub Vec<AstItem>);
     impl Synom for AstStruct {
-        named!(parse -> Self, map!(braces!(do_parse!(
+        named!(parse -> Self, do_parse!(
             many0!(Attribute::parse_outer) >>
             keyword!(pub) >>
             keyword!(struct) >>
             res: call!(ast_struct_inner) >>
-            (res)
-        )), |x| AstStruct(vec![x.0])));
+            (AstStruct(vec![res]))
+        ));
     }
 
     // ast_enum! parsing
     pub struct AstEnum(pub Vec<AstItem>);
     impl Synom for AstEnum {
-        named!(parse -> Self, map!(braces!(syn!(DeriveInput)), |x| {
+        named!(parse -> Self, map!(syn!(DeriveInput), |x| {
             AstEnum(vec![AstItem {
-                ast: x.0,
+                ast: x,
                 features: quote!(),
                 eos_full: false,
             }])
@@ -268,7 +268,7 @@
     // ast_enum_of_structs! parsing
     pub struct AstEnumOfStructs(pub Vec<AstItem>);
     impl Synom for AstEnumOfStructs {
-        named!(parse -> Self, map!(braces!(do_parse!(
+        named!(parse -> Self, do_parse!(
             many0!(Attribute::parse_outer) >>
             keyword!(pub) >>
             keyword!(enum) >>
@@ -298,7 +298,7 @@
                 items.extend(body.0.into_iter().filter_map(|v| v.inner));
                 AstEnumOfStructs(items)
             })
-        )), |x| x.0));
+        ));
     }
 }
 
diff --git a/src/expr.rs b/src/expr.rs
index 41edfad..101cc9d 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -796,7 +796,7 @@
     use ty::parsing::ty_no_eq_after;
 
     #[cfg(feature = "full")]
-    use proc_macro2::{Delimiter, Span, TokenNode, TokenStream};
+    use proc_macro2::{Span, TokenStream};
     use synom::Synom;
     use cursor::Cursor;
     #[cfg(feature = "full")]
@@ -2042,10 +2042,8 @@
             mac: Macro {
                 path: what,
                 bang_token: bang,
-                tt: proc_macro2::TokenTree {
-                    span: (data.1).0,
-                    kind: TokenNode::Group(Delimiter::Brace, data.0),
-                },
+                delimiter: MacroDelimiter::Brace(data.1),
+                tts: data.0,
             },
             semi_token: semi,
         }))))
diff --git a/src/gen/fold.rs b/src/gen/fold.rs
index 3013ab5..3faa53c 100644
--- a/src/gen/fold.rs
+++ b/src/gen/fold.rs
@@ -252,6 +252,8 @@
 
 fn fold_macro(&mut self, i: Macro) -> Macro { fold_macro(self, i) }
 
+fn fold_macro_delimiter(&mut self, i: MacroDelimiter) -> MacroDelimiter { fold_macro_delimiter(self, i) }
+
 fn fold_member(&mut self, i: Member) -> Member { fold_member(self, i) }
 
 fn fold_meta_item(&mut self, i: MetaItem) -> MetaItem { fold_meta_item(self, i) }
@@ -1798,7 +1800,9 @@
         vis: _visitor.fold_visibility(_i . vis),
         macro_token: Token ! [ macro ](tokens_helper(_visitor, &(_i . macro_token).0)),
         ident: _visitor.fold_ident(_i . ident),
+        paren_token: Paren(tokens_helper(_visitor, &(_i . paren_token).0)),
         args: _i . args,
+        brace_token: Brace(tokens_helper(_visitor, &(_i . brace_token).0)),
         body: _i . body,
     }
 }
@@ -1946,7 +1950,29 @@
     Macro {
         path: _visitor.fold_path(_i . path),
         bang_token: Token ! [ ! ](tokens_helper(_visitor, &(_i . bang_token).0)),
-        tt: _i . tt,
+        delimiter: _visitor.fold_macro_delimiter(_i . delimiter),
+        tts: _i . tts,
+    }
+}
+
+pub fn fold_macro_delimiter<V: Folder + ?Sized>(_visitor: &mut V, _i: MacroDelimiter) -> MacroDelimiter {
+    use ::MacroDelimiter::*;
+    match _i {
+        Paren(_binding_0, ) => {
+            Paren (
+                Paren(tokens_helper(_visitor, &(_binding_0).0)),
+            )
+        }
+        Brace(_binding_0, ) => {
+            Brace (
+                Brace(tokens_helper(_visitor, &(_binding_0).0)),
+            )
+        }
+        Bracket(_binding_0, ) => {
+            Bracket (
+                Bracket(tokens_helper(_visitor, &(_binding_0).0)),
+            )
+        }
     }
 }
 
diff --git a/src/gen/visit.rs b/src/gen/visit.rs
index 120d1fd..6beacf0 100644
--- a/src/gen/visit.rs
+++ b/src/gen/visit.rs
@@ -248,6 +248,8 @@
 
 fn visit_macro(&mut self, i: &'ast Macro) { visit_macro(self, i) }
 
+fn visit_macro_delimiter(&mut self, i: &'ast MacroDelimiter) { visit_macro_delimiter(self, i) }
+
 fn visit_member(&mut self, i: &'ast Member) { visit_member(self, i) }
 
 fn visit_meta_item(&mut self, i: &'ast MetaItem) { visit_meta_item(self, i) }
@@ -1408,7 +1410,9 @@
     _visitor.visit_visibility(& _i . vis);
     tokens_helper(_visitor, &(& _i . macro_token).0);
     _visitor.visit_ident(& _i . ident);
+    tokens_helper(_visitor, &(& _i . paren_token).0);
     // Skipped field _i . args;
+    tokens_helper(_visitor, &(& _i . brace_token).0);
     // Skipped field _i . body;
 }
 # [ cfg ( feature = "full" ) ]
@@ -1535,7 +1539,23 @@
 pub fn visit_macro<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Macro) {
     _visitor.visit_path(& _i . path);
     tokens_helper(_visitor, &(& _i . bang_token).0);
-    // Skipped field _i . tt;
+    _visitor.visit_macro_delimiter(& _i . delimiter);
+    // Skipped field _i . tts;
+}
+
+pub fn visit_macro_delimiter<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast MacroDelimiter) {
+    use ::MacroDelimiter::*;
+    match *_i {
+        Paren(ref _binding_0, ) => {
+            tokens_helper(_visitor, &(_binding_0).0);
+        }
+        Brace(ref _binding_0, ) => {
+            tokens_helper(_visitor, &(_binding_0).0);
+        }
+        Bracket(ref _binding_0, ) => {
+            tokens_helper(_visitor, &(_binding_0).0);
+        }
+    }
 }
 
 pub fn visit_member<'ast, V: Visitor<'ast> + ?Sized>(_visitor: &mut V, _i: &'ast Member) {
diff --git a/src/gen/visit_mut.rs b/src/gen/visit_mut.rs
index 00d9c17..9c164dc 100644
--- a/src/gen/visit_mut.rs
+++ b/src/gen/visit_mut.rs
@@ -248,6 +248,8 @@
 
 fn visit_macro_mut(&mut self, i: &mut Macro) { visit_macro_mut(self, i) }
 
+fn visit_macro_delimiter_mut(&mut self, i: &mut MacroDelimiter) { visit_macro_delimiter_mut(self, i) }
+
 fn visit_member_mut(&mut self, i: &mut Member) { visit_member_mut(self, i) }
 
 fn visit_meta_item_mut(&mut self, i: &mut MetaItem) { visit_meta_item_mut(self, i) }
@@ -1408,7 +1410,9 @@
     _visitor.visit_visibility_mut(& mut _i . vis);
     tokens_helper(_visitor, &mut (& mut _i . macro_token).0);
     _visitor.visit_ident_mut(& mut _i . ident);
+    tokens_helper(_visitor, &mut (& mut _i . paren_token).0);
     // Skipped field _i . args;
+    tokens_helper(_visitor, &mut (& mut _i . brace_token).0);
     // Skipped field _i . body;
 }
 # [ cfg ( feature = "full" ) ]
@@ -1535,7 +1539,23 @@
 pub fn visit_macro_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut Macro) {
     _visitor.visit_path_mut(& mut _i . path);
     tokens_helper(_visitor, &mut (& mut _i . bang_token).0);
-    // Skipped field _i . tt;
+    _visitor.visit_macro_delimiter_mut(& mut _i . delimiter);
+    // Skipped field _i . tts;
+}
+
+pub fn visit_macro_delimiter_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut MacroDelimiter) {
+    use ::MacroDelimiter::*;
+    match *_i {
+        Paren(ref mut _binding_0, ) => {
+            tokens_helper(_visitor, &mut (_binding_0).0);
+        }
+        Brace(ref mut _binding_0, ) => {
+            tokens_helper(_visitor, &mut (_binding_0).0);
+        }
+        Bracket(ref mut _binding_0, ) => {
+            tokens_helper(_visitor, &mut (_binding_0).0);
+        }
+    }
 }
 
 pub fn visit_member_mut<V: VisitorMut + ?Sized>(_visitor: &mut V, _i: &mut Member) {
diff --git a/src/item.rs b/src/item.rs
index 90b70f0..1953756 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1,9 +1,10 @@
 use super::*;
 use delimited::Delimited;
-use proc_macro2::{TokenTree, TokenStream};
+use proc_macro2::{TokenStream};
+use token::{Paren, Brace};
 
 #[cfg(feature = "extra-traits")]
-use mac::{TokenTreeHelper, TokenStreamHelper};
+use mac::TokenStreamHelper;
 #[cfg(feature = "extra-traits")]
 use std::hash::{Hash, Hasher};
 
@@ -186,14 +187,15 @@
             pub mac: Macro,
             pub semi_token: Option<Token![;]>,
         }),
-        /// FIXME will need to revisit what this looks like in the AST.
         pub Macro2(ItemMacro2 #manual_extra_traits {
             pub attrs: Vec<Attribute>,
             pub vis: Visibility,
             pub macro_token: Token![macro],
             pub ident: Ident,
-            pub args: TokenTree,
-            pub body: TokenTree,
+            pub paren_token: Paren,
+            pub args: TokenStream,
+            pub brace_token: Brace,
+            pub body: TokenStream,
         }),
         pub Verbatim(ItemVerbatim #manual_extra_traits {
             pub tts: TokenStream,
@@ -208,9 +210,10 @@
 impl PartialEq for ItemMacro2 {
     fn eq(&self, other: &Self) -> bool {
         self.attrs == other.attrs && self.vis == other.vis && self.macro_token == other.macro_token
-            && self.ident == other.ident
-            && TokenTreeHelper(&self.args) == TokenTreeHelper(&other.args)
-            && TokenTreeHelper(&self.body) == TokenTreeHelper(&other.body)
+            && self.ident == other.ident && self.paren_token == other.paren_token
+            && TokenStreamHelper(&self.args) == TokenStreamHelper(&other.args)
+            && self.brace_token == other.brace_token
+            && TokenStreamHelper(&self.body) == TokenStreamHelper(&other.body)
     }
 }
 
@@ -224,8 +227,10 @@
         self.vis.hash(state);
         self.macro_token.hash(state);
         self.ident.hash(state);
-        TokenTreeHelper(&self.args).hash(state);
-        TokenTreeHelper(&self.body).hash(state);
+        self.paren_token.hash(state);
+        TokenStreamHelper(&self.args).hash(state);
+        self.brace_token.hash(state);
+        TokenStreamHelper(&self.body).hash(state);
     }
 }
 
@@ -531,7 +536,6 @@
     use super::*;
 
     use synom::{Synom, Cursor, PResult};
-    use proc_macro2::{TokenNode, Delimiter};
 
     impl_synom!(Item "item" alt!(
         syn!(ItemExternCrate) => { Item::ExternCrate }
@@ -573,14 +577,15 @@
         bang: punct!(!) >>
         ident: option!(syn!(Ident)) >>
         body: call!(tt::delimited) >>
-        semi: cond!(!is_braced(&body), punct!(;)) >>
+        semi: cond!(!is_brace(&body.0), punct!(;)) >>
         (ItemMacro {
             attrs: attrs,
             ident: ident,
             mac: Macro {
                 path: what,
                 bang_token: bang,
-                tt: body,
+                delimiter: body.0,
+                tts: body.1,
             },
             semi_token: semi,
         })
@@ -599,8 +604,10 @@
             vis: vis,
             macro_token: macro_,
             ident: ident,
-            args: args,
-            body: body,
+            paren_token: args.0,
+            args: args.1,
+            brace_token: body.0,
+            body: body.1,
         })
     ));
 
@@ -1195,7 +1202,7 @@
     impl_synom!(TraitItemMacro "trait item macro" do_parse!(
         attrs: many0!(Attribute::parse_outer) >>
         mac: syn!(Macro) >>
-        semi: cond!(!is_braced(&mac.tt), punct!(;)) >>
+        semi: cond!(!is_brace(&mac.delimiter), punct!(;)) >>
         (TraitItemMacro {
             attrs: attrs,
             mac: mac,
@@ -1348,7 +1355,7 @@
     impl_synom!(ImplItemMacro "macro in impl block" do_parse!(
         attrs: many0!(Attribute::parse_outer) >>
         mac: syn!(Macro) >>
-        semi: cond!(!is_braced(&mac.tt), punct!(;)) >>
+        semi: cond!(!is_brace(&mac.delimiter), punct!(;)) >>
         (ImplItemMacro {
             attrs: attrs,
             mac: mac,
@@ -1356,10 +1363,10 @@
         })
     ));
 
-    fn is_braced(tt: &TokenTree) -> bool {
-        match tt.kind {
-            TokenNode::Group(Delimiter::Brace, _) => true,
-            _ => false,
+    fn is_brace(delimiter: &MacroDelimiter) -> bool {
+        match *delimiter {
+            MacroDelimiter::Brace(_) => true,
+            MacroDelimiter::Paren(_) | MacroDelimiter::Bracket(_) => false,
         }
     }
 }
@@ -1582,7 +1589,17 @@
             self.mac.path.to_tokens(tokens);
             self.mac.bang_token.to_tokens(tokens);
             self.ident.to_tokens(tokens);
-            self.mac.tt.to_tokens(tokens);
+            match self.mac.delimiter {
+                MacroDelimiter::Paren(ref paren) => {
+                    paren.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+                }
+                MacroDelimiter::Brace(ref brace) => {
+                    brace.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+                }
+                MacroDelimiter::Bracket(ref bracket) => {
+                    bracket.surround(tokens, |tokens| self.mac.tts.to_tokens(tokens));
+                }
+            }
             self.semi_token.to_tokens(tokens);
         }
     }
@@ -1593,8 +1610,12 @@
             self.vis.to_tokens(tokens);
             self.macro_token.to_tokens(tokens);
             self.ident.to_tokens(tokens);
-            self.args.to_tokens(tokens);
-            self.body.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.args.to_tokens(tokens);
+            });
+            self.brace_token.surround(tokens, |tokens| {
+                self.body.to_tokens(tokens);
+            });
         }
     }
 
diff --git a/src/lib.rs b/src/lib.rs
index 33a8fb4..56c3be0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -73,7 +73,7 @@
 pub use lit::{Lit, LitKind};
 
 mod mac;
-pub use mac::Macro;
+pub use mac::{Macro, MacroDelimiter};
 
 mod derive;
 pub use derive::{Body, BodyEnum, BodyStruct, DeriveInput};
diff --git a/src/mac.rs b/src/mac.rs
index 98aa49a..a43c311 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -1,20 +1,32 @@
 use super::*;
-
-use proc_macro2::TokenTree;
+use proc_macro2::TokenStream;
+use token::{Paren, Brace, Bracket};
 
 #[cfg(feature = "extra-traits")]
-use proc_macro2::{TokenStream, TokenNode, Delimiter};
+use proc_macro2::{TokenTree, TokenNode, Delimiter};
 #[cfg(feature = "extra-traits")]
 use std::hash::{Hash, Hasher};
 
 ast_struct! {
-    /// Represents a macro invocation. The Path indicates which macro
-    /// is being invoked, and the vector of token-trees contains the source
-    /// of the macro invocation.
+    /// Represents a macro invocation. The Path indicates which macro is being
+    /// invoked, and the `TokenStream` contains the source of the macro
+    /// invocation.
     pub struct Macro #manual_extra_traits {
         pub path: Path,
         pub bang_token: Token![!],
-        pub tt: TokenTree,
+        pub delimiter: MacroDelimiter,
+        pub tts: TokenStream,
+    }
+}
+
+ast_enum! {
+    pub enum MacroDelimiter {
+        /// `macro!(...)`
+        Paren(Paren),
+        /// `macro!{...}`
+        Brace(Brace),
+        /// `macro![...]`
+        Bracket(Bracket),
     }
 }
 
@@ -25,7 +37,8 @@
 impl PartialEq for Macro {
     fn eq(&self, other: &Self) -> bool {
         self.path == other.path && self.bang_token == other.bang_token
-            && TokenTreeHelper(&self.tt) == TokenTreeHelper(&other.tt)
+            && self.delimiter == other.delimiter
+            && TokenStreamHelper(&self.tts) == TokenStreamHelper(&other.tts)
     }
 }
 
@@ -37,7 +50,8 @@
     {
         self.path.hash(state);
         self.bang_token.hash(state);
-        TokenTreeHelper(&self.tt).hash(state);
+        self.delimiter.hash(state);
+        TokenStreamHelper(&self.tts).hash(state);
     }
 }
 
@@ -167,7 +181,8 @@
             (Macro {
                 path: what,
                 bang_token: bang,
-                tt: body,
+                delimiter: body.0,
+                tts: body.1,
             })
         ));
     }
@@ -182,7 +197,17 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
             self.bang_token.to_tokens(tokens);
-            self.tt.to_tokens(tokens);
+            match self.delimiter {
+                MacroDelimiter::Paren(ref paren) => {
+                    paren.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+                }
+                MacroDelimiter::Brace(ref brace) => {
+                    brace.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+                }
+                MacroDelimiter::Bracket(ref bracket) => {
+                    bracket.surround(tokens, |tokens| self.tts.to_tokens(tokens));
+                }
+            }
         }
     }
 }
diff --git a/src/tt.rs b/src/tt.rs
index db22284..b0952a0 100644
--- a/src/tt.rs
+++ b/src/tt.rs
@@ -1,48 +1,55 @@
-use proc_macro2::{TokenNode, TokenTree};
+use proc_macro2::{TokenNode, TokenStream, TokenTree, Delimiter};
 use cursor::Cursor;
 use parse_error;
 use synom::PResult;
+use MacroDelimiter;
+use token::{Paren, Brace, Bracket};
 
-#[cfg(feature = "full")]
-use proc_macro2::Delimiter;
-
-pub fn delimited(input: Cursor) -> PResult<TokenTree> {
+pub fn delimited(input: Cursor) -> PResult<(MacroDelimiter, TokenStream)> {
     match input.token_tree() {
         Some((
             rest,
-            token @ TokenTree {
-                kind: TokenNode::Group(..),
-                ..
+            TokenTree {
+                span,
+                kind: TokenNode::Group(delimiter, tts),
             },
-        )) => Ok((rest, token)),
+        )) => {
+            let delimiter = match delimiter {
+                Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
+                Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
+                Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
+                Delimiter::None => return parse_error(),
+            };
+            Ok((rest, (delimiter, tts)))
+        }
         _ => parse_error(),
     }
 }
 
 #[cfg(feature = "full")]
-pub fn braced(input: Cursor) -> PResult<TokenTree> {
+pub fn braced(input: Cursor) -> PResult<(Brace, TokenStream)> {
     match input.token_tree() {
         Some((
             rest,
-            token @ TokenTree {
-                kind: TokenNode::Group(Delimiter::Brace, ..),
-                ..
+            TokenTree {
+                span,
+                kind: TokenNode::Group(Delimiter::Brace, tts),
             },
-        )) => Ok((rest, token)),
+        )) => Ok((rest, (Brace(span), tts))),
         _ => parse_error(),
     }
 }
 
 #[cfg(feature = "full")]
-pub fn parenthesized(input: Cursor) -> PResult<TokenTree> {
+pub fn parenthesized(input: Cursor) -> PResult<(Paren, TokenStream)> {
     match input.token_tree() {
         Some((
             rest,
-            token @ TokenTree {
-                kind: TokenNode::Group(Delimiter::Parenthesis, ..),
-                ..
+            TokenTree {
+                span,
+                kind: TokenNode::Group(Delimiter::Parenthesis, tts),
             },
-        )) => Ok((rest, token)),
+        )) => Ok((rest, (Paren(span), tts))),
         _ => parse_error(),
     }
 }