Rewrite tokenization with `proc-macro2` tokens

This ended up being a bit larger of a commit than I intended! I imagine that
this'll be one of the larger of the commits working towards #142. The purpose of
this commit is to use an updated version of the `quote` crate which doesn't work
with strings but rather works with tokens form the `proc-macro2` crate. The
`proc-macro2` crate itself is based on the proposed API for `proc_macro` itself,
and will continue to mirror it. The hope is that we'll flip an easy switch
eventually to use compiler tokens, whereas for now we'll stick to string parsing
at the lowest layer.

The largest change here is the addition of span information to the AST. Building
on the previous PRs to refactor the AST this makes it relatively easy from a
user perspective to digest and use the AST still, it's just a few extra fields
on the side. The fallout from this was then quite large throughout the
`printing` feature of the crate. The `parsing`, `fold`, and `visit` features
then followed suit to get updated as well.

This commit also changes the the semantics of the AST somewhat as well.
Previously it was inferred what tokens should be printed, for example if you
have a closure argument `syn` would automatically not print the colon in `a: b`
if the type listed was "infer this type". Now the colon is a separate field and
must be in sync with the type listed as the colon/type will be printed
unconditionally (emitting no output if both are `None`).
diff --git a/src/aster/generics.rs b/src/aster/generics.rs
index caee562..8cc84d0 100644
--- a/src/aster/generics.rs
+++ b/src/aster/generics.rs
@@ -5,6 +5,8 @@
 use aster::ty_param::TyParamBuilder;
 use aster::where_predicate::WherePredicateBuilder;
 
+use delimited::Delimited;
+
 pub struct GenericsBuilder<F = Identity> {
     callback: F,
     lifetimes: Vec<LifetimeDef>,
@@ -37,16 +39,16 @@
     pub fn from_generics_with_callback(generics: Generics, callback: F) -> Self {
         GenericsBuilder {
             callback: callback,
-            lifetimes: generics.lifetimes,
-            ty_params: generics.ty_params,
-            predicates: generics.where_clause.predicates,
+            lifetimes: generics.lifetimes.into_vec(),
+            ty_params: generics.ty_params.into_vec(),
+            predicates: generics.where_clause.predicates.into_vec(),
         }
     }
 
     pub fn with(self, generics: Generics) -> Self {
-        self.with_lifetimes(generics.lifetimes.into_iter())
-            .with_ty_params(generics.ty_params.into_iter())
-            .with_predicates(generics.where_clause.predicates.into_iter())
+        self.with_lifetimes(generics.lifetimes.into_vec().into_iter())
+            .with_ty_params(generics.ty_params.into_vec().into_iter())
+            .with_predicates(generics.where_clause.predicates.into_vec().into_iter())
     }
 
     pub fn with_lifetimes<I, L>(mut self, iter: I) -> Self
@@ -141,7 +143,7 @@
         let lifetime = lifetime.into_lifetime();
 
         for lifetime_def in &mut self.lifetimes {
-            lifetime_def.bounds.push(lifetime.clone());
+            lifetime_def.bounds.push_default(lifetime.clone());
         }
 
         for ty_param in &mut self.ty_params {
@@ -174,14 +176,14 @@
 
     pub fn strip_lifetimes(mut self) -> Self {
         for lifetime in &mut self.lifetimes {
-            lifetime.bounds = vec![];
+            lifetime.bounds = Delimited::new();
         }
         self
     }
 
     pub fn strip_ty_params(mut self) -> Self {
         for ty_param in &mut self.ty_params {
-            ty_param.bounds = vec![];
+            ty_param.bounds = Delimited::new();
         }
         self
     }
@@ -193,10 +195,15 @@
 
     pub fn build(self) -> F::Result {
         self.callback.invoke(Generics {
-                                 lifetimes: self.lifetimes,
-                                 ty_params: self.ty_params,
-                                 where_clause: WhereClause { predicates: self.predicates },
-                             })
+            lifetimes: self.lifetimes.into(),
+            ty_params: self.ty_params.into(),
+            where_clause: WhereClause {
+                predicates: self.predicates.into(),
+                where_token: Default::default(),
+            },
+            lt_token: Default::default(),
+            gt_token: Default::default(),
+        })
     }
 }
 
diff --git a/src/aster/lifetime.rs b/src/aster/lifetime.rs
index 3bdf372..ead21fe 100644
--- a/src/aster/lifetime.rs
+++ b/src/aster/lifetime.rs
@@ -1,5 +1,6 @@
 use {Ident, Lifetime, LifetimeDef};
 use aster::invoke::{Invoke, Identity};
+use delimited::Delimited;
 
 // ////////////////////////////////////////////////////////////////////////////
 
@@ -36,7 +37,8 @@
         LifetimeDef {
             attrs: vec![],
             lifetime: self,
-            bounds: vec![],
+            bounds: Delimited::new(),
+            colon_token: Default::default(),
         }
     }
 }
@@ -95,9 +97,10 @@
 
     pub fn build(self) -> F::Result {
         self.callback.invoke(LifetimeDef {
-                                 attrs: vec![],
-                                 lifetime: self.lifetime,
-                                 bounds: self.bounds,
-                             })
+            attrs: vec![],
+            lifetime: self.lifetime,
+            bounds: self.bounds.into(),
+            colon_token: Default::default(),
+        })
     }
 }
diff --git a/src/aster/path.rs b/src/aster/path.rs
index e53b142..23d644e 100644
--- a/src/aster/path.rs
+++ b/src/aster/path.rs
@@ -1,5 +1,5 @@
 use {AngleBracketedParameterData, Generics, Ident, Lifetime, ParenthesizedParameterData, Path,
-     PathParameters, PathSegment, Ty, TypeBinding};
+     PathParameters, PathSegment, Ty, TypeBinding, FunctionRetTy};
 use aster::ident::ToIdent;
 use aster::invoke::{Invoke, Identity};
 use aster::lifetime::IntoLifetime;
@@ -139,9 +139,10 @@
 
     pub fn build(self) -> F::Result {
         self.callback.invoke(Path {
-                                 global: self.global,
-                                 segments: self.segments,
-                             })
+            global: self.global,
+            segments: self.segments.into(),
+            leading_colon: None,
+        })
     }
 }
 
@@ -181,10 +182,10 @@
 
     pub fn with_generics(self, generics: Generics) -> Self {
         // Strip off the bounds.
-        let lifetimes = generics.lifetimes.iter().map(|lifetime_def| lifetime_def.lifetime.clone());
+        let lifetimes = generics.lifetimes.iter().map(|lifetime_def| lifetime_def.item().lifetime.clone());
 
         let tys =
-            generics.ty_params.iter().map(|ty_param| TyBuilder::new().id(ty_param.ident.clone()));
+            generics.ty_params.iter().map(|ty_param| TyBuilder::new().id(ty_param.item().ident.clone()));
 
         self.with_lifetimes(lifetimes).with_tys(tys)
     }
@@ -252,23 +253,29 @@
 
     pub fn build_return(self, output: Option<Ty>) -> F::Result {
         let data = ParenthesizedParameterData {
-            inputs: self.tys,
-            output: output,
+            inputs: self.tys.into(),
+            output: match output {
+                Some(ty) => FunctionRetTy::Ty(ty, Default::default()),
+                None => FunctionRetTy::Default,
+            },
+            paren_token: Default::default(),
         };
 
         let parameters = PathParameters::Parenthesized(data);
 
         self.callback.invoke(PathSegment {
-                                 ident: self.id,
-                                 parameters: parameters,
-                             })
+            ident: self.id,
+            parameters: parameters,
+        })
     }
 
     pub fn build(self) -> F::Result {
         let data = AngleBracketedParameterData {
-            lifetimes: self.lifetimes,
-            types: self.tys,
-            bindings: self.bindings,
+            lifetimes: self.lifetimes.into(),
+            types: self.tys.into(),
+            bindings: self.bindings.into(),
+            gt_token: Default::default(),
+            lt_token: Default::default(),
         };
 
         let parameters = PathParameters::AngleBracketed(data);
@@ -306,9 +313,10 @@
         let id = self.id;
 
         self.builder.with_binding(TypeBinding {
-                                      ident: id,
-                                      ty: ty,
-                                  })
+            ident: id,
+            ty: ty,
+            eq_token: Default::default(),
+        })
     }
 }
 
diff --git a/src/aster/qpath.rs b/src/aster/qpath.rs
index 71f68b1..ea36837 100644
--- a/src/aster/qpath.rs
+++ b/src/aster/qpath.rs
@@ -3,6 +3,7 @@
 use aster::invoke::{Invoke, Identity};
 use aster::path::{PathBuilder, PathSegmentBuilder};
 use aster::ty::TyBuilder;
+use delimited::Delimited;
 
 // ////////////////////////////////////////////////////////////////////////////
 
@@ -74,7 +75,8 @@
     {
         let path = Path {
             global: false,
-            segments: vec![],
+            segments: Delimited::new(),
+            leading_colon: None,
         };
         self.as_().build(path).id(id)
     }
@@ -84,7 +86,8 @@
     {
         let path = Path {
             global: false,
-            segments: vec![],
+            segments: Delimited::new(),
+            leading_colon: None,
         };
         self.as_().build(path).segment(id)
     }
@@ -101,6 +104,9 @@
             qself: QSelf {
                 ty: Box::new(self.ty),
                 position: path.segments.len(),
+                as_token: Default::default(),
+                gt_token: Default::default(),
+                lt_token: Default::default(),
             },
             path: path,
         }
@@ -137,7 +143,7 @@
     type Result = F::Result;
 
     fn invoke(mut self, segment: PathSegment) -> F::Result {
-        self.path.segments.push(segment);
+        self.path.segments.push_default(segment);
         self.builder.build(self.qself, self.path)
     }
 }
diff --git a/src/aster/ty.rs b/src/aster/ty.rs
index f43e4a5..1d8962c 100644
--- a/src/aster/ty.rs
+++ b/src/aster/ty.rs
@@ -116,7 +116,10 @@
     }
 
     pub fn build_slice(self, ty: Ty) -> F::Result {
-        self.build(Ty::Slice(TySlice { ty: Box::new(ty) }))
+        self.build(Ty::Slice(TySlice {
+            ty: Box::new(ty),
+            bracket_token: Default::default(),
+        }))
     }
 
     pub fn slice(self) -> TyBuilder<TySliceBuilder<F>> {
@@ -132,11 +135,15 @@
     }
 
     pub fn never(self) -> F::Result {
-        self.build(Ty::Never(TyNever {}))
+        self.build(Ty::Never(TyNever {
+            bang_token: Default::default(),
+        }))
     }
 
     pub fn infer(self) -> F::Result {
-        self.build(Ty::Infer(TyInfer {}))
+        self.build(Ty::Infer(TyInfer {
+            underscore_token: Default::default()
+        }))
     }
 
     pub fn option(self) -> TyBuilder<TyOptionBuilder<F>> {
@@ -221,7 +228,7 @@
     where F: Invoke<Ty>
 {
     pub fn mut_(mut self) -> Self {
-        self.mutability = Mutability::Mutable;
+        self.mutability = Mutability::Mutable(Default::default());
         self
     }
 
@@ -240,6 +247,7 @@
         self.builder.build(Ty::Rptr(TyRptr {
             lifetime: self.lifetime,
             ty: Box::new(ty),
+            and_token: Default::default(),
         }))
     }
 
@@ -414,7 +422,9 @@
     }
 
     pub fn with_generics(self, generics: Generics) -> Self {
-        self.with_lifetimes(generics.lifetimes.into_iter().map(|def| def.lifetime))
+        self.with_lifetimes(generics.lifetimes.iter().map(|def| {
+            Lifetime { ident: def.item().lifetime.ident.clone() }
+        }))
     }
 
     pub fn with_lifetimes<I, L>(mut self, lifetimes: I) -> Self
@@ -437,7 +447,8 @@
     pub fn build(self) -> F::Result {
         let bounds = self.bounds;
         self.builder.build(Ty::ImplTrait(TyImplTrait {
-            bounds: bounds,
+            bounds: bounds.into(),
+            impl_token: Default::default(),
         }))
     }
 }
@@ -479,7 +490,11 @@
     }
 
     pub fn build(self) -> F::Result {
-        self.builder.build(Ty::Tup(TyTup { tys: self.tys }))
+        self.builder.build(Ty::Tup(TyTup {
+            tys: self.tys.into(),
+            paren_token: Default::default(),
+            lone_comma: None,
+        }))
     }
 }
 
diff --git a/src/aster/ty_param.rs b/src/aster/ty_param.rs
index d8d13d1..7f82f6b 100644
--- a/src/aster/ty_param.rs
+++ b/src/aster/ty_param.rs
@@ -1,4 +1,5 @@
 use {Ident, LifetimeDef, Path, PolyTraitRef, TraitBoundModifier, Ty, TyParam, TyParamBound};
+use BoundLifetimes;
 use aster::invoke::{Invoke, Identity};
 use aster::lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder};
 use aster::path::{IntoPath, PathBuilder};
@@ -43,7 +44,7 @@
         TyParamBuilder {
             callback: callback,
             id: ty_param.ident,
-            bounds: ty_param.bounds,
+            bounds: ty_param.bounds.into_vec(),
             default: ty_param.default,
         }
     }
@@ -87,11 +88,13 @@
 
     pub fn build(self) -> F::Result {
         self.callback.invoke(TyParam {
-                                 attrs: vec![],
-                                 ident: self.id,
-                                 bounds: self.bounds,
-                                 default: self.default,
-                             })
+            attrs: vec![],
+            ident: self.id,
+            bounds: self.bounds.into(),
+            default: self.default,
+            colon_token: Default::default(),
+            eq_token: Default::default(),
+        })
     }
 }
 
@@ -165,7 +168,7 @@
     {
         let builder = TraitTyParamBoundBuilder {
             builder: self,
-            modifier: TraitBoundModifier::Maybe,
+            modifier: TraitBoundModifier::Maybe(Default::default()),
         };
 
         PolyTraitRefBuilder::with_callback(path, builder)
@@ -245,9 +248,12 @@
 
     pub fn build(self) -> F::Result {
         self.callback.invoke(PolyTraitRef {
-                                 bound_lifetimes: self.lifetimes,
-                                 trait_ref: self.trait_ref,
-                             })
+            bound_lifetimes: Some(BoundLifetimes {
+                lifetimes: self.lifetimes.into(),
+                ..Default::default()
+            }),
+            trait_ref: self.trait_ref,
+        })
     }
 }
 
diff --git a/src/aster/where_predicate.rs b/src/aster/where_predicate.rs
index 611d058..16cdfd8 100644
--- a/src/aster/where_predicate.rs
+++ b/src/aster/where_predicate.rs
@@ -1,5 +1,5 @@
 use {Ident, Lifetime, LifetimeDef, Ty, TyParamBound, WhereBoundPredicate, WherePredicate,
-     WhereRegionPredicate};
+     WhereRegionPredicate, BoundLifetimes};
 use aster::invoke::{Invoke, Identity};
 use aster::lifetime::{IntoLifetime, IntoLifetimeDef, LifetimeDefBuilder};
 use aster::path::IntoPath;
@@ -201,9 +201,13 @@
 
     pub fn build(self) -> F::Result {
         let predicate = WhereBoundPredicate {
-            bound_lifetimes: self.bound_lifetimes,
+            bound_lifetimes: Some(BoundLifetimes {
+                lifetimes: self.bound_lifetimes.into(),
+                ..Default::default()
+            }),
             bounded_ty: self.ty,
-            bounds: self.bounds,
+            bounds: self.bounds.into(),
+            colon_token: Default::default(),
         };
 
         self.callback.invoke(WherePredicate::BoundPredicate(predicate))
@@ -251,7 +255,8 @@
     pub fn build(self) -> F::Result {
         let predicate = WhereRegionPredicate {
             lifetime: self.lifetime,
-            bounds: self.bounds,
+            bounds: self.bounds.into(),
+            colon_token: Default::default(),
         };
 
         self.callback.invoke(WherePredicate::RegionPredicate(predicate))
diff --git a/src/attr.rs b/src/attr.rs
index f839ec4..df51583 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -1,11 +1,16 @@
 use super::*;
+use delimited::Delimited;
 
 use std::iter;
 
+use proc_macro2::{self, Delimiter, TokenKind, OpKind};
+
 ast_struct! {
     /// Doc-comments are promoted to attributes that have `is_sugared_doc` = true
     pub struct Attribute {
         pub style: AttrStyle,
+        pub pound_token: tokens::Pound,
+        pub bracket_token: tokens::Bracket,
 
         /// The path of the attribute.
         ///
@@ -27,7 +32,7 @@
     /// Parses the tokens after the path as a [`MetaItem`](enum.MetaItem.html) if possible.
     pub fn meta_item(&self) -> Option<MetaItem> {
         let name = if self.path.segments.len() == 1 {
-            &self.path.segments[0].ident
+            &self.path.segments.get(0).item().ident
         } else {
             return None;
         };
@@ -37,76 +42,11 @@
         }
 
         if self.tts.len() == 1 {
-            if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, ref tts }) = self.tts[0] {
-                fn nested_meta_item_from_tokens(tts: &[TokenTree]) -> Option<(NestedMetaItem, &[TokenTree])> {
-                    assert!(!tts.is_empty());
-
-                    match tts[0] {
-                        TokenTree::Token(Token::Literal(ref lit)) => {
-                            Some((NestedMetaItem::Literal(lit.clone()), &tts[1..]))
-                        }
-
-                        TokenTree::Token(Token::Ident(ref ident)) => {
-                            if tts.len() >= 3 {
-                                if let TokenTree::Token(Token::Eq) = tts[1] {
-                                    if let TokenTree::Token(Token::Literal(ref lit)) = tts[2] {
-                                        let pair = MetaNameValue {
-                                            ident: ident.clone(),
-                                            lit: lit.clone(),
-                                        };
-                                        return Some((NestedMetaItem::MetaItem(MetaItem::NameValue(pair)), &tts[3..]));
-                                    }
-                                }
-                            }
-
-                            if tts.len() >= 2 {
-                                if let TokenTree::Delimited(Delimited { delim: DelimToken::Paren, tts: ref inner_tts }) = tts[1] {
-                                    return match list_of_nested_meta_items_from_tokens(vec![], inner_tts) {
-                                        Some(nested_meta_items) => {
-                                            let list = MetaItemList {
-                                                ident: ident.clone(),
-                                                nested: nested_meta_items,
-                                            };
-                                            Some((NestedMetaItem::MetaItem(MetaItem::List(list)), &tts[2..]))
-                                        }
-
-                                        None => None
-                                    };
-                                }
-                            }
-
-                            Some((NestedMetaItem::MetaItem(MetaItem::Word(ident.clone())), &tts[1..]))
-                        }
-
-                        _ => None
-                    }
-                }
-
-                fn list_of_nested_meta_items_from_tokens(mut result: Vec<NestedMetaItem>, tts: &[TokenTree]) -> Option<Vec<NestedMetaItem>> {
-                    if tts.is_empty() {
-                        return Some(result);
-                    }
-
-                    match nested_meta_item_from_tokens(tts) {
-                        Some((nested_meta_item, rest)) => {
-                            result.push(nested_meta_item);
-                            if rest.is_empty() {
-                                list_of_nested_meta_items_from_tokens(result, rest)
-                            }
-                            else if let TokenTree::Token(Token::Comma) = rest[0] {
-                                list_of_nested_meta_items_from_tokens(result, &rest[1..])
-                            }
-                            else {
-                                None
-                            }
-                        }
-
-                        None => None
-                    }
-                }
-
-                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(vec![], tts) {
+            if let TokenKind::Sequence(Delimiter::Parenthesis, ref ts) = self.tts[0].0.kind {
+                let tokens = ts.clone().into_iter().collect::<Vec<_>>();
+                if let Some(nested_meta_items) = list_of_nested_meta_items_from_tokens(&tokens) {
                     return Some(MetaItem::List(MetaItemList {
+                        paren_token: tokens::Paren(Span(self.tts[0].0.span)),
                         ident: name.clone(),
                         nested: nested_meta_items,
                     }));
@@ -115,11 +55,15 @@
         }
 
         if self.tts.len() == 2 {
-            if let TokenTree::Token(Token::Eq) = self.tts[0] {
-                if let TokenTree::Token(Token::Literal(ref lit)) = self.tts[1] {
+            if let TokenKind::Op('=', OpKind::Alone) = self.tts[0].0.kind {
+                if let TokenKind::Literal(ref lit) = self.tts[1].0.kind {
                     return Some(MetaItem::NameValue(MetaNameValue {
                         ident: name.clone(),
-                        lit: lit.clone(),
+                        eq_token: tokens::Eq([Span(self.tts[0].0.span)]),
+                        lit: Lit {
+                            value: LitKind::Other(lit.clone()),
+                            span: Span(self.tts[1].0.span),
+                        },
                     }));
                 }
             }
@@ -129,17 +73,109 @@
     }
 }
 
+fn nested_meta_item_from_tokens(tts: &[proc_macro2::TokenTree])
+    -> Option<(NestedMetaItem, &[proc_macro2::TokenTree])>
+{
+    assert!(!tts.is_empty());
+
+    match tts[0].kind {
+        TokenKind::Literal(ref lit) => {
+            let lit = Lit {
+                value: LitKind::Other(lit.clone()),
+                span: Span(tts[0].span),
+            };
+            Some((NestedMetaItem::Literal(lit), &tts[1..]))
+        }
+
+        TokenKind::Word(sym) => {
+            let ident = Ident::new(sym, Span(tts[0].span));
+            if tts.len() >= 3 {
+                if let TokenKind::Op('=', OpKind::Alone) = tts[1].kind {
+                    if let TokenKind::Literal(ref lit) = tts[2].kind {
+                        let pair = MetaNameValue {
+                            ident: Ident::new(sym, Span(tts[0].span)),
+                            eq_token: tokens::Eq([Span(tts[1].span)]),
+                            lit: Lit {
+                                value: LitKind::Other(lit.clone()),
+                                span: Span(tts[2].span),
+                            },
+                        };
+                        return Some((MetaItem::NameValue(pair).into(), &tts[3..]));
+                    }
+                }
+            }
+
+            if tts.len() >= 2 {
+                if let TokenKind::Sequence(Delimiter::Parenthesis, ref inner_tts) = tts[1].kind {
+                    let inner_tts = inner_tts.clone().into_iter().collect::<Vec<_>>();
+                    return match list_of_nested_meta_items_from_tokens(&inner_tts) {
+                        Some(nested_meta_items) => {
+                            let list = MetaItemList {
+                                ident: ident,
+                                paren_token: tokens::Paren(Span(tts[1].span)),
+                                nested: nested_meta_items,
+                            };
+                            Some((MetaItem::List(list).into(), &tts[2..]))
+                        }
+
+                        None => None
+                    };
+                }
+            }
+
+            Some((MetaItem::Word(ident).into(), &tts[1..]))
+        }
+
+        _ => None
+    }
+}
+
+fn list_of_nested_meta_items_from_tokens(mut tts: &[proc_macro2::TokenTree])
+    -> Option<Delimited<NestedMetaItem, tokens::Comma>>
+{
+    let mut delimited = Delimited::new();
+    let mut first = true;
+
+    while !tts.is_empty() {
+        let prev_comma = if first {
+            first = false;
+            None
+        } else if let TokenKind::Op(',', OpKind::Alone) = tts[0].kind {
+            let tok = tokens::Comma([Span(tts[0].span)]);
+            tts = &tts[1..];
+            if tts.is_empty() {
+                break
+            }
+            Some(tok)
+        } else {
+            return None
+        };
+        let (nested, rest) = match nested_meta_item_from_tokens(tts) {
+            Some(pair) => pair,
+            None => return None,
+        };
+        match prev_comma {
+            Some(comma) => delimited.push_next(nested, comma),
+            None => delimited.push_first(nested),
+        }
+        tts = rest;
+    }
+
+    Some(delimited)
+}
+
+
 ast_enum! {
     /// Distinguishes between Attributes that decorate items and Attributes that
     /// are contained as statements within items. These two cases need to be
     /// distinguished for pretty-printing.
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum AttrStyle {
-        /// Attribute of the form `#![...]`.
+        /// Attribute of the form `#[...]`.
         Outer,
 
-        /// Attribute of the form `#[...]`.
-        Inner,
+        /// Attribute of the form `#![...]`.
+        Inner(tokens::Bang),
     }
 }
 
@@ -162,10 +198,12 @@
             /// E.g. `derive` in `#[derive(..)]`
             pub ident: Ident,
 
+            pub paren_token: tokens::Paren,
+
             /// Arguments to this attribute
             ///
             /// E.g. `..` in `#[derive(..)]`
-            pub nested: Vec<NestedMetaItem>,
+            pub nested: Delimited<NestedMetaItem, tokens::Comma>,
         }),
 
         /// Name-value meta item.
@@ -177,6 +215,8 @@
             /// E.g. `feature` in `#[feature = "foo"]`
             pub ident: Ident,
 
+            pub eq_token: tokens::Eq,
+
             /// Arguments to this attribute
             ///
             /// E.g. `"foo"` in `#[feature = "foo"]`
@@ -241,7 +281,7 @@
     fn inner(self) -> Self::Ret {
         fn is_inner(attr: &&Attribute) -> bool {
             match attr.style {
-                AttrStyle::Inner => true,
+                AttrStyle::Inner(_) => true,
                 _ => false,
             }
         }
@@ -252,11 +292,25 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use lit::{Lit, StrStyle};
-    use mac::{Token, TokenTree};
+    use mac::TokenTree;
     use mac::parsing::token_trees;
     use synom::space::{block_comment, whitespace};
     use ty::parsing::mod_style_path;
+    use proc_macro2::{self, TokenKind, OpKind, Literal};
+
+    fn eq() -> TokenTree {
+        TokenTree(proc_macro2::TokenTree {
+            span: Default::default(),
+            kind: TokenKind::Op('=', OpKind::Alone),
+        })
+    }
+
+    fn doc(s: &str) -> TokenTree {
+        TokenTree(proc_macro2::TokenTree {
+            span: Default::default(),
+            kind: TokenKind::Literal(Literal::doccomment(s)),
+        })
+    }
 
     #[cfg(feature = "full")]
     named!(pub inner_attr -> Attribute, alt!(
@@ -272,10 +326,12 @@
                 let (path, tts) = path_and_tts;
 
                 Attribute {
-                    style: AttrStyle::Inner,
+                    style: AttrStyle::Inner(tokens::Bang::default()),
                     path: path,
                     tts: tts,
                     is_sugared_doc: false,
+                    pound_token: tokens::Pound::default(),
+                    bracket_token: tokens::Bracket::default(),
                 }
             })
         )
@@ -284,13 +340,15 @@
             punct!("//!") >>
             content: take_until!("\n") >>
             (Attribute {
-                style: AttrStyle::Inner,
+                style: AttrStyle::Inner(tokens::Bang::default()),
                 path: "doc".into(),
                 tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
+                    eq(),
+                    doc(&format!("//!{}", content)),
                 ],
                 is_sugared_doc: true,
+                pound_token: tokens::Pound::default(),
+                bracket_token: tokens::Bracket::default(),
             })
         )
         |
@@ -299,13 +357,15 @@
             peek!(tag!("/*!")) >>
             com: block_comment >>
             (Attribute {
-                style: AttrStyle::Inner,
+                style: AttrStyle::Inner(tokens::Bang::default()),
                 path: "doc".into(),
                 tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+                    eq(),
+                    doc(com),
                 ],
                 is_sugared_doc: true,
+                pound_token: tokens::Pound::default(),
+                bracket_token: tokens::Bracket::default(),
             })
         )
     ));
@@ -326,6 +386,8 @@
                     path: path,
                     tts: tts,
                     is_sugared_doc: false,
+                    pound_token: tokens::Pound::default(),
+                    bracket_token: tokens::Bracket::default(),
                 }
             })
         )
@@ -338,10 +400,12 @@
                 style: AttrStyle::Outer,
                 path: "doc".into(),
                 tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
+                    eq(),
+                    doc(&format!("///{}", content)),
                 ],
                 is_sugared_doc: true,
+                pound_token: tokens::Pound::default(),
+                bracket_token: tokens::Bracket::default(),
             })
         )
         |
@@ -353,10 +417,12 @@
                 style: AttrStyle::Outer,
                 path: "doc".into(),
                 tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+                    eq(),
+                    doc(com),
                 ],
                 is_sugared_doc: true,
+                pound_token: tokens::Pound::default(),
+                bracket_token: tokens::Bracket::default(),
             })
         )
     ));
@@ -365,77 +431,71 @@
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use lit::{Lit, StrStyle};
-    use mac::{Token, TokenTree};
     use quote::{Tokens, ToTokens};
-    use ty::Path;
+    use proc_macro2::{Literal, TokenTree};
 
     impl ToTokens for Attribute {
         fn to_tokens(&self, tokens: &mut Tokens) {
             // If this was a sugared doc, emit it in its original form instead of `#[doc = "..."]`
-            match *self {
-                Attribute {
-                    ref style,
-                    path: Path { global: false, ref segments },
-                    ref tts,
-                    is_sugared_doc: true,
-                } if segments.len() == 1 &&
-                     segments[0].ident == "doc" &&
-                     segments[0].parameters.is_empty() &&
-                     tts.len() == 2 =>
-                {
-                    if let TokenTree::Token(Token::Eq) = self.tts[0] {
-                        if let TokenTree::Token(Token::Literal(Lit::Str(ref value, StrStyle::Cooked))) = self.tts[1] {
-                            match *style {
-                                AttrStyle::Inner if value.starts_with("//!") => {
-                                    tokens.append(&format!("{}\n", value));
-                                    return;
-                                }
-                                AttrStyle::Inner if value.starts_with("/*!") => {
-                                    tokens.append(value);
-                                    return;
-                                }
-                                AttrStyle::Outer if value.starts_with("///") => {
-                                    tokens.append(&format!("{}\n", value));
-                                    return;
-                                }
-                                AttrStyle::Outer if value.starts_with("/**") => {
-                                    tokens.append(value);
-                                    return;
-                                }
-                                _ => {}
+            if self.is_sugared_doc {
+                if let Some(MetaItem::NameValue(ref pair)) = self.meta_item() {
+                    if pair.ident == "doc" {
+                        let value = pair.lit.value.to_string();
+                        match self.style {
+                            AttrStyle::Inner(_) if value.starts_with("//!") => {
+                                let doc = Literal::doccomment(&format!("{}\n", value));
+                                tokens.append(TokenTree {
+                                    span: pair.lit.span.0,
+                                    kind: TokenKind::Literal(doc),
+                                });
+                                return;
                             }
+                            AttrStyle::Inner(_) if value.starts_with("/*!") => {
+                                pair.lit.to_tokens(tokens);
+                                return;
+                            }
+                            AttrStyle::Outer if value.starts_with("///") => {
+                                let doc = Literal::doccomment(&format!("{}\n", value));
+                                tokens.append(TokenTree {
+                                    span: pair.lit.span.0,
+                                    kind: TokenKind::Literal(doc),
+                                });
+                                return;
+                            }
+                            AttrStyle::Outer if value.starts_with("/**") => {
+                                pair.lit.to_tokens(tokens);
+                                return;
+                            }
+                            _ => {}
                         }
                     }
                 }
-
-                _ => {}
             }
 
-            tokens.append("#");
-            if let AttrStyle::Inner = self.style {
-                tokens.append("!");
+            self.pound_token.to_tokens(tokens);
+            if let AttrStyle::Inner(ref b) = self.style {
+                b.to_tokens(tokens);
             }
-            tokens.append("[");
-            self.path.to_tokens(tokens);
-            tokens.append_all(&self.tts);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.path.to_tokens(tokens);
+                tokens.append_all(&self.tts);
+            });
         }
     }
 
     impl ToTokens for MetaItemList {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
-            tokens.append("(");
-            tokens.append_separated(&self.nested, ",");
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.nested.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for MetaNameValue {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.lit.to_tokens(tokens);
         }
     }
diff --git a/src/constant.rs b/src/constant.rs
index 2267b50..1a2818c 100644
--- a/src/constant.rs
+++ b/src/constant.rs
@@ -1,4 +1,5 @@
 use super::*;
+use delimited::Delimited;
 
 ast_enum_of_structs! {
     pub enum ConstExpr {
@@ -8,7 +9,9 @@
             pub func: Box<ConstExpr>,
 
             /// The arguments to the function being called
-            pub args: Vec<ConstExpr>,
+            pub args: Delimited<ConstExpr, tokens::Comma>,
+
+            pub paren_token: tokens::Paren,
         }),
 
         /// A binary operation (For example: `a + b`, `a * b`)
@@ -42,6 +45,8 @@
 
             /// Type casted to
             pub ty: Box<Ty>,
+
+            pub as_token: tokens::As,
         }),
 
         /// Variable reference, possibly containing `::` and/or type
@@ -55,12 +60,15 @@
 
             /// Index expression
             pub index: Box<ConstExpr>,
+
+            pub bracket_token: tokens::Bracket,
         }),
 
         /// No-op: used solely so we can pretty-print faithfully
         pub Paren(ConstParen {
             /// Expression that's parenthesized
             pub expr: Box<ConstExpr>,
+            pub paren_token: tokens::Paren,
         }),
 
         /// If compiling with full support for expression syntax, any expression is
@@ -103,7 +111,12 @@
         ) >>
         many0!(alt!(
             tap!(args: and_call => {
-                e = ConstCall { func: Box::new(e), args: args }.into();
+                let (args, paren) = args;
+                e = ConstCall {
+                    func: Box::new(e),
+                    args: args,
+                    paren_token: paren,
+                }.into();
             })
             |
             tap!(more: and_binary => {
@@ -112,21 +125,32 @@
             })
             |
             tap!(ty: and_cast => {
-                e = ConstCast { expr: Box::new(e), ty: Box::new(ty) }.into();
+                let (ty, token) = ty;
+                e = ConstCast {
+                    expr: Box::new(e),
+                    ty: Box::new(ty),
+                    as_token: token,
+                }.into();
             })
             |
             tap!(i: and_index => {
-                e = ConstIndex { expr: Box::new(e), index: Box::new(i) }.into();
+                let (i, bracket) = i;
+                e = ConstIndex {
+                    expr: Box::new(e),
+                    index: Box::new(i),
+                    bracket_token: bracket,
+                }.into();
             })
         )) >>
         (e)
     ));
 
-    named!(and_call -> Vec<ConstExpr>, do_parse!(
+    named!(and_call -> (Delimited<ConstExpr, tokens::Comma>, tokens::Paren), do_parse!(
         punct!("(") >>
-        args: terminated_list!(punct!(","), const_expr) >>
+        args: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                               const_expr) >>
         punct!(")") >>
-        (args)
+        (args, tokens::Paren::default())
     ));
 
     named!(and_binary -> (BinOp, ConstExpr), tuple!(binop, const_expr));
@@ -141,19 +165,27 @@
 
     named!(expr_path -> ConstExpr, map!(path, ConstExpr::Path));
 
-    named!(and_index -> ConstExpr, delimited!(punct!("["), const_expr, punct!("]")));
+    named!(and_index -> (ConstExpr, tokens::Bracket), do_parse!(
+        punct!("[") >>
+        expr: const_expr >>
+        punct!("]") >>
+        (expr, tokens::Bracket::default())
+    ));
 
     named!(expr_paren -> ConstExpr, do_parse!(
         punct!("(") >>
         e: const_expr >>
         punct!(")") >>
-        (ConstParen { expr: Box::new(e) }.into())
+        (ConstParen {
+            expr: Box::new(e),
+            paren_token: tokens::Paren::default(),
+        }.into())
     ));
 
-    named!(and_cast -> Ty, do_parse!(
+    named!(and_cast -> (Ty, tokens::As), do_parse!(
         keyword!("as") >>
         ty: ty >>
-        (ty)
+        (ty, tokens::As::default())
     ));
 }
 
@@ -165,9 +197,9 @@
     impl ToTokens for ConstCall {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.func.to_tokens(tokens);
-            tokens.append("(");
-            tokens.append_separated(&self.args, ",");
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.args.to_tokens(tokens);
+            })
         }
     }
 
@@ -189,7 +221,7 @@
     impl ToTokens for ConstCast {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append("as");
+            self.as_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
@@ -197,17 +229,17 @@
     impl ToTokens for ConstIndex {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append("[");
-            self.index.to_tokens(tokens);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.index.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for ConstParen {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            self.expr.to_tokens(tokens);
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.expr.to_tokens(tokens);
+            })
         }
     }
 
diff --git a/src/data.rs b/src/data.rs
index 3916b25..5085986 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -1,4 +1,5 @@
 use super::*;
+use delimited::Delimited;
 
 ast_struct! {
     /// An enum variant.
@@ -14,6 +15,8 @@
 
         /// Explicit discriminant, e.g. `Foo = 1`
         pub discriminant: Option<ConstExpr>,
+
+        pub eq_token: Option<tokens::Eq>,
     }
 }
 
@@ -21,10 +24,10 @@
     /// Data stored within an enum variant or struct.
     pub enum VariantData {
         /// Struct variant, e.g. `Point { x: f64, y: f64 }`.
-        Struct(Vec<Field>),
+        Struct(Delimited<Field, tokens::Comma>, tokens::Brace),
 
         /// Tuple variant, e.g. `Some(T)`.
-        Tuple(Vec<Field>),
+        Tuple(Delimited<Field, tokens::Comma>, tokens::Paren),
 
         /// Unit variant, e.g. `None`.
         Unit,
@@ -32,23 +35,24 @@
 }
 
 impl VariantData {
-    /// Slice containing the fields stored in the variant.
-    pub fn fields(&self) -> &[Field] {
-        match *self {
-            VariantData::Struct(ref fields) |
-            VariantData::Tuple(ref fields) => fields,
-            VariantData::Unit => &[],
-        }
-    }
-
-    /// Mutable slice containing the fields stored in the variant.
-    pub fn fields_mut(&mut self) -> &mut [Field] {
-        match *self {
-            VariantData::Struct(ref mut fields) |
-            VariantData::Tuple(ref mut fields) => fields,
-            VariantData::Unit => &mut [],
-        }
-    }
+    // TODO: expose this?
+    // /// Slice containing the fields stored in the variant.
+    // pub fn fields(&self) -> &Delimited<Field, tokens::Comma> {
+    //     match *self {
+    //         VariantData::Struct(ref fields, _) |
+    //         VariantData::Tuple(ref fields, _) => fields,
+    //         VariantData::Unit => &[],
+    //     }
+    // }
+    //
+    // /// Mutable slice containing the fields stored in the variant.
+    // pub fn fields_mut(&mut self) -> &mut Delimited<Field, tokens::Comma> {
+    //     match *self {
+    //         VariantData::Struct(ref mut fields, _) |
+    //         VariantData::Tuple(ref mut fields, _) => fields,
+    //         VariantData::Unit => &mut [],
+    //     }
+    // }
 }
 
 ast_struct! {
@@ -67,23 +71,36 @@
 
         /// Type of the field.
         pub ty: Ty,
+
+        pub colon_token: Option<tokens::Colon>,
     }
 }
 
-ast_enum! {
+ast_enum_of_structs! {
     /// Visibility level of an item.
     pub enum Visibility {
         /// Public, i.e. `pub`.
-        Public,
+        pub Public(VisPublic {
+            pub pub_token: tokens::Pub,
+        }),
 
         /// Crate-visible, i.e. `pub(crate)`.
-        Crate,
+        pub Crate(VisCrate {
+            pub pub_token: tokens::Pub,
+            pub paren_token: tokens::Paren,
+            pub crate_token: tokens::Crate,
+        }),
 
         /// Restricted, e.g. `pub(self)` or `pub(super)` or `pub(in some::module)`.
-        Restricted(Box<Path>),
+        pub Restricted(VisRestricted {
+            pub pub_token: tokens::Pub,
+            pub paren_token: tokens::Paren,
+            pub in_token: Option<tokens::In>,
+            pub path: Box<Path>,
+        }),
 
         /// Inherited, i.e. private.
-        Inherited,
+        pub Inherited(VisInherited {}),
     }
 }
 
@@ -102,42 +119,43 @@
     use ident::parsing::ident;
     use ty::parsing::{mod_style_path, ty};
 
-    named!(pub struct_body -> (WhereClause, VariantData), alt!(
+    named!(pub struct_body -> (WhereClause, VariantData, Option<tokens::Semi>), alt!(
         do_parse!(
             wh: where_clause >>
             body: struct_like_body >>
-            (wh, VariantData::Struct(body))
+            (wh, VariantData::Struct(body.0, body.1), None)
         )
         |
         do_parse!(
             body: tuple_like_body >>
             wh: where_clause >>
             punct!(";") >>
-            (wh, VariantData::Tuple(body))
+            (wh, VariantData::Tuple(body.0, body.1), Some(tokens::Semi::default()))
         )
         |
         do_parse!(
             wh: where_clause >>
             punct!(";") >>
-            (wh, VariantData::Unit)
+            (wh, VariantData::Unit, Some(tokens::Semi::default()))
         )
     ));
 
-    named!(pub enum_body -> (WhereClause, Vec<Variant>), do_parse!(
+    named!(pub enum_body -> (WhereClause, Delimited<Variant, tokens::Comma>, tokens::Brace), do_parse!(
         wh: where_clause >>
         punct!("{") >>
-        variants: terminated_list!(punct!(","), variant) >>
+        variants: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                   variant) >>
         punct!("}") >>
-        (wh, variants)
+        (wh, variants, tokens::Brace::default())
     ));
 
     named!(variant -> Variant, do_parse!(
         attrs: many0!(outer_attr) >>
         id: ident >>
         data: alt!(
-            struct_like_body => { VariantData::Struct }
+            struct_like_body => { |(d, b)| VariantData::Struct(d, b) }
             |
-            tuple_like_body => { VariantData::Tuple }
+            tuple_like_body => { |(d, b)| VariantData::Tuple(d, b) }
             |
             epsilon!() => { |_| VariantData::Unit }
         ) >>
@@ -146,6 +164,7 @@
             ident: id,
             attrs: attrs,
             data: data,
+            eq_token: disr.as_ref().map(|_| tokens::Eq::default()),
             discriminant: disr,
         })
     ));
@@ -163,18 +182,20 @@
     #[cfg(feature = "full")]
     named!(after_discriminant -> &str, peek!(alt!(punct!(",") | punct!("}"))));
 
-    named!(pub struct_like_body -> Vec<Field>, do_parse!(
+    named!(pub struct_like_body -> (Delimited<Field, tokens::Comma>, tokens::Brace), do_parse!(
         punct!("{") >>
-        fields: terminated_list!(punct!(","), struct_field) >>
+        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 struct_field) >>
         punct!("}") >>
-        (fields)
+        (fields, tokens::Brace::default())
     ));
 
-    named!(tuple_like_body -> Vec<Field>, do_parse!(
+    named!(tuple_like_body -> (Delimited<Field, tokens::Comma>, tokens::Paren), do_parse!(
         punct!("(") >>
-        fields: terminated_list!(punct!(","), tuple_field) >>
+        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 tuple_field) >>
         punct!(")") >>
-        (fields)
+        (fields, tokens::Paren::default())
     ));
 
     named!(struct_field -> Field, do_parse!(
@@ -188,6 +209,7 @@
             vis: vis,
             attrs: attrs,
             ty: ty,
+            colon_token: Some(tokens::Colon::default()),
         })
     ));
 
@@ -197,6 +219,7 @@
         ty: ty >>
         (Field {
             ident: None,
+            colon_token: None,
             vis: vis,
             attrs: attrs,
             ty: ty,
@@ -209,7 +232,11 @@
             punct!("(") >>
             keyword!("crate") >>
             punct!(")") >>
-            (Visibility::Crate)
+            (Visibility::Crate(VisCrate {
+                crate_token: tokens::Crate::default(),
+                paren_token: tokens::Paren::default(),
+                pub_token: tokens::Pub::default(),
+            }))
         )
         |
         do_parse!(
@@ -217,7 +244,12 @@
             punct!("(") >>
             keyword!("self") >>
             punct!(")") >>
-            (Visibility::Restricted(Box::new("self".into())))
+            (Visibility::Restricted(VisRestricted {
+                path: Box::new("self".into()),
+                in_token: None,
+                paren_token: tokens::Paren::default(),
+                pub_token: tokens::Pub::default(),
+            }))
         )
         |
         do_parse!(
@@ -225,7 +257,12 @@
             punct!("(") >>
             keyword!("super") >>
             punct!(")") >>
-            (Visibility::Restricted(Box::new("super".into())))
+            (Visibility::Restricted(VisRestricted {
+                path: Box::new("super".into()),
+                in_token: None,
+                paren_token: tokens::Paren::default(),
+                pub_token: tokens::Pub::default(),
+            }))
         )
         |
         do_parse!(
@@ -234,12 +271,21 @@
             keyword!("in") >>
             restricted: mod_style_path >>
             punct!(")") >>
-            (Visibility::Restricted(Box::new(restricted)))
+            (Visibility::Restricted(VisRestricted {
+                path: Box::new(restricted),
+                in_token: Some(tokens::In::default()),
+                paren_token: tokens::Paren::default(),
+                pub_token: tokens::Pub::default(),
+            }))
         )
         |
-        keyword!("pub") => { |_| Visibility::Public }
+        keyword!("pub") => { |_| {
+            Visibility::Public(VisPublic {
+                pub_token: tokens::Pub::default(),
+            })
+        } }
         |
-        epsilon!() => { |_| Visibility::Inherited }
+        epsilon!() => { |_| Visibility::Inherited(VisInherited {}) }
     ));
 }
 
@@ -250,30 +296,26 @@
 
     impl ToTokens for Variant {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            for attr in &self.attrs {
-                attr.to_tokens(tokens);
-            }
+            tokens.append_all(&self.attrs);
             self.ident.to_tokens(tokens);
             self.data.to_tokens(tokens);
-            if let Some(ref disr) = self.discriminant {
-                tokens.append("=");
-                disr.to_tokens(tokens);
-            }
+            self.eq_token.to_tokens(tokens);
+            self.discriminant.to_tokens(tokens);
         }
     }
 
     impl ToTokens for VariantData {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                VariantData::Struct(ref fields) => {
-                    tokens.append("{");
-                    tokens.append_separated(fields, ",");
-                    tokens.append("}");
+                VariantData::Struct(ref fields, ref brace) => {
+                    brace.surround(tokens, |tokens| {
+                        fields.to_tokens(tokens);
+                    });
                 }
-                VariantData::Tuple(ref fields) => {
-                    tokens.append("(");
-                    tokens.append_separated(fields, ",");
-                    tokens.append(")");
+                VariantData::Tuple(ref fields, ref paren) => {
+                    paren.surround(tokens, |tokens| {
+                        fields.to_tokens(tokens);
+                    });
                 }
                 VariantData::Unit => {}
             }
@@ -282,47 +324,41 @@
 
     impl ToTokens for Field {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            for attr in &self.attrs {
-                attr.to_tokens(tokens);
-            }
+            tokens.append_all(&self.attrs);
             self.vis.to_tokens(tokens);
-            if let Some(ref ident) = self.ident {
-                ident.to_tokens(tokens);
-                tokens.append(":");
-            }
+            self.ident.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
 
-    impl ToTokens for Visibility {
+    impl ToTokens for VisPublic {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                Visibility::Public => tokens.append("pub"),
-                Visibility::Crate => {
-                    tokens.append("pub");
-                    tokens.append("(");
-                    tokens.append("crate");
-                    tokens.append(")");
-                }
-                Visibility::Restricted(ref path) => {
-                    tokens.append("pub");
-                    tokens.append("(");
+            self.pub_token.to_tokens(tokens)
+        }
+    }
 
-                    if !path.global &&
-                       path.segments.len() == 1 &&
-                       (path.segments[0].ident == "self" || path.segments[0].ident == "super") &&
-                       path.segments[0].parameters.is_empty() {
+    impl ToTokens for VisCrate {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.pub_token.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.crate_token.to_tokens(tokens);
+            })
+        }
+    }
 
-                        // Don't emit preceding `in` if path is `self` or `super`
-                    } else {
-                        tokens.append("in");
-                    }
+    impl ToTokens for VisRestricted {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.pub_token.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.in_token.to_tokens(tokens);
+                self.path.to_tokens(tokens);
+            });
+        }
+    }
 
-                    path.to_tokens(tokens);
-                    tokens.append(")");
-                }
-                Visibility::Inherited => {}
-            }
+    impl ToTokens for VisInherited {
+        fn to_tokens(&self, _tokens: &mut Tokens) {
         }
     }
 }
diff --git a/src/derive.rs b/src/derive.rs
index 3b22b0f..cf44b4d 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -1,4 +1,5 @@
 use super::*;
+use delimited::Delimited;
 
 ast_struct! {
     /// Struct or enum sent to a `proc_macro_derive` macro.
@@ -21,15 +22,25 @@
 }
 
 
-ast_enum! {
+ast_enum_of_structs! {
     /// Body of a derived struct or enum.
     pub enum Body {
         /// It's an enum.
-        Enum(Vec<Variant>),
+        pub Enum(BodyEnum {
+            pub enum_token: tokens::Enum,
+            pub brace_token: tokens::Brace,
+            pub variants: Delimited<Variant, tokens::Comma>,
+        }),
 
         /// It's a struct.
-        Struct(VariantData),
+        pub Struct(BodyStruct {
+            pub data: VariantData,
+            pub struct_token: tokens::Struct,
+            pub semi_token: Option<tokens::Semi>,
+        }),
     }
+
+    do_not_generate_to_tokens
 }
 
 #[cfg(feature = "parsing")]
@@ -48,7 +59,7 @@
         id: ident >>
         generics: generics >>
         item: switch!(value!(which),
-            "struct" => map!(struct_body, move |(wh, body)| DeriveInput {
+            "struct" => map!(struct_body, move |(wh, body, semi)| DeriveInput {
                 ident: id,
                 vis: vis,
                 attrs: attrs,
@@ -56,10 +67,14 @@
                     where_clause: wh,
                     .. generics
                 },
-                body: Body::Struct(body),
+                body: Body::Struct(BodyStruct {
+                    struct_token: tokens::Struct::default(),
+                    data: body,
+                    semi_token: semi,
+                }),
             })
             |
-            "enum" => map!(enum_body, move |(wh, body)| DeriveInput {
+            "enum" => map!(enum_body, move |(wh, body, brace)| DeriveInput {
                 ident: id,
                 vis: vis,
                 attrs: attrs,
@@ -67,7 +82,11 @@
                     where_clause: wh,
                     .. generics
                 },
-                body: Body::Enum(body),
+                body: Body::Enum(BodyEnum {
+                    variants: body,
+                    brace_token: brace,
+                    enum_token: tokens::Enum::default(),
+                }),
             })
         ) >>
         (item)
@@ -88,38 +107,33 @@
             }
             self.vis.to_tokens(tokens);
             match self.body {
-                Body::Enum(_) => tokens.append("enum"),
-                Body::Struct(_) => tokens.append("struct"),
+                Body::Enum(ref d) => d.enum_token.to_tokens(tokens),
+                Body::Struct(ref d) => d.struct_token.to_tokens(tokens),
             }
             self.ident.to_tokens(tokens);
             self.generics.to_tokens(tokens);
             match self.body {
-                Body::Enum(ref variants) => {
+                Body::Enum(ref data) => {
                     self.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    for variant in variants {
-                        variant.to_tokens(tokens);
-                        tokens.append(",");
-                    }
-                    tokens.append("}");
+                    data.brace_token.surround(tokens, |tokens| {
+                        data.variants.to_tokens(tokens);
+                    });
                 }
-                Body::Struct(ref variant_data) => {
-                    match *variant_data {
-                        VariantData::Struct(_) => {
+                Body::Struct(ref data) => {
+                    match data.data {
+                        VariantData::Struct(..) => {
                             self.generics.where_clause.to_tokens(tokens);
-                            variant_data.to_tokens(tokens);
-                            // no semicolon
+                            data.data.to_tokens(tokens);
                         }
-                        VariantData::Tuple(_) => {
-                            variant_data.to_tokens(tokens);
+                        VariantData::Tuple(..) => {
+                            data.data.to_tokens(tokens);
                             self.generics.where_clause.to_tokens(tokens);
-                            tokens.append(";");
                         }
                         VariantData::Unit => {
                             self.generics.where_clause.to_tokens(tokens);
-                            tokens.append(";");
                         }
                     }
+                    data.semi_token.to_tokens(tokens);
                 }
             }
         }
diff --git a/src/expr.rs b/src/expr.rs
index 05f195a..2956ec9 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1,4 +1,5 @@
 use super::*;
+use delimited::Delimited;
 
 ast_struct! {
     /// An expression.
@@ -25,23 +26,27 @@
         /// A `box x` expression.
         pub Box(ExprBox {
             pub expr: Box<Expr>,
+            pub box_token: tokens::Box,
         }),
 
         /// E.g. 'place <- val'.
         pub InPlace(ExprInPlace {
             pub place: Box<Expr>,
             pub value: Box<Expr>,
+            pub in_token: tokens::In,
         }),
 
         /// An array, e.g. `[a, b, c, d]`.
         pub Array(ExprArray {
-            pub exprs: Vec<Expr>,
+            pub exprs: Delimited<Expr, tokens::Comma>,
+            pub bracket_token: tokens::Bracket,
         }),
 
         /// A function call.
         pub Call(ExprCall {
             pub func: Box<Expr>,
-            pub args: Vec<Expr>,
+            pub args: Delimited<Expr, tokens::Comma>,
+            pub paren_token: tokens::Paren,
         }),
 
         /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
@@ -50,21 +55,25 @@
         /// The vector of `Ty`s are the ascripted type parameters for the method
         /// (within the angle brackets).
         ///
-        /// The first element of the vector of `Expr`s is the expression that evaluates
-        /// to the object on which the method is being called on (the receiver),
-        /// and the remaining elements are the rest of the arguments.
-        ///
         /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
         /// `ExprKind::MethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
         pub MethodCall(ExprMethodCall {
+            pub expr: Box<Expr>,
             pub method: Ident,
-            pub typarams: Vec<Ty>,
-            pub args: Vec<Expr>,
+            pub typarams: Delimited<Ty, tokens::Comma>,
+            pub args: Delimited<Expr, tokens::Comma>,
+            pub paren_token: tokens::Paren,
+            pub dot_token: tokens::Dot,
+            pub lt_token: Option<tokens::Lt>,
+            pub colon2_token: Option<tokens::Colon2>,
+            pub gt_token: Option<tokens::Gt>,
         }),
 
         /// A tuple, e.g. `(a, b, c, d)`.
         pub Tup(ExprTup {
-            pub args: Vec<Expr>,
+            pub args: Delimited<Expr, tokens::Comma>,
+            pub paren_token: tokens::Paren,
+            pub lone_comma: Option<tokens::Comma>,
         }),
 
         /// A binary operation, e.g. `a + b`, `a * b`.
@@ -86,12 +95,14 @@
         /// A cast, e.g. `foo as f64`.
         pub Cast(ExprCast {
             pub expr: Box<Expr>,
+            pub as_token: tokens::As,
             pub ty: Box<Ty>,
         }),
 
         /// A type ascription, e.g. `foo: f64`.
         pub Type(ExprType {
             pub expr: Box<Expr>,
+            pub colon_token: tokens::Colon,
             pub ty: Box<Ty>,
         }),
 
@@ -102,6 +113,8 @@
             pub cond: Box<Expr>,
             pub if_true: Block,
             pub if_false: Option<Box<Expr>>,
+            pub if_token: tokens::If,
+            pub else_token: Option<tokens::Else>,
         }),
 
         /// An `if let` expression with an optional else block
@@ -114,6 +127,10 @@
             pub expr: Box<Expr>,
             pub if_true: Block,
             pub if_false: Option<Box<Expr>>,
+            pub if_token: tokens::If,
+            pub let_token: tokens::Let,
+            pub eq_token: tokens::Eq,
+            pub else_token: Option<tokens::Else>,
         }),
 
         /// A while loop, with an optional label
@@ -123,6 +140,8 @@
             pub cond: Box<Expr>,
             pub body: Block,
             pub label: Option<Ident>,
+            pub colon_token: Option<tokens::Colon>,
+            pub while_token: tokens::While,
         }),
 
         /// A while-let loop, with an optional label.
@@ -135,6 +154,10 @@
             pub expr: Box<Expr>,
             pub body: Block,
             pub label: Option<Ident>,
+            pub colon_token: Option<tokens::Colon>,
+            pub while_token: tokens::While,
+            pub let_token: tokens::Let,
+            pub eq_token: tokens::Eq,
         }),
 
         /// A for loop, with an optional label.
@@ -147,6 +170,9 @@
             pub expr: Box<Expr>,
             pub body: Block,
             pub label: Option<Ident>,
+            pub for_token: tokens::For,
+            pub colon_token: Option<tokens::Colon>,
+            pub in_token: tokens::In,
         }),
 
         /// Conditionless loop with an optional label.
@@ -155,10 +181,14 @@
         pub Loop(ExprLoop {
             pub body: Block,
             pub label: Option<Ident>,
+            pub loop_token: tokens::Loop,
+            pub colon_token: Option<tokens::Colon>,
         }),
 
         /// A `match` block.
         pub Match(ExprMatch {
+            pub match_token: tokens::Match,
+            pub brace_token: tokens::Brace,
             pub expr: Box<Expr>,
             pub arms: Vec<Arm>,
         }),
@@ -168,6 +198,8 @@
             pub capture: CaptureBy,
             pub decl: Box<FnDecl>,
             pub body: Box<Expr>,
+            pub or1_token: tokens::Or,
+            pub or2_token: tokens::Or,
         }),
 
         /// A block (`{ ... }` or `unsafe { ... }`)
@@ -180,6 +212,7 @@
         pub Assign(ExprAssign {
             pub left: Box<Expr>,
             pub right: Box<Expr>,
+            pub eq_token: tokens::Eq,
         }),
 
         /// An assignment with an operator
@@ -195,6 +228,7 @@
         pub Field(ExprField {
             pub expr: Box<Expr>,
             pub field: Ident,
+            pub dot_token: tokens::Dot,
         }),
 
         /// Access of an unnamed field of a struct or tuple-struct
@@ -202,13 +236,15 @@
         /// For example, `foo.0`.
         pub TupField(ExprTupField {
             pub expr: Box<Expr>,
-            pub field: usize,
+            pub field: Lit,
+            pub dot_token: tokens::Dot,
         }),
 
         /// An indexing operation (`foo[2]`)
         pub Index(ExprIndex {
             pub expr: Box<Expr>,
             pub index: Box<Expr>,
+            pub bracket_token: tokens::Bracket,
         }),
 
         /// A range (`1..2`, `1..`, `..2`, `1...2`, `1...`, `...2`)
@@ -230,6 +266,7 @@
 
         /// A referencing operation (`&a` or `&mut a`)
         pub AddrOf(ExprAddrOf {
+            pub and_token: tokens::And,
             pub mutbl: Mutability,
             pub expr: Box<Expr>,
         }),
@@ -238,16 +275,19 @@
         pub Break(ExprBreak {
             pub label: Option<Ident>,
             pub expr: Option<Box<Expr>>,
+            pub break_token: tokens::Break,
         }),
 
         /// A `continue`, with an optional label
         pub Continue(ExprContinue {
             pub label: Option<Ident>,
+            pub continue_token: tokens::Continue,
         }),
 
         /// A `return`, with an optional value to be returned
         pub Ret(ExprRet {
             pub expr: Option<Box<Expr>>,
+            pub return_token: tokens::Return,
         }),
 
         /// A macro invocation; pre-expansion
@@ -259,8 +299,10 @@
         /// `Foo {x: 1, .. base}`, where `base` is the `Option<Expr>`.
         pub Struct(ExprStruct {
             pub path: Path,
-            pub fields: Vec<FieldValue>,
+            pub fields: Delimited<FieldValue, tokens::Comma>,
             pub rest: Option<Box<Expr>>,
+            pub dot2_token: Option<tokens::Dot2>,
+            pub brace_token: tokens::Brace,
         }),
 
         /// An array literal constructed from one repeated element.
@@ -268,6 +310,8 @@
         /// For example, `[1; 5]`. The first expression is the element
         /// to be repeated; the second is the number of times to repeat it.
         pub Repeat(ExprRepeat {
+            pub bracket_token: tokens::Bracket,
+            pub semi_token: tokens::Semi,
             pub expr: Box<Expr>,
             pub amt: Box<Expr>,
         }),
@@ -275,17 +319,21 @@
         /// No-op: used solely so we can pretty-print faithfully
         pub Paren(ExprParen {
             pub expr: Box<Expr>,
+            pub paren_token: tokens::Paren,
         }),
 
         /// `expr?`
         pub Try(ExprTry {
             pub expr: Box<Expr>,
+            pub question_token: tokens::Question,
         }),
 
         /// A catch expression.
         ///
         /// E.g. `do catch { block }`
         pub Catch(ExprCatch {
+            pub do_token: tokens::Do,
+            pub catch_token: tokens::Catch,
             pub block: Block,
         }),
     }
@@ -306,6 +354,8 @@
 
         /// Attributes tagged on the field.
         pub attrs: Vec<Attribute>,
+
+        pub colon_token: Option<tokens::Colon>,
     }
 }
 
@@ -314,6 +364,7 @@
     ///
     /// E.g. `{ .. }` as in `fn foo() { .. }`
     pub struct Block {
+        pub brace_token: tokens::Brace,
         /// Statements in a block
         pub stmts: Vec<Stmt>,
     }
@@ -332,7 +383,7 @@
         Expr(Box<Expr>),
 
         /// Expression with trailing semicolon;
-        Semi(Box<Expr>),
+        Semi(Box<Expr>, tokens::Semi),
 
         /// Macro invocation.
         Mac(Box<(Mac, MacStmtStyle, Vec<Attribute>)>),
@@ -345,7 +396,7 @@
     pub enum MacStmtStyle {
         /// The macro statement had a trailing semicolon, e.g. `foo! { ... };`
         /// `foo!(...);`, `foo![...];`
-        Semicolon,
+        Semicolon(tokens::Semi),
 
         /// The macro statement had braces; e.g. foo! { ... }
         Braces,
@@ -360,6 +411,11 @@
 ast_struct! {
     /// Local represents a `let` statement, e.g., `let <pat>:<ty> = <expr>;`
     pub struct Local {
+        pub let_token: tokens::Let,
+        pub colon_token: Option<tokens::Colon>,
+        pub eq_token: Option<tokens::Eq>,
+        pub semi_token: tokens::Semi,
+
         pub pat: Box<Pat>,
         pub ty: Option<Box<Ty>>,
 
@@ -369,52 +425,95 @@
     }
 }
 
-ast_enum! {
+ast_enum_of_structs! {
     // Clippy false positive
     // https://github.com/Manishearth/rust-clippy/issues/1241
     #[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
     pub enum Pat {
         /// Represents a wildcard pattern (`_`)
-        Wild,
+        pub Wild(PatWild {
+            pub underscore_token: tokens::Underscore,
+        }),
 
         /// A `Pat::Ident` may either be a new bound variable (`ref mut binding @ OPT_SUBPATTERN`),
         /// or a unit struct/variant pattern, or a const pattern (in the last two cases the third
         /// field must be `None`). Disambiguation cannot be done with parser alone, so it happens
         /// during name resolution.
-        Ident(BindingMode, Ident, Option<Box<Pat>>),
+        pub Ident(PatIdent {
+            pub mode: BindingMode,
+            pub ident: Ident,
+            pub subpat: Option<Box<Pat>>,
+            pub at_token: Option<tokens::At>,
+        }),
 
         /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
         /// The `bool` is `true` in the presence of a `..`.
-        Struct(Path, Vec<FieldPat>, bool),
+        pub Struct(PatStruct {
+            pub path: Path,
+            pub fields: Delimited<FieldPat, tokens::Comma>,
+            pub brace_token: tokens::Brace,
+            pub dot2_token: Option<tokens::Dot2>,
+        }),
 
         /// A tuple struct/variant pattern `Variant(x, y, .., z)`.
         /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
         /// 0 <= position <= subpats.len()
-        TupleStruct(Path, Vec<Pat>, Option<usize>),
+        pub TupleStruct(PatTupleStruct {
+            pub path: Path,
+            pub pat: PatTuple,
+        }),
 
         /// A possibly qualified path pattern.
         /// Unquailfied path patterns `A::B::C` can legally refer to variants, structs, constants
         /// or associated constants. Quailfied path patterns `<A>::B::C`/`<A as Trait>::B::C` can
         /// only legally refer to associated constants.
-        Path(Option<QSelf>, Path),
+        pub Path(PatPath {
+            pub qself: Option<QSelf>,
+            pub path: Path,
+        }),
 
         /// A tuple pattern `(a, b)`.
         /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
         /// 0 <= position <= subpats.len()
-        Tuple(Vec<Pat>, Option<usize>),
+        pub Tuple(PatTuple {
+            pub pats: Delimited<Pat, tokens::Comma>,
+            pub dots_pos: Option<usize>,
+            pub paren_token: tokens::Paren,
+            pub dot2_token: Option<tokens::Dot2>,
+            pub comma_token: Option<tokens::Comma>,
+        }),
         /// A `box` pattern
-        Box(Box<Pat>),
+        pub Box(PatBox {
+            pub pat: Box<Pat>,
+            pub box_token: tokens::Box,
+        }),
         /// A reference pattern, e.g. `&mut (a, b)`
-        Ref(Box<Pat>, Mutability),
+        pub Ref(PatRef {
+            pub pat: Box<Pat>,
+            pub mutbl: Mutability,
+            pub and_token: tokens::And,
+        }),
         /// A literal
-        Lit(Box<Expr>),
+        pub Lit(PatLit {
+            pub expr: Box<Expr>,
+        }),
         /// A range pattern, e.g. `1...2`
-        Range(Box<Expr>, Box<Expr>, RangeLimits),
+        pub Range(PatRange {
+            pub lo: Box<Expr>,
+            pub hi: Box<Expr>,
+            pub limits: RangeLimits,
+        }),
         /// `[a, b, ..i, y, z]` is represented as:
-        ///     `Pat::Slice(box [a, b], Some(i), box [y, z])`
-        Slice(Vec<Pat>, Option<Box<Pat>>, Vec<Pat>),
+        pub Slice(PatSlice {
+            pub front: Delimited<Pat, tokens::Comma>,
+            pub middle: Option<Box<Pat>>,
+            pub back: Delimited<Pat, tokens::Comma>,
+            pub dot2_token: Option<tokens::Dot2>,
+            pub comma_token: Option<tokens::Comma>,
+            pub bracket_token: tokens::Bracket,
+        }),
         /// A macro pattern; pre-expansion
-        Mac(Mac),
+        pub Mac(Mac),
     }
 }
 
@@ -431,9 +530,12 @@
     /// ```
     pub struct Arm {
         pub attrs: Vec<Attribute>,
-        pub pats: Vec<Pat>,
+        pub pats: Delimited<Pat, tokens::Or>,
+        pub if_token: Option<tokens::If>,
         pub guard: Option<Box<Expr>>,
+        pub rocket_token: tokens::Rocket,
         pub body: Box<Expr>,
+        pub comma: Option<tokens::Comma>,
     }
 }
 
@@ -441,7 +543,7 @@
     /// A capture clause
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum CaptureBy {
-        Value,
+        Value(tokens::Move),
         Ref,
     }
 }
@@ -451,9 +553,9 @@
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum RangeLimits {
         /// Inclusive at the beginning, exclusive at the end
-        HalfOpen,
+        HalfOpen(tokens::Dot2),
         /// Inclusive at the beginning and end
-        Closed,
+        Closed(tokens::Dot3),
     }
 }
 
@@ -469,6 +571,7 @@
         /// The pattern the field is destructured to
         pub pat: Box<Pat>,
         pub is_shorthand: bool,
+        pub colon_token: Option<tokens::Colon>,
         pub attrs: Vec<Attribute>,
     }
 }
@@ -476,7 +579,7 @@
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum BindingMode {
-        ByRef(Mutability),
+        ByRef(tokens::Ref, Mutability),
         ByValue(Mutability),
     }
 }
@@ -484,18 +587,20 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use {BinOp, Delimited, DelimToken, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, Mac,
+    use {BinOp, FnArg, FnDecl, FunctionRetTy, Ident, Lifetime, Mac,
          TokenTree, Ty, UnOp, Unsafety, ArgCaptured, TyInfer};
     use attr::parsing::outer_attr;
     use generics::parsing::lifetime;
     use ident::parsing::{ident, wordlike};
     use item::parsing::item;
-    use lit::parsing::{digits, lit};
-    use mac::parsing::{mac, token_trees};
+    use lit::parsing::lit;
+    use mac::parsing::{mac, token_stream};
     use synom::IResult::{self, Error};
     use op::parsing::{assign_op, binop, unop};
     use ty::parsing::{mutability, path, qpath, ty, unsafety};
 
+    use proc_macro2::{self, TokenKind, Delimiter};
+
     // Struct literals are ambiguous in certain positions
     // https://github.com/rust-lang/rfcs/pull/92
     macro_rules! named_ambiguous_expr {
@@ -571,20 +676,18 @@
             ) >>
             many0!(alt!(
                 tap!(args: and_call => {
+                    let (args, paren) = args;
                     e = ExprCall {
                         func: Box::new(e.into()),
                         args: args,
+                        paren_token: paren,
                     }.into();
                 })
                 |
                 tap!(more: and_method_call => {
-                    let (method, ascript, mut args) = more;
-                    args.insert(0, e.into());
-                    e = ExprMethodCall {
-                        method: method,
-                        typarams: ascript,
-                        args: args,
-                    }.into();
+                    let mut call = more;
+                    call.expr = Box::new(e.into());
+                    e = call.into();
                 })
                 |
                 tap!(more: call!(and_binary, allow_struct) => {
@@ -597,22 +700,28 @@
                 })
                 |
                 tap!(ty: and_cast => {
+                    let (ty, token) = ty;
                     e = ExprCast {
                         expr: Box::new(e.into()),
                         ty: Box::new(ty),
+                        as_token: token,
                     }.into();
                 })
                 |
                 tap!(ty: and_ascription => {
+                    let (ty, token) = ty;
                     e = ExprType {
                         expr: Box::new(e.into()),
                         ty: Box::new(ty),
+                        colon_token: token,
                     }.into();
                 })
                 |
                 tap!(v: call!(and_assign, allow_struct) => {
+                    let (v, token) = v;
                     e = ExprAssign {
                         left: Box::new(e.into()),
+                        eq_token: token,
                         right: Box::new(v),
                     }.into();
                 })
@@ -627,22 +736,28 @@
                 })
                 |
                 tap!(field: and_field => {
+                    let (field, token) = field;
                     e = ExprField {
                         expr: Box::new(e.into()),
                         field: field,
+                        dot_token: token,
                     }.into();
                 })
                 |
                 tap!(field: and_tup_field => {
+                    let (field, token) = field;
                     e = ExprTupField {
                         expr: Box::new(e.into()),
-                        field: field as usize,
+                        field: field,
+                        dot_token: token,
                     }.into();
                 })
                 |
                 tap!(i: and_index => {
+                    let (i, token) = i;
                     e = ExprIndex {
                         expr: Box::new(e.into()),
+                        bracket_token: token,
                         index: Box::new(i),
                     }.into();
                 })
@@ -657,7 +772,10 @@
                 })
                 |
                 tap!(_try: punct!("?") => {
-                    e = ExprTry { expr: Box::new(e.into()) }.into();
+                    e = ExprTry {
+                        expr: Box::new(e.into()),
+                        question_token: tokens::Question::default(),
+                    }.into();
                 })
             )) >>
             (e.into())
@@ -670,13 +788,19 @@
         punct!("(") >>
         e: expr >>
         punct!(")") >>
-        (ExprParen { expr: Box::new(e) }.into())
+        (ExprParen {
+            expr: Box::new(e),
+            paren_token: tokens::Paren::default(),
+        }.into())
     ));
 
     named_ambiguous_expr!(expr_box -> ExprKind, allow_struct, do_parse!(
         keyword!("box") >>
         inner: ambiguous_expr!(allow_struct) >>
-        (ExprBox { expr: Box::new(inner) }.into())
+        (ExprBox {
+            expr: Box::new(inner),
+            box_token: tokens::Box::default(),
+        }.into())
     ));
 
     named!(expr_in_place -> ExprKind, do_parse!(
@@ -686,11 +810,15 @@
         value: within_block >>
         punct!("}") >>
         (ExprInPlace {
+            in_token: tokens::In::default(),
             place: Box::new(place),
             value: Box::new(Expr {
                 node: ExprBlock {
                     unsafety: Unsafety::Normal,
-                    block: Block { stmts: value, },
+                    block: Block {
+                        stmts: value,
+                        brace_token: tokens::Brace::default(),
+                    },
                 }.into(),
                 attrs: Vec::new(),
             }),
@@ -699,40 +827,66 @@
 
     named!(expr_array -> ExprKind, do_parse!(
         punct!("[") >>
-        elems: terminated_list!(punct!(","), expr) >>
+        elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                expr) >>
         punct!("]") >>
-        (ExprArray { exprs: elems }.into())
+        (ExprArray {
+            exprs: elems,
+            bracket_token: tokens::Bracket::default(),
+        }.into())
     ));
 
-    named!(and_call -> Vec<Expr>, do_parse!(
+    named!(and_call -> (Delimited<Expr, tokens::Comma>, tokens::Paren), do_parse!(
         punct!("(") >>
-        args: terminated_list!(punct!(","), expr) >>
+        args: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                               expr) >>
         punct!(")") >>
-        (args)
+        (args, tokens::Paren::default())
     ));
 
-    named!(and_method_call -> (Ident, Vec<Ty>, Vec<Expr>), do_parse!(
+    named!(and_method_call -> ExprMethodCall, do_parse!(
         punct!(".") >>
         method: ident >>
-        ascript: opt_vec!(preceded!(
-            punct!("::"),
-            delimited!(
-                punct!("<"),
-                terminated_list!(punct!(","), ty),
-                punct!(">")
-            )
+        typarams: option!(do_parse!(
+            punct!("::") >>
+            punct!("<") >>
+            tys: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                  ty) >>
+            punct!(">") >>
+            (tys)
         )) >>
         punct!("(") >>
-        args: terminated_list!(punct!(","), expr) >>
+        args: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                               expr) >>
         punct!(")") >>
-        (method, ascript, args)
+        (ExprMethodCall {
+            // this expr will get overwritten after being returned
+            expr: Box::new(ExprKind::Lit(Lit {
+                span: Span::default(),
+                value: LitKind::Bool(false),
+            }).into()),
+
+            method: method,
+            args: args,
+            paren_token: tokens::Paren::default(),
+            dot_token: tokens::Dot::default(),
+            lt_token: typarams.as_ref().map(|_| tokens::Lt::default()),
+            gt_token: typarams.as_ref().map(|_| tokens::Gt::default()),
+            colon2_token: typarams.as_ref().map(|_| tokens::Colon2::default()),
+            typarams: typarams.unwrap_or_default(),
+        })
     ));
 
     named!(expr_tup -> ExprKind, do_parse!(
         punct!("(") >>
-        elems: terminated_list!(punct!(","), expr) >>
+        elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                expr) >>
         punct!(")") >>
-        (ExprTup { args: elems }.into())
+        (ExprTup {
+            args: elems,
+            paren_token: tokens::Paren::default(),
+            lone_comma: None, // TODO: parse this
+        }.into())
     ));
 
     named_ambiguous_expr!(and_binary -> (BinOp, Expr), allow_struct, tuple!(
@@ -748,16 +902,17 @@
 
     named!(expr_lit -> ExprKind, map!(lit, ExprKind::Lit));
 
-    named!(and_cast -> Ty, do_parse!(
+    named!(and_cast -> (Ty, tokens::As), do_parse!(
         keyword!("as") >>
         ty: ty >>
-        (ty)
+        (ty, tokens::As::default())
     ));
 
-    named!(and_ascription -> Ty, preceded!(punct!(":"), ty));
+    named!(and_ascription -> (Ty, tokens::Colon),
+           preceded!(punct!(":"), map!(ty, |t| (t, tokens::Colon::default()))));
 
     enum Cond {
-        Let(Pat, Expr),
+        Let(Pat, Expr, tokens::Eq, tokens::Let),
         Expr(Expr),
     }
 
@@ -767,7 +922,7 @@
             pat: pat >>
             punct!("=") >>
             value: expr_no_struct >>
-            (Cond::Let(pat, value))
+            (Cond::Let(pat, value, tokens::Eq::default(), tokens::Let::default()))
         )
         |
         map!(expr_no_struct, Cond::Expr)
@@ -790,25 +945,36 @@
                     punct!("}") >>
                     (ExprKind::Block(ExprBlock {
                         unsafety: Unsafety::Normal,
-                        block: Block { stmts: else_block },
+                        block: Block {
+                            stmts: else_block,
+                            brace_token: tokens::Brace::default(),
+                        },
                     }).into())
                 )
             )
         )) >>
         (match cond {
-            Cond::Let(pat, expr) => ExprIfLet {
+            Cond::Let(pat, expr, eq_token, let_token) => ExprIfLet {
                 pat: Box::new(pat),
                 expr: Box::new(expr),
+                eq_token: eq_token,
+                let_token: let_token,
                 if_true: Block {
                     stmts: then_block,
+                    brace_token: tokens::Brace::default(),
                 },
+                if_token: tokens::If::default(),
+                else_token: else_block.as_ref().map(|_| tokens::Else::default()),
                 if_false: else_block.map(|els| Box::new(els.into())),
             }.into(),
             Cond::Expr(cond) => ExprIf {
                 cond: Box::new(cond),
                 if_true: Block {
                     stmts: then_block,
+                    brace_token: tokens::Brace::default(),
                 },
+                if_token: tokens::If::default(),
+                else_token: else_block.as_ref().map(|_| tokens::Else::default()),
                 if_false: else_block.map(|els| Box::new(els.into())),
             }.into(),
         })
@@ -822,6 +988,9 @@
         expr: expr_no_struct >>
         loop_block: block >>
         (ExprForLoop {
+            for_token: tokens::For::default(),
+            in_token: tokens::In::default(),
+            colon_token: lbl.as_ref().map(|_| tokens::Colon::default()),
             pat: Box::new(pat),
             expr: Box::new(expr),
             body: loop_block,
@@ -833,7 +1002,12 @@
         lbl: option!(terminated!(label, punct!(":"))) >>
         keyword!("loop") >>
         loop_block: block >>
-        (ExprLoop { body: loop_block, label: lbl }.into())
+        (ExprLoop {
+            loop_token: tokens::Loop::default(),
+            colon_token: lbl.as_ref().map(|_| tokens::Colon::default()),
+            body: loop_block,
+            label: lbl,
+        }.into())
     ));
 
     named!(expr_match -> ExprKind, do_parse!(
@@ -850,7 +1024,14 @@
         punct!("}") >>
         (ExprMatch {
             expr: Box::new(obj),
+            match_token: tokens::Match::default(),
+            brace_token: tokens::Brace::default(),
             arms: {
+                for arm in &mut arms {
+                    if arm_requires_comma(arm) {
+                        arm.comma = Some(tokens::Comma::default());
+                    }
+                }
                 arms.extend(last_arm);
                 arms
             },
@@ -861,7 +1042,11 @@
         keyword!("do") >>
         keyword!("catch") >>
         catch_block: block >>
-        (ExprCatch { block: catch_block }.into())
+        (ExprCatch {
+            block: catch_block,
+            do_token: tokens::Do::default(),
+            catch_token: tokens::Catch::default(),
+        }.into())
     ));
 
     fn arm_requires_comma(arm: &Arm) -> bool {
@@ -874,7 +1059,8 @@
 
     named!(match_arm -> Arm, do_parse!(
         attrs: many0!(outer_attr) >>
-        pats: separated_nonempty_list!(punct!("|"), pat) >>
+        pats: separated_nonempty_list!(map!(punct!("|"), |_| tokens::Or::default()),
+                                       pat) >>
         guard: option!(preceded!(keyword!("if"), expr)) >>
         punct!("=>") >>
         body: alt!(
@@ -888,24 +1074,29 @@
             expr
         ) >>
         (Arm {
+            rocket_token: tokens::Rocket::default(),
+            if_token: guard.as_ref().map(|_| tokens::If::default()),
             attrs: attrs,
             pats: pats,
             guard: guard.map(Box::new),
             body: Box::new(body),
+            comma: None,
         })
     ));
 
     named_ambiguous_expr!(expr_closure -> ExprKind, allow_struct, do_parse!(
         capture: capture_by >>
         punct!("|") >>
-        inputs: terminated_list!(punct!(","), closure_arg) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 closure_arg) >>
         punct!("|") >>
         ret_and_body: alt!(
             do_parse!(
                 punct!("->") >>
                 ty: ty >>
                 body: block >>
-                (FunctionRetTy::Ty(ty), ExprKind::Block(ExprBlock {
+                (FunctionRetTy::Ty(ty, tokens::RArrow::default()),
+                 ExprKind::Block(ExprBlock {
                     unsafety: Unsafety::Normal,
                     block: body,
                 }).into())
@@ -915,10 +1106,16 @@
         ) >>
         (ExprClosure {
             capture: capture,
+            or1_token: tokens::Or::default(),
+            or2_token: tokens::Or::default(),
             decl: Box::new(FnDecl {
                 inputs: inputs,
                 output: ret_and_body.0,
                 variadic: false,
+                dot_tokens: None,
+                fn_token: tokens::Fn::default(),
+                generics: Generics::default(),
+                paren_token: tokens::Paren::default(),
             }),
             body: Box::new(ret_and_body.1),
         }.into())
@@ -929,7 +1126,10 @@
         ty: option!(preceded!(punct!(":"), ty)) >>
         (ArgCaptured {
             pat: pat,
-            ty: ty.unwrap_or_else(|| TyInfer {}.into()),
+            colon_token: tokens::Colon::default(),
+            ty: ty.unwrap_or_else(|| TyInfer {
+                underscore_token: tokens::Underscore::default(),
+            }.into()),
         }.into())
     ));
 
@@ -939,13 +1139,19 @@
         cond: cond >>
         while_block: block >>
         (match cond {
-            Cond::Let(pat, expr) => ExprWhileLet {
+            Cond::Let(pat, expr, eq_token, let_token) => ExprWhileLet {
+                eq_token: eq_token,
+                let_token: let_token,
+                while_token: tokens::While::default(),
+                colon_token: lbl.as_ref().map(|_| tokens::Colon::default()),
                 pat: Box::new(pat),
                 expr: Box::new(expr),
                 body: while_block,
                 label: lbl,
             }.into(),
             Cond::Expr(cond) => ExprWhile {
+                while_token: tokens::While::default(),
+                colon_token: lbl.as_ref().map(|_| tokens::Colon::default()),
                 cond: Box::new(cond),
                 body: while_block,
                 label: lbl,
@@ -956,38 +1162,54 @@
     named!(expr_continue -> ExprKind, do_parse!(
         keyword!("continue") >>
         lbl: option!(label) >>
-        (ExprContinue { label: lbl }.into())
+        (ExprContinue {
+            continue_token: tokens::Continue::default(),
+            label: lbl,
+        }.into())
     ));
 
     named_ambiguous_expr!(expr_break -> ExprKind, allow_struct, do_parse!(
         keyword!("break") >>
         lbl: option!(label) >>
         val: option!(call!(ambiguous_expr, allow_struct, false)) >>
-        (ExprBreak { label: lbl, expr: val.map(Box::new) }.into())
+        (ExprBreak {
+            label: lbl,
+            expr: val.map(Box::new),
+            break_token: tokens::Break::default(),
+        }.into())
     ));
 
     named_ambiguous_expr!(expr_ret -> ExprKind, allow_struct, do_parse!(
         keyword!("return") >>
         ret_value: option!(ambiguous_expr!(allow_struct)) >>
-        (ExprRet { expr: ret_value.map(Box::new) }.into())
+        (ExprRet {
+            expr: ret_value.map(Box::new),
+            return_token: tokens::Return::default(),
+        }.into())
     ));
 
     named!(expr_struct -> ExprKind, do_parse!(
         path: path >>
         punct!("{") >>
-        fields: separated_list!(punct!(","), field_value) >>
-        base: option!(do_parse!(
-            cond!(!fields.is_empty(), punct!(",")) >>
-            punct!("..") >>
-            base: expr >>
-            (base)
-        )) >>
-        cond!(!fields.is_empty() && base.is_none(), option!(punct!(","))) >>
+        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 field_value) >>
+        base: option!(
+            cond!(fields.is_empty() || fields.trailing_delim(),
+                do_parse!(
+                    punct!("..") >>
+                    base: expr >>
+                    (base)
+                )
+            )
+        ) >>
         punct!("}") >>
         (ExprStruct {
+            brace_token: tokens::Brace::default(),
             path: path,
             fields: fields,
-            rest: base.map(Box::new),
+            dot2_token: base.as_ref().and_then(|b| b.as_ref())
+                            .map(|_| tokens::Dot2::default()),
+            rest: base.and_then(|b| b.map(Box::new)),
         }.into())
     ));
 
@@ -1001,6 +1223,7 @@
                 expr: value,
                 is_shorthand: false,
                 attrs: Vec::new(),
+                colon_token: Some(tokens::Colon::default()),
             })
         )
         |
@@ -1009,6 +1232,7 @@
             expr: ExprKind::Path(ExprPath { qself: None, path: name.into() }).into(),
             is_shorthand: true,
             attrs: Vec::new(),
+            colon_token: None,
         })
     ));
 
@@ -1018,7 +1242,12 @@
         punct!(";") >>
         times: expr >>
         punct!("]") >>
-        (ExprRepeat { expr: Box::new(value), amt: Box::new(times) }.into())
+        (ExprRepeat {
+            expr: Box::new(value),
+            amt: Box::new(times),
+            bracket_token: tokens::Bracket::default(),
+            semi_token: tokens::Semi::default(),
+        }.into())
     ));
 
     named!(expr_block -> ExprKind, do_parse!(
@@ -1026,7 +1255,7 @@
         b: block >>
         (ExprBlock {
             unsafety: rules,
-            block: Block { stmts: b.stmts },
+            block: b,
         }.into())
     ));
 
@@ -1037,9 +1266,9 @@
     ));
 
     named!(range_limits -> RangeLimits, alt!(
-        punct!("...") => { |_| RangeLimits::Closed }
+        punct!("...") => { |_| RangeLimits::Closed(tokens::Dot3::default()) }
         |
-        punct!("..") => { |_| RangeLimits::HalfOpen }
+        punct!("..") => { |_| RangeLimits::HalfOpen(tokens::Dot2::default()) }
     ));
 
     named!(expr_path -> ExprKind, map!(qpath, |(qself, path)| {
@@ -1050,12 +1279,16 @@
         punct!("&") >>
         mutability: mutability >>
         expr: ambiguous_expr!(allow_struct) >>
-        (ExprAddrOf { mutbl: mutability, expr: Box::new(expr) }.into())
+        (ExprAddrOf {
+            mutbl: mutability,
+            expr: Box::new(expr),
+            and_token: tokens::And::default(),
+        }.into())
     ));
 
-    named_ambiguous_expr!(and_assign -> Expr, allow_struct, preceded!(
+    named_ambiguous_expr!(and_assign -> (Expr, tokens::Eq), allow_struct, preceded!(
         punct!("="),
-        ambiguous_expr!(allow_struct)
+        map!(ambiguous_expr!(allow_struct), |t| (t, tokens::Eq::default()))
     ));
 
     named_ambiguous_expr!(and_assign_op -> (BinOp, Expr), allow_struct, tuple!(
@@ -1063,11 +1296,15 @@
         ambiguous_expr!(allow_struct)
     ));
 
-    named!(and_field -> Ident, preceded!(punct!("."), ident));
+    named!(and_field -> (Ident, tokens::Dot),
+           preceded!(punct!("."), map!(ident, |t| (t, tokens::Dot::default()))));
 
-    named!(and_tup_field -> u64, preceded!(punct!("."), digits));
+    named!(and_tup_field -> (Lit, tokens::Dot),
+           preceded!(punct!("."), map!(lit, |l| (l, tokens::Dot::default()))));
 
-    named!(and_index -> Expr, delimited!(punct!("["), expr, punct!("]")));
+    named!(and_index -> (Expr, tokens::Bracket),
+           map!(delimited!(punct!("["), expr, punct!("]")),
+                |t| (t, tokens::Bracket::default())));
 
     named_ambiguous_expr!(and_range -> (RangeLimits, Option<Expr>), allow_struct, tuple!(
         range_limits,
@@ -1080,6 +1317,7 @@
         punct!("}") >>
         (Block {
             stmts: stmts,
+            brace_token: tokens::Brace::default(),
         })
     ));
 
@@ -1113,19 +1351,20 @@
     // Only parse braces here; paren and bracket will get parsed as
     // expression statements
         punct!("{") >>
-        tts: token_trees >>
+        ts: token_stream >>
         punct!("}") >>
         semi: option!(punct!(";")) >>
         (Stmt::Mac(Box::new((
             Mac {
                 path: what,
-                tts: vec![TokenTree::Delimited(Delimited {
-                    delim: DelimToken::Brace,
-                    tts: tts,
+                bang_token: tokens::Bang::default(),
+                tokens: vec![TokenTree(proc_macro2::TokenTree {
+                    span: Default::default(),
+                    kind: TokenKind::Sequence(Delimiter::Brace, ts),
                 })],
             },
             if semi.is_some() {
-                MacStmtStyle::Semicolon
+                MacStmtStyle::Semicolon(tokens::Semi::default())
             } else {
                 MacStmtStyle::Braces
             },
@@ -1141,6 +1380,10 @@
         init: option!(preceded!(punct!("="), expr)) >>
         punct!(";") >>
         (Stmt::Local(Box::new(Local {
+            let_token: tokens::Let::default(),
+            semi_token: tokens::Semi::default(),
+            colon_token: ty.as_ref().map(|_| tokens::Colon::default()),
+            eq_token: init.as_ref().map(|_| tokens::Eq::default()),
             pat: Box::new(pat),
             ty: ty.map(Box::new),
             init: init.map(Box::new),
@@ -1172,7 +1415,7 @@
         ({
             e.attrs = attrs;
             if semi.is_some() {
-                Stmt::Semi(Box::new(e))
+                Stmt::Semi(Box::new(e), tokens::Semi::default())
             } else if requires_semi(&e) {
                 return Error;
             } else {
@@ -1200,7 +1443,7 @@
         |
         pat_path
         |
-        pat_tuple
+        map!(pat_tuple, |t: PatTuple| t.into())
         |
         pat_ref
         |
@@ -1209,12 +1452,17 @@
 
     named!(pat_mac -> Pat, map!(mac, Pat::Mac));
 
-    named!(pat_wild -> Pat, map!(keyword!("_"), |_| Pat::Wild));
+    named!(pat_wild -> Pat, map!(keyword!("_"), |_| {
+        PatWild { underscore_token: tokens::Underscore::default() }.into()
+    }));
 
     named!(pat_box -> Pat, do_parse!(
         keyword!("box") >>
         pat: pat >>
-        (Pat::Box(Box::new(pat)))
+        (PatBox {
+            pat: Box::new(pat),
+            box_token: tokens::Box::default(),
+        }.into())
     ));
 
     named!(pat_ident -> Pat, do_parse!(
@@ -1228,34 +1476,43 @@
         not!(punct!("<")) >>
         not!(punct!("::")) >>
         subpat: option!(preceded!(punct!("@"), pat)) >>
-        (Pat::Ident(
-            if mode.is_some() {
-                BindingMode::ByRef(mutability)
+        (PatIdent {
+            mode: if mode.is_some() {
+                BindingMode::ByRef(tokens::Ref::default(), mutability)
             } else {
                 BindingMode::ByValue(mutability)
             },
-            name,
-            subpat.map(Box::new),
-        ))
+            ident: name,
+            at_token: subpat.as_ref().map(|_| tokens::At::default()),
+            subpat: subpat.map(Box::new),
+        }.into())
     ));
 
     named!(pat_tuple_struct -> Pat, do_parse!(
         path: path >>
-        tuple: pat_tuple_helper >>
-        (Pat::TupleStruct(path, tuple.0, tuple.1))
+        tuple: pat_tuple >>
+        (PatTupleStruct {
+            path: path,
+            pat: tuple,
+        }.into())
     ));
 
     named!(pat_struct -> Pat, do_parse!(
         path: path >>
         punct!("{") >>
-        fields: separated_list!(punct!(","), field_pat) >>
-        more: option!(preceded!(
-            cond!(!fields.is_empty(), punct!(",")),
-            punct!("..")
-        )) >>
-        cond!(!fields.is_empty() && more.is_none(), option!(punct!(","))) >>
+        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 field_pat) >>
+        base: option!(
+            cond!(fields.is_empty() || fields.trailing_delim(),
+                  punct!(".."))
+        ) >>
         punct!("}") >>
-        (Pat::Struct(path, fields, more.is_some()))
+        (PatStruct {
+            path: path,
+            fields: fields,
+            brace_token: tokens::Brace::default(),
+            dot2_token: base.and_then(|m| m).map(|_| tokens::Dot2::default()),
+        }.into())
     ));
 
     named!(field_pat -> FieldPat, alt!(
@@ -1268,6 +1525,7 @@
                 pat: Box::new(pat),
                 is_shorthand: false,
                 attrs: Vec::new(),
+                colon_token: Some(tokens::Colon::default()),
             })
         )
         |
@@ -1277,54 +1535,72 @@
             mutability: mutability >>
             ident: ident >>
             ({
-                let mut pat = Pat::Ident(
-                    if mode.is_some() {
-                        BindingMode::ByRef(mutability)
+                let mut pat: Pat = PatIdent {
+                    mode: if mode.is_some() {
+                        BindingMode::ByRef(tokens::Ref::default(), mutability)
                     } else {
                         BindingMode::ByValue(mutability)
                     },
-                    ident.clone(),
-                    None,
-                );
+                    ident: ident.clone(),
+                    subpat: None,
+                    at_token: None,
+                }.into();
                 if boxed.is_some() {
-                    pat = Pat::Box(Box::new(pat));
+                    pat = PatBox {
+                        pat: Box::new(pat),
+                        box_token: tokens::Box::default(),
+                    }.into();
                 }
                 FieldPat {
                     ident: ident,
                     pat: Box::new(pat),
                     is_shorthand: true,
                     attrs: Vec::new(),
+                    colon_token: None,
                 }
             })
         )
     ));
 
-    named!(pat_path -> Pat, map!(qpath, |(qself, path)| Pat::Path(qself, path)));
+    named!(pat_path -> Pat, map!(qpath, |(qself, path)| {
+        PatPath { qself: qself, path: path }.into()
+    }));
 
-    named!(pat_tuple -> Pat, map!(
-        pat_tuple_helper,
-        |(pats, dotdot)| Pat::Tuple(pats, dotdot)
-    ));
-
-    named!(pat_tuple_helper -> (Vec<Pat>, Option<usize>), do_parse!(
+    named!(pat_tuple -> PatTuple, do_parse!(
         punct!("(") >>
-        mut elems: separated_list!(punct!(","), pat) >>
-        dotdot: option!(do_parse!(
-            cond!(!elems.is_empty(), punct!(",")) >>
-            punct!("..") >>
-            rest: many0!(preceded!(punct!(","), pat)) >>
-            cond!(!rest.is_empty(), option!(punct!(","))) >>
-            (rest)
-        )) >>
-        cond!(!elems.is_empty() && dotdot.is_none(), option!(punct!(","))) >>
+        mut elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                    pat) >>
+        dotdot: map!(cond!(
+            elems.is_empty() || elems.trailing_delim(),
+            option!(do_parse!(
+                punct!("..") >>
+                trailing: option!(punct!(",")) >>
+                (trailing.is_some())
+            ))
+        ), |x: Option<_>| x.and_then(|x| x)) >>
+        rest: cond!(dotdot == Some(true),
+                    terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                     pat)) >>
         punct!(")") >>
-        (match dotdot {
-            Some(rest) => {
-                let pos = elems.len();
-                elems.extend(rest);
-                (elems, Some(pos))
-            }
-            None => (elems, None),
+        (PatTuple {
+            paren_token: tokens::Paren::default(),
+            dots_pos: dotdot.map(|_| elems.len()),
+            dot2_token: dotdot.map(|_| tokens::Dot2::default()),
+            comma_token: dotdot.and_then(|b| {
+                if b {
+                    Some(tokens::Comma::default())
+                } else {
+                    None
+                }
+            }),
+            pats: {
+                if let Some(rest) = rest {
+                    for elem in rest.into_iter() {
+                        elems.push(elem);
+                    }
+                }
+                elems
+            },
         })
     ));
 
@@ -1332,7 +1608,11 @@
         punct!("&") >>
         mutability: mutability >>
         pat: pat >>
-        (Pat::Ref(Box::new(pat), mutability))
+        (PatRef {
+            pat: Box::new(pat),
+            mutbl: mutability,
+            and_token: tokens::And::default(),
+        }.into())
     ));
 
     named!(pat_lit -> Pat, do_parse!(
@@ -1340,7 +1620,9 @@
         (if let ExprKind::Path(_) = lit.node {
             return IResult::Error; // these need to be parsed by pat_path
         } else {
-            Pat::Lit(Box::new(lit))
+            PatLit {
+                expr: Box::new(lit),
+            }.into()
         })
     ));
 
@@ -1348,7 +1630,11 @@
         lo: pat_lit_expr >>
         limits: range_limits >>
         hi: pat_lit_expr >>
-        (Pat::Range(Box::new(lo), Box::new(hi), limits))
+        (PatRange {
+            lo: Box::new(lo),
+            hi: Box::new(hi),
+            limits: limits,
+        }.into())
     ));
 
     named!(pat_lit_expr -> Expr, do_parse!(
@@ -1360,7 +1646,7 @@
         ) >>
         (if neg.is_some() {
             ExprKind::Unary(ExprUnary {
-                op: UnOp::Neg,
+                op: UnOp::Neg(tokens::Sub::default()),
                 expr: Box::new(v.into())
             }).into()
         } else {
@@ -1370,33 +1656,43 @@
 
     named!(pat_slice -> Pat, do_parse!(
         punct!("[") >>
-        mut before: separated_list!(punct!(","), pat) >>
-        after: option!(do_parse!(
-            comma_before_dots: option!(cond_reduce!(!before.is_empty(), punct!(","))) >>
+        mut before: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 pat) >>
+        middle: option!(do_parse!(
             punct!("..") >>
-            after: many0!(preceded!(punct!(","), pat)) >>
-            cond!(!after.is_empty(), option!(punct!(","))) >>
-            (comma_before_dots.is_some(), after)
+            trailing: option!(punct!(",")) >>
+            (trailing.is_some())
         )) >>
-        cond!(after.is_none(), option!(punct!(","))) >>
+        after: cond!(
+            match middle {
+                Some(trailing) => trailing,
+                _ => false,
+            },
+            terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                             pat)
+        ) >>
         punct!("]") >>
-        (match after {
-            None => Pat::Slice(before, None, Vec::new()),
-            Some((true, after)) => {
-                if before.is_empty() {
-                    return IResult::Error;
+        (PatSlice {
+            dot2_token: middle.as_ref().map(|_| tokens::Dot2::default()),
+            comma_token: {
+                let trailing = middle.unwrap_or(false);
+                if trailing {Some(tokens::Comma::default())} else {None}
+            },
+            bracket_token: tokens::Bracket::default(),
+            middle: middle.and_then(|_| {
+                if !before.is_empty() && !before.trailing_delim() {
+                    Some(Box::new(before.pop().unwrap().into_item()))
+                } else {
+                    None
                 }
-                Pat::Slice(before, Some(Box::new(Pat::Wild)), after)
-            }
-            Some((false, after)) => {
-                let rest = before.pop().unwrap_or(Pat::Wild);
-                Pat::Slice(before, Some(Box::new(rest)), after)
-            }
-        })
+            }),
+            front: before,
+            back: after.unwrap_or_default(),
+        }.into())
     ));
 
     named!(capture_by -> CaptureBy, alt!(
-        keyword!("move") => { |_| CaptureBy::Value }
+        keyword!("move") => { |_| CaptureBy::Value(tokens::Move::default()) }
         |
         epsilon!() => { |_| CaptureBy::Ref }
     ));
@@ -1407,7 +1703,6 @@
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use {FnArg, FunctionRetTy, Mutability, Ty, Unsafety, ArgCaptured};
     use attr::FilterAttrs;
     use quote::{Tokens, ToTokens};
 
@@ -1420,14 +1715,14 @@
 
     impl ToTokens for ExprBox {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("box");
+            self.box_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprInPlace {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("in");
+            self.in_token.to_tokens(tokens);
             self.place.to_tokens(tokens);
             self.value.to_tokens(tokens);
         }
@@ -1435,46 +1730,42 @@
 
     impl ToTokens for ExprArray {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("[");
-            tokens.append_separated(&self.exprs, ",");
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.exprs.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for ExprCall {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.func.to_tokens(tokens);
-            tokens.append("(");
-            tokens.append_separated(&self.args, ",");
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.args.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for ExprMethodCall {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            self.args[0].to_tokens(tokens);
-            tokens.append(".");
+            self.expr.to_tokens(tokens);
+            self.dot_token.to_tokens(tokens);
             self.method.to_tokens(tokens);
-            if !self.typarams.is_empty() {
-                tokens.append("::");
-                tokens.append("<");
-                tokens.append_separated(&self.typarams, ",");
-                tokens.append(">");
-            }
-            tokens.append("(");
-            tokens.append_separated(&self.args[1..], ",");
-            tokens.append(")");
+            self.colon2_token.to_tokens(tokens);
+            self.lt_token.to_tokens(tokens);
+            self.typarams.to_tokens(tokens);
+            self.gt_token.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.args.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for ExprTup {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            tokens.append_separated(&self.args, ",");
-            if self.args.len() == 1 {
-                tokens.append(",");
-            }
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.args.to_tokens(tokens);
+                self.lone_comma.to_tokens(tokens);
+            })
         }
     }
 
@@ -1496,7 +1787,7 @@
     impl ToTokens for ExprCast {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append("as");
+            self.as_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
@@ -1504,45 +1795,39 @@
     impl ToTokens for ExprType {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append(":");
+            self.colon_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprIf {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("if");
+            self.if_token.to_tokens(tokens);
             self.cond.to_tokens(tokens);
             self.if_true.to_tokens(tokens);
-            if let Some(ref else_block) = self.if_false {
-                tokens.append("else");
-                else_block.to_tokens(tokens);
-            }
+            self.else_token.to_tokens(tokens);
+            self.if_false.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprIfLet {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("if");
-            tokens.append("let");
+            self.if_token.to_tokens(tokens);
+            self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
             self.if_true.to_tokens(tokens);
-            if let Some(ref else_block) = self.if_false {
-                tokens.append("else");
-                else_block.to_tokens(tokens);
-            }
+            self.else_token.to_tokens(tokens);
+            self.if_false.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprWhile {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref label) = self.label {
-                label.to_tokens(tokens);
-                tokens.append(":");
-            }
-            tokens.append("while");
+            self.label.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
+            self.while_token.to_tokens(tokens);
             self.cond.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
@@ -1550,14 +1835,12 @@
 
     impl ToTokens for ExprWhileLet {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref label) = self.label {
-                label.to_tokens(tokens);
-                tokens.append(":");
-            }
-            tokens.append("while");
-            tokens.append("let");
+            self.label.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
+            self.while_token.to_tokens(tokens);
+            self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
@@ -1565,13 +1848,11 @@
 
     impl ToTokens for ExprForLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref label) = self.label {
-                label.to_tokens(tokens);
-                tokens.append(":");
-            }
-            tokens.append("for");
+            self.label.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
+            self.for_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
-            tokens.append("in");
+            self.in_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
@@ -1579,29 +1860,27 @@
 
     impl ToTokens for ExprLoop {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref label) = self.label {
-                label.to_tokens(tokens);
-                tokens.append(":");
-            }
-            tokens.append("loop");
+            self.label.to_tokens(tokens);
+            self.colon_token.to_tokens(tokens);
+            self.loop_token.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprMatch {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("match");
+            self.match_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
-            tokens.append("{");
-            tokens.append_all(&self.arms);
-            tokens.append("}");
+            self.brace_token.surround(tokens, |tokens| {
+                tokens.append_all(&self.arms);
+            });
         }
     }
 
     impl ToTokens for ExprCatch {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("do");
-            tokens.append("catch");
+            self.do_token.to_tokens(tokens);
+            self.catch_token.to_tokens(tokens);
             self.block.to_tokens(tokens);
         }
     }
@@ -1609,26 +1888,18 @@
     impl ToTokens for ExprClosure {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.capture.to_tokens(tokens);
-            tokens.append("|");
-            for (i, input) in self.decl.inputs.iter().enumerate() {
-                if i > 0 {
-                    tokens.append(",");
-                }
-                match *input {
-                    FnArg::Captured(ArgCaptured { ref pat, ty: Ty::Infer(_) }) => {
+            self.or1_token.to_tokens(tokens);
+            for item in self.decl.inputs.iter() {
+                match **item.item() {
+                    FnArg::Captured(ArgCaptured { ref pat, ty: Ty::Infer(_), .. }) => {
                         pat.to_tokens(tokens);
                     }
-                    _ => input.to_tokens(tokens),
+                    _ => item.item().to_tokens(tokens),
                 }
+                item.delimiter().to_tokens(tokens);
             }
-            tokens.append("|");
-            match self.decl.output {
-                FunctionRetTy::Default => { /* nothing */ }
-                FunctionRetTy::Ty(ref ty) => {
-                    tokens.append("->");
-                    ty.to_tokens(tokens);
-                }
-            }
+            self.or2_token.to_tokens(tokens);
+            self.decl.output.to_tokens(tokens);
             self.body.to_tokens(tokens);
         }
     }
@@ -1643,7 +1914,7 @@
     impl ToTokens for ExprAssign {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.left.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.right.to_tokens(tokens);
         }
     }
@@ -1651,7 +1922,7 @@
     impl ToTokens for ExprAssignOp {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.left.to_tokens(tokens);
-            tokens.append(self.op.assign_op().unwrap());
+            self.op.to_tokens(tokens);
             self.right.to_tokens(tokens);
         }
     }
@@ -1659,7 +1930,7 @@
     impl ToTokens for ExprField {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append(".");
+            self.dot_token.to_tokens(tokens);
             self.field.to_tokens(tokens);
         }
     }
@@ -1667,17 +1938,17 @@
     impl ToTokens for ExprTupField {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append(".");
-            tokens.append(&self.field.to_string());
+            self.dot_token.to_tokens(tokens);
+            self.field.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprIndex {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append("[");
-            self.index.to_tokens(tokens);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.index.to_tokens(tokens);
+            });
         }
     }
 
@@ -1691,35 +1962,13 @@
 
     impl ToTokens for ExprPath {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let qself = match self.qself {
-                Some(ref qself) => qself,
-                None => return self.path.to_tokens(tokens),
-            };
-            tokens.append("<");
-            qself.ty.to_tokens(tokens);
-            if qself.position > 0 {
-                tokens.append("as");
-                for (i, segment) in self.path.segments
-                        .iter()
-                        .take(qself.position)
-                        .enumerate() {
-                    if i > 0 || self.path.global {
-                        tokens.append("::");
-                    }
-                    segment.to_tokens(tokens);
-                }
-            }
-            tokens.append(">");
-            for segment in self.path.segments.iter().skip(qself.position) {
-                tokens.append("::");
-                segment.to_tokens(tokens);
-            }
+            ::PathTokens(&self.qself, &self.path).to_tokens(tokens)
         }
     }
 
     impl ToTokens for ExprAddrOf {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("&");
+            self.and_token.to_tokens(tokens);
             self.mutbl.to_tokens(tokens);
             self.expr.to_tokens(tokens);
         }
@@ -1727,7 +1976,7 @@
 
     impl ToTokens for ExprBreak {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("break");
+            self.break_token.to_tokens(tokens);
             self.label.to_tokens(tokens);
             self.expr.to_tokens(tokens);
         }
@@ -1735,14 +1984,14 @@
 
     impl ToTokens for ExprContinue {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("continue");
+            self.continue_token.to_tokens(tokens);
             self.label.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ExprRet {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("return");
+            self.return_token.to_tokens(tokens);
             self.expr.to_tokens(tokens);
         }
     }
@@ -1750,41 +1999,36 @@
     impl ToTokens for ExprStruct {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
-            tokens.append("{");
-            tokens.append_separated(&self.fields, ",");
-            if let Some(ref base) = self.rest {
-                if !self.fields.is_empty() {
-                    tokens.append(",");
-                }
-                tokens.append("..");
-                base.to_tokens(tokens);
-            }
-            tokens.append("}");
+            self.brace_token.surround(tokens, |tokens| {
+                self.fields.to_tokens(tokens);
+                self.dot2_token.to_tokens(tokens);
+                self.rest.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for ExprRepeat {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("[");
-            self.expr.to_tokens(tokens);
-            tokens.append(";");
-            self.amt.to_tokens(tokens);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.expr.to_tokens(tokens);
+                self.semi_token.to_tokens(tokens);
+                self.amt.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for ExprParen {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            self.expr.to_tokens(tokens);
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.expr.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for ExprTry {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.expr.to_tokens(tokens);
-            tokens.append("?");
+            self.question_token.to_tokens(tokens);
         }
     }
 
@@ -1792,7 +2036,7 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
             if !self.is_shorthand {
-                tokens.append(":");
+                self.colon_token.to_tokens(tokens);
                 self.expr.to_tokens(tokens);
             }
         }
@@ -1800,157 +2044,118 @@
 
     impl ToTokens for Arm {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            for attr in &self.attrs {
-                attr.to_tokens(tokens);
-            }
-            tokens.append_separated(&self.pats, "|");
-            if let Some(ref guard) = self.guard {
-                tokens.append("if");
-                guard.to_tokens(tokens);
-            }
-            tokens.append("=>");
+            tokens.append_all(&self.attrs);
+            self.pats.to_tokens(tokens);
+            self.if_token.to_tokens(tokens);
+            self.guard.to_tokens(tokens);
+            self.rocket_token.to_tokens(tokens);
             self.body.to_tokens(tokens);
-            match self.body.node {
-                ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) => {
-                    // no comma
-                }
-                _ => tokens.append(","),
-            }
+            self.comma.to_tokens(tokens);
         }
     }
 
-    impl ToTokens for Pat {
+    impl ToTokens for PatWild {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                Pat::Wild => tokens.append("_"),
-                Pat::Ident(ref mode, ref ident, ref subpat) => {
-                    mode.to_tokens(tokens);
-                    ident.to_tokens(tokens);
-                    if let Some(ref subpat) = *subpat {
-                        tokens.append("@");
-                        subpat.to_tokens(tokens);
+            self.underscore_token.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatIdent {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.mode.to_tokens(tokens);
+            self.ident.to_tokens(tokens);
+            self.at_token.to_tokens(tokens);
+            self.subpat.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatStruct {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.path.to_tokens(tokens);
+            self.brace_token.surround(tokens, |tokens| {
+                self.fields.to_tokens(tokens);
+                self.dot2_token.to_tokens(tokens);
+            });
+        }
+    }
+
+    impl ToTokens for PatTupleStruct {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.path.to_tokens(tokens);
+            self.pat.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatPath {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            ::PathTokens(&self.qself, &self.path).to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatTuple {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.paren_token.surround(tokens, |tokens| {
+                for (i, token) in self.pats.iter().enumerate() {
+                    if Some(i) == self.dots_pos {
+                        self.dot2_token.to_tokens(tokens);
+                        self.comma_token.to_tokens(tokens);
                     }
+                    token.to_tokens(tokens);
                 }
-                Pat::Struct(ref path, ref fields, dots) => {
-                    path.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_separated(fields, ",");
-                    if dots {
-                        if !fields.is_empty() {
-                            tokens.append(",");
-                        }
-                        tokens.append("..");
-                    }
-                    tokens.append("}");
+
+                if Some(self.pats.len()) == self.dots_pos {
+                    self.dot2_token.to_tokens(tokens);
                 }
-                Pat::TupleStruct(ref path, ref pats, dotpos) => {
-                    path.to_tokens(tokens);
-                    tokens.append("(");
-                    match dotpos {
-                        Some(pos) => {
-                            if pos > 0 {
-                                tokens.append_separated(&pats[..pos], ",");
-                                tokens.append(",");
-                            }
-                            tokens.append("..");
-                            if pos < pats.len() {
-                                tokens.append(",");
-                                tokens.append_separated(&pats[pos..], ",");
-                            }
-                        }
-                        None => tokens.append_separated(pats, ","),
-                    }
-                    tokens.append(")");
-                }
-                Pat::Path(None, ref path) => path.to_tokens(tokens),
-                Pat::Path(Some(ref qself), ref path) => {
-                    tokens.append("<");
-                    qself.ty.to_tokens(tokens);
-                    if qself.position > 0 {
-                        tokens.append("as");
-                        for (i, segment) in path.segments
-                                .iter()
-                                .take(qself.position)
-                                .enumerate() {
-                            if i > 0 || path.global {
-                                tokens.append("::");
-                            }
-                            segment.to_tokens(tokens);
-                        }
-                    }
-                    tokens.append(">");
-                    for segment in path.segments.iter().skip(qself.position) {
-                        tokens.append("::");
-                        segment.to_tokens(tokens);
-                    }
-                }
-                Pat::Tuple(ref pats, dotpos) => {
-                    tokens.append("(");
-                    match dotpos {
-                        Some(pos) => {
-                            if pos > 0 {
-                                tokens.append_separated(&pats[..pos], ",");
-                                tokens.append(",");
-                            }
-                            tokens.append("..");
-                            if pos < pats.len() {
-                                tokens.append(",");
-                                tokens.append_separated(&pats[pos..], ",");
-                            }
-                        }
-                        None => {
-                            tokens.append_separated(pats, ",");
-                            if pats.len() == 1 {
-                                tokens.append(",");
-                            }
-                        }
-                    }
-                    tokens.append(")");
-                }
-                Pat::Box(ref inner) => {
-                    tokens.append("box");
-                    inner.to_tokens(tokens);
-                }
-                Pat::Ref(ref target, ref mutability) => {
-                    tokens.append("&");
-                    mutability.to_tokens(tokens);
-                    target.to_tokens(tokens);
-                }
-                Pat::Lit(ref lit) => lit.to_tokens(tokens),
-                Pat::Range(ref lo, ref hi, ref limits) => {
-                    lo.to_tokens(tokens);
-                    limits.to_tokens(tokens);
-                    hi.to_tokens(tokens);
-                }
-                Pat::Slice(ref before, ref rest, ref after) => {
-                    tokens.append("[");
-                    tokens.append_separated(before, ",");
-                    if let Some(ref rest) = *rest {
-                        if !before.is_empty() {
-                            tokens.append(",");
-                        }
-                        match **rest {
-                            Pat::Wild => {}
-                            _ => rest.to_tokens(tokens),
-                        }
-                        tokens.append("..");
-                        if !after.is_empty() {
-                            tokens.append(",");
-                        }
-                        tokens.append_separated(after, ",");
-                    }
-                    tokens.append("]");
-                }
-                Pat::Mac(ref mac) => mac.to_tokens(tokens),
-            }
+            });
+        }
+    }
+
+    impl ToTokens for PatBox {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.box_token.to_tokens(tokens);
+            self.pat.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatRef {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.and_token.to_tokens(tokens);
+            self.mutbl.to_tokens(tokens);
+            self.pat.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatLit {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.expr.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatRange {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.lo.to_tokens(tokens);
+            self.limits.to_tokens(tokens);
+            self.hi.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for PatSlice {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.bracket_token.surround(tokens, |tokens| {
+                self.front.to_tokens(tokens);
+                self.middle.to_tokens(tokens);
+                self.dot2_token.to_tokens(tokens);
+                self.comma_token.to_tokens(tokens);
+                self.back.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for RangeLimits {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                RangeLimits::HalfOpen => tokens.append(".."),
-                RangeLimits::Closed => tokens.append("..."),
+                RangeLimits::HalfOpen(ref t) => t.to_tokens(tokens),
+                RangeLimits::Closed(ref t) => t.to_tokens(tokens),
             }
         }
     }
@@ -1959,7 +2164,7 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             if !self.is_shorthand {
                 self.ident.to_tokens(tokens);
-                tokens.append(":");
+                self.colon_token.to_tokens(tokens);
             }
             self.pat.to_tokens(tokens);
         }
@@ -1968,16 +2173,12 @@
     impl ToTokens for BindingMode {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                BindingMode::ByRef(Mutability::Immutable) => {
-                    tokens.append("ref");
+                BindingMode::ByRef(ref t, ref m) => {
+                    t.to_tokens(tokens);
+                    m.to_tokens(tokens);
                 }
-                BindingMode::ByRef(Mutability::Mutable) => {
-                    tokens.append("ref");
-                    tokens.append("mut");
-                }
-                BindingMode::ByValue(Mutability::Immutable) => {}
-                BindingMode::ByValue(Mutability::Mutable) => {
-                    tokens.append("mut");
+                BindingMode::ByValue(ref m) => {
+                    m.to_tokens(tokens);
                 }
             }
         }
@@ -1986,7 +2187,7 @@
     impl ToTokens for CaptureBy {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                CaptureBy::Value => tokens.append("move"),
+                CaptureBy::Value(ref t) => t.to_tokens(tokens),
                 CaptureBy::Ref => {
                     // nothing
                 }
@@ -1996,9 +2197,9 @@
 
     impl ToTokens for Block {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("{");
-            tokens.append_all(&self.stmts);
-            tokens.append("}");
+            self.brace_token.surround(tokens, |tokens| {
+                tokens.append_all(&self.stmts);
+            });
         }
     }
 
@@ -2008,16 +2209,16 @@
                 Stmt::Local(ref local) => local.to_tokens(tokens),
                 Stmt::Item(ref item) => item.to_tokens(tokens),
                 Stmt::Expr(ref expr) => expr.to_tokens(tokens),
-                Stmt::Semi(ref expr) => {
+                Stmt::Semi(ref expr, ref semi) => {
                     expr.to_tokens(tokens);
-                    tokens.append(";");
+                    semi.to_tokens(tokens);
                 }
                 Stmt::Mac(ref mac) => {
                     let (ref mac, ref style, ref attrs) = **mac;
                     tokens.append_all(attrs.outer());
                     mac.to_tokens(tokens);
                     match *style {
-                        MacStmtStyle::Semicolon => tokens.append(";"),
+                        MacStmtStyle::Semicolon(ref s) => s.to_tokens(tokens),
                         MacStmtStyle::Braces | MacStmtStyle::NoBraces => {
                             // no semicolon
                         }
@@ -2030,17 +2231,13 @@
     impl ToTokens for Local {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
-            tokens.append("let");
+            self.let_token.to_tokens(tokens);
             self.pat.to_tokens(tokens);
-            if let Some(ref ty) = self.ty {
-                tokens.append(":");
-                ty.to_tokens(tokens);
-            }
-            if let Some(ref init) = self.init {
-                tokens.append("=");
-                init.to_tokens(tokens);
-            }
-            tokens.append(";");
+            self.colon_token.to_tokens(tokens);
+            self.ty.to_tokens(tokens);
+            self.eq_token.to_tokens(tokens);
+            self.init.to_tokens(tokens);
+            self.semi_token.to_tokens(tokens);
         }
     }
 }
diff --git a/src/fold.rs b/src/fold.rs
index 3a5c763..2f4ef1c 100644
--- a/src/fold.rs
+++ b/src/fold.rs
@@ -7,6 +7,8 @@
 #[cfg(not(feature = "full"))]
 use constant;
 
+use delimited::{Delimited, Element};
+
 /// AST->AST fold.
 ///
 /// Each method of the Folder trait is a hook to be potentially overridden. Each
@@ -174,6 +176,20 @@
     }
 }
 
+impl<T, D, U> LiftMut<T, U> for Delimited<T, D> {
+    type Output = Delimited<U, D>;
+    fn lift<F>(self, mut f: F) -> Self::Output
+        where F: FnMut(T) -> U
+    {
+        self.into_iter().map(|e| {
+            match e {
+                Element::Delimited(t, d) => Element::Delimited(f(t), d),
+                Element::End(t) => Element::End(f(t))
+            }
+        }).collect()
+    }
+}
+
 pub fn noop_fold_ident<F: ?Sized + Folder>(_: &mut F, _ident: Ident) -> Ident {
     _ident
 }
@@ -191,8 +207,18 @@
         attrs: attrs.lift(|a| folder.fold_attribute(a)),
         generics: folder.fold_generics(generics),
         body: match body {
-            Enum(variants) => Enum(variants.lift(move |v| folder.fold_variant(v))),
-            Struct(variant_data) => Struct(folder.fold_variant_data(variant_data)),
+            Enum(data) => {
+                Enum(BodyEnum {
+                    variants: data.variants.lift(move |v| folder.fold_variant(v)),
+                    ..data
+                })
+            }
+            Struct(data) => {
+                Struct(BodyStruct {
+                    data: folder.fold_variant_data(data.data),
+                    ..data
+                })
+            }
         },
     }
 }
@@ -202,136 +228,151 @@
     use Ty::*;
 
     match ty {
-        Slice(TySlice { ty }) => {
+        Slice(t) => {
             Slice(TySlice {
-                ty: ty.lift(|v| folder.fold_ty(v)),
+                ty: t.ty.lift(|v| folder.fold_ty(v)),
+                ..t
             })
         }
-        Paren(TyParen { ty }) => {
+        Paren(t) => {
             Paren(TyParen {
-                ty: ty.lift(|v| folder.fold_ty(v)),
+                ty: t.ty.lift(|v| folder.fold_ty(v)),
+                ..t
             })
         }
-        Ptr(TyPtr { ty }) => {
-            let ty = *ty;
+        Ptr(t) => {
+            let ty = *t.ty;
             let MutTy { ty, mutability } = ty;
             Ptr(TyPtr {
                 ty: Box::new(MutTy {
                     ty: folder.fold_ty(ty),
                     mutability: mutability,
                 }),
+                ..t
             })
         }
-        Rptr(TyRptr { lifetime, ty }) => {
-            let ty = *ty;
+        Rptr(t) => {
+            let ty = *t.ty;
             let MutTy { ty, mutability } = ty;
             Rptr(TyRptr {
-                lifetime: lifetime.map(|l| folder.fold_lifetime(l)),
+                lifetime: t.lifetime.map(|l| folder.fold_lifetime(l)),
                 ty: Box::new(MutTy {
                     ty: folder.fold_ty(ty),
                     mutability: mutability,
                 }),
+                ..t
             })
         }
         Never(t) => Never(t),
         Infer(t) => Infer(t),
-        Tup(TyTup { tys }) => {
+        Tup(t) => {
             Tup(TyTup {
-                tys: tys.lift(|x| folder.fold_ty(x)),
+                tys: t.tys.lift(|x| folder.fold_ty(x)),
+                ..t
             })
         }
-        BareFn(TyBareFn { ty }) => {
-            let ty = *ty;
-            let BareFnTy { unsafety, abi, lifetimes, inputs, output, variadic } = ty;
+        BareFn(t) => {
+            let ty = *t.ty;
             BareFn(TyBareFn {
                 ty: Box::new(BareFnTy {
-                    unsafety: unsafety,
-                    abi: abi,
-                    lifetimes: lifetimes.lift(|l| folder.fold_lifetime_def(l)),
-                    inputs: inputs.lift(|v| {
+                    lifetimes: ty.lifetimes.map(|l| {
+                        noop_fold_bound_lifetimes(folder, l)
+                    }),
+                    inputs: ty.inputs.lift(|v| {
                         BareFnArg {
-                            name: v.name.map(|n| folder.fold_ident(n)),
+                            name: v.name.map(|n| (folder.fold_ident(n.0), n.1)),
                             ty: folder.fold_ty(v.ty),
                         }
                     }),
-                    output: folder.fold_fn_ret_ty(output),
-                    variadic: variadic,
+                    output: folder.fold_fn_ret_ty(ty.output),
+                    ..ty
                 }),
             })
         }
-        Path(TyPath { qself, path }) => {
+        Path(t) => {
             Path(TyPath {
-                qself: qself.map(|v| noop_fold_qself(folder, v)),
-                path: folder.fold_path(path),
+                qself: t.qself.map(|v| noop_fold_qself(folder, v)),
+                path: folder.fold_path(t.path),
             })
         }
-        Array(TyArray { ty, amt }) => {
+        Array(t) => {
             Array(TyArray {
-                ty: ty.lift(|v| folder.fold_ty(v)),
-                amt: folder.fold_const_expr(amt),
+                ty: t.ty.lift(|v| folder.fold_ty(v)),
+                amt: folder.fold_const_expr(t.amt),
+                ..t
             })
         }
-        TraitObject(TyTraitObject { bounds }) => {
+        TraitObject(t) => {
             TraitObject(TyTraitObject {
-                bounds: bounds.lift(|v| folder.fold_ty_param_bound(v)),
+                bounds: t.bounds.lift(|v| folder.fold_ty_param_bound(v)),
             })
         }
-        ImplTrait(TyImplTrait { bounds }) => {
+        ImplTrait(t) => {
             ImplTrait(TyImplTrait {
-                bounds: bounds.lift(|v| folder.fold_ty_param_bound(v)),
+                bounds: t.bounds.lift(|v| folder.fold_ty_param_bound(v)),
+                ..t
             })
         }
         Mac(mac) => Mac(folder.fold_mac(mac)),
     }
 }
 
-fn noop_fold_qself<F: ?Sized + Folder>(folder: &mut F, QSelf { ty, position }: QSelf) -> QSelf {
+#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] // clippy lies
+fn noop_fold_qself<F: ?Sized + Folder>(folder: &mut F, qself: QSelf) -> QSelf {
     QSelf {
-        ty: Box::new(folder.fold_ty(*(ty))),
-        position: position,
+        ty: Box::new(folder.fold_ty(*(qself.ty))),
+        ..qself
     }
 }
 
 pub fn noop_fold_generics<F: ?Sized + Folder>(folder: &mut F,
-                                     Generics { lifetimes, ty_params, where_clause }: Generics)
+                                              generics: Generics)
 -> Generics{
     use WherePredicate::*;
     Generics {
-        lifetimes: lifetimes.lift(|l| folder.fold_lifetime_def(l)),
-        ty_params: ty_params.lift(|ty| {
+        lifetimes: generics.lifetimes.lift(|l| folder.fold_lifetime_def(l)),
+        ty_params: generics.ty_params.lift(|ty| {
             TyParam {
                 attrs: ty.attrs.lift(|a| folder.fold_attribute(a)),
                 ident: folder.fold_ident(ty.ident),
                 bounds: ty.bounds.lift(|ty_pb| folder.fold_ty_param_bound(ty_pb)),
                 default: ty.default.map(|v| folder.fold_ty(v)),
+                ..ty
             }
         }),
         where_clause: WhereClause {
-            predicates: where_clause.predicates.lift(|p| match p {
-                                                         BoundPredicate(bound_predicate) => {
+            predicates: generics.where_clause.predicates.lift(|p| {
+                match p {
+                    BoundPredicate(bound_predicate) => {
                         BoundPredicate(WhereBoundPredicate {
                             bound_lifetimes: bound_predicate.bound_lifetimes
-                                .lift(|l| folder.fold_lifetime_def(l)),
+                                .map(|l| noop_fold_bound_lifetimes(folder, l)),
                             bounded_ty: folder.fold_ty(bound_predicate.bounded_ty),
                             bounds: bound_predicate.bounds
                                 .lift(|ty_pb| folder.fold_ty_param_bound(ty_pb)),
+                            ..bound_predicate
                         })
                     }
-                                                         RegionPredicate(region_predicate) => {
+                    RegionPredicate(region_predicate) => {
                         RegionPredicate(WhereRegionPredicate {
                             lifetime: folder.fold_lifetime(region_predicate.lifetime),
                             bounds: region_predicate.bounds
                                 .lift(|b| folder.fold_lifetime(b)),
+                            ..region_predicate
                         })
                     }
-                                                         EqPredicate(eq_predicate) => {
+                    EqPredicate(eq_predicate) => {
                         EqPredicate(WhereEqPredicate {
                             lhs_ty: folder.fold_ty(eq_predicate.lhs_ty),
                             rhs_ty: folder.fold_ty(eq_predicate.rhs_ty),
+                            ..eq_predicate
                         })
                     }
-                                                     }),
+                }
+            }),
+            ..generics.where_clause
         },
+        ..generics
     }
 }
 
@@ -349,7 +390,9 @@
                                                     trait_ref: PolyTraitRef)
                                                     -> PolyTraitRef {
     PolyTraitRef {
-        bound_lifetimes: trait_ref.bound_lifetimes.lift(|bl| folder.fold_lifetime_def(bl)),
+        bound_lifetimes: trait_ref.bound_lifetimes.map(|bl| {
+            noop_fold_bound_lifetimes(folder, bl)
+        }),
         trait_ref: folder.fold_path(trait_ref.trait_ref),
     }
 }
@@ -359,8 +402,8 @@
                                                   -> VariantData {
     use VariantData::*;
     match data {
-        Struct(fields) => Struct(fields.lift(|f| folder.fold_field(f))),
-        Tuple(fields) => Tuple(fields.lift(|f| folder.fold_field(f))),
+        Struct(fields, t) => Struct(fields.lift(|f| folder.fold_field(f)), t),
+        Tuple(fields, t) => Tuple(fields.lift(|f| folder.fold_field(f)), t),
         Unit => Unit,
     }
 }
@@ -371,17 +414,20 @@
         vis: noop_fold_vis(folder, field.vis),
         attrs: field.attrs.lift(|a| folder.fold_attribute(a)),
         ty: folder.fold_ty(field.ty),
+        ..field
     }
 }
 
 pub fn noop_fold_variant<F: ?Sized + Folder>(folder: &mut F,
-                                    Variant { ident, attrs, data, discriminant }: Variant)
--> Variant{
+                                             variant: Variant)
+    -> Variant
+{
     Variant {
-        ident: folder.fold_ident(ident),
-        attrs: attrs.lift(|v| folder.fold_attribute(v)),
-        data: folder.fold_variant_data(data),
-        discriminant: discriminant.map(|ce| folder.fold_const_expr(ce)),
+        ident: folder.fold_ident(variant.ident),
+        attrs: variant.attrs.lift(|v| folder.fold_attribute(v)),
+        data: folder.fold_variant_data(variant.data),
+        discriminant: variant.discriminant.map(|ce| folder.fold_const_expr(ce)),
+        ..variant
     }
 }
 
@@ -389,29 +435,41 @@
     Lifetime { ident: folder.fold_ident(_lifetime.ident) }
 }
 
-pub fn noop_fold_lifetime_def<F: ?Sized + Folder>(folder: &mut F,
-                                         LifetimeDef { attrs, lifetime, bounds }: LifetimeDef)
--> LifetimeDef{
-    LifetimeDef {
-        attrs: attrs.lift(|x| folder.fold_attribute(x)),
-        lifetime: folder.fold_lifetime(lifetime),
-        bounds: bounds.lift(|l| folder.fold_lifetime(l)),
+pub fn noop_fold_bound_lifetimes<F: ?Sized + Folder>(folder: &mut F,
+                                                     b: BoundLifetimes)
+    -> BoundLifetimes
+{
+    BoundLifetimes {
+        lifetimes: b.lifetimes.lift(|l| folder.fold_lifetime_def(l)),
+        ..b
     }
 }
 
-pub fn noop_fold_path<F: ?Sized + Folder>(folder: &mut F, Path { global, segments }: Path) -> Path {
+pub fn noop_fold_lifetime_def<F: ?Sized + Folder>(folder: &mut F,
+                                                  def: LifetimeDef)
+    -> LifetimeDef
+{
+    LifetimeDef {
+        attrs: def.attrs.lift(|x| folder.fold_attribute(x)),
+        lifetime: folder.fold_lifetime(def.lifetime),
+        bounds: def.bounds.lift(|l| folder.fold_lifetime(l)),
+        ..def
+    }
+}
+
+pub fn noop_fold_path<F: ?Sized + Folder>(folder: &mut F, path: Path) -> Path {
     Path {
-        global: global,
-        segments: segments.lift(|s| folder.fold_path_segment(s)),
+        segments: path.segments.lift(|s| folder.fold_path_segment(s)),
+        ..path
     }
 }
 
 pub fn noop_fold_path_segment<F: ?Sized + Folder>(folder: &mut F,
-                                                  PathSegment { ident, parameters }: PathSegment)
+                                                  seg: PathSegment)
                                                   -> PathSegment {
     PathSegment {
-        ident: folder.fold_ident(ident),
-        parameters: folder.fold_path_parameters(parameters),
+        ident: folder.fold_ident(seg.ident),
+        parameters: folder.fold_path_parameters(seg.parameters),
     }
 }
 
@@ -421,37 +479,36 @@
     use PathParameters::*;
     match path_parameters {
         AngleBracketed(d) => {
-            let AngleBracketedParameterData { lifetimes, types, bindings } = d;
             AngleBracketed(AngleBracketedParameterData {
-                               lifetimes: lifetimes.into_iter()
-                                   .map(|l| folder.fold_lifetime(l))
-                                   .collect(),
-                               types: types.lift(|ty| folder.fold_ty(ty)),
-                               bindings: bindings.lift(|tb| folder.fold_assoc_type_binding(tb)),
-                           })
+                lifetimes: d.lifetimes.lift(|l| folder.fold_lifetime(l)),
+                types: d.types.lift(|ty| folder.fold_ty(ty)),
+                bindings: d.bindings.lift(|tb| folder.fold_assoc_type_binding(tb)),
+                ..d
+            })
         }
         Parenthesized(d) => {
-            let ParenthesizedParameterData { inputs, output } = d;
             Parenthesized(ParenthesizedParameterData {
-                              inputs: inputs.lift(|i| folder.fold_ty(i)),
-                              output: output.map(|v| folder.fold_ty(v)),
-                          })
+                inputs: d.inputs.lift(|i| folder.fold_ty(i)),
+                output: folder.fold_fn_ret_ty(d.output),
+                ..d
+            })
         }
     }
 }
 
 pub fn noop_fold_assoc_type_binding<F: ?Sized + Folder>(folder: &mut F,
-                                                        TypeBinding { ident, ty }: TypeBinding)
-                                                        -> TypeBinding {
+                                                        binding: TypeBinding)
+    -> TypeBinding
+{
     TypeBinding {
-        ident: folder.fold_ident(ident),
-        ty: folder.fold_ty(ty),
+        ident: folder.fold_ident(binding.ident),
+        ty: folder.fold_ty(binding.ty),
+        ..binding
     }
-
 }
 
-pub fn noop_fold_attribute<F: ?Sized + Folder>(_: &mut F, _attr: Attribute) -> Attribute {
-    _attr
+pub fn noop_fold_attribute<F: ?Sized + Folder>(_: &mut F, attr: Attribute) -> Attribute {
+    attr
 }
 
 pub fn noop_fold_fn_ret_ty<F: ?Sized + Folder>(folder: &mut F,
@@ -460,7 +517,7 @@
     use FunctionRetTy::*;
     match ret_ty {
         Default => Default,
-        Ty(ty) => Ty(folder.fold_ty(ty)),
+        Ty(ty, t) => Ty(folder.fold_ty(ty), t),
     }
 }
 
@@ -469,42 +526,46 @@
     use constant::ConstExpr::*;
 
     match expr {
-        Call(ConstCall { func, args }) => {
+        Call(c) => {
             Call(ConstCall {
-                func: func.lift(|e| folder.fold_const_expr(e)),
-                args: args.lift(|v| folder.fold_const_expr(v)),
+                func: c.func.lift(|e| folder.fold_const_expr(e)),
+                args: c.args.lift(|v| folder.fold_const_expr(v)),
+                ..c
             })
         }
-        Binary(ConstBinary { op, left, right }) => {
+        Binary(c) => {
             Binary(ConstBinary {
-                op: op,
-                left: left.lift(|e| folder.fold_const_expr(e)),
-                right: right.lift(|e| folder.fold_const_expr(e)),
+                left: c.left.lift(|e| folder.fold_const_expr(e)),
+                right: c.right.lift(|e| folder.fold_const_expr(e)),
+                ..c
             })
         }
-        Unary(ConstUnary { op, expr }) => {
+        Unary(c) => {
             Unary(ConstUnary {
-                op: op,
-                expr: expr.lift(|e| folder.fold_const_expr(e)),
+                expr: c.expr.lift(|e| folder.fold_const_expr(e)),
+                ..c
             })
         }
         Lit(l) => Lit(folder.fold_lit(l)),
-        Cast(ConstCast { expr, ty }) => {
+        Cast(c) => {
             Cast(ConstCast {
-                expr: expr.lift(|e| folder.fold_const_expr(e)),
-                ty: ty.lift(|v| folder.fold_ty(v)),
+                expr: c.expr.lift(|e| folder.fold_const_expr(e)),
+                ty: c.ty.lift(|v| folder.fold_ty(v)),
+                ..c
             })
         }
         Path(p) => Path(folder.fold_path(p)),
-        Index(ConstIndex { expr, index }) => {
+        Index(c) => {
             Index(ConstIndex {
-                expr: expr.lift(|e| folder.fold_const_expr(e)),
-                index: index.lift(|e| folder.fold_const_expr(e)),
+                expr: c.expr.lift(|e| folder.fold_const_expr(e)),
+                index: c.index.lift(|e| folder.fold_const_expr(e)),
+                ..c
             })
         }
-        Paren(ConstParen { expr }) => {
+        Paren(c) => {
             Paren(ConstParen {
-                expr: expr.lift(|e| folder.fold_const_expr(e)),
+                expr: c.expr.lift(|e| folder.fold_const_expr(e)),
+                ..c
             })
         }
         Other(e) => Other(noop_fold_other_const_expr(folder, e)),
@@ -528,57 +589,74 @@
 }
 
 pub fn noop_fold_tt<F: ?Sized + Folder>(folder: &mut F, tt: TokenTree) -> TokenTree {
-    use TokenTree::*;
-    use Token::*;
-    match tt {
-        Token(token) => {
-            Token(match token {
-                      Literal(lit) => Literal(folder.fold_lit(lit)),
-                      Ident(ident) => Ident(folder.fold_ident(ident)),
-                      Lifetime(ident) => Lifetime(folder.fold_ident(ident)),
-                      x => x,
-                  })
+    use proc_macro2::{TokenKind, TokenTree as TokenTree2};
+    match tt.0.kind {
+        TokenKind::Word(sym) => {
+            let sym = folder.fold_ident(Ident::new(sym, Span(tt.0.span)));
+            TokenTree(TokenTree2 {
+                span: sym.span.0,
+                kind: TokenKind::Word(sym.sym),
+            })
         }
-        Delimited(super::Delimited { delim, tts }) => {
-            Delimited(super::Delimited {
-                          delim: delim,
-                          tts: tts.lift(|v| noop_fold_tt(folder, v)),
-                      })
+        TokenKind::Op(..) => tt,
+        TokenKind::Literal(lit) => {
+            folder.fold_lit(Lit {
+                value: LitKind::Other(lit),
+                span: Span(tt.0.span),
+            }).into_token_tree()
+        }
+        TokenKind::Sequence(delim, stream) => {
+            let stream = stream.into_iter().map(|tt| {
+                noop_fold_tt(folder, TokenTree(tt)).0
+            }).collect();
+            TokenTree(TokenTree2 {
+                span: tt.0.span,
+                kind: TokenKind::Sequence(delim, stream),
+            })
         }
     }
 }
 
-pub fn noop_fold_mac<F: ?Sized + Folder>(folder: &mut F, Mac { path, tts }: Mac) -> Mac {
+pub fn noop_fold_mac<F: ?Sized + Folder>(folder: &mut F, mac: Mac) -> Mac {
     Mac {
-        path: folder.fold_path(path),
-        tts: tts.lift(|tt| noop_fold_tt(folder, tt)),
+        path: folder.fold_path(mac.path),
+        tokens: mac.tokens.lift(|tt| noop_fold_tt(folder, tt)),
+        ..mac
     }
 }
 
 #[cfg(feature = "full")]
 pub fn noop_fold_crate<F: ?Sized + Folder>(folder: &mut F,
-                                           Crate { shebang, attrs, items }: Crate)
+                                           krate: Crate)
                                            -> Crate {
     Crate {
-        shebang: shebang,
-        attrs: attrs.lift(|a| folder.fold_attribute(a)),
-        items: items.lift(|i| folder.fold_item(i)),
+        attrs: krate.attrs.lift(|a| folder.fold_attribute(a)),
+        items: krate.items.lift(|i| folder.fold_item(i)),
+        ..krate
     }
 
 }
 
 #[cfg(feature = "full")]
 pub fn noop_fold_block<F: ?Sized + Folder>(folder: &mut F, block: Block) -> Block {
-    Block { stmts: block.stmts.lift(|s| folder.fold_stmt(s)) }
+    Block {
+        stmts: block.stmts.lift(|s| folder.fold_stmt(s)),
+        ..block
+    }
 }
 
 fn noop_fold_vis<F: ?Sized + Folder>(folder: &mut F, vis: Visibility) -> Visibility {
     use Visibility::*;
     match vis {
-        Crate => Crate,
-        Inherited => Inherited,
-        Public => Public,
-        Restricted(path) => Restricted(path.lift(|p| folder.fold_path(p))),
+        Crate(t) => Crate(t),
+        Inherited(i) => Inherited(i),
+        Public(p) => Public(p),
+        Restricted(data) => {
+            Restricted(VisRestricted {
+                path: data.path.lift(|p| folder.fold_path(p)),
+                ..data
+            })
+        }
     }
 }
 
@@ -593,105 +671,105 @@
         vis: noop_fold_vis(folder, vis),
         attrs: attrs.lift(|a| folder.fold_attribute(a)),
         node: match node {
-            ExternCrate(ItemExternCrate { original }) => {
+            ExternCrate(i) => {
                 ExternCrate(ItemExternCrate {
-                    original: original.map(|i| folder.fold_ident(i)),
+                    original: i.original.map(|i| folder.fold_ident(i)),
+                    ..i
                 })
             }
-            Use(ItemUse { path }) => {
+            Use(i) => {
                 Use(ItemUse {
-                    path: Box::new(folder.fold_view_path(*path)),
+                    path: Box::new(folder.fold_view_path(*i.path)),
+                    ..i
                 })
             }
-            Static(ItemStatic { ty, mutbl, expr }) => {
+            Static(i) => {
                 Static(ItemStatic {
-                    ty: Box::new(folder.fold_ty(*ty)),
-                    mutbl: mutbl,
-                    expr: expr.lift(|e| folder.fold_expr(e)),
+                    ty: Box::new(folder.fold_ty(*i.ty)),
+                    mutbl: i.mutbl,
+                    expr: i.expr.lift(|e| folder.fold_expr(e)),
+                    ..i
                 })
             }
-            Const(ItemConst { ty, expr }) => {
+            Const(i) => {
                 Const(ItemConst {
-                    ty: ty.lift(|ty| folder.fold_ty(ty)),
-                    expr: expr.lift(|e| folder.fold_expr(e)),
+                    ty: i.ty.lift(|ty| folder.fold_ty(ty)),
+                    expr: i.expr.lift(|e| folder.fold_expr(e)),
+                    ..i
                 })
             }
-            Fn(ItemFn { decl, unsafety, constness, abi, generics, block }) => {
+            Fn(i) => {
                 Fn(ItemFn {
-                    decl: decl.lift(|v| folder.fold_fn_decl(v)),
-                    unsafety: unsafety,
-                    constness: constness,
-                    abi: abi,
-                    generics: folder.fold_generics(generics),
-                    block: block.lift(|v| folder.fold_block(v)),
+                    decl: i.decl.lift(|v| folder.fold_fn_decl(v)),
+                    block: i.block.lift(|v| folder.fold_block(v)),
+                    ..i
                 })
             }
-            Mod(ItemMod { items }) => {
+            Mod(i) => {
                 Mod(ItemMod {
-                    items: items.map(|items| items.lift(|i| folder.fold_item(i))),
+                    items: i.items.map(|items| {
+                        (items.0.lift(|i| folder.fold_item(i)), items.1)
+                    }),
+                    ..i
                 })
             }
-            ForeignMod(ItemForeignMod { abi, items }) => {
+            ForeignMod(i) => {
                 ForeignMod(ItemForeignMod {
-                    abi: abi,
-                    items: items.lift(|foreign_item| {
+                    items: i.items.lift(|foreign_item| {
                         folder.fold_foreign_item(foreign_item)
                     }),
+                    ..i
                 })
             }
-            Ty(ItemTy { ty, generics }) => {
+            Ty(i) => {
                 Ty(ItemTy {
-                    ty: ty.lift(|ty| folder.fold_ty(ty)),
-                    generics: folder.fold_generics(generics),
+                    ty: i.ty.lift(|ty| folder.fold_ty(ty)),
+                    generics: folder.fold_generics(i.generics),
+                    ..i
                 })
             }
-            Enum(ItemEnum { variants, generics }) => {
+            Enum(i) => {
                 Enum(ItemEnum {
-                    variants: variants.lift(|v| folder.fold_variant(v)),
-                    generics: folder.fold_generics(generics),
+                    variants: i.variants.lift(|v| folder.fold_variant(v)),
+                    generics: folder.fold_generics(i.generics),
+                    ..i
                 })
             }
-            Struct(ItemStruct { data, generics }) => {
+            Struct(i) => {
                 Struct(ItemStruct {
-                    data: folder.fold_variant_data(data),
-                    generics: folder.fold_generics(generics),
+                    data: folder.fold_variant_data(i.data),
+                    generics: folder.fold_generics(i.generics),
+                    ..i
                 })
             }
-            Union(ItemUnion { data, generics }) => {
+            Union(i) => {
                 Union(ItemUnion {
-                    data: folder.fold_variant_data(data),
-                    generics: folder.fold_generics(generics),
+                    data: folder.fold_variant_data(i.data),
+                    generics: folder.fold_generics(i.generics),
+                    ..i
                 })
             }
-            Trait(ItemTrait { unsafety, generics, supertraits, items }) => {
+            Trait(i) => {
                 Trait(ItemTrait {
-                    unsafety: unsafety,
-                    generics: folder.fold_generics(generics),
-                    supertraits: supertraits.lift(|typb| folder.fold_ty_param_bound(typb)),
-                    items: items.lift(|ti| folder.fold_trait_item(ti)),
+                    generics: folder.fold_generics(i.generics),
+                    supertraits: i.supertraits.lift(|typb| folder.fold_ty_param_bound(typb)),
+                    items: i.items.lift(|ti| folder.fold_trait_item(ti)),
+                    ..i
                 })
             }
-            DefaultImpl(ItemDefaultImpl { unsafety, path }) => {
+            DefaultImpl(i) => {
                 DefaultImpl(ItemDefaultImpl {
-                    unsafety: unsafety,
-                    path: folder.fold_path(path),
+                    path: folder.fold_path(i.path),
+                    ..i
                 })
             }
-            Impl(ItemImpl {
-                unsafety,
-                polarity,
-                generics,
-                trait_,
-                self_ty,
-                items,
-            }) => {
+            Impl(i) => {
                 Impl(ItemImpl {
-                    unsafety: unsafety,
-                    polarity: polarity,
-                    generics: folder.fold_generics(generics),
-                    trait_: trait_.map(|p| folder.fold_path(p)),
-                    self_ty: self_ty.lift(|ty| folder.fold_ty(ty)),
-                    items: items.lift(|i| folder.fold_impl_item(i)),
+                    generics: folder.fold_generics(i.generics),
+                    trait_: i.trait_.map(|p| folder.fold_path(p)),
+                    self_ty: i.self_ty.lift(|ty| folder.fold_ty(ty)),
+                    items: i.items.lift(|i| folder.fold_impl_item(i)),
+                    ..i
                 })
             }
             Mac(mac) => Mac(folder.fold_mac(mac)),
@@ -706,229 +784,264 @@
 
     Expr {
         node: match node {
-            Box(ExprBox { expr }) => {
-                Box(ExprBox { expr: expr.lift(|e| folder.fold_expr(e)) })
+            Box(e) => {
+                Box(ExprBox {
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
+                })
             }
-            InPlace(ExprInPlace { place, value }) => {
+            InPlace(e) => {
                 InPlace(ExprInPlace {
-                    place: place.lift(|e| folder.fold_expr(e)),
-                    value: value.lift(|e| folder.fold_expr(e)),
+                    place: e.place.lift(|e| folder.fold_expr(e)),
+                    value: e.value.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Array(ExprArray { exprs }) => {
+            Array(e) => {
                 Array(ExprArray {
-                    exprs: exprs.lift(|e| folder.fold_expr(e)),
+                    exprs: e.exprs.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Call(ExprCall { func, args }) => {
+            Call(e) => {
                 Call(ExprCall {
-                    func: func.lift(|e| folder.fold_expr(e)),
-                    args: args.lift(|e| folder.fold_expr(e)),
+                    func: e.func.lift(|e| folder.fold_expr(e)),
+                    args: e.args.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            MethodCall(ExprMethodCall { method, typarams, args }) => {
+            MethodCall(e) => {
                 MethodCall(ExprMethodCall {
-                    method: folder.fold_ident(method),
-                    typarams: typarams.lift(|t| folder.fold_ty(t)),
-                    args: args.lift(|e| folder.fold_expr(e)),
+                    method: folder.fold_ident(e.method),
+                    typarams: e.typarams.lift(|t| folder.fold_ty(t)),
+                    args: e.args.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Tup(ExprTup { args }) => {
+            Tup(e) => {
                 Tup(ExprTup {
-                    args: args.lift(|e| folder.fold_expr(e)),
+                    args: e.args.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Binary(ExprBinary { op, left, right }) => {
+            Binary(e) => {
                 Binary(ExprBinary {
-                    op: op,
-                    left: left.lift(|e| folder.fold_expr(e)),
-                    right: right.lift(|e| folder.fold_expr(e)),
+                    left: e.left.lift(|e| folder.fold_expr(e)),
+                    right: e.right.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Unary(ExprUnary { op, expr }) => {
+            Unary(e) => {
                 Unary(ExprUnary {
-                    op: op,
-                    expr: expr.lift(|e| folder.fold_expr(e)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
             Lit(lit) => Lit(folder.fold_lit(lit)),
-            Cast(ExprCast { expr, ty }) => {
+            Cast(e) => {
                 Cast(ExprCast {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    ty: ty.lift(|t| folder.fold_ty(t)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ty: e.ty.lift(|t| folder.fold_ty(t)),
+                    ..e
                 })
             }
-            Type(ExprType { expr, ty }) => {
+            Type(e) => {
                 Type(ExprType {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    ty: ty.lift(|t| folder.fold_ty(t)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ty: e.ty.lift(|t| folder.fold_ty(t)),
+                    ..e
                 })
             }
-            If(ExprIf { cond, if_true, if_false }) => {
+            If(e) => {
                 If(ExprIf {
-                    cond: cond.lift(|e| folder.fold_expr(e)),
-                    if_true: folder.fold_block(if_true),
-                    if_false: if_false.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    cond: e.cond.lift(|e| folder.fold_expr(e)),
+                    if_true: folder.fold_block(e.if_true),
+                    if_false: e.if_false.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
-            IfLet(ExprIfLet { pat, expr, if_true, if_false }) => {
+            IfLet(e) => {
                 IfLet(ExprIfLet {
-                    pat: pat.lift(|p| folder.fold_pat(p)),
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    if_true: folder.fold_block(if_true),
-                    if_false: if_false.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    pat: e.pat.lift(|p| folder.fold_pat(p)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    if_true: folder.fold_block(e.if_true),
+                    if_false: e.if_false.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
-            While(ExprWhile { cond, body, label }) => {
+            While(e) => {
                 While(ExprWhile {
-                    cond: cond.lift(|e| folder.fold_expr(e)),
-                    body: folder.fold_block(body),
-                    label: label.map(|i| folder.fold_ident(i)),
+                    cond: e.cond.lift(|e| folder.fold_expr(e)),
+                    body: folder.fold_block(e.body),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    ..e
                 })
             }
-            WhileLet(ExprWhileLet { pat, expr, body, label }) => {
+            WhileLet(e) => {
                 WhileLet(ExprWhileLet {
-                    pat: pat.lift(|p| folder.fold_pat(p)),
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    body: folder.fold_block(body),
-                    label: label.map(|i| folder.fold_ident(i)),
+                    pat: e.pat.lift(|p| folder.fold_pat(p)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    body: folder.fold_block(e.body),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    ..e
                 })
             }
-            ForLoop(ExprForLoop { pat, expr, body, label }) => {
+            ForLoop(e) => {
                 ForLoop(ExprForLoop {
-                    pat: pat.lift(|p| folder.fold_pat(p)),
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    body: folder.fold_block(body),
-                    label: label.map(|i| folder.fold_ident(i)),
+                    pat: e.pat.lift(|p| folder.fold_pat(p)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    body: folder.fold_block(e.body),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    ..e
                 })
             }
-            Loop(ExprLoop { body, label }) => {
+            Loop(e) => {
                 Loop(ExprLoop {
-                    body: folder.fold_block(body),
-                    label: label.map(|i| folder.fold_ident(i)),
+                    body: folder.fold_block(e.body),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    ..e
                 })
             }
-            Match(ExprMatch { expr, arms }) => {
+            Match(e) => {
                 Match(ExprMatch {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    arms: arms.lift(|Arm { attrs, pats, guard, body }: Arm| {
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    arms: e.arms.lift(|a: Arm| {
                         Arm {
-                            attrs: attrs.lift(|a| folder.fold_attribute(a)),
-                            pats: pats.lift(|p| folder.fold_pat(p)),
-                            guard: guard.map(|v| v.lift(|e| folder.fold_expr(e))),
-                            body: body.lift(|e| folder.fold_expr(e)),
+                            attrs: a.attrs.lift(|a| folder.fold_attribute(a)),
+                            pats: a.pats.lift(|p| folder.fold_pat(p)),
+                            guard: a.guard.map(|v| v.lift(|e| folder.fold_expr(e))),
+                            body: a.body.lift(|e| folder.fold_expr(e)),
+                            ..a
                         }
-                    })
+                    }),
+                    ..e
                 })
             }
-            Catch(ExprCatch { block }) => {
-                Catch(ExprCatch { block: folder.fold_block(block) })
+            Catch(e) => {
+                Catch(ExprCatch {
+                    block: folder.fold_block(e.block),
+                    ..e
+                })
             }
-            Closure(ExprClosure { capture, decl, body }) => {
+            Closure(e) => {
                 Closure(ExprClosure {
-                    capture: capture,
-                    decl: decl.lift(|v| folder.fold_fn_decl(v)),
-                    body: body.lift(|e| folder.fold_expr(e)),
+                    decl: e.decl.lift(|v| folder.fold_fn_decl(v)),
+                    body: e.body.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Block(ExprBlock { unsafety, block }) => {
+            Block(e) => {
                 Block(ExprBlock {
-                    unsafety: unsafety,
-                    block: folder.fold_block(block),
+                    block: folder.fold_block(e.block),
+                    ..e
                 })
             }
-            Assign(ExprAssign { left, right }) => {
+            Assign(e) => {
                 Assign(ExprAssign {
-                    left: left.lift(|e| folder.fold_expr(e)),
-                    right: right.lift(|e| folder.fold_expr(e)),
+                    left: e.left.lift(|e| folder.fold_expr(e)),
+                    right: e.right.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            AssignOp(ExprAssignOp { op, left, right }) => {
+            AssignOp(e) => {
                 AssignOp(ExprAssignOp {
-                    op: op,
-                    left: left.lift(|e| folder.fold_expr(e)),
-                    right: right.lift(|e| folder.fold_expr(e)),
+                    left: e.left.lift(|e| folder.fold_expr(e)),
+                    right: e.right.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Field(ExprField { expr, field }) => {
+            Field(e) => {
                 Field(ExprField {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    field: folder.fold_ident(field),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    field: folder.fold_ident(e.field),
+                    ..e
                 })
             }
-            TupField(ExprTupField { expr, field }) => {
+            TupField(e) => {
                 TupField(ExprTupField {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    field: field,
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Index(ExprIndex { expr, index }) => {
+            Index(e) => {
                 Index(ExprIndex {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    index: index.lift(|e| folder.fold_expr(e)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    index: e.index.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Range(ExprRange { from, to, limits }) => {
+            Range(e) => {
                 Range(ExprRange {
-                    from: from.map(|v| v.lift(|e| folder.fold_expr(e))),
-                    to: to.map(|v| v.lift(|e| folder.fold_expr(e))),
-                    limits: limits,
+                    from: e.from.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    to: e.to.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
-            Path(ExprPath { qself, path }) => {
+            Path(e) => {
                 Path(ExprPath {
-                    qself: qself.map(|v| noop_fold_qself(folder, v)),
-                    path: folder.fold_path(path),
+                    qself: e.qself.map(|v| noop_fold_qself(folder, v)),
+                    path: folder.fold_path(e.path),
                 })
             }
-            AddrOf(ExprAddrOf { mutbl, expr }) => {
+            AddrOf(e) => {
                 AddrOf(ExprAddrOf {
-                    mutbl: mutbl,
-                    expr: expr.lift(|e| folder.fold_expr(e)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Break(ExprBreak { label, expr }) => {
+            Break(e) => {
                 Break(ExprBreak {
-                    label: label.map(|i| folder.fold_ident(i)),
-                    expr: expr.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    expr: e.expr.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
-            Continue(ExprContinue { label }) => {
+            Continue(e) => {
                 Continue(ExprContinue {
-                    label: label.map(|i| folder.fold_ident(i)),
+                    label: e.label.map(|i| folder.fold_ident(i)),
+                    ..e
                 })
             }
-            Ret(ExprRet { expr }) => {
+            Ret(e) => {
                 Ret(ExprRet {
-                    expr: expr.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    expr: e.expr.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
             Mac(mac) => Mac(folder.fold_mac(mac)),
-            Struct(ExprStruct { path, fields, rest }) => {
+            Struct(e) => {
                 Struct(ExprStruct {
-                    path: folder.fold_path(path),
-                    fields: fields.lift(|FieldValue { ident, expr, is_shorthand, attrs }: FieldValue| {
+                    path: folder.fold_path(e.path),
+                    fields: e.fields.lift(|field: FieldValue| {
                         FieldValue {
-                            ident: folder.fold_ident(ident),
-                            expr: folder.fold_expr(expr),
-                            is_shorthand: is_shorthand,
-                            attrs: attrs.lift(|v| folder.fold_attribute(v)),
+                            ident: folder.fold_ident(field.ident),
+                            expr: folder.fold_expr(field.expr),
+                            attrs: field.attrs.lift(|v| folder.fold_attribute(v)),
+                            ..field
                         }
                     }),
-                    rest: rest.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    rest: e.rest.map(|v| v.lift(|e| folder.fold_expr(e))),
+                    ..e
                 })
             }
-            Repeat(ExprRepeat { expr, amt }) => {
+            Repeat(e) => {
                 Repeat(ExprRepeat {
-                    expr: expr.lift(|e| folder.fold_expr(e)),
-                    amt: amt.lift(|e| folder.fold_expr(e)),
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    amt: e.amt.lift(|e| folder.fold_expr(e)),
+                    ..e
                 })
             }
-            Paren(ExprParen { expr }) => {
-                Paren(ExprParen { expr: expr.lift(|e| folder.fold_expr(e)) })
+            Paren(e) => {
+                Paren(ExprParen {
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
+                })
             }
-            Try(ExprTry { expr }) => {
-                Try(ExprTry { expr: expr.lift(|e| folder.fold_expr(e)) })
+            Try(e) => {
+                Try(ExprTry {
+                    expr: e.expr.lift(|e| folder.fold_expr(e)),
+                    ..e
+                })
             }
         },
         attrs: attrs.into_iter().map(|a| folder.fold_attribute(a)).collect(),
@@ -937,28 +1050,28 @@
 
 #[cfg(feature = "full")]
 pub fn noop_fold_foreign_item<F: ?Sized + Folder>(folder: &mut F,
-                                         ForeignItem { ident, attrs, node, vis }: ForeignItem)
+                                                  item: ForeignItem)
 -> ForeignItem{
     use item::*;
 
     ForeignItem {
-        ident: folder.fold_ident(ident),
-        attrs: attrs.into_iter().map(|a| folder.fold_attribute(a)).collect(),
-        node: match node {
-            ForeignItemKind::Fn(ForeignItemFn { decl, generics }) => {
+        ident: folder.fold_ident(item.ident),
+        attrs: item.attrs.into_iter().map(|a| folder.fold_attribute(a)).collect(),
+        node: match item.node {
+            ForeignItemKind::Fn(item) => {
                 ForeignItemKind::Fn(ForeignItemFn {
-                    decl: decl.lift(|v| folder.fold_fn_decl(v)),
-                    generics: folder.fold_generics(generics),
+                    decl: item.decl.lift(|v| folder.fold_fn_decl(v)),
                 })
             }
-            ForeignItemKind::Static(ForeignItemStatic { ty, mutbl }) => {
+            ForeignItemKind::Static(item) => {
                 ForeignItemKind::Static(ForeignItemStatic {
-                    ty: ty.lift(|v| folder.fold_ty(v)),
-                    mutbl: mutbl,
+                    ty: item.ty.lift(|v| folder.fold_ty(v)),
+                    ..item
                 })
             }
         },
-        vis: noop_fold_vis(folder, vis),
+        vis: noop_fold_vis(folder, item.vis),
+        ..item
     }
 }
 
@@ -966,113 +1079,146 @@
 pub fn noop_fold_pat<F: ?Sized + Folder>(folder: &mut F, pat: Pat) -> Pat {
     use Pat::*;
     match pat {
-        Wild => Wild,
-        Ident(binding_mode, ident, pat) => {
-            Ident(binding_mode,
-                  folder.fold_ident(ident),
-                  pat.map(|p| p.lift(|p| folder.fold_pat(p))))
+        Wild(b) => Wild(b),
+        Ident(p) => {
+            Ident(PatIdent {
+                ident: folder.fold_ident(p.ident),
+                subpat: p.subpat.map(|p| p.lift(|p| folder.fold_pat(p))),
+                ..p
+            })
         }
-        Struct(path, field_patterns, dots) => {
-            Struct(folder.fold_path(path),
-                   field_patterns.lift(|FieldPat { ident, pat, is_shorthand, attrs }: FieldPat| {
+        Struct(p) => {
+            Struct(PatStruct {
+                path: folder.fold_path(p.path),
+                fields: p.fields.lift(|field: FieldPat| {
                     FieldPat {
-                        ident: folder.fold_ident(ident),
-                        pat: pat.lift(|p| folder.fold_pat(p)),
-                        is_shorthand: is_shorthand,
-                        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+                        ident: folder.fold_ident(field.ident),
+                        pat: field.pat.lift(|p| folder.fold_pat(p)),
+                        attrs: field.attrs.lift(|a| folder.fold_attribute(a)),
+                        ..field
                     }
                 }),
-                   dots)
+                ..p
+            })
         }
-        TupleStruct(path, pats, len) => {
-            TupleStruct(folder.fold_path(path),
-                        pats.lift(|p| folder.fold_pat(p)),
-                        len)
+        TupleStruct(p) => {
+            TupleStruct(PatTupleStruct {
+                path: folder.fold_path(p.path),
+                pat: PatTuple {
+                    pats: p.pat.pats.lift(|p| folder.fold_pat(p)),
+                    ..p.pat
+                },
+            })
         }
-        Path(qself, path) => {
-            Path(qself.map(|v| noop_fold_qself(folder, v)),
-                 folder.fold_path(path))
+        Path(p) => {
+            Path(PatPath {
+                qself: p.qself.map(|v| noop_fold_qself(folder, v)),
+                path: folder.fold_path(p.path),
+            })
         }
-        Tuple(pats, len) => Tuple(pats.lift(|p| folder.fold_pat(p)), len),
-        Box(b) => Box(b.lift(|p| folder.fold_pat(p))),
-        Ref(b, mutability) => Ref(b.lift(|p| folder.fold_pat(p)), mutability),
-        Lit(expr) => Lit(expr.lift(|e| folder.fold_expr(e))),
-        Range(l, r, limits) => {
-            Range(l.lift(|e| folder.fold_expr(e)),
-                  r.lift(|e| folder.fold_expr(e)),
-                  limits)
+        Tuple(p) => {
+            Tuple(PatTuple {
+                pats: p.pats.lift(|p| folder.fold_pat(p)),
+                ..p
+            })
         }
-        Slice(lefts, pat, rights) => {
-            Slice(lefts.lift(|p| folder.fold_pat(p)),
-                  pat.map(|v| v.lift(|p| folder.fold_pat(p))),
-                  rights.lift(|p| folder.fold_pat(p)))
+        Box(p) => {
+            Box(PatBox {
+                pat: p.pat.lift(|p| folder.fold_pat(p)),
+                ..p
+            })
+        }
+        Ref(p) => {
+            Ref(PatRef {
+                pat: p.pat.lift(|p| folder.fold_pat(p)),
+                ..p
+            })
+        }
+        Lit(p) => {
+            Lit(PatLit {
+                expr: p.expr.lift(|e| folder.fold_expr(e)),
+            })
+        }
+        Range(p) => {
+            Range(PatRange {
+                hi: p.hi.lift(|e| folder.fold_expr(e)),
+                lo: p.lo.lift(|e| folder.fold_expr(e)),
+                ..p
+            })
+        }
+        Slice(p) => {
+            Slice(PatSlice {
+                front: p.front.lift(|p| folder.fold_pat(p)),
+                middle: p.middle.map(|v| v.lift(|p| folder.fold_pat(p))),
+                back: p.back.lift(|p| folder.fold_pat(p)),
+                ..p
+            })
         }
         Mac(mac) => Mac(folder.fold_mac(mac)),
     }
 }
 
 #[cfg(feature = "full")]
-pub fn noop_fold_fn_decl<F: ?Sized + Folder>(folder: &mut F,
-                                             FnDecl { inputs, output, variadic }: FnDecl)
-                                             -> FnDecl {
-
+pub fn noop_fold_fn_decl<F: ?Sized + Folder>(folder: &mut F, decl: FnDecl)
+    -> FnDecl
+{
     FnDecl {
-        inputs: inputs.lift(|a| {
+        inputs: decl.inputs.lift(|a| {
             use item::*;
             use FnArg::*;
             match a {
-                SelfRef(ArgSelfRef { lifetime, mutbl }) => {
+                SelfRef(a) => {
                     SelfRef(ArgSelfRef {
-                        lifetime: lifetime.map(|v| folder.fold_lifetime(v)),
-                        mutbl: mutbl,
+                        lifetime: a.lifetime.map(|v| folder.fold_lifetime(v)),
+                        ..a
                     })
                 }
-                SelfValue(ArgSelf { mutbl } ) => {
-                    SelfValue(ArgSelf {
-                        mutbl: mutbl,
-                    })
-                }
-                Captured(ArgCaptured { pat, ty }) => {
+                SelfValue(a) => SelfValue(a),
+                Captured(a) => {
                     Captured(ArgCaptured {
-                        pat: folder.fold_pat(pat),
-                        ty: folder.fold_ty(ty),
+                        pat: folder.fold_pat(a.pat),
+                        ty: folder.fold_ty(a.ty),
+                        ..a
                     })
                 }
                 Ignored(ty) => Ignored(folder.fold_ty(ty)),
             }
         }),
-        output: folder.fold_fn_ret_ty(output),
-        variadic: variadic,
+        output: folder.fold_fn_ret_ty(decl.output),
+        generics: folder.fold_generics(decl.generics),
+        ..decl
     }
-
 }
 
 #[cfg(feature = "full")]
 pub fn noop_fold_trait_item<F: ?Sized + Folder>(folder: &mut F,
-                                                TraitItem { ident, attrs, node }: TraitItem)
+                                                item: TraitItem)
                                                 -> TraitItem {
     use item::*;
     use TraitItemKind::*;
     TraitItem {
-        ident: folder.fold_ident(ident),
-        attrs: attrs.lift(|v| folder.fold_attribute(v)),
-        node: match node {
-            Const(TraitItemConst { ty, default }) => {
+        ident: folder.fold_ident(item.ident),
+        attrs: item.attrs.lift(|v| folder.fold_attribute(v)),
+        node: match item.node {
+            Const(i) => {
                 Const(TraitItemConst {
-                    ty: folder.fold_ty(ty),
-                    default: default.map(|v| folder.fold_expr(v)),
+                    ty: folder.fold_ty(i.ty),
+                    default: i.default.map(|v| folder.fold_expr(v)),
+                    ..i
                 })
             }
-            Method(TraitItemMethod { sig, default }) => {
+            Method(i) => {
                 Method(TraitItemMethod {
-                    sig: folder.fold_method_sig(sig),
-                    default: default.map(|v| folder.fold_block(v)),
+                    sig: folder.fold_method_sig(i.sig),
+                    default: i.default.map(|v| folder.fold_block(v)),
+                    ..i
                 })
             }
-            Type(TraitItemType { bounds, default }) => {
+            Type(i) => {
                 Type(TraitItemType {
-                    bounds: bounds.lift(|v| folder.fold_ty_param_bound(v)),
-                    default: default.map(|v| folder.fold_ty(v)),
+                    bounds: i.bounds.lift(|v| folder.fold_ty_param_bound(v)),
+                    default: i.default.map(|v| folder.fold_ty(v)),
+                    ..i
                 })
             }
             Macro(mac) => Macro(folder.fold_mac(mac)),
@@ -1081,48 +1227,49 @@
 }
 
 #[cfg(feature = "full")]
-pub fn noop_fold_impl_item<F: ?Sized + Folder>(folder: &mut F,
-                                      ImplItem { ident, vis, defaultness, attrs, node }: ImplItem)
--> ImplItem{
+pub fn noop_fold_impl_item<F: ?Sized + Folder>(folder: &mut F, item: ImplItem)
+    -> ImplItem
+{
     use item::*;
     use ImplItemKind::*;
 
     ImplItem {
-        ident: folder.fold_ident(ident),
-        vis: noop_fold_vis(folder, vis),
-        defaultness: defaultness,
-        attrs: attrs.lift(|v| folder.fold_attribute(v)),
-        node: match node {
-            Const(ImplItemConst { ty, expr }) => {
+        ident: folder.fold_ident(item.ident),
+        vis: noop_fold_vis(folder, item.vis),
+        attrs: item.attrs.lift(|v| folder.fold_attribute(v)),
+        node: match item.node {
+            Const(i) => {
                 Const(ImplItemConst {
-                    ty: folder.fold_ty(ty),
-                    expr: folder.fold_expr(expr),
+                    ty: folder.fold_ty(i.ty),
+                    expr: folder.fold_expr(i.expr),
+                    ..i
                 })
             }
-            Method(ImplItemMethod { sig, block }) => {
+            Method(i) => {
                 Method(ImplItemMethod {
-                    sig: folder.fold_method_sig(sig),
-                    block: folder.fold_block(block),
+                    sig: folder.fold_method_sig(i.sig),
+                    block: folder.fold_block(i.block),
                 })
             }
-            Type(ImplItemType { ty }) => {
+            Type(i) => {
                 Type(ImplItemType {
-                    ty: folder.fold_ty(ty),
+                    ty: folder.fold_ty(i.ty),
+                    ..i
                 })
             }
             Macro(mac) => Macro(folder.fold_mac(mac)),
         },
+        ..item
     }
 }
 
 #[cfg(feature = "full")]
-pub fn noop_fold_method_sig<F: ?Sized + Folder>(folder: &mut F, MethodSig{unsafety, constness, abi, decl, generics}:MethodSig) -> MethodSig{
+pub fn noop_fold_method_sig<F: ?Sized + Folder>(folder: &mut F, sig: MethodSig)
+    -> MethodSig
+{
     MethodSig {
-        unsafety: unsafety,
-        constness: constness,
-        abi: abi,
-        decl: folder.fold_fn_decl(decl),
-        generics: folder.fold_generics(generics),
+        decl: folder.fold_fn_decl(sig.decl),
+        ..sig
     }
 
 }
@@ -1134,7 +1281,7 @@
         Local(local) => Local(local.lift(|l| folder.fold_local(l))),
         Item(item) => Item(item.lift(|v| folder.fold_item(v))),
         Expr(expr) => Expr(expr.lift(|v| folder.fold_expr(v))),
-        Semi(expr) => Semi(expr.lift(|v| folder.fold_expr(v))),
+        Semi(expr, t) => Semi(expr.lift(|v| folder.fold_expr(v)), t),
         Mac(mac_stmt) => {
             Mac(mac_stmt.lift(|(mac, style, attrs)| {
                                   (folder.fold_mac(mac),
@@ -1147,14 +1294,15 @@
 }
 
 #[cfg(feature = "full")]
-pub fn noop_fold_local<F: ?Sized + Folder>(folder: &mut F,
-                                           Local { pat, ty, init, attrs }: Local)
-                                           -> Local {
+pub fn noop_fold_local<F: ?Sized + Folder>(folder: &mut F, local: Local)
+    -> Local
+{
     Local {
-        pat: pat.lift(|v| folder.fold_pat(v)),
-        ty: ty.map(|v| v.lift(|t| folder.fold_ty(t))),
-        init: init.map(|v| v.lift(|e| folder.fold_expr(e))),
-        attrs: attrs.lift(|a| folder.fold_attribute(a)),
+        pat: local.pat.lift(|v| folder.fold_pat(v)),
+        ty: local.ty.map(|v| v.lift(|t| folder.fold_ty(t))),
+        init: local.init.map(|v| v.lift(|e| folder.fold_expr(e))),
+        attrs: local.attrs.lift(|a| folder.fold_attribute(a)),
+        ..local
     }
 }
 
@@ -1163,26 +1311,30 @@
     use item::*;
     use ViewPath::*;
     match view_path {
-        Simple(PathSimple { path, rename }) => {
+        Simple(p) => {
             Simple(PathSimple {
-                path: folder.fold_path(path),
-                rename: rename.map(|i| folder.fold_ident(i)),
+                path: folder.fold_path(p.path),
+                rename: p.rename.map(|i| folder.fold_ident(i)),
+                ..p
             })
         }
-        Glob(PathGlob { path }) => {
+        Glob(p) => {
             Glob(PathGlob {
-                path: folder.fold_path(path),
+                path: folder.fold_path(p.path),
+                ..p
             })
         }
-        List(PathList { path, items }) => {
+        List(p) => {
             List(PathList {
-                path: folder.fold_path(path),
-                items: items.lift(|PathListItem { name, rename }: PathListItem| {
+                path: folder.fold_path(p.path),
+                items: p.items.lift(|item: PathListItem| {
                     PathListItem {
-                        name: folder.fold_ident(name),
-                        rename: rename.map(|i| folder.fold_ident(i)),
+                        name: folder.fold_ident(item.name),
+                        rename: item.rename.map(|i| folder.fold_ident(i)),
+                        ..item
                     }
                 }),
+                ..p
             })
         }
     }
diff --git a/src/generics.rs b/src/generics.rs
index adf6dfa..c6d697a 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -1,12 +1,15 @@
 use super::*;
+use delimited::Delimited;
 
 ast_struct! {
     /// Represents lifetimes and type parameters attached to a declaration
     /// of a function, enum, trait, etc.
     #[derive(Default)]
     pub struct Generics {
-        pub lifetimes: Vec<LifetimeDef>,
-        pub ty_params: Vec<TyParam>,
+        pub lt_token: Option<tokens::Lt>,
+        pub gt_token: Option<tokens::Gt>,
+        pub lifetimes: Delimited<LifetimeDef, tokens::Comma>,
+        pub ty_params: Delimited<TyParam, tokens::Comma>,
         pub where_clause: WhereClause,
     }
 }
@@ -40,7 +43,7 @@
     /// # extern crate quote;
     /// # fn main() {
     /// # let generics: syn::Generics = Default::default();
-    /// # let name = syn::Ident::new("MyType");
+    /// # let name = syn::Ident::from("MyType");
     /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
     /// quote! {
     ///     impl #impl_generics MyTrait for #name #ty_generics #where_clause {
@@ -71,7 +74,7 @@
 
 impl Lifetime {
     pub fn new<T: Into<Ident>>(t: T) -> Self {
-        let id = Ident::new(t);
+        let id = t.into();
         if !id.as_ref().starts_with('\'') {
             panic!("lifetime name must start with apostrophe as in \"'a\", \
                    got {:?}",
@@ -82,11 +85,23 @@
 }
 
 ast_struct! {
+    /// A set of bound lifetimes, e.g. `for<'a, 'b, 'c>`
+    #[derive(Default)]
+    pub struct BoundLifetimes {
+        pub for_token: tokens::For,
+        pub lt_token: tokens::Lt,
+        pub lifetimes: Delimited<LifetimeDef, tokens::Comma>,
+        pub gt_token: tokens::Gt,
+    }
+}
+
+ast_struct! {
     /// A lifetime definition, e.g. `'a: 'b+'c+'d`
     pub struct LifetimeDef {
         pub attrs: Vec<Attribute>,
         pub lifetime: Lifetime,
-        pub bounds: Vec<Lifetime>,
+        pub colon_token: Option<tokens::Colon>,
+        pub bounds: Delimited<Lifetime, tokens::Add>,
     }
 }
 
@@ -95,7 +110,8 @@
         LifetimeDef {
             attrs: Vec::new(),
             lifetime: Lifetime::new(t),
-            bounds: Vec::new(),
+            colon_token: None,
+            bounds: Delimited::new(),
         }
     }
 }
@@ -105,7 +121,9 @@
     pub struct TyParam {
         pub attrs: Vec<Attribute>,
         pub ident: Ident,
-        pub bounds: Vec<TyParamBound>,
+        pub colon_token: Option<tokens::Colon>,
+        pub bounds: Delimited<TyParamBound, tokens::Add>,
+        pub eq_token: Option<tokens::Eq>,
         pub default: Option<Ty>,
     }
 }
@@ -115,7 +133,9 @@
         TyParam {
             attrs: vec![],
             ident: ident,
-            bounds: vec![],
+            colon_token: None,
+            bounds: Delimited::new(),
+            eq_token: None,
             default: None,
         }
     }
@@ -138,7 +158,7 @@
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum TraitBoundModifier {
         None,
-        Maybe,
+        Maybe(tokens::Question),
     }
 }
 
@@ -146,13 +166,14 @@
     /// A `where` clause in a definition
     #[derive(Default)]
     pub struct WhereClause {
-        pub predicates: Vec<WherePredicate>,
+        pub where_token: Option<tokens::Where>,
+        pub predicates: Delimited<WherePredicate, tokens::Comma>,
     }
 }
 
 impl WhereClause {
     pub fn none() -> Self {
-        WhereClause { predicates: Vec::new() }
+        WhereClause::default()
     }
 }
 
@@ -162,22 +183,25 @@
         /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
         pub BoundPredicate(WhereBoundPredicate {
             /// Any lifetimes from a `for` binding
-            pub bound_lifetimes: Vec<LifetimeDef>,
+            pub bound_lifetimes: Option<BoundLifetimes>,
             /// The type being bounded
             pub bounded_ty: Ty,
+            pub colon_token: tokens::Colon,
             /// Trait and lifetime bounds (`Clone+Send+'static`)
-            pub bounds: Vec<TyParamBound>,
+            pub bounds: Delimited<TyParamBound, tokens::Add>,
         }),
 
         /// A lifetime predicate, e.g. `'a: 'b+'c`
         pub RegionPredicate(WhereRegionPredicate {
             pub lifetime: Lifetime,
-            pub bounds: Vec<Lifetime>,
+            pub colon_token: Option<tokens::Colon>,
+            pub bounds: Delimited<Lifetime, tokens::Add>,
         }),
 
         /// An equality predicate (unsupported)
         pub EqPredicate(WhereEqPredicate {
             pub lhs_ty: Ty,
+            pub eq_token: tokens::Eq,
             pub rhs_ty: Ty,
         }),
     }
@@ -194,22 +218,29 @@
         alt!(
             do_parse!(
                 punct!("<") >>
-                lifetimes: separated_list!(punct!(","), lifetime_def) >>
-                ty_params: opt_vec!(preceded!(
-                    cond!(!lifetimes.is_empty(), punct!(",")),
-                    separated_nonempty_list!(punct!(","), ty_param)
-                )) >>
-                cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
+                lifetimes: terminated_list!(
+                    map!(punct!(","), |_| tokens::Comma::default()),
+                    lifetime_def
+                ) >>
+                ty_params: cond!(
+                    lifetimes.is_empty() || lifetimes.trailing_delim(),
+                    terminated_list!(
+                        map!(punct!(","), |_| tokens::Comma::default()),
+                        ty_param
+                    )
+                ) >>
                 punct!(">") >>
-                (lifetimes, ty_params)
+                (lifetimes, ty_params, true)
             )
             |
-            epsilon!() => { |_| (Vec::new(), Vec::new()) }
+            epsilon!() => { |_| (Delimited::new(), None, false) }
         ),
-        |(lifetimes, ty_params)| Generics {
+        |(lifetimes, ty_params, any): (_, Option<_>, _)| Generics {
             lifetimes: lifetimes,
-            ty_params: ty_params,
-            where_clause: Default::default(),
+            ty_params: ty_params.unwrap_or_default(),
+            where_clause: WhereClause::default(),
+            gt_token: if any {Some(tokens::Gt::default())} else {None},
+            lt_token: if any {Some(tokens::Lt::default())} else {None},
         }
     ));
 
@@ -229,32 +260,43 @@
     named!(pub lifetime_def -> LifetimeDef, do_parse!(
         attrs: many0!(outer_attr) >>
         life: lifetime >>
-        bounds: opt_vec!(preceded!(
-            punct!(":"),
-            separated_list!(punct!("+"), lifetime)
-        )) >>
+        colon: option!(punct!(":")) >>
+        bounds: cond!(
+            colon.is_some(),
+            separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                     lifetime)
+        ) >>
         (LifetimeDef {
             attrs: attrs,
             lifetime: life,
-            bounds: bounds,
+            bounds: bounds.unwrap_or_default(),
+            colon_token: colon.map(|_| tokens::Colon::default()),
         })
     ));
 
-    named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
+    named!(pub bound_lifetimes -> Option<BoundLifetimes>, option!(do_parse!(
         keyword!("for") >>
         punct!("<") >>
-        lifetimes: terminated_list!(punct!(","), lifetime_def) >>
+        lifetimes: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                    lifetime_def) >>
         punct!(">") >>
-        (lifetimes)
+        (BoundLifetimes {
+            for_token: tokens::For::default(),
+            lt_token: tokens::Lt::default(),
+            gt_token: tokens::Gt::default(),
+            lifetimes: lifetimes,
+        })
     )));
 
     named!(ty_param -> TyParam, do_parse!(
         attrs: many0!(outer_attr) >>
         id: ident >>
-        bounds: opt_vec!(preceded!(
-            punct!(":"),
-            separated_nonempty_list!(punct!("+"), ty_param_bound)
-        )) >>
+        colon: option!(punct!(":")) >>
+        bounds: cond!(
+            colon.is_some(),
+            separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                     ty_param_bound)
+        ) >>
         default: option!(preceded!(
             punct!("="),
             ty
@@ -262,14 +304,16 @@
         (TyParam {
             attrs: attrs,
             ident: id,
-            bounds: bounds,
+            bounds: bounds.unwrap_or_default(),
+            colon_token: colon.map(|_| tokens::Colon::default()),
+            eq_token: default.as_ref().map(|_| tokens::Eq::default()),
             default: default,
         })
     ));
 
     named!(pub ty_param_bound -> TyParamBound, alt!(
         preceded!(punct!("?"), poly_trait_ref) => {
-            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
+            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe(tokens::Question::default()))
         }
         |
         lifetime => { TyParamBound::Region }
@@ -282,24 +326,32 @@
     named!(pub where_clause -> WhereClause, alt!(
         do_parse!(
             keyword!("where") >>
-            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
-            option!(punct!(",")) >>
-            (WhereClause { predicates: predicates })
+            predicates: terminated_list!(
+                map!(punct!(","), |_| tokens::Comma::default()),
+                where_predicate
+            ) >>
+            (WhereClause {
+                predicates: predicates,
+                where_token: Some(tokens::Where::default()),
+            })
         )
         |
-        epsilon!() => { |_| Default::default() }
+        epsilon!() => { |_| WhereClause::default() }
     ));
 
     named!(where_predicate -> WherePredicate, alt!(
         do_parse!(
             ident: lifetime >>
-            bounds: opt_vec!(preceded!(
-                punct!(":"),
-                separated_list!(punct!("+"), lifetime)
-            )) >>
+            colon: option!(punct!(":")) >>
+            bounds: cond!(
+                colon.is_some(),
+                separated_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                lifetime)
+            ) >>
             (WherePredicate::RegionPredicate(WhereRegionPredicate {
                 lifetime: ident,
-                bounds: bounds,
+                bounds: bounds.unwrap_or_default(),
+                colon_token: colon.map(|_| tokens::Colon::default()),
             }))
         )
         |
@@ -307,11 +359,13 @@
             bound_lifetimes: bound_lifetimes >>
             bounded_ty: ty >>
             punct!(":") >>
-            bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
+            bounds: separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                             ty_param_bound) >>
             (WherePredicate::BoundPredicate(WhereBoundPredicate {
                 bound_lifetimes: bound_lifetimes,
                 bounded_ty: bounded_ty,
                 bounds: bounds,
+                colon_token: tokens::Colon::default(),
             }))
         )
     ));
@@ -325,70 +379,44 @@
 
     impl ToTokens for Generics {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let has_lifetimes = !self.lifetimes.is_empty();
-            let has_ty_params = !self.ty_params.is_empty();
-            if has_lifetimes || has_ty_params {
-                tokens.append("<");
-                tokens.append_separated(&self.lifetimes, ",");
-                if has_lifetimes && has_ty_params {
-                    tokens.append(",");
-                }
-                tokens.append_separated(&self.ty_params, ",");
-                tokens.append(">");
-            }
+            self.lt_token.to_tokens(tokens);
+            self.lifetimes.to_tokens(tokens);
+            self.ty_params.to_tokens(tokens);
+            self.gt_token.to_tokens(tokens);
         }
     }
 
     impl<'a> ToTokens for ImplGenerics<'a> {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let has_lifetimes = !self.0.lifetimes.is_empty();
-            let has_ty_params = !self.0.ty_params.is_empty();
-            if has_lifetimes || has_ty_params {
-                tokens.append("<");
-                tokens.append_separated(&self.0.lifetimes, ",");
-                // Leave off the type parameter defaults
-                for (i, ty_param) in self.0
-                        .ty_params
-                        .iter()
-                        .enumerate() {
-                    if i > 0 || has_lifetimes {
-                        tokens.append(",");
-                    }
-                    tokens.append_all(ty_param.attrs.outer());
-                    ty_param.ident.to_tokens(tokens);
-                    if !ty_param.bounds.is_empty() {
-                        tokens.append(":");
-                        tokens.append_separated(&ty_param.bounds, "+");
-                    }
-                }
-                tokens.append(">");
+            self.0.lt_token.to_tokens(tokens);
+            self.0.lifetimes.to_tokens(tokens);
+            for param in self.0.ty_params.iter() {
+                 // Leave off the type parameter defaults
+                let item = param.item();
+                tokens.append_all(item.attrs.outer());
+                item.ident.to_tokens(tokens);
+                item.colon_token.to_tokens(tokens);
+                item.bounds.to_tokens(tokens);
+                param.delimiter().to_tokens(tokens);
             }
+            self.0.gt_token.to_tokens(tokens);
         }
     }
 
     impl<'a> ToTokens for TyGenerics<'a> {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let has_lifetimes = !self.0.lifetimes.is_empty();
-            let has_ty_params = !self.0.ty_params.is_empty();
-            if has_lifetimes || has_ty_params {
-                tokens.append("<");
-                // Leave off the lifetime bounds and attributes
-                let lifetimes = self.0
-                    .lifetimes
-                    .iter()
-                    .map(|ld| &ld.lifetime);
-                tokens.append_separated(lifetimes, ",");
-                if has_lifetimes && has_ty_params {
-                    tokens.append(",");
-                }
-                // Leave off the type parameter bounds, defaults, and attributes
-                let ty_params = self.0
-                    .ty_params
-                    .iter()
-                    .map(|tp| &tp.ident);
-                tokens.append_separated(ty_params, ",");
-                tokens.append(">");
+            self.0.lt_token.to_tokens(tokens);
+            // Leave off the lifetime bounds and attributes
+            for param in self.0.lifetimes.iter() {
+                param.item().lifetime.to_tokens(tokens);
+                param.delimiter().to_tokens(tokens);
             }
+            // Leave off the type parameter defaults
+            for param in self.0.ty_params.iter() {
+                param.item().ident.to_tokens(tokens);
+                param.delimiter().to_tokens(tokens);
+            }
+            self.0.gt_token.to_tokens(tokens);
         }
     }
 
@@ -397,7 +425,7 @@
             let has_lifetimes = !self.0.lifetimes.is_empty();
             let has_ty_params = !self.0.ty_params.is_empty();
             if has_lifetimes || has_ty_params {
-                tokens.append("::");
+                tokens::Colon2::default().to_tokens(tokens);
                 TyGenerics(self.0).to_tokens(tokens);
             }
         }
@@ -409,14 +437,21 @@
         }
     }
 
+    impl ToTokens for BoundLifetimes {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.for_token.to_tokens(tokens);
+            self.lt_token.to_tokens(tokens);
+            self.lifetimes.to_tokens(tokens);
+            self.gt_token.to_tokens(tokens);
+        }
+    }
+
     impl ToTokens for LifetimeDef {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
             self.lifetime.to_tokens(tokens);
-            if !self.bounds.is_empty() {
-                tokens.append(":");
-                tokens.append_separated(&self.bounds, "+");
-            }
+            self.colon_token.to_tokens(tokens);
+            self.bounds.to_tokens(tokens);
         }
     }
 
@@ -424,14 +459,10 @@
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
             self.ident.to_tokens(tokens);
-            if !self.bounds.is_empty() {
-                tokens.append(":");
-                tokens.append_separated(&self.bounds, "+");
-            }
-            if let Some(ref default) = self.default {
-                tokens.append("=");
-                default.to_tokens(tokens);
-            }
+            self.colon_token.to_tokens(tokens);
+            self.bounds.to_tokens(tokens);
+            self.eq_token.to_tokens(tokens);
+            self.default.to_tokens(tokens);
         }
     }
 
@@ -440,55 +471,50 @@
             match *self {
                 TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
                 TyParamBound::Trait(ref trait_ref, ref modifier) => {
-                    match *modifier {
-                        TraitBoundModifier::None => {}
-                        TraitBoundModifier::Maybe => tokens.append("?"),
-                    }
+                    modifier.to_tokens(tokens);
                     trait_ref.to_tokens(tokens);
                 }
             }
         }
     }
 
+    impl ToTokens for TraitBoundModifier {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                TraitBoundModifier::None => {}
+                TraitBoundModifier::Maybe(ref t) => t.to_tokens(tokens),
+            }
+        }
+    }
+
     impl ToTokens for WhereClause {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if !self.predicates.is_empty() {
-                tokens.append("where");
-                tokens.append_separated(&self.predicates, ",");
-            }
+            self.where_token.to_tokens(tokens);
+            self.predicates.to_tokens(tokens);
         }
     }
 
     impl ToTokens for WhereBoundPredicate {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if !self.bound_lifetimes.is_empty() {
-                tokens.append("for");
-                tokens.append("<");
-                tokens.append_separated(&self.bound_lifetimes, ",");
-                tokens.append(">");
-            }
+            self.bound_lifetimes.to_tokens(tokens);
             self.bounded_ty.to_tokens(tokens);
-            if !self.bounds.is_empty() {
-                tokens.append(":");
-                tokens.append_separated(&self.bounds, "+");
-            }
+            self.colon_token.to_tokens(tokens);
+            self.bounds.to_tokens(tokens);
         }
     }
 
     impl ToTokens for WhereRegionPredicate {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.lifetime.to_tokens(tokens);
-            if !self.bounds.is_empty() {
-                tokens.append(":");
-                tokens.append_separated(&self.bounds, "+");
-            }
+            self.colon_token.to_tokens(tokens);
+            self.bounds.to_tokens(tokens);
         }
     }
 
     impl ToTokens for WhereEqPredicate {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.lhs_ty.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.rhs_ty.to_tokens(tokens);
         }
     }
diff --git a/src/ident.rs b/src/ident.rs
index 8f698be..3df1b61 100644
--- a/src/ident.rs
+++ b/src/ident.rs
@@ -1,48 +1,66 @@
 use std::borrow::Cow;
+use std::cmp::Ordering;
 use std::fmt::{self, Display};
+use std::hash::{Hash, Hasher};
 
-#[derive(Debug, Clone, Eq, Hash, Ord, PartialOrd)]
-pub struct Ident(String);
+use proc_macro2::Symbol;
+
+use Span;
+
+#[derive(Clone)]
+pub struct Ident {
+    pub sym: Symbol,
+    pub span: Span,
+}
 
 impl Ident {
-    pub fn new<T: Into<Ident>>(t: T) -> Self {
-        t.into()
+    pub fn new(sym: Symbol, span: Span) -> Self {
+        Ident {
+            sym: sym,
+            span: span,
+        }
     }
 }
 
 impl<'a> From<&'a str> for Ident {
     fn from(s: &str) -> Self {
-        Ident(s.to_owned())
+        Ident::new(s.into(), Span::default())
     }
 }
 
 impl<'a> From<Cow<'a, str>> for Ident {
     fn from(s: Cow<'a, str>) -> Self {
-        Ident(s.into_owned())
+        Ident::new(s[..].into(), Span::default())
     }
 }
 
 impl From<String> for Ident {
     fn from(s: String) -> Self {
-        Ident(s)
+        Ident::new(s[..].into(), Span::default())
     }
 }
 
 impl From<usize> for Ident {
     fn from(u: usize) -> Self {
-        Ident(u.to_string())
+        Ident::new(u.to_string()[..].into(), Span::default())
     }
 }
 
 impl AsRef<str> for Ident {
     fn as_ref(&self) -> &str {
-        &self.0
+        self.sym.as_str()
     }
 }
 
 impl Display for Ident {
-    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-        self.0.fmt(formatter)
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        self.sym.as_str().fmt(formatter)
+    }
+}
+
+impl fmt::Debug for Ident {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(self.sym.as_str(), formatter)
     }
 }
 
@@ -50,7 +68,27 @@
     where T: AsRef<str>
 {
     fn eq(&self, other: &T) -> bool {
-        self.0 == other.as_ref()
+        self.as_ref() == other.as_ref()
+    }
+}
+
+impl Eq for Ident {}
+
+impl PartialOrd for Ident {
+    fn partial_cmp(&self, other: &Ident) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Ident {
+    fn cmp(&self, other: &Ident) -> Ordering {
+        self.as_ref().cmp(other.as_ref())
+    }
+}
+
+impl Hash for Ident {
+    fn hash<H: Hasher>(&self, h: &mut H) {
+        self.as_ref().hash(h)
     }
 }
 
@@ -120,10 +158,14 @@
 mod printing {
     use super::*;
     use quote::{Tokens, ToTokens};
+    use proc_macro2::{TokenTree, TokenKind};
 
     impl ToTokens for Ident {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.as_ref())
+            tokens.append(TokenTree {
+                span: self.span.0,
+                kind: TokenKind::Word(self.sym),
+            })
         }
     }
 }
diff --git a/src/item.rs b/src/item.rs
index 611e52a..f7373a6 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -1,4 +1,5 @@
 use super::*;
+use delimited::Delimited;
 
 ast_struct! {
     /// An item
@@ -18,18 +19,28 @@
         ///
         /// E.g. `extern crate foo` or `extern crate foo_bar as foo`
         pub ExternCrate(ItemExternCrate {
+            pub extern_token: tokens::Extern,
+            pub crate_token: tokens::Crate,
+            pub as_token: Option<tokens::As>,
             pub original: Option<Ident>,
+            pub semi_token: tokens::Semi,
         }),
         /// A use declaration (`use` or `pub use`) item.
         ///
         /// E.g. `use foo;`, `use foo::bar;` or `use foo::bar as FooBar;`
         pub Use(ItemUse {
+            pub use_token: tokens::Use,
             pub path: Box<ViewPath>,
+            pub semi_token: tokens::Semi,
         }),
         /// A static item (`static` or `pub static`).
         ///
         /// E.g. `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`
         pub Static(ItemStatic {
+            pub static_token: tokens::Static,
+            pub colon_token: tokens::Colon,
+            pub eq_token: tokens::Eq,
+            pub semi_token: tokens::Semi,
             pub ty: Box<Ty>,
             pub mutbl: Mutability,
             pub expr: Box<Expr>,
@@ -38,6 +49,10 @@
         ///
         /// E.g. `const FOO: i32 = 42;`
         pub Const(ItemConst {
+            pub const_token: tokens::Const,
+            pub colon_token: tokens::Colon,
+            pub eq_token: tokens::Eq,
+            pub semi_token: tokens::Semi,
             pub ty: Box<Ty>,
             pub expr: Box<Expr>,
         }),
@@ -49,23 +64,32 @@
             pub unsafety: Unsafety,
             pub constness: Constness,
             pub abi: Option<Abi>,
-            pub generics: Generics,
             pub block: Box<Block>,
         }),
         /// A module declaration (`mod` or `pub mod`).
         ///
         /// E.g. `mod foo;` or `mod foo { .. }`
         pub Mod(ItemMod {
-            pub items: Option<Vec<Item>>,
+            pub mod_token: tokens::Mod,
+            pub semi_token: Option<tokens::Semi>,
+            pub items: Option<(Vec<Item>, tokens::Brace)>,
         }),
         /// An external module (`extern` or `pub extern`).
         ///
         /// E.g. `extern {}` or `extern "C" {}`
-        pub ForeignMod(ItemForeignMod),
+        pub ForeignMod(ItemForeignMod {
+            pub brace_token: tokens::Brace,
+            pub abi: Abi,
+            pub items: Vec<ForeignItem>,
+        }),
+
         /// A type alias (`type` or `pub type`).
         ///
         /// E.g. `type Foo = Bar<u8>;`
         pub Ty(ItemTy {
+            pub type_token: tokens::Type,
+            pub eq_token: tokens::Eq,
+            pub semi_token: tokens::Semi,
             pub ty: Box<Ty>,
             pub generics: Generics,
         }),
@@ -73,20 +97,25 @@
         ///
         /// E.g. `enum Foo<A, B> { C<A>, D<B> }`
         pub Enum(ItemEnum {
-            pub variants: Vec<Variant>,
+            pub enum_token: tokens::Enum,
+            pub brace_token: tokens::Brace,
+            pub variants: Delimited<Variant, tokens::Comma>,
             pub generics: Generics,
         }),
         /// A struct definition (`struct` or `pub struct`).
         ///
         /// E.g. `struct Foo<A> { x: A }`
         pub Struct(ItemStruct {
+            pub struct_token: tokens::Struct,
             pub data: VariantData,
             pub generics: Generics,
+            pub semi_token: Option<tokens::Semi>,
         }),
         /// A union definition (`union` or `pub union`).
         ///
         /// E.g. `union Foo<A, B> { x: A, y: B }`
         pub Union(ItemUnion {
+            pub union_token: tokens::Union,
             pub data: VariantData,
             pub generics: Generics,
         }),
@@ -94,9 +123,12 @@
         ///
         /// E.g. `trait Foo { .. }` or `trait Foo<T> { .. }`
         pub Trait(ItemTrait {
+            pub trait_token: tokens::Trait,
             pub unsafety: Unsafety,
             pub generics: Generics,
-            pub supertraits: Vec<TyParamBound>,
+            pub colon_token: Option<tokens::Colon>,
+            pub supertraits: Delimited<TyParamBound, tokens::Add>,
+            pub brace_token: tokens::Brace,
             pub items: Vec<TraitItem>,
         }),
         /// Default trait implementation.
@@ -105,16 +137,23 @@
         pub DefaultImpl(ItemDefaultImpl {
             pub unsafety: Unsafety,
             pub path: Path,
+            pub impl_token: tokens::Impl,
+            pub for_token: tokens::For,
+            pub dot2_token: tokens::Dot2,
+            pub brace_token: tokens::Brace,
         }),
         /// An implementation.
         ///
         /// E.g. `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`
         pub Impl(ItemImpl {
+            pub impl_token: tokens::Impl,
             pub unsafety: Unsafety,
             pub polarity: ImplPolarity,
             pub generics: Generics,
+            pub for_token: Option<tokens::For>,
             pub trait_: Option<Path>, // (optional) trait this impl implements
             pub self_ty: Box<Ty>, // self
+            pub brace_token: tokens::Brace,
             pub items: Vec<ImplItem>,
         }),
         /// A macro invocation (which includes macro definition).
@@ -133,16 +172,20 @@
             vis: input.vis,
             attrs: input.attrs,
             node: match input.body {
-                Body::Enum(variants) => {
+                Body::Enum(data) => {
                     ItemEnum {
-                        variants: variants,
+                        variants: data.variants,
                         generics: input.generics,
+                        brace_token: data.brace_token,
+                        enum_token: data.enum_token,
                     }.into()
                 }
-                Body::Struct(variant_data) => {
+                Body::Struct(data) => {
                     ItemStruct {
-                        data: variant_data,
+                        data: data.data,
                         generics: input.generics,
+                        semi_token: data.semi_token,
+                        struct_token: data.struct_token,
                     }.into()
                 }
             },
@@ -159,18 +202,23 @@
         /// `foo::bar::baz` (with `as baz` implicitly on the right)
         pub Simple(PathSimple {
             pub path: Path,
+            pub as_token: Option<tokens::As>,
             pub rename: Option<Ident>,
         }),
 
         /// `foo::bar::*`
         pub Glob(PathGlob {
             pub path: Path,
+            pub colon2_token: tokens::Colon2,
+            pub star_token: tokens::Star,
         }),
 
         /// `foo::bar::{a, b, c}`
         pub List(PathList {
             pub path: Path,
-            pub items: Vec<PathListItem>,
+            pub colon2_token: tokens::Colon2,
+            pub brace_token: tokens::Brace,
+            pub items: Delimited<PathListItem, tokens::Comma>,
         }),
     }
 }
@@ -180,13 +228,14 @@
         pub name: Ident,
         /// renamed in list, e.g. `use foo::{bar as baz};`
         pub rename: Option<Ident>,
+        pub as_token: Option<tokens::As>,
     }
 }
 
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Constness {
-        Const,
+        Const(tokens::Const),
         NotConst,
     }
 }
@@ -194,27 +243,18 @@
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Defaultness {
-        Default,
+        Default(tokens::Default),
         Final,
     }
 }
 
 ast_struct! {
-    /// Foreign module declaration.
-    ///
-    /// E.g. `extern { .. }` or `extern "C" { .. }`
-    pub struct ItemForeignMod {
-        pub abi: Abi,
-        pub items: Vec<ForeignItem>,
-    }
-}
-
-ast_struct! {
     pub struct ForeignItem {
         pub ident: Ident,
         pub attrs: Vec<Attribute>,
         pub node: ForeignItemKind,
         pub vis: Visibility,
+        pub semi_token: tokens::Semi,
     }
 }
 
@@ -224,11 +264,12 @@
         /// A foreign function
         pub Fn(ForeignItemFn {
             pub decl: Box<FnDecl>,
-            pub generics: Generics,
         }),
         /// A foreign static item (`static ext: u8`)
         pub Static(ForeignItemStatic {
+            pub static_token: tokens::Static,
             pub ty: Box<Ty>,
+            pub colon_token: tokens::Colon,
             pub mutbl: Mutability,
         }),
     }
@@ -251,16 +292,25 @@
 ast_enum_of_structs! {
     pub enum TraitItemKind {
         pub Const(TraitItemConst {
+            pub const_token: tokens::Const,
+            pub colon_token: tokens::Colon,
             pub ty: Ty,
             pub default: Option<Expr>,
+            pub eq_token: Option<tokens::Eq>,
+            pub semi_token: tokens::Semi,
         }),
         pub Method(TraitItemMethod {
             pub sig: MethodSig,
             pub default: Option<Block>,
+            pub semi_token: Option<tokens::Semi>,
         }),
         pub Type(TraitItemType {
-            pub bounds: Vec<TyParamBound>,
+            pub type_token: tokens::Type,
+            pub colon_token: Option<tokens::Colon>,
+            pub bounds: Delimited<TyParamBound, tokens::Add>,
+            pub eq_token: Option<tokens::Eq>,
             pub default: Option<Ty>,
+            pub semi_token: tokens::Semi,
         }),
         pub Macro(Mac),
     }
@@ -274,7 +324,7 @@
         /// `impl Trait for Type`
         Positive,
         /// `impl !Trait for Type`
-        Negative,
+        Negative(tokens::Bang),
     }
 }
 
@@ -291,6 +341,10 @@
 ast_enum_of_structs! {
     pub enum ImplItemKind {
         pub Const(ImplItemConst {
+            pub const_token: tokens::Const,
+            pub colon_token: tokens::Colon,
+            pub eq_token: tokens::Eq,
+            pub semi_token: tokens::Semi,
             pub ty: Ty,
             pub expr: Expr,
         }),
@@ -299,6 +353,9 @@
             pub block: Block,
         }),
         pub Type(ImplItemType {
+            pub type_token: tokens::Type,
+            pub eq_token: tokens::Eq,
+            pub semi_token: tokens::Semi,
             pub ty: Ty,
         }),
         pub Macro(Mac),
@@ -315,7 +372,6 @@
         pub constness: Constness,
         pub abi: Option<Abi>,
         pub decl: FnDecl,
-        pub generics: Generics,
     }
 }
 
@@ -324,9 +380,13 @@
     ///
     /// E.g. `fn foo(bar: baz)`
     pub struct FnDecl {
-        pub inputs: Vec<FnArg>,
+        pub fn_token: tokens::Fn,
+        pub paren_token: tokens::Paren,
+        pub inputs: Delimited<FnArg, tokens::Comma>,
         pub output: FunctionRetTy,
+        pub generics: Generics,
         pub variadic: bool,
+        pub dot_tokens: Option<tokens::Dot3>,
     }
 }
 
@@ -336,14 +396,18 @@
     /// E.g. `bar: usize` as in `fn foo(bar: usize)`
     pub enum FnArg {
         pub SelfRef(ArgSelfRef {
+            pub and_token: tokens::And,
+            pub self_token: tokens::Self_,
             pub lifetime: Option<Lifetime>,
             pub mutbl: Mutability,
         }),
         pub SelfValue(ArgSelf {
             pub mutbl: Mutability,
+            pub self_token: tokens::Self_,
         }),
         pub Captured(ArgCaptured {
             pub pat: Pat,
+            pub colon_token: tokens::Colon,
             pub ty: Ty,
         }),
         pub Ignored(Ty),
@@ -353,8 +417,7 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use {Block, DelimToken, FunctionRetTy, Generics, Ident, Mac, Path, TokenTree, VariantData,
-         Visibility};
+    use {Block, Generics, Ident, Mac, Path, VariantData};
     use attr::parsing::{inner_attr, outer_attr};
     use data::parsing::{struct_like_body, visibility};
     use expr::parsing::{expr, pat, within_block};
@@ -363,7 +426,7 @@
     use mac::parsing::delimited;
     use derive::{Body, DeriveInput};
     use derive::parsing::derive_input;
-    use ty::parsing::{abi, mutability, path, ty, unsafety};
+    use ty::parsing::{abi, mutability, path, ty, unsafety, fn_ret_ty};
 
     named!(pub item -> Item, alt!(
         item_extern_crate
@@ -403,17 +466,15 @@
         punct!("!") >>
         name: option!(ident) >>
         body: delimited >>
-        cond!(match body.delim {
-            DelimToken::Paren | DelimToken::Bracket => true,
-            DelimToken::Brace => false,
-        }, punct!(";")) >>
+        cond!(!body.is_braced(), punct!(";")) >>
         (Item {
-            ident: name.unwrap_or_else(|| Ident::new("")),
-            vis: Visibility::Inherited,
+            ident: name.unwrap_or_else(|| Ident::from("")),
+            vis: VisInherited {}.into(),
             attrs: attrs,
             node: ItemKind::Mac(Mac {
+                bang_token: tokens::Bang::default(),
                 path: what,
-                tts: vec![TokenTree::Delimited(body)],
+                tokens: vec![body],
             }),
         })
     ));
@@ -438,7 +499,13 @@
                 ident: name,
                 vis: vis,
                 attrs: attrs,
-                node: ItemExternCrate { original: original_name }.into(),
+                node: ItemExternCrate {
+                    as_token: original_name.as_ref().map(|_| tokens::As::default()),
+                    original: original_name,
+                    extern_token: tokens::Extern::default(),
+                    crate_token: tokens::Crate::default(),
+                    semi_token: tokens::Semi::default(),
+                }.into(),
             }
         })
     ));
@@ -453,7 +520,11 @@
             ident: "".into(),
             vis: vis,
             attrs: attrs,
-            node: ItemUse { path: Box::new(what) }.into(),
+            node: ItemUse {
+                path: Box::new(what),
+                use_token: tokens::Use::default(),
+                semi_token: tokens::Semi::default(),
+            }.into(),
         })
     ));
 
@@ -471,35 +542,53 @@
     named!(view_path_simple -> ViewPath, do_parse!(
         path: path >>
         rename: option!(preceded!(keyword!("as"), ident)) >>
-        (PathSimple { path: path, rename: rename }.into())
+        (PathSimple {
+            path: path,
+            as_token: rename.as_ref().map(|_| tokens::As::default()),
+            rename: rename,
+        }.into())
     ));
 
     named!(view_path_glob -> ViewPath, do_parse!(
         path: path >>
         punct!("::") >>
         punct!("*") >>
-        (PathGlob { path: path }.into())
+        (PathGlob {
+            path: path,
+            colon2_token: tokens::Colon2::default(),
+            star_token: tokens::Star::default(),
+        }.into())
     ));
 
     named!(view_path_list -> ViewPath, do_parse!(
         path: path >>
         punct!("::") >>
         punct!("{") >>
-        items: terminated_list!(punct!(","), path_list_item) >>
+        items: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                path_list_item) >>
         punct!("}") >>
-        (PathList { path: path, items: items }.into())
+        (PathList {
+            path: path,
+            items: items,
+            brace_token: tokens::Brace::default(),
+            colon2_token: tokens::Colon2::default(),
+        }.into())
     ));
 
     named!(view_path_list_root -> ViewPath, do_parse!(
         global: option!(punct!("::")) >>
         punct!("{") >>
-        items: terminated_list!(punct!(","), path_list_item) >>
+        items: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                path_list_item) >>
         punct!("}") >>
         (PathList {
             path: Path {
                 global: global.is_some(),
-                segments: Vec::new(),
+                segments: Delimited::new(),
+                leading_colon: None,
             },
+            colon2_token: tokens::Colon2::default(),
+            brace_token: tokens::Brace::default(),
             items: items,
         }.into())
     ));
@@ -513,6 +602,7 @@
         rename: option!(preceded!(keyword!("as"), ident)) >>
         (PathListItem {
             name: name,
+            as_token: rename.as_ref().map(|_| tokens::As::default()),
             rename: rename,
         })
     ));
@@ -536,6 +626,10 @@
                 ty: Box::new(ty),
                 mutbl: mutability,
                 expr: Box::new(value),
+                static_token: tokens::Static::default(),
+                colon_token: tokens::Colon::default(),
+                eq_token: tokens::Eq::default(),
+                semi_token: tokens::Semi::default(),
             }.into(),
         })
     ));
@@ -554,7 +648,14 @@
             ident: id,
             vis: vis,
             attrs: attrs,
-            node: ItemConst { ty: Box::new(ty), expr: Box::new(value) }.into(),
+            node: ItemConst {
+                ty: Box::new(ty),
+                expr: Box::new(value),
+                const_token: tokens::Const::default(),
+                colon_token: tokens::Colon::default(),
+                eq_token: tokens::Eq::default(),
+                semi_token: tokens::Semi::default(),
+            }.into(),
         })
     ));
 
@@ -568,9 +669,10 @@
         name: ident >>
         generics: generics >>
         punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 fn_arg) >>
         punct!(")") >>
-        ret: option!(preceded!(punct!("->"), ty)) >>
+        ret: fn_ret_ty >>
         where_clause: where_clause >>
         punct!("{") >>
         inner_attrs: many0!(inner_attr) >>
@@ -586,19 +688,23 @@
             },
             node: ItemFn {
                 decl: Box::new(FnDecl {
+                    dot_tokens: None,
+                    fn_token: tokens::Fn::default(),
+                    paren_token: tokens::Paren::default(),
                     inputs: inputs,
-                    output: ret.map(FunctionRetTy::Ty).unwrap_or(FunctionRetTy::Default),
+                    output: ret,
                     variadic: false,
+                    generics: Generics {
+                        where_clause: where_clause,
+                        .. generics
+                    },
                 }),
                 unsafety: unsafety,
                 constness: constness,
                 abi: abi,
-                generics: Generics {
-                    where_clause: where_clause,
-                    .. generics
-                },
                 block: Box::new(Block {
                     stmts: stmts,
+                    brace_token: tokens::Brace::default(),
                 }),
             }.into(),
         })
@@ -611,21 +717,33 @@
             mutability: mutability >>
             keyword!("self") >>
             not!(punct!(":")) >>
-            (ArgSelfRef { lifetime: lt, mutbl: mutability }.into())
+            (ArgSelfRef {
+                lifetime: lt,
+                mutbl: mutability,
+                and_token: tokens::And::default(),
+                self_token: tokens::Self_::default(),
+            }.into())
         )
         |
         do_parse!(
             mutability: mutability >>
             keyword!("self") >>
             not!(punct!(":")) >>
-            (ArgSelf { mutbl: mutability }.into())
+            (ArgSelf {
+                mutbl: mutability,
+                self_token: tokens::Self_::default(),
+            }.into())
         )
         |
         do_parse!(
             pat: pat >>
             punct!(":") >>
             ty: ty >>
-            (ArgCaptured { pat: pat, ty: ty }.into())
+            (ArgCaptured {
+                pat: pat,
+                ty: ty,
+                colon_token: tokens::Colon::default(),
+            }.into())
         )
         |
         ty => { FnArg::Ignored }
@@ -657,13 +775,21 @@
                     attrs.extend(inner_attrs);
                     attrs
                 },
-                node: ItemMod { items: Some(items) }.into(),
+                node: ItemMod {
+                    mod_token: tokens::Mod::default(),
+                    semi_token: None,
+                    items: Some((items, tokens::Brace::default())),
+                }.into(),
             },
             None => Item {
                 ident: id,
                 vis: vis,
                 attrs: outer_attrs,
-                node: ItemMod { items: None }.into(),
+                node: ItemMod {
+                    items: None,
+                    mod_token: tokens::Mod::default(),
+                    semi_token: Some(tokens::Semi::default()),
+                }.into(),
             },
         })
     ));
@@ -676,9 +802,10 @@
         punct!("}") >>
         (Item {
             ident: "".into(),
-            vis: Visibility::Inherited,
+            vis: VisInherited {}.into(),
             attrs: attrs,
             node: ItemForeignMod {
+                brace_token: tokens::Brace::default(),
                 abi: abi,
                 items: items,
             }.into(),
@@ -698,26 +825,35 @@
         name: ident >>
         generics: generics >>
         punct!("(") >>
-        inputs: separated_list!(punct!(","), fn_arg) >>
-        trailing_comma: option!(punct!(",")) >>
-        variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 fn_arg) >>
+        variadic: cond!(inputs.is_empty() || inputs.trailing_delim(),
+                        option!(punct!("..."))) >>
         punct!(")") >>
-        ret: option!(preceded!(punct!("->"), ty)) >>
+        ret: fn_ret_ty >>
         where_clause: where_clause >>
         punct!(";") >>
         (ForeignItem {
             ident: name,
             attrs: attrs,
+            semi_token: tokens::Semi::default(),
             node: ForeignItemFn {
                 decl: Box::new(FnDecl {
+                    fn_token: tokens::Fn::default(),
+                    paren_token: tokens::Paren::default(),
                     inputs: inputs,
-                    output: ret.map(FunctionRetTy::Ty).unwrap_or(FunctionRetTy::Default),
-                    variadic: variadic.is_some(),
+                    variadic: variadic.map(|m| m.is_some()).unwrap_or(false),
+                    dot_tokens: if variadic.map(|m| m.is_some()).unwrap_or(false) {
+                        Some(tokens::Dot3::default())
+                    } else {
+                        None
+                    },
+                    output: ret,
+                    generics: Generics {
+                        where_clause: where_clause,
+                        .. generics
+                    },
                 }),
-                generics: Generics {
-                    where_clause: where_clause,
-                    .. generics
-                },
             }.into(),
             vis: vis,
         })
@@ -735,7 +871,13 @@
         (ForeignItem {
             ident: id,
             attrs: attrs,
-            node: ForeignItemStatic { ty: Box::new(ty), mutbl: mutability }.into(),
+            semi_token: tokens::Semi::default(),
+            node: ForeignItemStatic {
+                ty: Box::new(ty),
+                mutbl: mutability,
+                static_token: tokens::Static::default(),
+                colon_token: tokens::Colon::default(),
+            }.into(),
             vis: vis,
         })
     ));
@@ -755,6 +897,9 @@
             vis: vis,
             attrs: attrs,
             node: ItemTy {
+                type_token: tokens::Type::default(),
+                eq_token: tokens::Eq::default(),
+                semi_token: tokens::Semi::default(),
                 ty: Box::new(ty),
                 generics: Generics {
                     where_clause: where_clause,
@@ -771,11 +916,21 @@
             vis: def.vis,
             attrs: def.attrs,
             node: match def.body {
-                Body::Enum(variants) => {
-                    ItemEnum { variants: variants, generics: def.generics }.into()
+                Body::Enum(data) => {
+                    ItemEnum {
+                        variants: data.variants,
+                        brace_token: data.brace_token,
+                        enum_token: data.enum_token,
+                        generics: def.generics,
+                    }.into()
                 }
-                Body::Struct(variant_data) => {
-                    ItemStruct { data: variant_data, generics: def.generics }.into()
+                Body::Struct(data) => {
+                    ItemStruct {
+                        data: data.data,
+                        struct_token: data.struct_token,
+                        semi_token: data.semi_token,
+                        generics: def.generics,
+                    }.into()
                 }
             }
         }
@@ -794,7 +949,8 @@
             vis: vis,
             attrs: attrs,
             node: ItemUnion {
-                data: VariantData::Struct(fields),
+                union_token: tokens::Union::default(),
+                data: VariantData::Struct(fields.0, fields.1),
                 generics: Generics {
                     where_clause: where_clause,
                     .. generics
@@ -810,10 +966,11 @@
         keyword!("trait") >>
         id: ident >>
         generics: generics >>
-        bounds: opt_vec!(preceded!(
-            punct!(":"),
-            separated_nonempty_list!(punct!("+"), ty_param_bound)
-        )) >>
+        colon: option!(punct!(":")) >>
+        bounds: cond!(colon.is_some(),
+            separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                     ty_param_bound)
+        ) >>
         where_clause: where_clause >>
         punct!("{") >>
         body: many0!(trait_item) >>
@@ -823,12 +980,15 @@
             vis: vis,
             attrs: attrs,
             node: ItemTrait {
+                trait_token: tokens::Trait::default(),
+                brace_token: tokens::Brace::default(),
+                colon_token: colon.map(|_| tokens::Colon::default()),
                 unsafety: unsafety,
                 generics: Generics {
                     where_clause: where_clause,
                     .. generics
                 },
-                supertraits: bounds,
+                supertraits: bounds.unwrap_or_default(),
                 items: body,
             }.into(),
         })
@@ -845,9 +1005,16 @@
         punct!("}") >>
         (Item {
             ident: "".into(),
-            vis: Visibility::Inherited,
+            vis: VisInherited {}.into(),
             attrs: attrs,
-            node: ItemDefaultImpl { unsafety: unsafety, path: path }.into(),
+            node: ItemDefaultImpl {
+                unsafety: unsafety,
+                path: path,
+                impl_token: tokens::Impl::default(),
+                for_token: tokens::For::default(),
+                dot2_token: tokens::Dot2::default(),
+                brace_token: tokens::Brace::default(),
+            }.into(),
         })
     ));
 
@@ -872,7 +1039,14 @@
         (TraitItem {
             ident: id,
             attrs: attrs,
-            node: TraitItemConst { ty: ty, default: value }.into(),
+            node: TraitItemConst {
+                ty: ty,
+                const_token: tokens::Const::default(),
+                colon_token: tokens::Colon::default(),
+                eq_token: value.as_ref().map(|_| tokens::Eq::default()),
+                default: value,
+                semi_token: tokens::Semi::default(),
+            }.into(),
         })
     ));
 
@@ -885,16 +1059,16 @@
         name: ident >>
         generics: generics >>
         punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()), fn_arg) >>
         punct!(")") >>
-        ret: option!(preceded!(punct!("->"), ty)) >>
+        ret: fn_ret_ty >>
         where_clause: where_clause >>
         body: option!(delimited!(
             punct!("{"),
             tuple!(many0!(inner_attr), within_block),
             punct!("}")
         )) >>
-        cond!(body.is_none(), punct!(";")) >>
+        semi: cond!(body.is_none(), punct!(";")) >>
         ({
             let (inner_attrs, stmts) = match body {
                 Some((inner_attrs, stmts)) => (inner_attrs, Some(stmts)),
@@ -908,21 +1082,30 @@
                     attrs
                 },
                 node: TraitItemMethod {
+                    semi_token: semi.map(|_| tokens::Semi::default()),
                     sig: MethodSig {
                         unsafety: unsafety,
                         constness: constness,
                         abi: abi,
                         decl: FnDecl {
                             inputs: inputs,
-                            output: ret.map(FunctionRetTy::Ty).unwrap_or(FunctionRetTy::Default),
+                            output: ret,
                             variadic: false,
-                        },
-                        generics: Generics {
-                            where_clause: where_clause,
-                            .. generics
+                            fn_token: tokens::Fn::default(),
+                            paren_token: tokens::Paren::default(),
+                            dot_tokens: None,
+                            generics: Generics {
+                                where_clause: where_clause,
+                                .. generics
+                            },
                         },
                     },
-                    default: stmts.map(|stmts| Block { stmts: stmts }),
+                    default: stmts.map(|stmts| {
+                        Block {
+                            stmts: stmts,
+                            brace_token: tokens::Brace::default(),
+                        }
+                    }),
                 }.into(),
             }
         })
@@ -932,16 +1115,24 @@
         attrs: many0!(outer_attr) >>
         keyword!("type") >>
         id: ident >>
-        bounds: opt_vec!(preceded!(
-            punct!(":"),
-            separated_nonempty_list!(punct!("+"), ty_param_bound)
-        )) >>
+        colon: option!(punct!(":")) >>
+        bounds: cond!(colon.is_some(),
+            separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                     ty_param_bound)
+        ) >>
         default: option!(preceded!(punct!("="), ty)) >>
         punct!(";") >>
         (TraitItem {
             ident: id,
             attrs: attrs,
-            node: TraitItemType { bounds: bounds, default: default }.into(),
+            node: TraitItemType {
+                type_token: tokens::Type::default(),
+                colon_token: colon.map(|_| tokens::Colon::default()),
+                bounds: bounds.unwrap_or_default(),
+                eq_token: default.as_ref().map(|_| tokens::Eq::default()),
+                semi_token: tokens::Semi::default(),
+                default: default,
+            }.into(),
         })
     ));
 
@@ -950,16 +1141,14 @@
         what: path >>
         punct!("!") >>
         body: delimited >>
-        cond!(match body.delim {
-            DelimToken::Paren | DelimToken::Bracket => true,
-            DelimToken::Brace => false,
-        }, punct!(";")) >>
+        cond!(!body.is_braced(), punct!(";")) >>
         (TraitItem {
-            ident: Ident::new(""),
+            ident: "".into(),
             attrs: attrs,
             node: TraitItemKind::Macro(Mac {
                 path: what,
-                tts: vec![TokenTree::Delimited(body)],
+                bang_token: tokens::Bang::default(),
+                tokens: vec![body],
             }),
         })
     ));
@@ -986,9 +1175,12 @@
         punct!("}") >>
         (Item {
             ident: "".into(),
-            vis: Visibility::Inherited,
+            vis: VisInherited {}.into(),
             attrs: attrs,
             node: ItemImpl {
+                impl_token: tokens::Impl::default(),
+                brace_token: tokens::Brace::default(),
+                for_token: polarity_path.1.as_ref().map(|_| tokens::For::default()),
                 unsafety: unsafety,
                 polarity: polarity_path.0,
                 generics: Generics {
@@ -1028,7 +1220,14 @@
             vis: vis,
             defaultness: defaultness,
             attrs: attrs,
-            node: ImplItemConst { ty: ty, expr: value}.into(),
+            node: ImplItemConst {
+                ty: ty,
+                expr: value,
+                const_token: tokens::Const::default(),
+                colon_token: tokens::Colon::default(),
+                eq_token: tokens::Eq::default(),
+                semi_token: tokens::Semi::default(),
+            }.into(),
         })
     ));
 
@@ -1043,9 +1242,10 @@
         name: ident >>
         generics: generics >>
         punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 fn_arg) >>
         punct!(")") >>
-        ret: option!(preceded!(punct!("->"), ty)) >>
+        ret: fn_ret_ty >>
         where_clause: where_clause >>
         punct!("{") >>
         inner_attrs: many0!(inner_attr) >>
@@ -1066,16 +1266,20 @@
                     constness: constness,
                     abi: abi,
                     decl: FnDecl {
+                        fn_token: tokens::Fn::default(),
+                        paren_token: tokens::Paren::default(),
                         inputs: inputs,
-                        output: ret.map(FunctionRetTy::Ty).unwrap_or(FunctionRetTy::Default),
+                        output: ret,
                         variadic: false,
-                    },
-                    generics: Generics {
-                        where_clause: where_clause,
-                        .. generics
+                        generics: Generics {
+                            where_clause: where_clause,
+                            .. generics
+                        },
+                        dot_tokens: None,
                     },
                 },
                 block: Block {
+                    brace_token: tokens::Brace::default(),
                     stmts: stmts,
                 },
             }.into(),
@@ -1096,7 +1300,12 @@
             vis: vis,
             defaultness: defaultness,
             attrs: attrs,
-            node: ImplItemType { ty: ty }.into(),
+            node: ImplItemType {
+                type_token: tokens::Type::default(),
+                eq_token: tokens::Eq::default(),
+                semi_token: tokens::Semi::default(),
+                ty: ty,
+            }.into(),
         })
     ));
 
@@ -1105,36 +1314,34 @@
         what: path >>
         punct!("!") >>
         body: delimited >>
-        cond!(match body.delim {
-            DelimToken::Paren | DelimToken::Bracket => true,
-            DelimToken::Brace => false,
-        }, punct!(";")) >>
+        cond!(!body.is_braced(), punct!(";")) >>
         (ImplItem {
-            ident: Ident::new(""),
-            vis: Visibility::Inherited,
+            ident: "".into(),
+            vis: VisInherited {}.into(),
             defaultness: Defaultness::Final,
             attrs: attrs,
             node: ImplItemKind::Macro(Mac {
                 path: what,
-                tts: vec![TokenTree::Delimited(body)],
+                bang_token: tokens::Bang::default(),
+                tokens: vec![body],
             }),
         })
     ));
 
     named!(impl_polarity -> ImplPolarity, alt!(
-        punct!("!") => { |_| ImplPolarity::Negative }
+        punct!("!") => { |_| ImplPolarity::Negative(tokens::Bang::default()) }
         |
         epsilon!() => { |_| ImplPolarity::Positive }
     ));
 
     named!(constness -> Constness, alt!(
-        keyword!("const") => { |_| Constness::Const }
+        keyword!("const") => { |_| Constness::Const(tokens::Const::default()) }
         |
         epsilon!() => { |_| Constness::NotConst }
     ));
 
     named!(defaultness -> Defaultness, alt!(
-        keyword!("default") => { |_| Defaultness::Default }
+        keyword!("default") => { |_| Defaultness::Default(tokens::Default::default()) }
         |
         epsilon!() => { |_| Defaultness::Final }
     ));
@@ -1143,7 +1350,6 @@
 #[cfg(feature = "printing")]
 mod printing {
     use super::*;
-    use {Delimited, DelimToken, FunctionRetTy, TokenTree};
     use attr::FilterAttrs;
     use data::VariantData;
     use quote::{Tokens, ToTokens};
@@ -1154,132 +1360,113 @@
             match self.node {
                 ItemKind::ExternCrate(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("extern");
-                    tokens.append("crate");
-                    if let Some(ref original) = item.original {
-                        original.to_tokens(tokens);
-                        tokens.append("as");
-                    }
+                    item.extern_token.to_tokens(tokens);
+                    item.crate_token.to_tokens(tokens);
+                    item.original.to_tokens(tokens);
+                    item.as_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Use(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("use");
+                    item.use_token.to_tokens(tokens);
                     item.path.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Static(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("static");
+                    item.static_token.to_tokens(tokens);
                     item.mutbl.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(":");
+                    item.colon_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append("=");
+                    item.eq_token.to_tokens(tokens);
                     item.expr.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Const(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("const");
+                    item.const_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(":");
+                    item.colon_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append("=");
+                    item.eq_token.to_tokens(tokens);
                     item.expr.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Fn(ref item) => {
                     self.vis.to_tokens(tokens);
                     item.constness.to_tokens(tokens);
                     item.unsafety.to_tokens(tokens);
                     item.abi.to_tokens(tokens);
-                    tokens.append("fn");
-                    self.ident.to_tokens(tokens);
-                    item.generics.to_tokens(tokens);
-                    tokens.append("(");
-                    tokens.append_separated(&item.decl.inputs, ",");
-                    tokens.append(")");
-                    if let FunctionRetTy::Ty(ref ty) = item.decl.output {
-                        tokens.append("->");
-                        ty.to_tokens(tokens);
-                    }
-                    item.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_all(self.attrs.inner());
-                    tokens.append_all(&item.block.stmts);
-                    tokens.append("}");
+                    NamedDecl(&item.decl, &self.ident).to_tokens(tokens);
+                    item.block.brace_token.surround(tokens, |tokens| {
+                        tokens.append_all(self.attrs.inner());
+                        tokens.append_all(&item.block.stmts);
+                    });
                 }
                 ItemKind::Mod(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("mod");
+                    item.mod_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    match item.items {
-                        Some(ref items) => {
-                            tokens.append("{");
+                    if let Some((ref items, ref brace)) = item.items {
+                        brace.surround(tokens, |tokens| {
                             tokens.append_all(self.attrs.inner());
                             tokens.append_all(items);
-                            tokens.append("}");
-                        }
-                        None => tokens.append(";"),
+                        });
                     }
+                    item.semi_token.to_tokens(tokens);
                 }
-                ItemKind::ForeignMod(ref foreign_mod) => {
+                ItemKind::ForeignMod(ref item) => {
                     self.vis.to_tokens(tokens);
-                    foreign_mod.abi.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_all(&foreign_mod.items);
-                    tokens.append("}");
+                    item.abi.to_tokens(tokens);
+                    item.brace_token.surround(tokens, |tokens| {
+                        tokens.append_all(&item.items);
+                    });
                 }
                 ItemKind::Ty(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("type");
+                    item.type_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
                     item.generics.where_clause.to_tokens(tokens);
-                    tokens.append("=");
+                    item.eq_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Enum(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("enum");
+                    item.enum_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
                     item.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    for variant in &item.variants {
-                        variant.to_tokens(tokens);
-                        tokens.append(",");
-                    }
-                    tokens.append("}");
+                    item.brace_token.surround(tokens, |tokens| {
+                        item.variants.to_tokens(tokens);
+                    });
                 }
                 ItemKind::Struct(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("struct");
+                    item.struct_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
                     match item.data {
-                        VariantData::Struct(_) => {
+                        VariantData::Struct(..) => {
                             item.generics.where_clause.to_tokens(tokens);
                             item.data.to_tokens(tokens);
-                            // no semicolon
                         }
-                        VariantData::Tuple(_) => {
+                        VariantData::Tuple(..) => {
                             item.data.to_tokens(tokens);
                             item.generics.where_clause.to_tokens(tokens);
-                            tokens.append(";");
                         }
                         VariantData::Unit => {
                             item.generics.where_clause.to_tokens(tokens);
-                            tokens.append(";");
                         }
                     }
+                    item.semi_token.to_tokens(tokens);
                 }
                 ItemKind::Union(ref item) => {
                     self.vis.to_tokens(tokens);
-                    tokens.append("union");
+                    item.union_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
                     item.generics.where_clause.to_tokens(tokens);
@@ -1288,54 +1475,44 @@
                 ItemKind::Trait(ref item) => {
                     self.vis.to_tokens(tokens);
                     item.unsafety.to_tokens(tokens);
-                    tokens.append("trait");
+                    item.trait_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
-                    if !item.supertraits.is_empty() {
-                        tokens.append(":");
-                        tokens.append_separated(&item.supertraits, "+");
-                    }
+                    item.colon_token.to_tokens(tokens);
+                    item.supertraits.to_tokens(tokens);
                     item.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_all(&item.items);
-                    tokens.append("}");
+                    item.brace_token.surround(tokens, |tokens| {
+                        tokens.append_all(&item.items);
+                    });
                 }
                 ItemKind::DefaultImpl(ref item) => {
                     item.unsafety.to_tokens(tokens);
-                    tokens.append("impl");
+                    item.impl_token.to_tokens(tokens);
                     item.path.to_tokens(tokens);
-                    tokens.append("for");
-                    tokens.append("..");
-                    tokens.append("{");
-                    tokens.append("}");
+                    item.for_token.to_tokens(tokens);
+                    item.dot2_token.to_tokens(tokens);
+                    item.brace_token.surround(tokens, |_tokens| {});
                 }
                 ItemKind::Impl(ref item) => {
                     item.unsafety.to_tokens(tokens);
-                    tokens.append("impl");
+                    item.impl_token.to_tokens(tokens);
                     item.generics.to_tokens(tokens);
-                    if let Some(ref path) = item.trait_ {
-                        item.polarity.to_tokens(tokens);
-                        path.to_tokens(tokens);
-                        tokens.append("for");
-                    }
+                    item.polarity.to_tokens(tokens);
+                    item.trait_.to_tokens(tokens);
+                    item.for_token.to_tokens(tokens);
                     item.self_ty.to_tokens(tokens);
                     item.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_all(&item.items);
-                    tokens.append("}");
+                    item.brace_token.surround(tokens, |tokens| {
+                        tokens.append_all(&item.items);
+                    });
                 }
                 ItemKind::Mac(ref mac) => {
                     mac.path.to_tokens(tokens);
-                    tokens.append("!");
+                    mac.bang_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    for tt in &mac.tts {
-                        tt.to_tokens(tokens);
-                    }
-                    match mac.tts.last() {
-                        Some(&TokenTree::Delimited(Delimited { delim: DelimToken::Brace, .. })) => {
-                            // no semicolon
-                        }
-                        _ => tokens.append(";"),
+                    tokens.append_all(&mac.tokens);
+                    if !mac.is_braced() {
+                        tokens::Semi::default().to_tokens(tokens);
                     }
                 }
             }
@@ -1345,40 +1522,34 @@
     impl ToTokens for PathSimple {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
-            if let Some(ref rename) = self.rename {
-                tokens.append("as");
-                rename.to_tokens(tokens);
-            }
+            self.as_token.to_tokens(tokens);
+            self.rename.to_tokens(tokens);
         }
     }
 
     impl ToTokens for PathGlob {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
-            tokens.append("::");
-            tokens.append("*");
+            self.colon2_token.to_tokens(tokens);
+            self.star_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for PathList {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
-            if self.path.global || !self.path.segments.is_empty() {
-                tokens.append("::");
-            }
-            tokens.append("{");
-            tokens.append_separated(&self.items, ",");
-            tokens.append("}");
+            self.colon2_token.to_tokens(tokens);
+            self.brace_token.surround(tokens, |tokens| {
+                self.items.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for PathListItem {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.name.to_tokens(tokens);
-            if let Some(ref rename) = self.rename {
-                tokens.append("as");
-                rename.to_tokens(tokens);
-            }
+            self.as_token.to_tokens(tokens);
+            self.rename.to_tokens(tokens);
         }
     }
 
@@ -1387,61 +1558,41 @@
             tokens.append_all(self.attrs.outer());
             match self.node {
                 TraitItemKind::Const(ref item) => {
-                    tokens.append("const");
+                    item.const_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(":");
+                    item.colon_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    if let Some(ref expr) = item.default {
-                        tokens.append("=");
-                        expr.to_tokens(tokens);
-                    }
-                    tokens.append(";");
+                    item.eq_token.to_tokens(tokens);
+                    item.default.to_tokens(tokens);
+                    item.semi_token.to_tokens(tokens);
                 }
                 TraitItemKind::Method(ref item) => {
-                    item.sig.constness.to_tokens(tokens);
-                    item.sig.unsafety.to_tokens(tokens);
-                    item.sig.abi.to_tokens(tokens);
-                    tokens.append("fn");
-                    self.ident.to_tokens(tokens);
-                    item.sig.generics.to_tokens(tokens);
-                    tokens.append("(");
-                    tokens.append_separated(&item.sig.decl.inputs, ",");
-                    tokens.append(")");
-                    if let FunctionRetTy::Ty(ref ty) = item.sig.decl.output {
-                        tokens.append("->");
-                        ty.to_tokens(tokens);
-                    }
-                    item.sig.generics.where_clause.to_tokens(tokens);
+                    NamedMethod(&item.sig, &self.ident).to_tokens(tokens);
                     match item.default {
                         Some(ref block) => {
-                            tokens.append("{");
-                            tokens.append_all(self.attrs.inner());
-                            tokens.append_all(&block.stmts);
-                            tokens.append("}");
+                            block.brace_token.surround(tokens, |tokens| {
+                                tokens.append_all(self.attrs.inner());
+                                tokens.append_all(&block.stmts);
+                            });
                         }
-                        None => tokens.append(";"),
+                        None => {
+                            item.semi_token.to_tokens(tokens);
+                        }
                     }
                 }
                 TraitItemKind::Type(ref item) => {
-                    tokens.append("type");
+                    item.type_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    if !item.bounds.is_empty() {
-                        tokens.append(":");
-                        tokens.append_separated(&item.bounds, "+");
-                    }
-                    if let Some(ref default) = item.default {
-                        tokens.append("=");
-                        default.to_tokens(tokens);
-                    }
-                    tokens.append(";");
+                    item.colon_token.to_tokens(tokens);
+                    item.bounds.to_tokens(tokens);
+                    item.eq_token.to_tokens(tokens);
+                    item.default.to_tokens(tokens);
+                    item.semi_token.to_tokens(tokens);
                 }
                 TraitItemKind::Macro(ref mac) => {
                     mac.to_tokens(tokens);
-                    match mac.tts.last() {
-                        Some(&TokenTree::Delimited(Delimited { delim: DelimToken::Brace, .. })) => {
-                            // no semicolon
-                        }
-                        _ => tokens.append(";"),
+                    if !mac.is_braced() {
+                        tokens::Semi::default().to_tokens(tokens);
                     }
                 }
             }
@@ -1451,56 +1602,36 @@
     impl ToTokens for ImplItem {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
+            self.vis.to_tokens(tokens);
+            self.defaultness.to_tokens(tokens);
             match self.node {
                 ImplItemKind::Const(ref item) => {
-                    self.vis.to_tokens(tokens);
-                    self.defaultness.to_tokens(tokens);
-                    tokens.append("const");
+                    item.const_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(":");
+                    item.colon_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append("=");
+                    item.eq_token.to_tokens(tokens);
                     item.expr.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ImplItemKind::Method(ref item) => {
-                    self.vis.to_tokens(tokens);
-                    self.defaultness.to_tokens(tokens);
-                    item.sig.constness.to_tokens(tokens);
-                    item.sig.unsafety.to_tokens(tokens);
-                    item.sig.abi.to_tokens(tokens);
-                    tokens.append("fn");
-                    self.ident.to_tokens(tokens);
-                    item.sig.generics.to_tokens(tokens);
-                    tokens.append("(");
-                    tokens.append_separated(&item.sig.decl.inputs, ",");
-                    tokens.append(")");
-                    if let FunctionRetTy::Ty(ref ty) = item.sig.decl.output {
-                        tokens.append("->");
-                        ty.to_tokens(tokens);
-                    }
-                    item.sig.generics.where_clause.to_tokens(tokens);
-                    tokens.append("{");
-                    tokens.append_all(self.attrs.inner());
-                    tokens.append_all(&item.block.stmts);
-                    tokens.append("}");
+                    NamedMethod(&item.sig, &self.ident).to_tokens(tokens);
+                    item.block.brace_token.surround(tokens, |tokens| {
+                        tokens.append_all(self.attrs.inner());
+                        tokens.append_all(&item.block.stmts);
+                    });
                 }
                 ImplItemKind::Type(ref item) => {
-                    self.vis.to_tokens(tokens);
-                    self.defaultness.to_tokens(tokens);
-                    tokens.append("type");
+                    item.type_token.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append("=");
+                    item.eq_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append(";");
+                    item.semi_token.to_tokens(tokens);
                 }
                 ImplItemKind::Macro(ref mac) => {
                     mac.to_tokens(tokens);
-                    match mac.tts.last() {
-                        Some(&TokenTree::Delimited(Delimited { delim: DelimToken::Brace, .. })) => {
-                            // no semicolon
-                        }
-                        _ => tokens.append(";"),
+                    if !mac.is_braced() {
+                        tokens::Semi::default().to_tokens(tokens);
                     }
                 }
             }
@@ -1510,61 +1641,70 @@
     impl ToTokens for ForeignItem {
         fn to_tokens(&self, tokens: &mut Tokens) {
             tokens.append_all(self.attrs.outer());
+            self.vis.to_tokens(tokens);
             match self.node {
                 ForeignItemKind::Fn(ref item) => {
-                    self.vis.to_tokens(tokens);
-                    tokens.append("fn");
-                    self.ident.to_tokens(tokens);
-                    item.generics.to_tokens(tokens);
-                    tokens.append("(");
-                    tokens.append_separated(&item.decl.inputs, ",");
-                    if item.decl.variadic {
-                        if !item.decl.inputs.is_empty() {
-                            tokens.append(",");
-                        }
-                        tokens.append("...");
-                    }
-                    tokens.append(")");
-                    if let FunctionRetTy::Ty(ref ty) = item.decl.output {
-                        tokens.append("->");
-                        ty.to_tokens(tokens);
-                    }
-                    item.generics.where_clause.to_tokens(tokens);
-                    tokens.append(";");
+                    NamedDecl(&item.decl, &self.ident).to_tokens(tokens)
                 }
                 ForeignItemKind::Static(ref item) => {
-                    self.vis.to_tokens(tokens);
-                    tokens.append("static");
+                    item.static_token.to_tokens(tokens);
                     item.mutbl.to_tokens(tokens);
                     self.ident.to_tokens(tokens);
-                    tokens.append(":");
+                    item.colon_token.to_tokens(tokens);
                     item.ty.to_tokens(tokens);
-                    tokens.append(";");
                 }
             }
+            self.semi_token.to_tokens(tokens);
+        }
+    }
+
+    struct NamedMethod<'a>(&'a MethodSig, &'a Ident);
+
+    impl<'a> ToTokens for NamedMethod<'a> {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.0.constness.to_tokens(tokens);
+            self.0.unsafety.to_tokens(tokens);
+            self.0.abi.to_tokens(tokens);
+            NamedDecl(&self.0.decl, self.1).to_tokens(tokens);
+        }
+    }
+
+    struct NamedDecl<'a>(&'a FnDecl, &'a Ident);
+
+    impl<'a> ToTokens for NamedDecl<'a> {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            self.0.fn_token.to_tokens(tokens);
+            self.1.to_tokens(tokens);
+            self.0.generics.to_tokens(tokens);
+            self.0.paren_token.surround(tokens, |tokens| {
+                self.0.inputs.to_tokens(tokens);
+                self.0.dot_tokens.to_tokens(tokens);
+            });
+            self.0.output.to_tokens(tokens);
+            self.0.generics.where_clause.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ArgSelfRef {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("&");
+            self.and_token.to_tokens(tokens);
             self.lifetime.to_tokens(tokens);
             self.mutbl.to_tokens(tokens);
-            tokens.append("self");
+            self.self_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ArgSelf {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.mutbl.to_tokens(tokens);
-            tokens.append("self");
+            self.self_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ArgCaptured {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.pat.to_tokens(tokens);
-            tokens.append(":");
+            self.colon_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
@@ -1572,7 +1712,7 @@
     impl ToTokens for Constness {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                Constness::Const => tokens.append("const"),
+                Constness::Const(ref t) => t.to_tokens(tokens),
                 Constness::NotConst => {
                     // nothing
                 }
@@ -1583,7 +1723,7 @@
     impl ToTokens for Defaultness {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                Defaultness::Default => tokens.append("default"),
+                Defaultness::Default(ref t) => t.to_tokens(tokens),
                 Defaultness::Final => {
                     // nothing
                 }
@@ -1594,7 +1734,7 @@
     impl ToTokens for ImplPolarity {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                ImplPolarity::Negative => tokens.append("!"),
+                ImplPolarity::Negative(ref t) => t.to_tokens(tokens),
                 ImplPolarity::Positive => {
                     // nothing
                 }
diff --git a/src/krate.rs b/src/krate.rs
index 113e142..1d83d9b 100644
--- a/src/krate.rs
+++ b/src/krate.rs
@@ -44,15 +44,12 @@
 
     impl ToTokens for Crate {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref shebang) = self.shebang {
-                tokens.append(&format!("{}\n", shebang));
-            }
-            for attr in self.attrs.inner() {
-                attr.to_tokens(tokens);
-            }
-            for item in &self.items {
-                item.to_tokens(tokens);
-            }
+            // TODO: how to handle shebang?
+            // if let Some(ref shebang) = self.shebang {
+            //     tokens.append(&format!("{}\n", shebang));
+            // }
+            tokens.append_all(self.attrs.inner());
+            tokens.append_all(&self.items);
         }
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index f30683f..b422c6c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,14 +2,15 @@
 
 #![cfg_attr(feature = "cargo-clippy", allow(large_enum_variant))]
 
+extern crate proc_macro2;
+
 #[cfg(feature = "printing")]
 extern crate quote;
 
 #[cfg(feature = "parsing")]
 extern crate unicode_xid;
 
-#[cfg(feature = "parsing")]
-#[macro_use]
+#[cfg_attr(feature = "parsing", macro_use)]
 extern crate synom;
 
 #[cfg(feature = "aster")]
@@ -27,7 +28,8 @@
                    ConstIndex, ConstParen};
 
 mod data;
-pub use data::{Field, Variant, VariantData, Visibility};
+pub use data::{Field, Variant, VariantData, Visibility, VisRestricted, VisCrate,
+               VisPublic, VisInherited};
 
 #[cfg(feature = "parsing")]
 mod escape;
@@ -42,12 +44,14 @@
                ExprForLoop, ExprLoop, ExprMatch, ExprClosure, ExprBlock,
                ExprAssign, ExprAssignOp, ExprField, ExprTupField, ExprIndex,
                ExprRange, ExprPath, ExprAddrOf, ExprBreak, ExprContinue,
-               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch};
+               ExprRet, ExprStruct, ExprRepeat, ExprParen, ExprTry, ExprCatch,
+               PatIdent, PatWild, PatStruct, PatTuple, PatTupleStruct, PatPath,
+               PatBox, PatRef, PatLit, PatRange, PatSlice};
 
 mod generics;
 pub use generics::{Generics, Lifetime, LifetimeDef, TraitBoundModifier, TyParam, TyParamBound,
                    WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate,
-                   WhereRegionPredicate};
+                   WhereRegionPredicate, BoundLifetimes};
 #[cfg(feature = "printing")]
 pub use generics::{ImplGenerics, Turbofish, TyGenerics};
 
@@ -73,15 +77,13 @@
 pub use krate::Crate;
 
 mod lit;
-pub use lit::{FloatTy, IntTy, Lit, StrStyle};
-#[cfg(feature = "parsing")]
-pub use lit::{ByteStrLit, FloatLit, IntLit, StrLit};
+pub use lit::{Lit, LitKind};
 
 mod mac;
-pub use mac::{BinOpToken, DelimToken, Delimited, Mac, Token, TokenTree};
+pub use mac::{Mac, TokenTree};
 
 mod derive;
-pub use derive::{Body, DeriveInput};
+pub use derive::{Body, DeriveInput, BodyEnum, BodyStruct};
 // Deprecated. Use `DeriveInput` instead.
 #[doc(hidden)]
 pub type MacroInput = DeriveInput;
@@ -95,6 +97,14 @@
              PolyTraitRef, QSelf, Ty, TypeBinding, Unsafety, TySlice, TyArray,
              TyPtr, TyRptr, TyBareFn, TyNever, TyTup, TyPath, TyTraitObject,
              TyImplTrait, TyParen, TyInfer};
+#[cfg(feature = "printing")]
+pub use ty::PathTokens;
+
+mod span;
+pub use span::Span;
+
+pub mod tokens;
+pub use synom::delimited;
 
 #[cfg(feature = "visit")]
 pub mod visit;
diff --git a/src/lit.rs b/src/lit.rs
index 72a2f43..9c9f274 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -1,170 +1,100 @@
-ast_enum! {
-    /// Literal kind.
-    ///
-    /// E.g. `"foo"`, `42`, `12.34` or `bool`
-    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
-    pub enum Lit {
-        /// A string literal (`"foo"`)
-        Str(String, StrStyle),
-        /// A byte string (`b"foo"`)
-        ByteStr(Vec<u8>, StrStyle),
-        /// A byte char (`b'f'`)
-        Byte(u8),
-        /// A character literal (`'a'`)
-        Char(char),
-        /// An integer literal (`1`)
-        Int(u64, IntTy),
-        /// A float literal (`1f64` or `1E10f64` or `1.0E10`)
-        Float(String, FloatTy),
-        /// A boolean literal
-        Bool(bool),
+use std::fmt;
+use std::hash::{Hash, Hasher};
+
+use proc_macro2::{self, Literal, TokenKind};
+
+use {Span, TokenTree};
+
+#[derive(Clone)]
+pub struct Lit {
+    pub value: LitKind,
+    pub span: Span,
+}
+
+#[derive(Clone)]
+pub enum LitKind {
+    Bool(bool),
+    Other(Literal),
+}
+
+impl Lit {
+    pub fn into_token_tree(self) -> TokenTree {
+        let kind = match self.value {
+            LitKind::Bool(true) => TokenKind::Word("true".into()),
+            LitKind::Bool(false) => TokenKind::Word("false".into()),
+            LitKind::Other(l) => TokenKind::Literal(l),
+        };
+        TokenTree(proc_macro2::TokenTree {
+            span: self.span.0,
+            kind: kind,
+        })
     }
 }
 
-ast_enum! {
-    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
-    pub enum StrStyle {
-        /// A regular string, like `"foo"`
-        Cooked,
-        /// A raw string, like `r##"foo"##`
-        ///
-        /// The uint is the number of `#` symbols used
-        Raw(usize),
+impl fmt::Display for Lit {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.value, f)
     }
 }
 
-impl From<String> for Lit {
-    fn from(input: String) -> Lit {
-        Lit::Str(input, StrStyle::Cooked)
+impl fmt::Debug for Lit {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.value, f)
     }
 }
 
-impl<'a> From<&'a str> for Lit {
-    fn from(input: &str) -> Lit {
-        Lit::Str(input.into(), StrStyle::Cooked)
+impl PartialEq for Lit {
+    fn eq(&self, other: &Lit) -> bool {
+        self.value == other.value
     }
 }
 
-impl From<Vec<u8>> for Lit {
-    fn from(input: Vec<u8>) -> Lit {
-        Lit::ByteStr(input, StrStyle::Cooked)
+impl Eq for Lit {}
+
+impl Hash for Lit {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        self.value.hash(hasher)
     }
 }
 
-impl<'a> From<&'a [u8]> for Lit {
-    fn from(input: &[u8]) -> Lit {
-        Lit::ByteStr(input.into(), StrStyle::Cooked)
+impl fmt::Display for LitKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LitKind::Bool(b) => b.fmt(f),
+            LitKind::Other(ref l) => l.fmt(f),
+        }
     }
 }
 
-impl From<char> for Lit {
-    fn from(input: char) -> Lit {
-        Lit::Char(input)
+impl fmt::Debug for LitKind {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            LitKind::Bool(b) => b.fmt(f),
+            LitKind::Other(ref l) => fmt::Display::fmt(l, f),
+        }
     }
 }
 
-impl From<bool> for Lit {
-    fn from(input: bool) -> Lit {
-        Lit::Bool(input)
-    }
-}
-
-ast_enum! {
-    #[derive(Copy)]
-    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
-    pub enum IntTy {
-        Isize,
-        I8,
-        I16,
-        I32,
-        I64,
-        Usize,
-        U8,
-        U16,
-        U32,
-        U64,
-        Unsuffixed,
-    }
-}
-
-ast_enum! {
-    #[derive(Copy)]
-    #[cfg_attr(not(feature = "clone-impls"), derive(Clone))]
-    pub enum FloatTy {
-        F32,
-        F64,
-        Unsuffixed,
-    }
-}
-
-macro_rules! impl_from_for_lit {
-    (Int, [$($rust_type:ty => $syn_type:expr),+]) => {
-        $(
-            impl From<$rust_type> for Lit {
-                fn from(input: $rust_type) -> Lit {
-                    Lit::Int(input as u64, $syn_type)
-                }
+impl PartialEq for LitKind {
+    fn eq(&self, other: &LitKind) -> bool {
+        match (self, other) {
+            (&LitKind::Bool(b1), &LitKind::Bool(b2)) => b1 == b2,
+            (&LitKind::Other(ref l1), &LitKind::Other(ref l2)) => {
+                l1.to_string() == l2.to_string()
             }
-        )+
-    };
-    (Float, [$($rust_type:ty => $syn_type:expr),+]) => {
-        $(
-            impl From<$rust_type> for Lit {
-                fn from(input: $rust_type) -> Lit {
-                    Lit::Float(format!("{}", input), $syn_type)
-                }
-            }
-        )+
-    };
-}
-
-impl_from_for_lit! {Int, [
-    isize => IntTy::Isize,
-    i8 => IntTy::I8,
-    i16 => IntTy::I16,
-    i32 => IntTy::I32,
-    i64 => IntTy::I64,
-    usize => IntTy::Usize,
-    u8 => IntTy::U8,
-    u16 => IntTy::U16,
-    u32 => IntTy::U32,
-    u64 => IntTy::U64
-]}
-
-impl_from_for_lit! {Float, [
-    f32 => FloatTy::F32,
-    f64 => FloatTy::F64
-]}
-
-#[cfg(feature = "parsing")]
-ast_struct! {
-    pub struct StrLit {
-        pub value: String,
-        pub style: StrStyle,
+            _ => false,
+        }
     }
 }
 
-#[cfg(feature = "parsing")]
-ast_struct! {
-    pub struct ByteStrLit {
-        pub value: Vec<u8>,
-        pub style: StrStyle,
-    }
-}
+impl Eq for LitKind {}
 
-#[cfg(feature = "parsing")]
-ast_struct! {
-    pub struct IntLit {
-        pub value: u64,
-        pub suffix: IntTy,
-    }
-}
-
-#[cfg(feature = "parsing")]
-ast_struct! {
-    pub struct FloatLit {
-        pub value: String,
-        pub suffix: FloatTy,
+impl Hash for LitKind {
+    fn hash<H: Hasher>(&self, hasher: &mut H) {
+        match *self {
+            LitKind::Bool(b) => (0u8, b).hash(hasher),
+            LitKind::Other(ref l) => (1u8, l.to_string()).hash(hasher),
+        }
     }
 }
 
@@ -172,33 +102,41 @@
 pub mod parsing {
     use super::*;
     use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
-    use synom::space::skip_whitespace;
+    use proc_macro2::Literal;
     use synom::IResult;
+    use synom::space::skip_whitespace;
     use unicode_xid::UnicodeXID;
 
+    fn l<T: Into<Literal>>(t: T) -> Lit {
+        Lit {
+            value: LitKind::Other(t.into()),
+            span: Default::default(),
+        }
+    }
+
     named!(pub lit -> Lit, alt!(
-        string => { |StrLit { value, style }| Lit::Str(value, style) }
+        string
         |
-        byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
+        byte_string
         |
-        byte => { |b| Lit::Byte(b) }
+        byte
         |
-        character => { |ch| Lit::Char(ch) }
+        character
         |
-        float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
+        float
         |
-        int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
+        int
         |
-        boolean => { |value| Lit::Bool(value) }
+        boolean
     ));
 
-    named!(pub string -> StrLit, alt!(
-        quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
+    named!(pub string -> Lit, alt!(
+        quoted_string => { |s: String| l(&s[..]) }
         |
         preceded!(
             punct!("r"),
             raw_string
-        ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
+        ) => { |(s, n): (String, _)| l(Literal::raw_string(&s[..], n)) }
     ));
 
     named!(pub quoted_string -> String, delimited!(
@@ -207,78 +145,84 @@
         tag!("\"")
     ));
 
-    named!(pub byte_string -> ByteStrLit, alt!(
+    named!(pub byte_string -> Lit, alt!(
         delimited!(
             punct!("b\""),
             cooked_byte_string,
             tag!("\"")
-        ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
+        ) => { |vec: Vec<u8>| l(Literal::byte_string(&vec)) }
         |
         preceded!(
             punct!("br"),
             raw_string
-        ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
+        ) => { |(s, n): (String, _)| l(Literal::raw_byte_string(&s, n)) }
     ));
 
-    named!(pub byte -> u8, do_parse!(
+    named!(pub byte -> Lit, do_parse!(
         punct!("b") >>
         tag!("'") >>
         b: cooked_byte >>
         tag!("'") >>
-        (b)
+        (l(Literal::byte_char(b)))
     ));
 
-    named!(pub character -> char, do_parse!(
+    named!(pub character -> Lit, do_parse!(
         punct!("'") >>
         ch: cooked_char >>
         tag!("'") >>
-        (ch)
+        (l(ch))
     ));
 
-    named!(pub float -> FloatLit, do_parse!(
+    named!(pub float -> Lit, do_parse!(
         value: float_string >>
         suffix: alt!(
-            tag!("f32") => { |_| FloatTy::F32 }
+            tag!("f32")
             |
-            tag!("f64") => { |_| FloatTy::F64 }
+            tag!("f64")
             |
-            epsilon!() => { |_| FloatTy::Unsuffixed }
+            epsilon!() => { |_| "" }
         ) >>
-        (FloatLit { value: value, suffix: suffix })
+        (l(Literal::float(&format!("{}{}", value, suffix))))
     ));
 
-    named!(pub int -> IntLit, do_parse!(
+    named!(pub int -> Lit, do_parse!(
         value: digits >>
         suffix: alt!(
-            tag!("isize") => { |_| IntTy::Isize }
+            tag!("isize")
             |
-            tag!("i8") => { |_| IntTy::I8 }
+            tag!("i8")
             |
-            tag!("i16") => { |_| IntTy::I16 }
+            tag!("i16")
             |
-            tag!("i32") => { |_| IntTy::I32 }
+            tag!("i32")
             |
-            tag!("i64") => { |_| IntTy::I64 }
+            tag!("i64")
             |
-            tag!("usize") => { |_| IntTy::Usize }
+            tag!("usize")
             |
-            tag!("u8") => { |_| IntTy::U8 }
+            tag!("u8")
             |
-            tag!("u16") => { |_| IntTy::U16 }
+            tag!("u16")
             |
-            tag!("u32") => { |_| IntTy::U32 }
+            tag!("u32")
             |
-            tag!("u64") => { |_| IntTy::U64 }
+            tag!("u64")
             |
-            epsilon!() => { |_| IntTy::Unsuffixed }
+            epsilon!() => { |_| "" }
         ) >>
-        (IntLit { value: value, suffix: suffix })
+        (l(Literal::integer(&format!("{}{}", value, suffix))))
     ));
 
-    named!(pub boolean -> bool, alt!(
-        keyword!("true") => { |_| true }
+    named!(pub boolean -> Lit, alt!(
+        keyword!("true") => { |_| Lit {
+            span: Span::default(),
+            value: LitKind::Bool(true),
+        } }
         |
-        keyword!("false") => { |_| false }
+        keyword!("false") => { |_| Lit {
+            span: Span::default(),
+            value: LitKind::Bool(false),
+        } }
     ));
 
     fn float_string(mut input: &str) -> IResult<&str, String> {
@@ -358,26 +302,23 @@
         IResult::Done(&input[len..], input[..len].replace("_", ""))
     }
 
-    pub fn digits(mut input: &str) -> IResult<&str, u64> {
+    pub fn digits(mut input: &str) -> IResult<&str, &str> {
         input = skip_whitespace(input);
 
         let base = if input.starts_with("0x") {
-            input = &input[2..];
             16
         } else if input.starts_with("0o") {
-            input = &input[2..];
             8
         } else if input.starts_with("0b") {
-            input = &input[2..];
             2
         } else {
             10
         };
 
         let mut value = 0u64;
-        let mut len = 0;
+        let mut len = if base == 10 {0} else {2};
         let mut empty = true;
-        for b in input.bytes() {
+        for b in input[len..].bytes() {
             let digit = match b {
                 b'0'...b'9' => (b - b'0') as u64,
                 b'a'...b'f' => 10 + (b - b'a') as u64,
@@ -408,7 +349,7 @@
         if empty {
             IResult::Error
         } else {
-            IResult::Done(&input[len..], value)
+            IResult::Done(&input[len..], &input[..len])
         }
     }
 }
@@ -417,82 +358,20 @@
 mod printing {
     use super::*;
     use quote::{Tokens, ToTokens};
-    use std::{ascii, iter};
-    use std::fmt::{self, Display};
-    use std::str;
+
+    use proc_macro2::{TokenTree, TokenKind};
 
     impl ToTokens for Lit {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                Lit::Str(ref s, StrStyle::Cooked) => s.to_tokens(tokens),
-                Lit::Str(ref s, StrStyle::Raw(n)) => {
-                    tokens.append(&format!("r{delim}\"{string}\"{delim}",
-                                           delim = iter::repeat("#").take(n).collect::<String>(),
-                                           string = s));
-                }
-                Lit::ByteStr(ref v, StrStyle::Cooked) => {
-                    let mut escaped = "b\"".to_string();
-                    for &ch in v.iter() {
-                        match ch {
-                            0 => escaped.push_str(r"\0"),
-                            b'\'' => escaped.push('\''),
-                            _ => escaped.extend(ascii::escape_default(ch).map(|c| c as char)),
-                        }
-                    }
-                    escaped.push('"');
-                    tokens.append(&escaped);
-                }
-                Lit::ByteStr(ref vec, StrStyle::Raw(n)) => {
-                    tokens.append(&format!("br{delim}\"{string}\"{delim}",
-                                           delim = iter::repeat("#").take(n).collect::<String>(),
-                                           string = str::from_utf8(vec).unwrap()));
-                }
-                Lit::Byte(b) => {
-                    match b {
-                        0 => tokens.append(r"b'\0'"),
-                        b'\"' => tokens.append("b'\"'"),
-                        _ => {
-                            let mut escaped = "b'".to_string();
-                            escaped.extend(ascii::escape_default(b).map(|c| c as char));
-                            escaped.push('\'');
-                            tokens.append(&escaped);
-                        }
-                    }
-                }
-                Lit::Char(ch) => ch.to_tokens(tokens),
-                Lit::Int(value, ty) => tokens.append(&format!("{}{}", value, ty)),
-                Lit::Float(ref value, ty) => tokens.append(&format!("{}{}", value, ty)),
-                Lit::Bool(true) => tokens.append("true"),
-                Lit::Bool(false) => tokens.append("false"),
-            }
-        }
-    }
-
-    impl Display for IntTy {
-        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-            match *self {
-                IntTy::Isize => formatter.write_str("isize"),
-                IntTy::I8 => formatter.write_str("i8"),
-                IntTy::I16 => formatter.write_str("i16"),
-                IntTy::I32 => formatter.write_str("i32"),
-                IntTy::I64 => formatter.write_str("i64"),
-                IntTy::Usize => formatter.write_str("usize"),
-                IntTy::U8 => formatter.write_str("u8"),
-                IntTy::U16 => formatter.write_str("u16"),
-                IntTy::U32 => formatter.write_str("u32"),
-                IntTy::U64 => formatter.write_str("u64"),
-                IntTy::Unsuffixed => Ok(()),
-            }
-        }
-    }
-
-    impl Display for FloatTy {
-        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
-            match *self {
-                FloatTy::F32 => formatter.write_str("f32"),
-                FloatTy::F64 => formatter.write_str("f64"),
-                FloatTy::Unsuffixed => Ok(()),
-            }
+            let kind = match self.value {
+                LitKind::Bool(true) => TokenKind::Word("true".into()),
+                LitKind::Bool(false) => TokenKind::Word("false".into()),
+                LitKind::Other(ref l) => TokenKind::Literal(l.clone()),
+            };
+            tokens.append(TokenTree {
+                span: self.span.0,
+                kind: kind,
+            });
         }
     }
 }
diff --git a/src/mac.rs b/src/mac.rs
index dbed4eb..789bf82 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -1,5 +1,10 @@
+#[cfg(feature = "extra-traits")]
+use std::fmt;
+
 use super::*;
 
+use proc_macro2::{TokenKind, Delimiter};
+
 ast_struct! {
     /// Represents a macro invocation. The Path indicates which macro
     /// is being invoked, and the vector of token-trees contains the source
@@ -9,123 +14,141 @@
     /// stored in the enclosing item. Oog.
     pub struct Mac {
         pub path: Path,
-        pub tts: Vec<TokenTree>,
+        pub bang_token: tokens::Bang,
+        pub tokens: Vec<TokenTree>,
     }
 }
 
-ast_enum! {
-    /// When the main rust parser encounters a syntax-extension invocation, it
-    /// parses the arguments to the invocation as a token-tree. This is a very
-    /// loose structure, such that all sorts of different AST-fragments can
-    /// be passed to syntax extensions using a uniform type.
-    ///
-    /// If the syntax extension is an MBE macro, it will attempt to match its
-    /// LHS token tree against the provided token tree, and if it finds a
-    /// match, will transcribe the RHS token tree, splicing in any captured
-    /// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
-    ///
-    /// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
-    /// Nothing special happens to misnamed or misplaced `SubstNt`s.
-    pub enum TokenTree {
-        /// A single token
-        Token(Token),
-        /// A delimited sequence of token trees
-        Delimited(Delimited),
+#[cfg_attr(feature = "clone-impls", derive(Clone))]
+pub struct TokenTree(pub proc_macro2::TokenTree);
+
+impl Mac {
+    pub fn is_braced(&self) -> bool {
+        match self.tokens.last() {
+            Some(t) => t.is_braced(),
+            None => false,
+        }
     }
 }
 
-ast_struct! {
-    pub struct Delimited {
-        /// The type of delimiter
-        pub delim: DelimToken,
-        /// The delimited sequence of token trees
-        pub tts: Vec<TokenTree>,
+impl TokenTree {
+    pub fn is_braced(&self) -> bool {
+        match self.0.kind {
+            TokenKind::Sequence(Delimiter::Brace, _) => true,
+            _ => false,
+        }
     }
 }
 
-ast_enum! {
-    pub enum Token {
-        // Expression-operator symbols.
-        Eq,
-        Lt,
-        Le,
-        EqEq,
-        Ne,
-        Ge,
-        Gt,
-        AndAnd,
-        OrOr,
-        Not,
-        Tilde,
-        BinOp(BinOpToken),
-        BinOpEq(BinOpToken),
+#[cfg(feature = "extra-traits")]
+impl PartialEq for TokenTree {
+    fn eq(&self, other: &TokenTree) -> bool {
+        use proc_macro2::OpKind;
 
-        // Structural symbols
-        At,
-        Dot,
-        DotDot,
-        DotDotDot,
-        Comma,
-        Semi,
-        Colon,
-        ModSep,
-        RArrow,
-        LArrow,
-        FatArrow,
-        Pound,
-        Dollar,
-        Question,
+        match (&self.0.kind, &other.0.kind) {
+            (&TokenKind::Sequence(d1, ref s1), &TokenKind::Sequence(d2, ref s2)) => {
+                match (d1, d2) {
+                    (Delimiter::Parenthesis, Delimiter::Parenthesis) |
+                    (Delimiter::Brace, Delimiter::Brace) |
+                    (Delimiter::Bracket, Delimiter::Bracket) => {}
+                    (Delimiter::None, Delimiter::None) => {}
+                    _ => return false,
+                }
 
-        // Literals
-        Literal(Lit),
+                let s1 = s1.clone().into_iter();
+                let mut s2 = s2.clone().into_iter();
 
-        // Name components
-        Ident(Ident),
-        Underscore,
-        Lifetime(Ident),
-
-        DocComment(String),
+                for item1 in s1 {
+                    let item2 = match s2.next() {
+                        Some(item) => item,
+                        None => return false,
+                    };
+                    if TokenTree(item1) != TokenTree(item2) {
+                        return false
+                    }
+                }
+                s2.next().is_none()
+            }
+            (&TokenKind::Op(o1, k1), &TokenKind::Op(o2, k2)) => {
+                o1 == o2 && match (k1, k2) {
+                    (OpKind::Alone, OpKind::Alone) |
+                    (OpKind::Joint, OpKind::Joint) => true,
+                    _ => false,
+                }
+            }
+            (&TokenKind::Literal(ref l1), &TokenKind::Literal(ref l2)) => {
+                l1.to_string() == l2.to_string()
+            }
+            (&TokenKind::Word(ref s1), &TokenKind::Word(ref s2)) => {
+                s1.as_str() == s2.as_str()
+            }
+            _ => false,
+        }
     }
 }
 
-ast_enum! {
-    #[cfg_attr(feature = "clone-impls", derive(Copy))]
-    pub enum BinOpToken {
-        Plus,
-        Minus,
-        Star,
-        Slash,
-        Percent,
-        Caret,
-        And,
-        Or,
-        Shl,
-        Shr,
+#[cfg(feature = "extra-traits")]
+impl Eq for TokenTree {}
+
+#[cfg(feature = "extra-traits")]
+impl ::std::hash::Hash for TokenTree {
+    fn hash<H: ::std::hash::Hasher>(&self, h: &mut H) {
+        use proc_macro2::OpKind;
+
+        match self.0.kind {
+            TokenKind::Sequence(delim, ref stream) => {
+                0u8.hash(h);
+                match delim {
+                    Delimiter::Parenthesis => 0u8.hash(h),
+                    Delimiter::Brace => 1u8.hash(h),
+                    Delimiter::Bracket => 2u8.hash(h),
+                    Delimiter::None => 3u8.hash(h),
+                }
+
+                for item in stream.clone().into_iter() {
+                    TokenTree(item).hash(h);
+                }
+                0xffu8.hash(h); // terminator w/ a variant we don't normally hash
+            }
+            TokenKind::Op(op, kind) => {
+                1u8.hash(h);
+                op.hash(h);
+                match kind {
+                    OpKind::Alone => 0u8.hash(h),
+                    OpKind::Joint => 1u8.hash(h),
+                }
+            }
+            TokenKind::Literal(ref lit) => (2u8, lit.to_string()).hash(h),
+            TokenKind::Word(ref word) => (3u8, word.as_str()).hash(h),
+        }
     }
 }
 
-ast_enum! {
-    /// A delimiter token
-    #[cfg_attr(feature = "clone-impls", derive(Copy))]
-    pub enum DelimToken {
-        /// A round parenthesis: `(` or `)`
-        Paren,
-        /// A square bracket: `[` or `]`
-        Bracket,
-        /// A curly brace: `{` or `}`
-        Brace,
+#[cfg(feature = "extra-traits")]
+impl fmt::Debug for TokenTree {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.0.to_string().fmt(f)
     }
 }
 
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use Lifetime;
+    use {Lifetime};
     use generics::parsing::lifetime;
     use ident::parsing::word;
     use lit::parsing::lit;
-    use synom::space::{block_comment, whitespace};
+    use synom::IResult;
+    use synom::space::{block_comment, whitespace, skip_whitespace};
     use ty::parsing::path;
+    use proc_macro2::{self, TokenStream, TokenKind, Delimiter, OpKind, Literal};
+
+    fn tt(kind: TokenKind) -> TokenTree {
+        TokenTree(proc_macro2::TokenTree {
+            kind: kind,
+            span: Default::default(),
+        })
+    }
 
     named!(pub mac -> Mac, do_parse!(
         what: path >>
@@ -133,146 +156,166 @@
         body: delimited >>
         (Mac {
             path: what,
-            tts: vec![TokenTree::Delimited(body)],
+            bang_token: tokens::Bang::default(),
+            tokens: vec![body],
         })
     ));
 
     named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
 
-    named!(pub delimited -> Delimited, alt!(
+    named!(pub token_stream -> TokenStream,
+           map!(token_trees, |t: Vec<TokenTree>| t.into_iter().map(|t| t.0).collect()));
+
+    named!(pub delimited -> TokenTree, alt!(
         delimited!(
             punct!("("),
-            token_trees,
+            token_stream,
             punct!(")")
-        ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
+        ) => { |ts| tt(TokenKind::Sequence(Delimiter::Parenthesis, ts)) }
         |
         delimited!(
             punct!("["),
-            token_trees,
+            token_stream,
             punct!("]")
-        ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
+        ) => { |ts| tt(TokenKind::Sequence(Delimiter::Bracket, ts)) }
         |
         delimited!(
             punct!("{"),
-            token_trees,
+            token_stream,
             punct!("}")
-        ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
+        ) => { |ts| tt(TokenKind::Sequence(Delimiter::Brace, ts)) }
     ));
 
     named!(pub token_tree -> TokenTree, alt!(
-        map!(token, TokenTree::Token)
+        token
         |
-        map!(delimited, TokenTree::Delimited)
+        delimited
     ));
 
-    named!(token -> Token, alt!(
-        keyword!("_") => { |_| Token::Underscore }
+    macro_rules! punct1 {
+        ($i:expr, $punct:expr) => {
+            punct1($i, $punct)
+        }
+    }
+
+    fn punct1<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, char> {
+        let input = skip_whitespace(input);
+        if input.starts_with(token) {
+            IResult::Done(&input[1..], token.chars().next().unwrap())
+        } else {
+            IResult::Error
+        }
+    }
+
+    named!(token -> TokenTree, alt!(
+        keyword!("_") => { |_| tt(TokenKind::Op('_', OpKind::Alone)) }
         |
-        punct!("&&") => { |_| Token::AndAnd } // must be before BinOp
+        punct1!("&&") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
         |
-        punct!("||") => { |_| Token::OrOr } // must be before BinOp
+        punct1!("||") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
         |
-        punct!("->") => { |_| Token::RArrow } // must be before BinOp
+        punct1!("->") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before BinOp
         |
-        punct!("<-") => { |_| Token::LArrow } // must be before Lt
+        punct1!("<-") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Lt
         |
-        punct!("=>") => { |_| Token::FatArrow } // must be before Eq
+        punct1!("=>") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Eq
         |
-        punct!("...") => { |_| Token::DotDotDot } // must be before DotDot
+        punct1!("...") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before DotDot
         |
-        punct!("..") => { |_| Token::DotDot } // must be before Dot
+        punct1!("..") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) } // must be before Dot
         |
-        punct!(".") => { |_| Token::Dot }
+        punct1!(".") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        map!(doc_comment, Token::DocComment) // must be before bin_op
+        // must be before bin_op
+        map!(doc_comment, |s: String| tt(TokenKind::Literal(Literal::doccomment(&s))))
         |
-        map!(bin_op_eq, Token::BinOpEq) // must be before bin_op
+        bin_op_eq // must be before bin_op
         |
-        map!(bin_op, Token::BinOp)
+        bin_op
         |
-        map!(lit, Token::Literal)
+        map!(lit, |l: Lit| l.into_token_tree())
         |
-        map!(word, Token::Ident)
+        map!(word, |w: Ident| tt(TokenKind::Word(w.sym)))
         |
-        map!(lifetime, |lt: Lifetime| Token::Lifetime(lt.ident))
+        map!(lifetime, |lt: Lifetime| tt(TokenKind::Word(lt.ident.sym)))
         |
-        punct!("<=") => { |_| Token::Le }
+        punct1!("<=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("==") => { |_| Token::EqEq }
+        punct1!("==") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("!=") => { |_| Token::Ne }
+        punct1!("!=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!(">=") => { |_| Token::Ge }
+        punct1!(">=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("::") => { |_| Token::ModSep }
+        punct1!("::") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("=") => { |_| Token::Eq }
+        punct1!("=") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("<") => { |_| Token::Lt }
+        punct1!("<") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!(">") => { |_| Token::Gt }
+        punct1!(">") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("!") => { |_| Token::Not }
+        punct1!("!") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("~") => { |_| Token::Tilde }
+        punct1!("~") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("@") => { |_| Token::At }
+        punct1!("@") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!(",") => { |_| Token::Comma }
+        punct1!(",") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!(";") => { |_| Token::Semi }
+        punct1!(";") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!(":") => { |_| Token::Colon }
+        punct1!(":") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("#") => { |_| Token::Pound }
+        punct1!("#") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("$") => { |_| Token::Dollar }
+        punct1!("$") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("?") => { |_| Token::Question }
+        punct1!("?") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
     ));
 
-    named!(bin_op -> BinOpToken, alt!(
-        punct!("+") => { |_| BinOpToken::Plus }
+    named!(bin_op -> TokenTree, alt!(
+        punct1!("+") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("-") => { |_| BinOpToken::Minus }
+        punct1!("-") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("*") => { |_| BinOpToken::Star }
+        punct1!("*") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("/") => { |_| BinOpToken::Slash }
+        punct1!("/") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("%") => { |_| BinOpToken::Percent }
+        punct1!("%") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("^") => { |_| BinOpToken::Caret }
+        punct1!("^") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("&") => { |_| BinOpToken::And }
+        punct1!("&") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("|") => { |_| BinOpToken::Or }
+        punct1!("|") => { |c| tt(TokenKind::Op(c, OpKind::Alone)) }
         |
-        punct!("<<") => { |_| BinOpToken::Shl }
+        punct1!("<<") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!(">>") => { |_| BinOpToken::Shr }
+        punct1!(">>") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
     ));
 
-    named!(bin_op_eq -> BinOpToken, alt!(
-        punct!("+=") => { |_| BinOpToken::Plus }
+    named!(bin_op_eq -> TokenTree, alt!(
+        punct1!("+=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("-=") => { |_| BinOpToken::Minus }
+        punct1!("-=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("*=") => { |_| BinOpToken::Star }
+        punct1!("*=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("/=") => { |_| BinOpToken::Slash }
+        punct1!("/=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("%=") => { |_| BinOpToken::Percent }
+        punct1!("%=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("^=") => { |_| BinOpToken::Caret }
+        punct1!("^=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("&=") => { |_| BinOpToken::And }
+        punct1!("&=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("|=") => { |_| BinOpToken::Or }
+        punct1!("|=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!("<<=") => { |_| BinOpToken::Shl }
+        punct1!("<<=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
         |
-        punct!(">>=") => { |_| BinOpToken::Shr }
+        punct1!(">>=") => { |c| tt(TokenKind::Op(c, OpKind::Joint)) }
     ));
 
     named!(doc_comment -> String, alt!(
@@ -313,126 +356,14 @@
     impl ToTokens for Mac {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.path.to_tokens(tokens);
-            tokens.append("!");
-            for tt in &self.tts {
-                tt.to_tokens(tokens);
-            }
+            self.bang_token.to_tokens(tokens);
+            tokens.append_all(&self.tokens);
         }
     }
 
     impl ToTokens for TokenTree {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                TokenTree::Token(ref token) => token.to_tokens(tokens),
-                TokenTree::Delimited(ref delimited) => delimited.to_tokens(tokens),
-            }
-        }
-    }
-
-    impl DelimToken {
-        fn open(&self) -> &'static str {
-            match *self {
-                DelimToken::Paren => "(",
-                DelimToken::Bracket => "[",
-                DelimToken::Brace => "{",
-            }
-        }
-
-        fn close(&self) -> &'static str {
-            match *self {
-                DelimToken::Paren => ")",
-                DelimToken::Bracket => "]",
-                DelimToken::Brace => "}",
-            }
-        }
-    }
-
-    impl ToTokens for Delimited {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.delim.open());
-            for tt in &self.tts {
-                tt.to_tokens(tokens);
-            }
-            tokens.append(self.delim.close());
-        }
-    }
-
-    impl ToTokens for Token {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            match *self {
-                Token::Eq => tokens.append("="),
-                Token::Lt => tokens.append("<"),
-                Token::Le => tokens.append("<="),
-                Token::EqEq => tokens.append("=="),
-                Token::Ne => tokens.append("!="),
-                Token::Ge => tokens.append(">="),
-                Token::Gt => tokens.append(">"),
-                Token::AndAnd => tokens.append("&&"),
-                Token::OrOr => tokens.append("||"),
-                Token::Not => tokens.append("!"),
-                Token::Tilde => tokens.append("~"),
-                Token::BinOp(ref binop) => tokens.append(binop.op()),
-                Token::BinOpEq(ref binop) => tokens.append(binop.assign_op()),
-                Token::At => tokens.append("@"),
-                Token::Dot => tokens.append("."),
-                Token::DotDot => tokens.append(".."),
-                Token::DotDotDot => tokens.append("..."),
-                Token::Comma => tokens.append(","),
-                Token::Semi => tokens.append(";"),
-                Token::Colon => tokens.append(":"),
-                Token::ModSep => tokens.append("::"),
-                Token::RArrow => tokens.append("->"),
-                Token::LArrow => tokens.append("<-"),
-                Token::FatArrow => tokens.append("=>"),
-                Token::Pound => tokens.append("#"),
-                Token::Dollar => tokens.append("$"),
-                Token::Question => tokens.append("?"),
-                Token::Literal(ref lit) => lit.to_tokens(tokens),
-                Token::Ident(ref ident) |
-                Token::Lifetime(ref ident) => ident.to_tokens(tokens),
-                Token::Underscore => tokens.append("_"),
-                Token::DocComment(ref com) => {
-                    tokens.append(&format!("{}\n", com));
-                }
-            }
-        }
-    }
-
-    impl BinOpToken {
-        fn op(&self) -> &'static str {
-            match *self {
-                BinOpToken::Plus => "+",
-                BinOpToken::Minus => "-",
-                BinOpToken::Star => "*",
-                BinOpToken::Slash => "/",
-                BinOpToken::Percent => "%",
-                BinOpToken::Caret => "^",
-                BinOpToken::And => "&",
-                BinOpToken::Or => "|",
-                BinOpToken::Shl => "<<",
-                BinOpToken::Shr => ">>",
-            }
-        }
-
-        fn assign_op(&self) -> &'static str {
-            match *self {
-                BinOpToken::Plus => "+=",
-                BinOpToken::Minus => "-=",
-                BinOpToken::Star => "*=",
-                BinOpToken::Slash => "/=",
-                BinOpToken::Percent => "%=",
-                BinOpToken::Caret => "^=",
-                BinOpToken::And => "&=",
-                BinOpToken::Or => "|=",
-                BinOpToken::Shl => "<<=",
-                BinOpToken::Shr => ">>=",
-            }
-        }
-    }
-
-    impl ToTokens for BinOpToken {
-        fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.op());
+            self.0.to_tokens(tokens);
         }
     }
 }
diff --git a/src/op.rs b/src/op.rs
index 6393e00..636b974 100644
--- a/src/op.rs
+++ b/src/op.rs
@@ -1,42 +1,64 @@
+use tokens;
+
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum BinOp {
         /// The `+` operator (addition)
-        Add,
+        Add(tokens::Add),
         /// The `-` operator (subtraction)
-        Sub,
+        Sub(tokens::Sub),
         /// The `*` operator (multiplication)
-        Mul,
+        Mul(tokens::Star),
         /// The `/` operator (division)
-        Div,
+        Div(tokens::Div),
         /// The `%` operator (modulus)
-        Rem,
+        Rem(tokens::Rem),
         /// The `&&` operator (logical and)
-        And,
+        And(tokens::AndAnd),
         /// The `||` operator (logical or)
-        Or,
+        Or(tokens::OrOr),
         /// The `^` operator (bitwise xor)
-        BitXor,
+        BitXor(tokens::Caret),
         /// The `&` operator (bitwise and)
-        BitAnd,
+        BitAnd(tokens::And),
         /// The `|` operator (bitwise or)
-        BitOr,
+        BitOr(tokens::Or),
         /// The `<<` operator (shift left)
-        Shl,
+        Shl(tokens::Shl),
         /// The `>>` operator (shift right)
-        Shr,
+        Shr(tokens::Shr),
         /// The `==` operator (equality)
-        Eq,
+        Eq(tokens::EqEq),
         /// The `<` operator (less than)
-        Lt,
+        Lt(tokens::Lt),
         /// The `<=` operator (less than or equal to)
-        Le,
+        Le(tokens::Le),
         /// The `!=` operator (not equal to)
-        Ne,
+        Ne(tokens::Ne),
         /// The `>=` operator (greater than or equal to)
-        Ge,
+        Ge(tokens::Ge),
         /// The `>` operator (greater than)
-        Gt,
+        Gt(tokens::Gt),
+        /// The `+=` operator
+        AddEq(tokens::AddEq),
+        /// The `-=` operator
+        SubEq(tokens::SubEq),
+        /// The `*=` operator
+        MulEq(tokens::MulEq),
+        /// The `/=` operator
+        DivEq(tokens::DivEq),
+        /// The `%=` operator
+        RemEq(tokens::RemEq),
+        /// The `^=` operator
+        BitXorEq(tokens::CaretEq),
+        /// The `&=` operator
+        BitAndEq(tokens::AndEq),
+        /// The `|=` operator
+        BitOrEq(tokens::OrEq),
+        /// The `<<=` operator
+        ShlEq(tokens::ShlEq),
+        /// The `>>=` operator
+        ShrEq(tokens::ShrEq),
     }
 }
 
@@ -44,11 +66,11 @@
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum UnOp {
         /// The `*` operator for dereferencing
-        Deref,
+        Deref(tokens::Star),
         /// The `!` operator for logical inversion
-        Not,
+        Not(tokens::Bang),
         /// The `-` operator for negation
-        Neg,
+        Neg(tokens::Sub),
     }
 }
 
@@ -57,72 +79,72 @@
     use super::*;
 
     named!(pub binop -> BinOp, alt!(
-        punct!("&&") => { |_| BinOp::And }
+        punct!("&&") => { |_| BinOp::And(tokens::AndAnd::default()) }
         |
-        punct!("||") => { |_| BinOp::Or }
+        punct!("||") => { |_| BinOp::Or(tokens::OrOr::default()) }
         |
-        punct!("<<") => { |_| BinOp::Shl }
+        punct!("<<") => { |_| BinOp::Shl(tokens::Shl::default()) }
         |
-        punct!(">>") => { |_| BinOp::Shr }
+        punct!(">>") => { |_| BinOp::Shr(tokens::Shr::default()) }
         |
-        punct!("==") => { |_| BinOp::Eq }
+        punct!("==") => { |_| BinOp::Eq(tokens::EqEq::default()) }
         |
-        punct!("<=") => { |_| BinOp::Le }
+        punct!("<=") => { |_| BinOp::Le(tokens::Le::default()) }
         |
-        punct!("!=") => { |_| BinOp::Ne }
+        punct!("!=") => { |_| BinOp::Ne(tokens::Ne::default()) }
         |
-        punct!(">=") => { |_| BinOp::Ge }
+        punct!(">=") => { |_| BinOp::Ge(tokens::Ge::default()) }
         |
-        punct!("+") => { |_| BinOp::Add }
+        punct!("+") => { |_| BinOp::Add(tokens::Add::default()) }
         |
-        punct!("-") => { |_| BinOp::Sub }
+        punct!("-") => { |_| BinOp::Sub(tokens::Sub::default()) }
         |
-        punct!("*") => { |_| BinOp::Mul }
+        punct!("*") => { |_| BinOp::Mul(tokens::Star::default()) }
         |
-        punct!("/") => { |_| BinOp::Div }
+        punct!("/") => { |_| BinOp::Div(tokens::Div::default()) }
         |
-        punct!("%") => { |_| BinOp::Rem }
+        punct!("%") => { |_| BinOp::Rem(tokens::Rem::default()) }
         |
-        punct!("^") => { |_| BinOp::BitXor }
+        punct!("^") => { |_| BinOp::BitXor(tokens::Caret::default()) }
         |
-        punct!("&") => { |_| BinOp::BitAnd }
+        punct!("&") => { |_| BinOp::BitAnd(tokens::And::default()) }
         |
-        punct!("|") => { |_| BinOp::BitOr }
+        punct!("|") => { |_| BinOp::BitOr(tokens::Or::default()) }
         |
-        punct!("<") => { |_| BinOp::Lt }
+        punct!("<") => { |_| BinOp::Lt(tokens::Lt::default()) }
         |
-        punct!(">") => { |_| BinOp::Gt }
+        punct!(">") => { |_| BinOp::Gt(tokens::Gt::default()) }
     ));
 
     #[cfg(feature = "full")]
     named!(pub assign_op -> BinOp, alt!(
-        punct!("+=") => { |_| BinOp::Add }
+        punct!("+=") => { |_| BinOp::AddEq(tokens::AddEq::default()) }
         |
-        punct!("-=") => { |_| BinOp::Sub }
+        punct!("-=") => { |_| BinOp::SubEq(tokens::SubEq::default()) }
         |
-        punct!("*=") => { |_| BinOp::Mul }
+        punct!("*=") => { |_| BinOp::MulEq(tokens::MulEq::default()) }
         |
-        punct!("/=") => { |_| BinOp::Div }
+        punct!("/=") => { |_| BinOp::DivEq(tokens::DivEq::default()) }
         |
-        punct!("%=") => { |_| BinOp::Rem }
+        punct!("%=") => { |_| BinOp::RemEq(tokens::RemEq::default()) }
         |
-        punct!("^=") => { |_| BinOp::BitXor }
+        punct!("^=") => { |_| BinOp::BitXorEq(tokens::CaretEq::default()) }
         |
-        punct!("&=") => { |_| BinOp::BitAnd }
+        punct!("&=") => { |_| BinOp::BitAndEq(tokens::AndEq::default()) }
         |
-        punct!("|=") => { |_| BinOp::BitOr }
+        punct!("|=") => { |_| BinOp::BitOrEq(tokens::OrEq::default()) }
         |
-        punct!("<<=") => { |_| BinOp::Shl }
+        punct!("<<=") => { |_| BinOp::ShlEq(tokens::ShlEq::default()) }
         |
-        punct!(">>=") => { |_| BinOp::Shr }
+        punct!(">>=") => { |_| BinOp::ShrEq(tokens::ShrEq::default()) }
     ));
 
     named!(pub unop -> UnOp, alt!(
-        punct!("*") => { |_| UnOp::Deref }
+        punct!("*") => { |_| UnOp::Deref(tokens::Star::default()) }
         |
-        punct!("!") => { |_| UnOp::Not }
+        punct!("!") => { |_| UnOp::Not(tokens::Bang::default()) }
         |
-        punct!("-") => { |_| UnOp::Neg }
+        punct!("-") => { |_| UnOp::Neg(tokens::Sub::default()) }
     ));
 }
 
@@ -131,66 +153,48 @@
     use super::*;
     use quote::{Tokens, ToTokens};
 
-    impl BinOp {
-        pub fn op(&self) -> &'static str {
-            match *self {
-                BinOp::Add => "+",
-                BinOp::Sub => "-",
-                BinOp::Mul => "*",
-                BinOp::Div => "/",
-                BinOp::Rem => "%",
-                BinOp::And => "&&",
-                BinOp::Or => "||",
-                BinOp::BitXor => "^",
-                BinOp::BitAnd => "&",
-                BinOp::BitOr => "|",
-                BinOp::Shl => "<<",
-                BinOp::Shr => ">>",
-                BinOp::Eq => "==",
-                BinOp::Lt => "<",
-                BinOp::Le => "<=",
-                BinOp::Ne => "!=",
-                BinOp::Ge => ">=",
-                BinOp::Gt => ">",
-            }
-        }
-
-        pub fn assign_op(&self) -> Option<&'static str> {
-            match *self {
-                BinOp::Add => Some("+="),
-                BinOp::Sub => Some("-="),
-                BinOp::Mul => Some("*="),
-                BinOp::Div => Some("/="),
-                BinOp::Rem => Some("%="),
-                BinOp::BitXor => Some("^="),
-                BinOp::BitAnd => Some("&="),
-                BinOp::BitOr => Some("|="),
-                BinOp::Shl => Some("<<="),
-                BinOp::Shr => Some(">>="),
-                _ => None,
-            }
-        }
-    }
-
     impl ToTokens for BinOp {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.op());
-        }
-    }
-
-    impl UnOp {
-        pub fn op(&self) -> &'static str {
             match *self {
-                UnOp::Deref => "*",
-                UnOp::Not => "!",
-                UnOp::Neg => "-",
+                BinOp::Add(ref t) => t.to_tokens(tokens),
+                BinOp::Sub(ref t) => t.to_tokens(tokens),
+                BinOp::Mul(ref t) => t.to_tokens(tokens),
+                BinOp::Div(ref t) => t.to_tokens(tokens),
+                BinOp::Rem(ref t) => t.to_tokens(tokens),
+                BinOp::And(ref t) => t.to_tokens(tokens),
+                BinOp::Or(ref t) => t.to_tokens(tokens),
+                BinOp::BitXor(ref t) => t.to_tokens(tokens),
+                BinOp::BitAnd(ref t) => t.to_tokens(tokens),
+                BinOp::BitOr(ref t) => t.to_tokens(tokens),
+                BinOp::Shl(ref t) => t.to_tokens(tokens),
+                BinOp::Shr(ref t) => t.to_tokens(tokens),
+                BinOp::Eq(ref t) => t.to_tokens(tokens),
+                BinOp::Lt(ref t) => t.to_tokens(tokens),
+                BinOp::Le(ref t) => t.to_tokens(tokens),
+                BinOp::Ne(ref t) => t.to_tokens(tokens),
+                BinOp::Ge(ref t) => t.to_tokens(tokens),
+                BinOp::Gt(ref t) => t.to_tokens(tokens),
+                BinOp::AddEq(ref t) => t.to_tokens(tokens),
+                BinOp::SubEq(ref t) => t.to_tokens(tokens),
+                BinOp::MulEq(ref t) => t.to_tokens(tokens),
+                BinOp::DivEq(ref t) => t.to_tokens(tokens),
+                BinOp::RemEq(ref t) => t.to_tokens(tokens),
+                BinOp::BitXorEq(ref t) => t.to_tokens(tokens),
+                BinOp::BitAndEq(ref t) => t.to_tokens(tokens),
+                BinOp::BitOrEq(ref t) => t.to_tokens(tokens),
+                BinOp::ShlEq(ref t) => t.to_tokens(tokens),
+                BinOp::ShrEq(ref t) => t.to_tokens(tokens),
             }
         }
     }
 
     impl ToTokens for UnOp {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append(self.op());
+            match *self {
+                UnOp::Deref(ref t) => t.to_tokens(tokens),
+                UnOp::Not(ref t) => t.to_tokens(tokens),
+                UnOp::Neg(ref t) => t.to_tokens(tokens),
+            }
         }
     }
 }
diff --git a/src/span.rs b/src/span.rs
new file mode 100644
index 0000000..a652c41
--- /dev/null
+++ b/src/span.rs
@@ -0,0 +1,27 @@
+use std::hash::{Hash, Hasher};
+use std::fmt;
+
+use proc_macro2;
+
+#[derive(Clone, Copy, Default)]
+pub struct Span(pub proc_macro2::Span);
+
+impl PartialEq for Span {
+    fn eq(&self, _other: &Span) -> bool {
+        true
+    }
+}
+
+impl Eq for Span {}
+
+impl Hash for Span {
+    fn hash<H: Hasher>(&self, _hasher: &mut H) {
+    }
+}
+
+impl fmt::Debug for Span {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("Span")
+         .finish()
+    }
+}
diff --git a/src/tokens.rs b/src/tokens.rs
new file mode 100644
index 0000000..744cb97
--- /dev/null
+++ b/src/tokens.rs
@@ -0,0 +1,205 @@
+use Span;
+
+macro_rules! tokens {
+    (
+        ops: {
+            $(($($op:tt)*),)*
+        }
+        delim: {
+            $(($($delim:tt)*),)*
+        }
+        syms: {
+            $(($($sym:tt)*),)*
+        }
+    ) => (
+        $(op! { $($op)* })*
+        $(delim! { $($delim)* })*
+        $(sym! { $($sym)* })*
+    )
+}
+
+macro_rules! op {
+    (pub struct $name:ident($($contents:tt)*) => $s:expr) => {
+        ast_struct! {
+            #[cfg_attr(feature = "clone-impls", derive(Copy))]
+            #[derive(Default)]
+            pub struct $name(pub $($contents)*);
+        }
+
+        #[cfg(feature = "printing")]
+        impl ::quote::ToTokens for $name {
+            fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
+                printing::op($s, &self.0, tokens);
+            }
+        }
+    }
+}
+
+macro_rules! sym {
+    (pub struct $name:ident => $s:expr) => {
+        ast_struct! {
+            #[cfg_attr(feature = "clone-impls", derive(Copy))]
+            #[derive(Default)]
+            pub struct $name(pub Span);
+        }
+
+        #[cfg(feature = "printing")]
+        impl ::quote::ToTokens for $name {
+            fn to_tokens(&self, tokens: &mut ::quote::Tokens) {
+                printing::sym($s, &self.0, tokens);
+            }
+        }
+    }
+}
+
+macro_rules! delim {
+    (pub struct $name:ident => $s:expr) => {
+        ast_struct! {
+            #[cfg_attr(feature = "clone-impls", derive(Copy))]
+            #[derive(Default)]
+            pub struct $name(pub Span);
+        }
+
+        #[cfg(feature = "printing")]
+        impl $name {
+            pub fn surround<F>(&self,
+                               tokens: &mut ::quote::Tokens,
+                               f: F)
+                where F: FnOnce(&mut ::quote::Tokens)
+            {
+                printing::delim($s, &self.0, tokens, f);
+            }
+        }
+    }
+}
+
+tokens! {
+    ops: {
+        (pub struct Add([Span; 1])          => "+"),
+        (pub struct AddEq([Span; 2])        => "+="),
+        (pub struct And([Span; 1])          => "&"),
+        (pub struct AndAnd([Span; 2])       => "&&"),
+        (pub struct AndEq([Span; 2])        => "&="),
+        (pub struct At([Span; 1])           => "@"),
+        (pub struct Bang([Span; 1])         => "!"),
+        (pub struct Caret([Span; 1])        => "^"),
+        (pub struct CaretEq([Span; 2])      => "^="),
+        (pub struct Colon([Span; 1])        => ":"),
+        (pub struct Colon2([Span; 2])       => "::"),
+        (pub struct Comma([Span; 1])        => ","),
+        (pub struct Div([Span; 1])          => "/"),
+        (pub struct DivEq([Span; 2])        => "/="),
+        (pub struct Dot([Span; 1])          => "."),
+        (pub struct Dot2([Span; 2])         => ".."),
+        (pub struct Dot3([Span; 3])         => "..."),
+        (pub struct Eq([Span; 1])           => "="),
+        (pub struct EqEq([Span; 2])         => "=="),
+        (pub struct Ge([Span; 2])           => ">="),
+        (pub struct Gt([Span; 1])           => ">"),
+        (pub struct Le([Span; 2])           => "<="),
+        (pub struct Lt([Span; 1])           => "<"),
+        (pub struct MulEq([Span; 2])        => "*="),
+        (pub struct Ne([Span; 2])           => "!="),
+        (pub struct Or([Span; 1])           => "|"),
+        (pub struct OrEq([Span; 2])         => "|="),
+        (pub struct OrOr([Span; 2])         => "||"),
+        (pub struct Pound([Span; 1])        => "#"),
+        (pub struct Question([Span; 1])     => "?"),
+        (pub struct RArrow([Span; 2])       => "->"),
+        (pub struct Rem([Span; 1])          => "%"),
+        (pub struct RemEq([Span; 2])        => "%="),
+        (pub struct Rocket([Span; 2])       => "=>"),
+        (pub struct Semi([Span; 1])         => ";"),
+        (pub struct Shl([Span; 2])          => "<<"),
+        (pub struct ShlEq([Span; 3])        => "<<="),
+        (pub struct Shr([Span; 2])          => ">>"),
+        (pub struct ShrEq([Span; 3])        => ">>="),
+        (pub struct Star([Span; 1])         => "*"),
+        (pub struct Sub([Span; 1])          => "-"),
+        (pub struct SubEq([Span; 2])        => "-="),
+        (pub struct Underscore([Span; 1])   => "_"),
+    }
+    delim: {
+        (pub struct Brace                   => "{"),
+        (pub struct Bracket                 => "["),
+        (pub struct Paren                   => "("),
+    }
+    syms: {
+        (pub struct As                      => "as"),
+        (pub struct Box                     => "box"),
+        (pub struct Break                   => "break"),
+        (pub struct Catch                   => "catch"),
+        (pub struct Const                   => "const"),
+        (pub struct Continue                => "continue"),
+        (pub struct Crate                   => "crate"),
+        (pub struct Default                 => "default"),
+        (pub struct Do                      => "do"),
+        (pub struct Else                    => "else"),
+        (pub struct Enum                    => "enum"),
+        (pub struct Extern                  => "extern"),
+        (pub struct Fn                      => "fn"),
+        (pub struct For                     => "for"),
+        (pub struct If                      => "if"),
+        (pub struct Impl                    => "impl"),
+        (pub struct In                      => "in"),
+        (pub struct Let                     => "let"),
+        (pub struct Loop                    => "loop"),
+        (pub struct Match                   => "match"),
+        (pub struct Mod                     => "mod"),
+        (pub struct Move                    => "move"),
+        (pub struct Mut                     => "mut"),
+        (pub struct Pub                     => "pub"),
+        (pub struct Ref                     => "ref"),
+        (pub struct Return                  => "return"),
+        (pub struct Self_                   => "self"),
+        (pub struct Static                  => "static"),
+        (pub struct Struct                  => "struct"),
+        (pub struct Trait                   => "trait"),
+        (pub struct Type                    => "type"),
+        (pub struct Union                   => "union"),
+        (pub struct Unsafe                  => "unsafe"),
+        (pub struct Use                     => "use"),
+        (pub struct Where                   => "where"),
+        (pub struct While                   => "while"),
+    }
+}
+
+#[cfg(feature = "printing")]
+mod printing {
+    use Span;
+    use proc_macro2::{TokenTree, TokenKind, OpKind};
+    use quote::Tokens;
+
+    pub fn op(s: &str, spans: &[Span], tokens: &mut Tokens) {
+        assert_eq!(s.len(), spans.len());
+
+        let mut chars = s.chars();
+        let mut spans = spans.iter();
+        let ch = chars.next_back().unwrap();
+        let span = spans.next_back().unwrap();
+        for (ch, span) in chars.zip(spans) {
+            tokens.append(TokenTree {
+                span: span.0,
+                kind: TokenKind::Op(ch, OpKind::Joint),
+            });
+        }
+
+        tokens.append(TokenTree {
+            span: span.0,
+            kind: TokenKind::Op(ch, OpKind::Alone),
+        });
+    }
+
+    pub fn sym(s: &str, span: &Span, tokens: &mut Tokens) {
+        tokens.append(TokenTree {
+            span: span.0,
+            kind: TokenKind::Word(s.into()),
+        });
+    }
+
+    pub fn delim<F>(s: &str, span: &Span, tokens: &mut Tokens, f: F)
+        where F: FnOnce(&mut Tokens)
+    {
+        tokens.append_delimited(s, span.0, f)
+    }
+}
diff --git a/src/ty.rs b/src/ty.rs
index 7345da7..45fb637 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -1,3 +1,4 @@
+use delimited::Delimited;
 use super::*;
 
 ast_enum_of_structs! {
@@ -6,18 +7,24 @@
         /// A variable-length array (`[T]`)
         pub Slice(TySlice {
             pub ty: Box<Ty>,
+            pub bracket_token: tokens::Bracket,
         }),
         /// A fixed length array (`[T; n]`)
         pub Array(TyArray {
+            pub bracket_token: tokens::Bracket,
             pub ty: Box<Ty>,
+            pub semi_token: tokens::Semi,
             pub amt: ConstExpr,
         }),
         /// A raw pointer (`*const T` or `*mut T`)
         pub Ptr(TyPtr {
+            pub star_token: tokens::Star,
+            pub const_token: Option<tokens::Const>,
             pub ty: Box<MutTy>,
         }),
         /// A reference (`&'a T` or `&'a mut T`)
         pub Rptr(TyRptr {
+            pub and_token: tokens::And,
             pub lifetime: Option<Lifetime>,
             pub ty: Box<MutTy>,
         }),
@@ -26,10 +33,14 @@
             pub ty: Box<BareFnTy>,
         }),
         /// The never type (`!`)
-        pub Never(TyNever {}),
+        pub Never(TyNever {
+            pub bang_token: tokens::Bang,
+        }),
         /// A tuple (`(A, B, C, D, ...)`)
         pub Tup(TyTup {
-            pub tys: Vec<Ty>,
+            pub paren_token: tokens::Paren,
+            pub tys: Delimited<Ty, tokens::Comma>,
+            pub lone_comma: Option<tokens::Comma>,
         }),
         /// A path (`module::module::...::Type`), optionally
         /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
@@ -42,20 +53,24 @@
         /// A trait object type `Bound1 + Bound2 + Bound3`
         /// where `Bound` is a trait or a lifetime.
         pub TraitObject(TyTraitObject {
-            pub bounds: Vec<TyParamBound>,
+            pub bounds: Delimited<TyParamBound, tokens::Add>,
         }),
         /// An `impl Bound1 + Bound2 + Bound3` type
         /// where `Bound` is a trait or a lifetime.
         pub ImplTrait(TyImplTrait {
-            pub bounds: Vec<TyParamBound>,
+            pub impl_token: tokens::Impl,
+            pub bounds: Delimited<TyParamBound, tokens::Add>,
         }),
         /// No-op; kept solely so that we can pretty-print faithfully
         pub Paren(TyParen {
+            pub paren_token: tokens::Paren,
             pub ty: Box<Ty>,
         }),
         /// TyKind::Infer means the type should be inferred instead of it having been
         /// specified. This can appear anywhere in a type.
-        pub Infer(TyInfer {}),
+        pub Infer(TyInfer {
+            pub underscore_token: tokens::Underscore
+        }),
         /// A macro in the type position.
         pub Mac(Mac),
     }
@@ -71,7 +86,7 @@
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Mutability {
-        Mutable,
+        Mutable(tokens::Mut),
         Immutable,
     }
 }
@@ -87,18 +102,25 @@
         /// A `::foo` path, is relative to the crate root rather than current
         /// module (like paths in an import).
         pub global: bool,
+        pub leading_colon: Option<tokens::Colon2>,
         /// The segments in the path: the things separated by `::`.
-        pub segments: Vec<PathSegment>,
+        pub segments: Delimited<PathSegment, tokens::Colon2>,
     }
 }
 
+#[cfg(feature = "printing")]
+ast_struct! {
+    pub struct PathTokens<'a>(pub &'a Option<QSelf>, pub &'a Path);
+}
+
 impl<T> From<T> for Path
     where T: Into<PathSegment>
 {
     fn from(segment: T) -> Self {
         Path {
             global: false,
-            segments: vec![segment.into()],
+            leading_colon: None,
+            segments: vec![(segment.into(), None)].into(),
         }
     }
 }
@@ -162,14 +184,17 @@
     /// A path like `Foo<'a, T>`
     #[derive(Default)]
     pub struct AngleBracketedParameterData {
+        pub lt_token: Option<tokens::Lt>,
+        pub gt_token: Option<tokens::Gt>,
+
         /// The lifetime parameters for this path segment.
-        pub lifetimes: Vec<Lifetime>,
+        pub lifetimes: Delimited<Lifetime, tokens::Comma>,
         /// The type parameters for this path segment, if present.
-        pub types: Vec<Ty>,
+        pub types: Delimited<Ty, tokens::Comma>,
         /// Bindings (equality constraints) on associated types, if present.
         ///
         /// E.g., `Foo<A=Bar>`.
-        pub bindings: Vec<TypeBinding>,
+        pub bindings: Delimited<TypeBinding, tokens::Comma>,
     }
 }
 
@@ -177,6 +202,7 @@
     /// Bind a type to an associated type: `A=Foo`.
     pub struct TypeBinding {
         pub ident: Ident,
+        pub eq_token: tokens::Eq,
         pub ty: Ty,
     }
 }
@@ -185,17 +211,18 @@
 ast_struct! {
     /// A path like `Foo(A,B) -> C`
     pub struct ParenthesizedParameterData {
+        pub paren_token: tokens::Paren,
         /// `(A, B)`
-        pub inputs: Vec<Ty>,
+        pub inputs: Delimited<Ty, tokens::Comma>,
         /// `C`
-        pub output: Option<Ty>,
+        pub output: FunctionRetTy,
     }
 }
 
 ast_struct! {
     pub struct PolyTraitRef {
-        /// The `'a` in `<'a> Foo<&'a T>`
-        pub bound_lifetimes: Vec<LifetimeDef>,
+        /// The `for<'a>` in `for<'a> Foo<&'a T>`
+        pub bound_lifetimes: Option<BoundLifetimes>,
         /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
         pub trait_ref: Path,
     }
@@ -217,6 +244,9 @@
     ///  ty       position = 0
     /// ```
     pub struct QSelf {
+        pub lt_token: tokens::Lt,
+        pub gt_token: tokens::Gt,
+        pub as_token: Option<tokens::As>,
         pub ty: Box<Ty>,
         pub position: usize,
     }
@@ -224,27 +254,36 @@
 
 ast_struct! {
     pub struct BareFnTy {
+        pub lifetimes: Option<BoundLifetimes>,
         pub unsafety: Unsafety,
         pub abi: Option<Abi>,
-        pub lifetimes: Vec<LifetimeDef>,
-        pub inputs: Vec<BareFnArg>,
+        pub fn_token: tokens::Fn,
+        pub paren_token: tokens::Paren,
+        pub inputs: Delimited<BareFnArg, tokens::Comma>,
+        pub variadic: Option<tokens::Dot3>,
         pub output: FunctionRetTy,
-        pub variadic: bool,
     }
 }
 
 ast_enum! {
     #[cfg_attr(feature = "clone-impls", derive(Copy))]
     pub enum Unsafety {
-        Unsafe,
+        Unsafe(tokens::Unsafe),
         Normal,
     }
 }
 
+ast_struct! {
+    pub struct Abi {
+        pub extern_token: tokens::Extern,
+        pub kind: AbiKind,
+    }
+}
+
 ast_enum! {
-    pub enum Abi {
-        Named(String),
-        Rust,
+    pub enum AbiKind {
+        Named(Lit),
+        Default,
     }
 }
 
@@ -253,7 +292,7 @@
     ///
     /// E.g. `bar: usize` as in `fn foo(bar: usize)`
     pub struct BareFnArg {
-        pub name: Option<Ident>,
+        pub name: Option<(Ident, tokens::Colon)>,
         pub ty: Ty,
     }
 }
@@ -268,7 +307,7 @@
         /// type would be inserted.
         Default,
         /// Everything else
-        Ty(Ty),
+        Ty(Ty, tokens::RArrow),
     }
 }
 
@@ -282,9 +321,9 @@
     use constant::parsing::const_expr;
     #[cfg(feature = "full")]
     use expr::parsing::expr;
-    use generics::parsing::{lifetime, lifetime_def, ty_param_bound, bound_lifetimes};
+    use generics::parsing::{lifetime, ty_param_bound, bound_lifetimes};
     use ident::parsing::ident;
-    use lit::parsing::quoted_string;
+    use lit::parsing::string;
     use mac::parsing::mac;
     use std::str;
 
@@ -320,7 +359,10 @@
         punct!("[") >>
         elem: ty >>
         punct!("]") >>
-        (TySlice { ty: Box::new(elem) }.into())
+        (TySlice {
+            ty: Box::new(elem),
+            bracket_token: tokens::Bracket::default(),
+        }.into())
     ));
 
     named!(ty_array -> Ty, do_parse!(
@@ -329,7 +371,12 @@
         punct!(";") >>
         len: array_len >>
         punct!("]") >>
-        (TyArray { ty: Box::new(elem), amt: len }.into())
+        (TyArray {
+            ty: Box::new(elem),
+            amt: len,
+            bracket_token: tokens::Bracket::default(),
+            semi_token: tokens::Semi::default(),
+        }.into())
     ));
 
     #[cfg(not(feature = "full"))]
@@ -350,10 +397,15 @@
         mutability: alt!(
             keyword!("const") => { |_| Mutability::Immutable }
             |
-            keyword!("mut") => { |_| Mutability::Mutable }
+            keyword!("mut") => { |_| Mutability::Mutable(tokens::Mut::default()) }
         ) >>
         target: ty >>
         (TyPtr {
+            const_token: match mutability {
+                Mutability::Mutable(_) => None,
+                Mutability::Immutable => Some(tokens::Const::default()),
+            },
+            star_token: tokens::Star::default(),
             ty: Box::new(MutTy {
                 ty: target,
                 mutability: mutability,
@@ -372,97 +424,113 @@
                 ty: target,
                 mutability: mutability,
             }),
+            and_token: tokens::And::default(),
         }.into())
     ));
 
     named!(ty_bare_fn -> Ty, do_parse!(
-        lifetimes: opt_vec!(do_parse!(
-            keyword!("for") >>
-            punct!("<") >>
-            lifetimes: terminated_list!(punct!(","), lifetime_def) >>
-            punct!(">") >>
-            (lifetimes)
-        )) >>
+        lifetimes: bound_lifetimes >>
         unsafety: unsafety >>
         abi: option!(abi) >>
         keyword!("fn") >>
         punct!("(") >>
-        inputs: separated_list!(punct!(","), fn_arg) >>
-        trailing_comma: option!(punct!(",")) >>
-        variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 fn_arg) >>
+        variadic: option!(cond_reduce!(inputs.is_empty() || inputs.trailing_delim(),
+                                       punct!("..."))) >>
         punct!(")") >>
-        output: option!(preceded!(
-            punct!("->"),
-            ty
-        )) >>
+        output: fn_ret_ty >>
         (TyBareFn {
             ty: Box::new(BareFnTy {
                 unsafety: unsafety,
                 abi: abi,
                 lifetimes: lifetimes,
                 inputs: inputs,
-                output: match output {
-                    Some(ty) => FunctionRetTy::Ty(ty),
-                    None => FunctionRetTy::Default,
-                },
-                variadic: variadic.is_some(),
+                output: output,
+                variadic: variadic.map(|_| tokens::Dot3::default()),
+                fn_token: tokens::Fn::default(),
+                paren_token: tokens::Paren::default(),
             }),
         }.into())
     ));
 
-    named!(ty_never -> Ty, map!(punct!("!"), |_| TyNever {}.into()));
+    named!(ty_never -> Ty, map!(punct!("!"), |_| TyNever {
+        bang_token: tokens::Bang::default(),
+    }.into()));
 
     named!(ty_tup -> Ty, do_parse!(
         punct!("(") >>
-        elems: terminated_list!(punct!(","), ty) >>
+        elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                ty) >>
         punct!(")") >>
-        (TyTup { tys: elems }.into())
+        (TyTup {
+            tys: elems,
+            paren_token: tokens::Paren::default(),
+            lone_comma: None, // TODO: does this just not parse?
+        }.into())
     ));
 
     named!(ty_path -> Ty, do_parse!(
         qpath: qpath >>
         parenthesized: cond!(
-            qpath.1.segments.last().unwrap().parameters.is_empty(),
+            qpath.1.segments.get(qpath.1.segments.len() - 1).item().parameters.is_empty(),
             option!(parenthesized_parameter_data)
         ) >>
         bounds: many0!(preceded!(punct!("+"), ty_param_bound)) >>
         ({
             let (qself, mut path) = qpath;
             if let Some(Some(parenthesized)) = parenthesized {
-                path.segments.last_mut().unwrap().parameters = parenthesized;
+                let len = path.segments.len();
+                path.segments.get_mut(len - 1).item_mut().parameters = parenthesized;
             }
             if bounds.is_empty() {
                 TyPath { qself: qself, path: path }.into()
             } else {
                 let path = TyParamBound::Trait(
                     PolyTraitRef {
-                        bound_lifetimes: Vec::new(),
+                        bound_lifetimes: None,
                         trait_ref: path,
                     },
                     TraitBoundModifier::None,
                 );
-                let bounds = Some(path).into_iter().chain(bounds).collect();
-                TyTraitObject { bounds: bounds }.into()
+                let mut new_bounds = Delimited::new();
+                new_bounds.push_first(path);
+                for bound in bounds {
+                    new_bounds.push_default(bound);
+                }
+                TyTraitObject { bounds: new_bounds }.into()
             }
         })
     ));
 
     named!(parenthesized_parameter_data -> PathParameters, do_parse!(
         punct!("(") >>
-        inputs: terminated_list!(punct!(","), ty) >>
+        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
+                                 ty) >>
         punct!(")") >>
-        output: option!(preceded!(
-            punct!("->"),
-            ty
-        )) >>
+        output: fn_ret_ty >>
         (PathParameters::Parenthesized(
             ParenthesizedParameterData {
+                paren_token: tokens::Paren::default(),
                 inputs: inputs,
                 output: output,
             },
         ))
     ));
 
+    named!(pub fn_ret_ty -> FunctionRetTy, map!(
+        option!(preceded!(
+            punct!("->"),
+            ty
+        )),
+        |ty| {
+            match ty {
+                Some(ty) => FunctionRetTy::Ty(ty, tokens::RArrow::default()),
+                None => FunctionRetTy::Default,
+            }
+        }
+    ));
+
     named!(pub qpath -> (Option<QSelf>, Path), alt!(
         map!(path, |p| (None, p))
         |
@@ -475,21 +543,38 @@
             )) >>
             punct!(">") >>
             punct!("::") >>
-            rest: separated_nonempty_list!(punct!("::"), path_segment) >>
+            rest: separated_nonempty_list!(
+                map!(punct!("::"), |_| tokens::Colon2::default()),
+                path_segment
+            ) >>
             ({
-                match path {
+                let as_token = path.as_ref().map(|_| tokens::As::default());
+                let (pos, path) = match path {
                     Some(mut path) => {
                         let pos = path.segments.len();
-                        path.segments.extend(rest);
-                        (Some(QSelf { ty: this, position: pos }), path)
+                        if !path.segments.is_empty() && !path.segments.trailing_delim() {
+                            path.segments.push_trailing(tokens::Colon2::default());
+                        }
+                        for item in rest.into_iter() {
+                            path.segments.push(item);
+                        }
+                        (pos, path)
                     }
                     None => {
-                        (Some(QSelf { ty: this, position: 0 }), Path {
+                        (0, Path {
+                            leading_colon: None,
                             global: false,
                             segments: rest,
                         })
                     }
-                }
+                };
+                (Some(QSelf {
+                    ty: this,
+                    position: pos,
+                    gt_token: tokens::Gt::default(),
+                    lt_token: tokens::Lt::default(),
+                    as_token: as_token,
+                }), path)
             })
         )
         |
@@ -497,35 +582,45 @@
     ));
 
     named!(ty_poly_trait_ref -> Ty, map!(
-        separated_nonempty_list!(punct!("+"), ty_param_bound),
+        separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                 ty_param_bound),
         |x| TyTraitObject { bounds: x }.into()
     ));
 
     named!(ty_impl_trait -> Ty, do_parse!(
         keyword!("impl") >>
-        elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
-        (TyImplTrait { bounds: elem }.into())
+        elem: separated_nonempty_list!(map!(punct!("+"), |_| tokens::Add::default()),
+                                       ty_param_bound) >>
+        (TyImplTrait {
+            impl_token: tokens::Impl::default(),
+            bounds: elem,
+        }.into())
     ));
 
     named!(ty_paren -> Ty, do_parse!(
         punct!("(") >>
         elem: ty >>
         punct!(")") >>
-        (TyParen { ty: Box::new(elem) }.into())
+        (TyParen {
+            paren_token: tokens::Paren::default(),
+            ty: Box::new(elem),
+        }.into())
     ));
 
     named!(pub mutability -> Mutability, alt!(
-        keyword!("mut") => { |_| Mutability::Mutable }
+        keyword!("mut") => { |_| Mutability::Mutable(tokens::Mut::default()) }
         |
         epsilon!() => { |_| Mutability::Immutable }
     ));
 
     named!(pub path -> Path, do_parse!(
         global: option!(punct!("::")) >>
-        segments: separated_nonempty_list!(punct!("::"), path_segment) >>
+        segments: separated_nonempty_list!(map!(punct!("::"), |_| tokens::Colon2::default()),
+                                           path_segment) >>
         (Path {
             global: global.is_some(),
             segments: segments,
+            leading_colon: global.map(|_| tokens::Colon2::default()),
         })
     ));
 
@@ -533,27 +628,37 @@
         do_parse!(
             id: option!(ident) >>
             punct!("<") >>
-            lifetimes: separated_list!(punct!(","), lifetime) >>
-            types: opt_vec!(preceded!(
-                cond!(!lifetimes.is_empty(), punct!(",")),
-                separated_nonempty_list!(
-                    punct!(","),
+            lifetimes: terminated_list!(
+                map!(punct!(","), |_| tokens::Comma::default()),
+                lifetime
+            ) >>
+            types: cond!(
+                lifetimes.is_empty() || lifetimes.trailing_delim(),
+                terminated_list!(
+                    map!(punct!(","), |_| tokens::Comma::default()),
                     terminated!(ty, not!(punct!("=")))
                 )
-            )) >>
-            bindings: opt_vec!(preceded!(
-                cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
-                separated_nonempty_list!(punct!(","), type_binding)
-            )) >>
-            cond!(!lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty(), option!(punct!(","))) >>
+            ) >>
+            bindings: cond!(
+                match types {
+                    Some(ref t) => t.is_empty() || t.trailing_delim(),
+                    None => lifetimes.is_empty() || lifetimes.trailing_delim(),
+                },
+                terminated_list!(
+                    map!(punct!(","), |_| tokens::Comma::default()),
+                    type_binding
+                )
+            ) >>
             punct!(">") >>
             (PathSegment {
                 ident: id.unwrap_or_else(|| "".into()),
                 parameters: PathParameters::AngleBracketed(
                     AngleBracketedParameterData {
+                        gt_token: Some(tokens::Gt::default()),
+                        lt_token: Some(tokens::Lt::default()),
                         lifetimes: lifetimes,
-                        types: types,
-                        bindings: bindings,
+                        types: types.unwrap_or_default(),
+                        bindings: bindings.unwrap_or_default(),
                     }
                 ),
             })
@@ -572,10 +677,12 @@
 
     named!(pub mod_style_path -> Path, do_parse!(
         global: option!(punct!("::")) >>
-        segments: separated_nonempty_list!(punct!("::"), mod_style_path_segment) >>
+        segments: separated_nonempty_list!(map!(punct!("::"), |_| tokens::Colon2::default()),
+                                           mod_style_path_segment) >>
         (Path {
             global: global.is_some(),
             segments: segments,
+            leading_colon: global.map(|_| tokens::Colon2::default()),
         })
     ));
 
@@ -597,6 +704,7 @@
         ty: ty >>
         (TypeBinding {
             ident: id,
+            eq_token: tokens::Eq::default(),
             ty: ty,
         })
     ));
@@ -605,13 +713,14 @@
         bound_lifetimes: bound_lifetimes >>
         trait_ref: path >>
         parenthesized: option!(cond_reduce!(
-            trait_ref.segments.last().unwrap().parameters.is_empty(),
+            trait_ref.segments.get(trait_ref.segments.len() - 1).item().parameters.is_empty(),
             parenthesized_parameter_data
         )) >>
         ({
             let mut trait_ref = trait_ref;
             if let Some(parenthesized) = parenthesized {
-                trait_ref.segments.last_mut().unwrap().parameters = parenthesized;
+                let len = trait_ref.segments.len();
+                trait_ref.segments.get_mut(len - 1).item_mut().parameters = parenthesized;
             }
             PolyTraitRef {
                 bound_lifetimes: bound_lifetimes,
@@ -629,23 +738,26 @@
         )) >>
         ty: ty >>
         (BareFnArg {
-            name: name,
+            name: name.map(|t| (t, tokens::Colon::default())),
             ty: ty,
         })
     ));
 
     named!(pub unsafety -> Unsafety, alt!(
-        keyword!("unsafe") => { |_| Unsafety::Unsafe }
+        keyword!("unsafe") => { |_| Unsafety::Unsafe(tokens::Unsafe::default()) }
         |
         epsilon!() => { |_| Unsafety::Normal }
     ));
 
     named!(pub abi -> Abi, do_parse!(
         keyword!("extern") >>
-        name: option!(quoted_string) >>
-        (match name {
-            Some(name) => Abi::Named(name),
-            None => Abi::Rust,
+        name: option!(string) >>
+        (Abi {
+            extern_token: tokens::Extern::default(),
+            kind: match name {
+                Some(name) => AbiKind::Named(name),
+                None => AbiKind::Default,
+            },
         })
     ));
 }
@@ -657,41 +769,36 @@
 
     impl ToTokens for TySlice {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("[");
-            self.ty.to_tokens(tokens);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.ty.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for TyArray {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("[");
-            self.ty.to_tokens(tokens);
-            tokens.append(";");
-            self.amt.to_tokens(tokens);
-            tokens.append("]");
+            self.bracket_token.surround(tokens, |tokens| {
+                self.ty.to_tokens(tokens);
+                self.semi_token.to_tokens(tokens);
+                self.amt.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for TyPtr {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("*");
-            match self.ty.mutability {
-                Mutability::Mutable => tokens.append("mut"),
-                Mutability::Immutable => tokens.append("const"),
-            }
+            self.star_token.to_tokens(tokens);
+            self.const_token.to_tokens(tokens);
+            self.ty.mutability.to_tokens(tokens);
             self.ty.ty.to_tokens(tokens);
         }
     }
 
     impl ToTokens for TyRptr {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("&");
+            self.and_token.to_tokens(tokens);
             self.lifetime.to_tokens(tokens);
-            match self.ty.mutability {
-                Mutability::Mutable => tokens.append("mut"),
-                Mutability::Immutable => {}
-            }
+            self.ty.mutability.to_tokens(tokens);
             self.ty.ty.to_tokens(tokens);
         }
     }
@@ -704,44 +811,52 @@
 
     impl ToTokens for TyNever {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("!");
+            self.bang_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for TyTup {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            tokens.append_separated(&self.tys, ",");
-            if self.tys.len() == 1 {
-                tokens.append(",");
-            }
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.tys.to_tokens(tokens);
+                self.lone_comma.to_tokens(tokens);
+            })
         }
     }
 
     impl ToTokens for TyPath {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let qself = match self.qself {
+            PathTokens(&self.qself, &self.path).to_tokens(tokens);
+        }
+    }
+
+    impl<'a> ToTokens for PathTokens<'a> {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            let qself = match *self.0 {
                 Some(ref qself) => qself,
-                None => return self.path.to_tokens(tokens),
+                None => return self.1.to_tokens(tokens),
             };
-            tokens.append("<");
+            qself.lt_token.to_tokens(tokens);
             qself.ty.to_tokens(tokens);
             if qself.position > 0 {
-                tokens.append("as");
-                for (i, segment) in self.path.segments
+                qself.as_token.to_tokens(tokens);
+                self.1.leading_colon.to_tokens(tokens);
+                for (i, segment) in self.1.segments
                         .iter()
                         .take(qself.position)
                         .enumerate() {
-                    if i > 0 || self.path.global {
-                        tokens.append("::");
+                    if i == qself.position - 1 {
+                        segment.item().to_tokens(tokens);
+                        qself.gt_token.to_tokens(tokens);
+                        segment.delimiter().to_tokens(tokens);
+                    } else {
+                        segment.to_tokens(tokens);
                     }
-                    segment.to_tokens(tokens);
                 }
+            } else {
+                qself.gt_token.to_tokens(tokens);
             }
-            tokens.append(">");
-            for segment in self.path.segments.iter().skip(qself.position) {
-                tokens.append("::");
+            for segment in self.1.segments.iter().skip(qself.position) {
                 segment.to_tokens(tokens);
             }
         }
@@ -749,59 +864,50 @@
 
     impl ToTokens for TyTraitObject {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append_separated(&self.bounds, "+");
+            self.bounds.to_tokens(tokens);
         }
     }
 
     impl ToTokens for TyImplTrait {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("impl");
-            tokens.append_separated(&self.bounds, "+");
+            self.impl_token.to_tokens(tokens);
+            self.bounds.to_tokens(tokens);
         }
     }
 
     impl ToTokens for TyParen {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            self.ty.to_tokens(tokens);
-            tokens.append(")");
+            self.paren_token.surround(tokens, |tokens| {
+                self.ty.to_tokens(tokens);
+            });
         }
     }
 
     impl ToTokens for TyInfer {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("_");
+            self.underscore_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for Mutability {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Mutability::Mutable = *self {
-                tokens.append("mut");
+            if let Mutability::Mutable(ref t) = *self {
+                t.to_tokens(tokens);
             }
         }
     }
 
     impl ToTokens for Path {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            for (i, segment) in self.segments.iter().enumerate() {
-                if i > 0 || self.global {
-                    tokens.append("::");
-                }
-                segment.to_tokens(tokens);
-            }
+            self.leading_colon.to_tokens(tokens);
+            self.segments.to_tokens(tokens);
         }
     }
 
     impl ToTokens for PathSegment {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
-            if self.ident.as_ref().is_empty() && self.parameters.is_empty() {
-                tokens.append("<");
-                tokens.append(">");
-            } else {
-                self.parameters.to_tokens(tokens);
-            }
+            self.parameters.to_tokens(tokens);
         }
     }
 
@@ -820,106 +926,69 @@
 
     impl ToTokens for AngleBracketedParameterData {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            let has_lifetimes = !self.lifetimes.is_empty();
-            let has_types = !self.types.is_empty();
-            let has_bindings = !self.bindings.is_empty();
-            if !has_lifetimes && !has_types && !has_bindings {
-                return;
-            }
-
-            tokens.append("<");
-
-            let mut first = true;
-            for lifetime in &self.lifetimes {
-                if !first {
-                    tokens.append(",");
-                }
-                lifetime.to_tokens(tokens);
-                first = false;
-            }
-            for ty in &self.types {
-                if !first {
-                    tokens.append(",");
-                }
-                ty.to_tokens(tokens);
-                first = false;
-            }
-            for binding in &self.bindings {
-                if !first {
-                    tokens.append(",");
-                }
-                binding.to_tokens(tokens);
-                first = false;
-            }
-
-            tokens.append(">");
+            self.lt_token.to_tokens(tokens);
+            self.lifetimes.to_tokens(tokens);
+            self.types.to_tokens(tokens);
+            self.bindings.to_tokens(tokens);
+            self.gt_token.to_tokens(tokens);
         }
     }
 
     impl ToTokens for TypeBinding {
         fn to_tokens(&self, tokens: &mut Tokens) {
             self.ident.to_tokens(tokens);
-            tokens.append("=");
+            self.eq_token.to_tokens(tokens);
             self.ty.to_tokens(tokens);
         }
     }
 
     impl ToTokens for ParenthesizedParameterData {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("(");
-            tokens.append_separated(&self.inputs, ",");
-            tokens.append(")");
-            if let Some(ref output) = self.output {
-                tokens.append("->");
-                output.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.inputs.to_tokens(tokens);
+            });
+            self.output.to_tokens(tokens);
+        }
+    }
+
+    impl ToTokens for FunctionRetTy {
+        fn to_tokens(&self, tokens: &mut Tokens) {
+            match *self {
+                FunctionRetTy::Default => {}
+                FunctionRetTy::Ty(ref ty, ref arrow) => {
+                    arrow.to_tokens(tokens);
+                    ty.to_tokens(tokens);
+                }
             }
         }
     }
 
     impl ToTokens for PolyTraitRef {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if !self.bound_lifetimes.is_empty() {
-                tokens.append("for");
-                tokens.append("<");
-                tokens.append_separated(&self.bound_lifetimes, ",");
-                tokens.append(">");
-            }
+            self.bound_lifetimes.to_tokens(tokens);
             self.trait_ref.to_tokens(tokens);
         }
     }
 
     impl ToTokens for BareFnTy {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if !self.lifetimes.is_empty() {
-                tokens.append("for");
-                tokens.append("<");
-                tokens.append_separated(&self.lifetimes, ",");
-                tokens.append(">");
-            }
+            self.lifetimes.to_tokens(tokens);
             self.unsafety.to_tokens(tokens);
             self.abi.to_tokens(tokens);
-            tokens.append("fn");
-            tokens.append("(");
-            tokens.append_separated(&self.inputs, ",");
-            if self.variadic {
-                if !self.inputs.is_empty() {
-                    tokens.append(",");
-                }
-                tokens.append("...");
-            }
-            tokens.append(")");
-            if let FunctionRetTy::Ty(ref ty) = self.output {
-                tokens.append("->");
-                ty.to_tokens(tokens);
-            }
+            self.fn_token.to_tokens(tokens);
+            self.paren_token.surround(tokens, |tokens| {
+                self.inputs.to_tokens(tokens);
+                self.variadic.to_tokens(tokens);
+            });
+            self.output.to_tokens(tokens);
         }
     }
 
     impl ToTokens for BareFnArg {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            if let Some(ref name) = self.name {
+            if let Some((ref name, ref colon)) = self.name {
                 name.to_tokens(tokens);
-                tokens.append(":");
+                colon.to_tokens(tokens);
             }
             self.ty.to_tokens(tokens);
         }
@@ -928,7 +997,7 @@
     impl ToTokens for Unsafety {
         fn to_tokens(&self, tokens: &mut Tokens) {
             match *self {
-                Unsafety::Unsafe => tokens.append("unsafe"),
+                Unsafety::Unsafe(ref t) => t.to_tokens(tokens),
                 Unsafety::Normal => {
                     // nothing
                 }
@@ -938,10 +1007,10 @@
 
     impl ToTokens for Abi {
         fn to_tokens(&self, tokens: &mut Tokens) {
-            tokens.append("extern");
-            match *self {
-                Abi::Named(ref named) => named.to_tokens(tokens),
-                Abi::Rust => {}
+            self.extern_token.to_tokens(tokens);
+            match self.kind {
+                AbiKind::Named(ref named) => named.to_tokens(tokens),
+                AbiKind::Default => {}
             }
         }
     }
diff --git a/src/visit.rs b/src/visit.rs
index c2b6d53..df49e71 100644
--- a/src/visit.rs
+++ b/src/visit.rs
@@ -147,13 +147,15 @@
 
 pub fn walk_lifetime_def<V: Visitor>(visitor: &mut V, lifetime_def: &LifetimeDef) {
     visitor.visit_lifetime(&lifetime_def.lifetime);
-    walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
+    walk_list!(visitor, visit_lifetime, lifetime_def.bounds.items());
 }
 
 pub fn walk_poly_trait_ref<V>(visitor: &mut V, trait_ref: &PolyTraitRef, _: &TraitBoundModifier)
     where V: Visitor
 {
-    walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
+    if let Some(ref bl) = trait_ref.bound_lifetimes {
+        walk_list!(visitor, visit_lifetime_def, bl.lifetimes.items());
+    }
     visitor.visit_path(&trait_ref.trait_ref);
 }
 
@@ -161,11 +163,13 @@
     visitor.visit_ident(&derive_input.ident);
     visitor.visit_generics(&derive_input.generics);
     match derive_input.body {
-        Body::Enum(ref variants) => {
-            walk_list!(visitor, visit_variant, variants, &derive_input.generics);
+        Body::Enum(ref data) => {
+            walk_list!(visitor, visit_variant,
+                       data.variants.items(),
+                       &derive_input.generics);
         }
-        Body::Struct(ref variant_data) => {
-            visitor.visit_variant_data(variant_data, &derive_input.ident, &derive_input.generics);
+        Body::Struct(ref data) => {
+            visitor.visit_variant_data(&data.data, &derive_input.ident, &derive_input.generics);
         }
     }
     walk_list!(visitor, visit_attribute, &derive_input.attrs);
@@ -183,21 +187,25 @@
     use ty::*;
 
     match *ty {
-        Ty::Slice(TySlice { ref ty }) |
-        Ty::Paren(TyParen { ref ty }) => visitor.visit_ty(ty),
-        Ty::Ptr(TyPtr { ref ty }) => visitor.visit_ty(&ty.ty),
-        Ty::Rptr(TyRptr { ref lifetime, ref ty }) => {
+        Ty::Slice(TySlice { ref ty, .. }) |
+        Ty::Paren(TyParen { ref ty, .. }) => visitor.visit_ty(ty),
+        Ty::Ptr(TyPtr { ref ty, .. }) => visitor.visit_ty(&ty.ty),
+        Ty::Rptr(TyRptr { ref lifetime, ref ty, .. }) => {
             walk_list!(visitor, visit_lifetime, lifetime);
             visitor.visit_ty(&ty.ty)
         }
         Ty::Never(_) | Ty::Infer(_) => {}
-        Ty::Tup(TyTup { ref tys }) => {
-            walk_list!(visitor, visit_ty, tys);
+        Ty::Tup(TyTup { ref tys, .. }) => {
+            walk_list!(visitor, visit_ty, tys.items());
         }
         Ty::BareFn(TyBareFn { ref ty }) => {
-            walk_list!(visitor, visit_lifetime_def, &ty.lifetimes);
-            for argument in &ty.inputs {
-                walk_opt_ident(visitor, &argument.name);
+            if let Some(ref l) = ty.lifetimes {
+                walk_list!(visitor, visit_lifetime_def, l.lifetimes.items());
+            }
+            for argument in ty.inputs.items() {
+                if let Some((ref name, _)) = argument.name {
+                    visitor.visit_ident(name);
+                }
                 visitor.visit_ty(&argument.ty)
             }
             visitor.visit_fn_ret_ty(&ty.output)
@@ -208,13 +216,13 @@
             }
             visitor.visit_path(path);
         }
-        Ty::Array(TyArray { ref ty, ref amt }) => {
+        Ty::Array(TyArray { ref ty, ref amt, .. }) => {
             visitor.visit_ty(ty);
             visitor.visit_const_expr(amt);
         }
-        Ty::TraitObject(TyTraitObject { ref bounds })  |
-        Ty::ImplTrait(TyImplTrait { ref bounds }) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+        Ty::TraitObject(TyTraitObject { ref bounds, .. })  |
+        Ty::ImplTrait(TyImplTrait { ref bounds, .. }) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds.items());
         }
         Ty::Mac(ref mac) => {
             visitor.visit_mac(mac);
@@ -223,7 +231,7 @@
 }
 
 pub fn walk_path<V: Visitor>(visitor: &mut V, path: &Path) {
-    for segment in &path.segments {
+    for segment in path.segments.items() {
         visitor.visit_path_segment(segment);
     }
 }
@@ -238,13 +246,13 @@
 {
     match *path_parameters {
         PathParameters::AngleBracketed(ref data) => {
-            walk_list!(visitor, visit_ty, &data.types);
-            walk_list!(visitor, visit_lifetime, &data.lifetimes);
-            walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
+            walk_list!(visitor, visit_ty, data.types.items());
+            walk_list!(visitor, visit_lifetime, data.lifetimes.items());
+            walk_list!(visitor, visit_assoc_type_binding, data.bindings.items());
         }
         PathParameters::Parenthesized(ref data) => {
-            walk_list!(visitor, visit_ty, &data.inputs);
-            walk_list!(visitor, visit_ty, &data.output);
+            walk_list!(visitor, visit_ty, data.inputs.items());
+            visitor.visit_fn_ret_ty(&data.output);
         }
     }
 }
@@ -266,27 +274,29 @@
 }
 
 pub fn walk_generics<V: Visitor>(visitor: &mut V, generics: &Generics) {
-    for param in &generics.ty_params {
+    for param in generics.ty_params.items() {
         visitor.visit_ident(&param.ident);
-        walk_list!(visitor, visit_ty_param_bound, &param.bounds);
+        walk_list!(visitor, visit_ty_param_bound, param.bounds.items());
         walk_list!(visitor, visit_ty, &param.default);
     }
-    walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
-    for predicate in &generics.where_clause.predicates {
+    walk_list!(visitor, visit_lifetime_def, generics.lifetimes.items());
+    for predicate in generics.where_clause.predicates.items() {
         match *predicate {
             WherePredicate::BoundPredicate(WhereBoundPredicate { ref bounded_ty,
                                                                  ref bounds,
                                                                  ref bound_lifetimes,
                                                                  .. }) => {
                 visitor.visit_ty(bounded_ty);
-                walk_list!(visitor, visit_ty_param_bound, bounds);
-                walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+                walk_list!(visitor, visit_ty_param_bound, bounds.items());
+                if let Some(ref l) = *bound_lifetimes {
+                    walk_list!(visitor, visit_lifetime_def, l.lifetimes.items());
+                }
             }
             WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime,
                                                                    ref bounds,
                                                                    .. }) => {
                 visitor.visit_lifetime(lifetime);
-                walk_list!(visitor, visit_lifetime, bounds);
+                walk_list!(visitor, visit_lifetime, bounds.items());
             }
             WherePredicate::EqPredicate(WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => {
                 visitor.visit_ty(lhs_ty);
@@ -297,13 +307,18 @@
 }
 
 pub fn walk_fn_ret_ty<V: Visitor>(visitor: &mut V, ret_ty: &FunctionRetTy) {
-    if let FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+    if let FunctionRetTy::Ty(ref output_ty, _) = *ret_ty {
         visitor.visit_ty(output_ty)
     }
 }
 
 pub fn walk_variant_data<V: Visitor>(visitor: &mut V, data: &VariantData) {
-    walk_list!(visitor, visit_field, data.fields());
+    let fields = match *data {
+        VariantData::Struct(ref f, _) |
+        VariantData::Tuple(ref f, _) => f,
+        VariantData::Unit => return,
+    };
+    walk_list!(visitor, visit_field, fields.items());
 }
 
 pub fn walk_field<V: Visitor>(visitor: &mut V, field: &Field) {
@@ -317,9 +332,9 @@
     use constant::ConstExpr::*;
 
     match *len {
-        Call(ConstCall { ref func, ref args }) => {
+        Call(ConstCall { ref func, ref args, .. }) => {
             visitor.visit_const_expr(func);
-            walk_list!(visitor, visit_const_expr, args);
+            walk_list!(visitor, visit_const_expr, args.items());
         }
         Binary(ConstBinary { ref left, ref right, .. }) => {
             visitor.visit_const_expr(left);
@@ -328,19 +343,19 @@
         Lit(ref lit) => {
             visitor.visit_lit(lit);
         }
-        Cast(ConstCast { ref expr, ref ty }) => {
+        Cast(ConstCast { ref expr, ref ty, .. }) => {
             visitor.visit_const_expr(expr);
             visitor.visit_ty(ty);
         }
         Path(ref path) => {
             visitor.visit_path(path);
         }
-        Index(ConstIndex { ref expr, ref index }) => {
+        Index(ConstIndex { ref expr, ref index, .. }) => {
             visitor.visit_const_expr(expr);
             visitor.visit_const_expr(index);
         }
         Unary(ConstUnary { ref expr, .. }) |
-        Paren(ConstParen { ref expr }) => {
+        Paren(ConstParen { ref expr, .. }) => {
             visitor.visit_const_expr(expr);
         }
         Other(ref other) => {
@@ -372,39 +387,38 @@
     visitor.visit_ident(&item.ident);
     walk_list!(visitor, visit_attribute, &item.attrs);
     match item.node {
-        ItemKind::ExternCrate(ItemExternCrate { ref original }) => {
+        ItemKind::ExternCrate(ItemExternCrate { ref original, .. }) => {
             walk_opt_ident(visitor, original);
         }
-        ItemKind::Use(ItemUse { ref path }) => {
+        ItemKind::Use(ItemUse { ref path, .. }) => {
             visitor.visit_view_path(path);
         }
         ItemKind::Static(ItemStatic { ref ty, ref expr, .. }) |
-        ItemKind::Const(ItemConst { ref ty, ref expr }) => {
+        ItemKind::Const(ItemConst { ref ty, ref expr, .. }) => {
             visitor.visit_ty(ty);
             visitor.visit_expr(expr);
         }
-        ItemKind::Fn(ItemFn { ref decl, ref generics, ref block, ..  }) => {
+        ItemKind::Fn(ItemFn { ref decl, ref block, ..  }) => {
             visitor.visit_fn_decl(decl);
-            visitor.visit_generics(generics);
             walk_list!(visitor, visit_stmt, &block.stmts);
         }
-        ItemKind::Mod(ItemMod { ref items }) => {
-            if let Some(ref items) = *items {
+        ItemKind::Mod(ItemMod { ref items, .. }) => {
+            if let Some((ref items, _)) = *items {
                 walk_list!(visitor, visit_item, items);
             }
         }
         ItemKind::ForeignMod(ItemForeignMod { ref items, .. }) => {
             walk_list!(visitor, visit_foreign_item, items);
         }
-        ItemKind::Ty(ItemTy { ref ty, ref generics }) => {
+        ItemKind::Ty(ItemTy { ref ty, ref generics, .. }) => {
             visitor.visit_ty(ty);
             visitor.visit_generics(generics);
         }
-        ItemKind::Enum(ItemEnum { ref variants, ref generics }) => {
-            walk_list!(visitor, visit_variant, variants, generics);
+        ItemKind::Enum(ItemEnum { ref variants, ref generics, ..}) => {
+            walk_list!(visitor, visit_variant, variants.items(), generics);
         }
-        ItemKind::Struct(ItemStruct { ref data, ref generics }) |
-        ItemKind::Union(ItemUnion { ref data, ref generics }) => {
+        ItemKind::Struct(ItemStruct { ref data, ref generics, .. }) |
+        ItemKind::Union(ItemUnion { ref data, ref generics, .. }) => {
             visitor.visit_variant_data(data, &item.ident, generics);
         }
         ItemKind::Trait(ItemTrait {
@@ -414,7 +428,7 @@
             ..
         }) => {
             visitor.visit_generics(generics);
-            walk_list!(visitor, visit_ty_param_bound, supertraits);
+            walk_list!(visitor, visit_ty_param_bound, supertraits.items());
             walk_list!(visitor, visit_trait_item, items);
         }
         ItemKind::DefaultImpl(ItemDefaultImpl { ref path, .. }) => {
@@ -446,39 +460,39 @@
 
     walk_list!(visitor, visit_attribute, &expr.attrs);
     match expr.node {
-        InPlace(ExprInPlace { ref place, ref value }) => {
+        InPlace(ExprInPlace { ref place, ref value, .. }) => {
             visitor.visit_expr(place);
             visitor.visit_expr(value);
         }
-        Call(ExprCall { ref func, ref args }) => {
+        Call(ExprCall { ref func, ref args, .. }) => {
             visitor.visit_expr(func);
-            walk_list!(visitor, visit_expr, args);
+            walk_list!(visitor, visit_expr, args.items());
         }
-        MethodCall(ExprMethodCall { ref method, ref typarams, ref args }) => {
+        MethodCall(ExprMethodCall { ref method, ref typarams, ref args, .. }) => {
             visitor.visit_ident(method);
-            walk_list!(visitor, visit_ty, typarams);
-            walk_list!(visitor, visit_expr, args);
+            walk_list!(visitor, visit_ty, typarams.items());
+            walk_list!(visitor, visit_expr, args.items());
         }
-        Array(ExprArray { ref exprs }) |
-        Tup(ExprTup { args: ref exprs }) => {
-            walk_list!(visitor, visit_expr, exprs);
+        Array(ExprArray { ref exprs, ..}) |
+        Tup(ExprTup { args: ref exprs, .. }) => {
+            walk_list!(visitor, visit_expr, exprs.items());
         }
         Lit(ref lit) => {
             visitor.visit_lit(lit);
         }
-        Cast(ExprCast { ref expr, ref ty }) |
-        Type(ExprType { ref expr, ref ty }) => {
+        Cast(ExprCast { ref expr, ref ty, .. }) |
+        Type(ExprType { ref expr, ref ty, .. }) => {
             visitor.visit_expr(expr);
             visitor.visit_ty(ty);
         }
-        If(ExprIf { ref cond, ref if_true, ref if_false }) => {
+        If(ExprIf { ref cond, ref if_true, ref if_false, .. }) => {
             visitor.visit_expr(cond);
             walk_list!(visitor, visit_stmt, &if_true.stmts);
             if let Some(ref alt) = *if_false {
                 visitor.visit_expr(alt);
             }
         }
-        IfLet(ExprIfLet { ref pat, ref expr, ref if_true, ref if_false }) => {
+        IfLet(ExprIfLet { ref pat, ref expr, ref if_true, ref if_false, .. }) => {
             visitor.visit_pat(pat);
             visitor.visit_expr(expr);
             walk_list!(visitor, visit_stmt, &if_true.stmts);
@@ -486,27 +500,27 @@
                 visitor.visit_expr(alt);
             }
         }
-        While(ExprWhile { ref cond, ref body, ref label }) => {
+        While(ExprWhile { ref cond, ref body, ref label, .. }) => {
             visitor.visit_expr(cond);
             walk_list!(visitor, visit_stmt, &body.stmts);
             walk_opt_ident(visitor, label);
         }
-        WhileLet(ExprWhileLet { ref pat, ref expr, ref body, ref label }) |
-        ForLoop(ExprForLoop { ref pat, ref expr, ref body, ref label }) => {
+        WhileLet(ExprWhileLet { ref pat, ref expr, ref body, ref label, .. }) |
+        ForLoop(ExprForLoop { ref pat, ref expr, ref body, ref label, .. }) => {
             visitor.visit_pat(pat);
             visitor.visit_expr(expr);
             walk_list!(visitor, visit_stmt, &body.stmts);
             walk_opt_ident(visitor, label);
         }
-        Loop(ExprLoop { ref body, ref label }) => {
+        Loop(ExprLoop { ref body, ref label, .. }) => {
             walk_list!(visitor, visit_stmt, &body.stmts);
             walk_opt_ident(visitor, label);
         }
-        Match(ExprMatch { ref expr, ref arms }) => {
+        Match(ExprMatch { ref expr, ref arms, .. }) => {
             visitor.visit_expr(expr);
-            for &Arm { ref attrs, ref pats, ref guard, ref body } in arms {
+            for &Arm { ref attrs, ref pats, ref guard, ref body, .. } in arms {
                 walk_list!(visitor, visit_attribute, attrs);
-                walk_list!(visitor, visit_pat, pats);
+                walk_list!(visitor, visit_pat, pats.items());
                 if let Some(ref guard) = *guard {
                     visitor.visit_expr(guard);
                 }
@@ -517,21 +531,21 @@
             visitor.visit_fn_decl(decl);
             visitor.visit_expr(body);
         }
-        Catch(ExprCatch { ref block }) |
+        Catch(ExprCatch { ref block, .. }) |
         Block(ExprBlock { ref block, .. }) => {
             walk_list!(visitor, visit_stmt, &block.stmts);
         }
         Binary(ExprBinary { ref left, ref right, .. }) |
-        Assign(ExprAssign { ref left, ref right }) |
+        Assign(ExprAssign { ref left, ref right, .. }) |
         AssignOp(ExprAssignOp { ref left, ref right, .. }) => {
             visitor.visit_expr(left);
             visitor.visit_expr(right);
         }
-        Field(ExprField { ref expr, ref field }) => {
+        Field(ExprField { ref expr, ref field, .. }) => {
             visitor.visit_expr(expr);
             visitor.visit_ident(field);
         }
-        Index(ExprIndex { ref expr, ref index }) => {
+        Index(ExprIndex { ref expr, ref index, .. }) => {
             visitor.visit_expr(expr);
             visitor.visit_expr(index);
         }
@@ -549,16 +563,16 @@
             }
             visitor.visit_path(path);
         }
-        Break(ExprBreak { ref label, ref expr }) => {
+        Break(ExprBreak { ref label, ref expr, .. }) => {
             walk_opt_ident(visitor, label);
             if let Some(ref expr) = *expr {
                 visitor.visit_expr(expr);
             }
         }
-        Continue(ExprContinue { ref label }) => {
+        Continue(ExprContinue { ref label, .. }) => {
             walk_opt_ident(visitor, label);
         }
-        Ret(ExprRet { ref expr }) => {
+        Ret(ExprRet { ref expr, .. }) => {
             if let Some(ref expr) = *expr {
                 visitor.visit_expr(expr);
             }
@@ -566,9 +580,9 @@
         Mac(ref mac) => {
             visitor.visit_mac(mac);
         }
-        Struct(ExprStruct { ref path, ref fields, ref rest }) => {
+        Struct(ExprStruct { ref path, ref fields, ref rest, .. }) => {
             visitor.visit_path(path);
-            for &FieldValue { ref ident, ref expr, .. } in fields {
+            for &FieldValue { ref ident, ref expr, .. } in fields.items() {
                 visitor.visit_ident(ident);
                 visitor.visit_expr(expr);
             }
@@ -576,16 +590,16 @@
                 visitor.visit_expr(base);
             }
         }
-        Repeat(ExprRepeat { ref expr, ref amt }) => {
+        Repeat(ExprRepeat { ref expr, ref amt, .. }) => {
             visitor.visit_expr(expr);
             visitor.visit_expr(amt);
         }
         TupField(ExprTupField { ref expr, .. }) |
         Unary(ExprUnary { ref expr, .. }) |
-        Box(ExprBox { ref expr }) |
+        Box(ExprBox { ref expr, .. }) |
         AddrOf(ExprAddrOf { ref expr, .. }) |
-        Paren(ExprParen { ref expr }) |
-        Try(ExprTry { ref expr }) => {
+        Paren(ExprParen { ref expr, .. }) |
+        Try(ExprTry { ref expr, .. }) => {
             visitor.visit_expr(expr);
         }
     }
@@ -598,9 +612,8 @@
     visitor.visit_ident(&foreign_item.ident);
     walk_list!(visitor, visit_attribute, &foreign_item.attrs);
     match foreign_item.node {
-        ForeignItemKind::Fn(ForeignItemFn { ref decl, ref generics }) => {
+        ForeignItemKind::Fn(ForeignItemFn { ref decl, .. }) => {
             visitor.visit_fn_decl(decl);
-            visitor.visit_generics(generics);
         }
         ForeignItemKind::Static(ForeignItemStatic { ref ty, .. }) => {
             visitor.visit_ty(ty);
@@ -610,51 +623,53 @@
 
 #[cfg(feature = "full")]
 pub fn walk_pat<V: Visitor>(visitor: &mut V, pat: &Pat) {
+    use expr::*;
+
     match *pat {
-        Pat::Wild => {}
-        Pat::Ident(_, ref ident, ref maybe_pat) => {
+        Pat::Wild(_) => {}
+        Pat::Ident(PatIdent { ref ident, ref subpat, .. }) => {
             visitor.visit_ident(ident);
-            if let Some(ref pat) = *maybe_pat {
+            if let Some(ref pat) = *subpat {
                 visitor.visit_pat(pat);
             }
         }
-        Pat::Struct(ref path, ref field_pats, _) => {
+        Pat::Struct(PatStruct { ref path, ref fields, .. }) => {
             visitor.visit_path(path);
-            for &FieldPat { ref ident, ref pat, .. } in field_pats {
+            for &FieldPat { ref ident, ref pat, .. } in fields.items() {
                 visitor.visit_ident(ident);
                 visitor.visit_pat(pat);
             }
         }
-        Pat::TupleStruct(ref path, ref pats, _) => {
+        Pat::TupleStruct(PatTupleStruct { ref path, ref pat, .. }) => {
             visitor.visit_path(path);
-            walk_list!(visitor, visit_pat, pats);
+            walk_list!(visitor, visit_pat, pat.pats.items());
         }
-        Pat::Path(ref maybe_qself, ref path) => {
-            if let Some(ref qself) = *maybe_qself {
+        Pat::Path(PatPath { ref qself, ref path }) => {
+            if let Some(ref qself) = *qself {
                 visitor.visit_ty(&qself.ty);
             }
             visitor.visit_path(path);
         }
-        Pat::Tuple(ref pats, _) => {
-            walk_list!(visitor, visit_pat, pats);
+        Pat::Tuple(PatTuple { ref pats, .. }) => {
+            walk_list!(visitor, visit_pat, pats.items());
         }
-        Pat::Box(ref pat) |
-        Pat::Ref(ref pat, _) => {
+        Pat::Box(PatBox { ref pat, .. }) |
+        Pat::Ref(PatRef { ref pat, .. }) => {
             visitor.visit_pat(pat);
         }
-        Pat::Lit(ref expr) => {
+        Pat::Lit(PatLit { ref expr }) => {
             visitor.visit_expr(expr);
         }
-        Pat::Range(ref start, ref end, _) => {
-            visitor.visit_expr(start);
-            visitor.visit_expr(end);
+        Pat::Range(PatRange { ref lo, ref hi, .. }) => {
+            visitor.visit_expr(lo);
+            visitor.visit_expr(hi);
         }
-        Pat::Slice(ref start, ref maybe_mid, ref end) => {
-            walk_list!(visitor, visit_pat, start);
-            if let Some(ref mid) = *maybe_mid {
+        Pat::Slice(PatSlice { ref front, ref middle, ref back, .. }) => {
+            walk_list!(visitor, visit_pat, front.items());
+            if let Some(ref mid) = *middle {
                 visitor.visit_pat(mid);
             }
-            walk_list!(visitor, visit_pat, end);
+            walk_list!(visitor, visit_pat, back.items());
         }
         Pat::Mac(ref mac) => {
             visitor.visit_mac(mac);
@@ -666,11 +681,11 @@
 pub fn walk_fn_decl<V: Visitor>(visitor: &mut V, fn_decl: &FnDecl) {
     use item::*;
 
-    for input in &fn_decl.inputs {
+    for input in fn_decl.inputs.items() {
         match *input {
             FnArg::SelfRef(_) |
             FnArg::SelfValue(_) => {}
-            FnArg::Captured(ArgCaptured { ref pat, ref ty }) => {
+            FnArg::Captured(ArgCaptured { ref pat, ref ty, .. }) => {
                 visitor.visit_pat(pat);
                 visitor.visit_ty(ty);
             }
@@ -679,6 +694,7 @@
             }
         }
     }
+    visitor.visit_generics(&fn_decl.generics);
     visitor.visit_fn_ret_ty(&fn_decl.output);
 }
 
@@ -689,20 +705,20 @@
     visitor.visit_ident(&trait_item.ident);
     walk_list!(visitor, visit_attribute, &trait_item.attrs);
     match trait_item.node {
-        TraitItemKind::Const(TraitItemConst { ref ty, ref default }) => {
+        TraitItemKind::Const(TraitItemConst { ref ty, ref default, ..}) => {
             visitor.visit_ty(ty);
             if let Some(ref expr) = *default {
                 visitor.visit_expr(expr);
             }
         }
-        TraitItemKind::Method(TraitItemMethod { ref sig, ref default }) => {
+        TraitItemKind::Method(TraitItemMethod { ref sig, ref default, .. }) => {
             visitor.visit_method_sig(sig);
             if let Some(ref block) = *default {
                 walk_list!(visitor, visit_stmt, &block.stmts);
             }
         }
-        TraitItemKind::Type(TraitItemType { ref bounds, ref default }) => {
-            walk_list!(visitor, visit_ty_param_bound, bounds);
+        TraitItemKind::Type(TraitItemType { ref bounds, ref default, .. }) => {
+            walk_list!(visitor, visit_ty_param_bound, bounds.items());
             if let Some(ref ty) = *default {
                 visitor.visit_ty(ty);
             }
@@ -720,15 +736,15 @@
     visitor.visit_ident(&impl_item.ident);
     walk_list!(visitor, visit_attribute, &impl_item.attrs);
     match impl_item.node {
-        ImplItemKind::Const(ImplItemConst { ref ty, ref expr }) => {
+        ImplItemKind::Const(ImplItemConst { ref ty, ref expr, .. }) => {
             visitor.visit_ty(ty);
             visitor.visit_expr(expr);
         }
-        ImplItemKind::Method(ImplItemMethod { ref sig, ref block }) => {
+        ImplItemKind::Method(ImplItemMethod { ref sig, ref block, .. }) => {
             visitor.visit_method_sig(sig);
             walk_list!(visitor, visit_stmt, &block.stmts);
         }
-        ImplItemKind::Type(ImplItemType { ref ty }) => {
+        ImplItemKind::Type(ImplItemType { ref ty, .. }) => {
             visitor.visit_ty(ty);
         }
         ImplItemKind::Macro(ref mac) => {
@@ -740,7 +756,6 @@
 #[cfg(feature = "full")]
 pub fn walk_method_sig<V: Visitor>(visitor: &mut V, method_sig: &MethodSig) {
     visitor.visit_fn_decl(&method_sig.decl);
-    visitor.visit_generics(&method_sig.generics);
 }
 
 #[cfg(feature = "full")]
@@ -753,7 +768,7 @@
             visitor.visit_item(item);
         }
         Stmt::Expr(ref expr) |
-        Stmt::Semi(ref expr) => {
+        Stmt::Semi(ref expr, _) => {
             visitor.visit_expr(expr);
         }
         Stmt::Mac(ref details) => {
@@ -780,16 +795,16 @@
 pub fn walk_view_path<V: Visitor>(visitor: &mut V, view_path: &ViewPath) {
     use item::*;
     match *view_path {
-        ViewPath::Simple(PathSimple { ref path, ref rename }) => {
+        ViewPath::Simple(PathSimple { ref path, ref rename, .. }) => {
             visitor.visit_path(path);
             walk_opt_ident(visitor, rename);
         }
-        ViewPath::Glob(PathGlob { ref path }) => {
+        ViewPath::Glob(PathGlob { ref path, .. }) => {
             visitor.visit_path(path);
         }
-        ViewPath::List(PathList { ref path, ref items }) => {
+        ViewPath::List(PathList { ref path, ref items, .. }) => {
             visitor.visit_path(path);
-            for &PathListItem { ref name, ref rename } in items {
+            for &PathListItem { ref name, ref rename, .. } in items.items() {
                 visitor.visit_ident(name);
                 walk_opt_ident(visitor, rename);
             }