Finish porting to the `Synom` trait
diff --git a/src/expr.rs b/src/expr.rs
index 6ec7253..23f2faa 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -26,7 +26,7 @@
         /// A `box x` expression.
         pub Box(ExprBox {
             pub expr: Box<Expr>,
-            pub box_token: tokens::Box,
+            pub box_token: tokens::Box_,
         }),
 
         /// E.g. 'place <- val'.
@@ -485,7 +485,7 @@
         /// A `box` pattern
         pub Box(PatBox {
             pub pat: Box<Pat>,
-            pub box_token: tokens::Box,
+            pub box_token: tokens::Box_,
         }),
         /// A reference pattern, e.g. `&mut (a, b)`
         pub Ref(PatRef {
@@ -587,20 +587,11 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    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::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 synom::{self, IResult};
+    use ty::parsing::qpath;
 
-    use proc_macro2::{self, TokenKind, Delimiter};
+    use proc_macro2::{TokenTree, TokenStream, TokenKind, Delimiter};
+    use synom::{IResult, Synom};
+    use synom::tokens::*;
 
     // Struct literals are ambiguous in certain positions
     // https://github.com/rust-lang/rfcs/pull/92
@@ -619,7 +610,16 @@
         };
     }
 
-    named!(pub expr -> Expr, ambiguous_expr!(true));
+    impl Synom for Expr {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            ambiguous_expr!(input, true)
+        }
+
+        fn description() -> Option<&'static str> {
+            Some("expression")
+        }
+    }
+
 
     named!(expr_no_struct -> Expr, ambiguous_expr!(false));
 
@@ -628,56 +628,61 @@
                       allow_struct: bool,
                       allow_block: bool)
                       -> IResult<&[synom::TokenTree], Expr> {
-        do_parse!(
+        do_parse! {
             i,
             mut e: alt!(
-                expr_lit // must be before expr_struct
+                syn!(Lit) => { ExprKind::Lit } // must be before expr_struct
                 |
-                cond_reduce!(allow_struct, expr_struct) // must be before expr_path
+                // must be before expr_path
+                cond_reduce!(allow_struct, map!(syn!(ExprStruct), ExprKind::Struct))
                 |
-                expr_paren // must be before expr_tup
+                syn!(ExprParen) => { ExprKind::Paren } // must be before expr_tup
                 |
-                expr_mac // must be before expr_path
+                syn!(Mac) => { ExprKind::Mac } // must be before expr_path
                 |
                 call!(expr_break, allow_struct) // must be before expr_path
                 |
-                expr_continue // must be before expr_path
+                syn!(ExprContinue) => { ExprKind::Continue } // must be before expr_path
                 |
                 call!(expr_ret, allow_struct) // must be before expr_path
                 |
                 call!(expr_box, allow_struct)
                 |
-                expr_in_place
+                syn!(ExprInPlace) => { ExprKind::InPlace }
                 |
-                expr_array
+                syn!(ExprArray) => { ExprKind::Array }
                 |
-                expr_tup
+                syn!(ExprTup) => { ExprKind::Tup }
                 |
                 call!(expr_unary, allow_struct)
                 |
-                expr_if
+                syn!(ExprIf) => { ExprKind::If }
                 |
-                expr_while
+                syn!(ExprIfLet) => { ExprKind::IfLet }
                 |
-                expr_for_loop
+                syn!(ExprWhile) => { ExprKind::While }
                 |
-                expr_loop
+                syn!(ExprWhileLet) => { ExprKind::WhileLet }
                 |
-                expr_match
+                syn!(ExprForLoop) => { ExprKind::ForLoop }
                 |
-                expr_catch
+                syn!(ExprLoop) => { ExprKind::Loop }
+                |
+                syn!(ExprMatch) => { ExprKind::Match }
+                |
+                syn!(ExprCatch) => { ExprKind::Catch }
                 |
                 call!(expr_closure, allow_struct)
                 |
-                cond_reduce!(allow_block, expr_block)
+                cond_reduce!(allow_block, map!(syn!(ExprBlock), ExprKind::Block))
                 |
                 call!(expr_range, allow_struct)
                 |
-                expr_path
+                syn!(ExprPath) => { ExprKind::Path }
                 |
                 call!(expr_addr_of, allow_struct)
                 |
-                expr_repeat
+                syn!(ExprRepeat) => { ExprKind::Repeat }
             ) >>
             many0!(alt!(
                 tap!(args: and_call => {
@@ -776,287 +781,315 @@
                     }.into();
                 })
                 |
-                tap!(_try: punct!("?") => {
+                tap!(question: syn!(Question) => {
                     e = ExprTry {
                         expr: Box::new(e.into()),
-                        question_token: tokens::Question::default(),
+                        question_token: question,
                     }.into();
                 })
             )) >>
             (e.into())
-        )
+        }
     }
 
-    named!(expr_mac -> ExprKind, map!(mac, ExprKind::Mac));
-
-    named!(expr_paren -> ExprKind, do_parse!(
-        punct!("(") >>
-        e: expr >>
-        punct!(")") >>
-        (ExprParen {
-            expr: Box::new(e),
-            paren_token: tokens::Paren::default(),
-        }.into())
-    ));
+    impl Synom for ExprParen {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                e: parens!(syn!(Expr)) >>
+                (ExprParen {
+                    expr: Box::new(e.0),
+                    paren_token: e.1,
+                }.into())
+            }
+        }
+    }
 
     named_ambiguous_expr!(expr_box -> ExprKind, allow_struct, do_parse!(
-        keyword!("box") >>
+        box_: syn!(Box_) >>
         inner: ambiguous_expr!(allow_struct) >>
         (ExprBox {
             expr: Box::new(inner),
-            box_token: tokens::Box::default(),
+            box_token: box_,
         }.into())
     ));
 
-    named!(expr_in_place -> ExprKind, do_parse!(
-        keyword!("in") >>
-        place: expr_no_struct >>
-        punct!("{") >>
-        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,
-                        brace_token: tokens::Brace::default(),
-                    },
-                }.into(),
-                attrs: Vec::new(),
-            }),
-        }.into())
-    ));
+    impl Synom for ExprInPlace {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                in_: syn!(In) >>
+                place: expr_no_struct >>
+                value: braces!(call!(Block::parse_within)) >>
+                (ExprInPlace {
+                    in_token: in_,
+                    place: Box::new(place),
+                    value: Box::new(Expr {
+                        node: ExprBlock {
+                            unsafety: Unsafety::Normal,
+                            block: Block {
+                                stmts: value.0,
+                                brace_token: value.1,
+                            },
+                        }.into(),
+                        attrs: Vec::new(),
+                    }),
+                })
+            }
+        }
+    }
 
-    named!(expr_array -> ExprKind, do_parse!(
-        punct!("[") >>
-        elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                expr) >>
-        punct!("]") >>
-        (ExprArray {
-            exprs: elems,
-            bracket_token: tokens::Bracket::default(),
-        }.into())
-    ));
+    impl Synom for ExprArray {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                elems: brackets!(call!(Delimited::parse_terminated)) >>
+                (ExprArray {
+                    exprs: elems.0,
+                    bracket_token: elems.1,
+                })
+            }
+        }
+    }
 
-    named!(and_call -> (Delimited<Expr, tokens::Comma>, tokens::Paren), do_parse!(
-        punct!("(") >>
-        args: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                               expr) >>
-        punct!(")") >>
-        (args, tokens::Paren::default())
-    ));
+    named!(and_call -> (Delimited<Expr, tokens::Comma>, tokens::Paren),
+           parens!(call!(Delimited::parse_terminated)));
 
     named!(and_method_call -> ExprMethodCall, do_parse!(
-        punct!(".") >>
-        method: ident >>
+        dot: syn!(Dot) >>
+        method: syn!(Ident) >>
         typarams: option!(do_parse!(
-            punct!("::") >>
-            punct!("<") >>
-            tys: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                  ty) >>
-            punct!(">") >>
-            (tys)
+            colon2: syn!(Colon2) >>
+            lt: syn!(Lt) >>
+            tys: call!(Delimited::parse_terminated) >>
+            gt: syn!(Gt) >>
+            (colon2, lt, tys, gt)
         )) >>
-        punct!("(") >>
-        args: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                               expr) >>
-        punct!(")") >>
-        (ExprMethodCall {
-            // this expr will get overwritten after being returned
-            expr: Box::new(ExprKind::Lit(Lit {
-                span: Span::default(),
-                value: LitKind::Bool(false),
-            }).into()),
+        args: parens!(call!(Delimited::parse_terminated)) >>
+        ({
+            let (colon2, lt, tys, gt) = match typarams {
+                Some((a, b, c, d)) => (Some(a), Some(b), Some(c), Some(d)),
+                None => (None, None, None, None),
+            };
+            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(),
+                method: method,
+                args: args.0,
+                paren_token: args.1,
+                dot_token: dot,
+                lt_token: lt,
+                gt_token: gt,
+                colon2_token: colon2,
+                typarams: tys.unwrap_or_default(),
+            }
         })
     ));
 
-    named!(expr_tup -> ExprKind, do_parse!(
-        punct!("(") >>
-        elems: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                expr) >>
-        punct!(")") >>
-        (ExprTup {
-            args: elems,
-            paren_token: tokens::Paren::default(),
-            lone_comma: None, // TODO: parse this
-        }.into())
-    ));
+    impl Synom for ExprTup {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                elems: parens!(call!(Delimited::parse_terminated)) >>
+                (ExprTup {
+                    args: elems.0,
+                    paren_token: elems.1,
+                    lone_comma: None, // TODO: parse this
+                })
+            }
+        }
+    }
 
     named_ambiguous_expr!(and_binary -> (BinOp, Expr), allow_struct, tuple!(
-        binop,
+        call!(BinOp::parse_binop),
         ambiguous_expr!(allow_struct)
     ));
 
     named_ambiguous_expr!(expr_unary -> ExprKind, allow_struct, do_parse!(
-        operator: unop >>
+        operator: syn!(UnOp) >>
         operand: ambiguous_expr!(allow_struct) >>
         (ExprUnary { op: operator, expr: Box::new(operand) }.into())
     ));
 
-    named!(expr_lit -> ExprKind, map!(lit, ExprKind::Lit));
-
-    named!(and_cast -> (Ty, tokens::As), do_parse!(
-        keyword!("as") >>
-        ty: ty >>
-        (ty, tokens::As::default())
+    named!(and_cast -> (Ty, As), do_parse!(
+        as_: syn!(As) >>
+        ty: syn!(Ty) >>
+        (ty, as_)
     ));
 
-    named!(and_ascription -> (Ty, tokens::Colon),
-           preceded!(punct!(":"), map!(ty, |t| (t, tokens::Colon::default()))));
+    named!(and_ascription -> (Ty, Colon),
+           map!(tuple!(syn!(Colon), syn!(Ty)), |(a, b)| (b, a)));
 
-    enum Cond {
-        Let(Pat, Expr, tokens::Eq, tokens::Let),
-        Expr(Expr),
+    impl Synom for ExprIfLet {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                if_: syn!(If) >>
+                let_: syn!(Let) >>
+                pat: syn!(Pat) >>
+                eq: syn!(Eq) >>
+                cond: expr_no_struct >>
+                then_block: braces!(call!(Block::parse_within)) >>
+                else_block: option!(else_block) >>
+                (ExprIfLet {
+                    pat: Box::new(pat),
+                    let_token: let_,
+                    eq_token: eq,
+                    expr: Box::new(cond),
+                    if_true: Block {
+                        stmts: then_block.0,
+                        brace_token: then_block.1,
+                    },
+                    if_token: if_,
+                    else_token: else_block.as_ref().map(|p| Else((p.0).0)),
+                    if_false: else_block.map(|p| Box::new(p.1.into())),
+                })
+            }
+        }
     }
 
-    named!(cond -> Cond, alt!(
-        do_parse!(
-            keyword!("let") >>
-            pat: pat >>
-            punct!("=") >>
-            value: expr_no_struct >>
-            (Cond::Let(pat, value, tokens::Eq::default(), tokens::Let::default()))
-        )
-        |
-        map!(expr_no_struct, Cond::Expr)
-    ));
+    impl Synom for ExprIf {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                if_: syn!(If) >>
+                cond: expr_no_struct >>
+                then_block: braces!(call!(Block::parse_within)) >>
+                else_block: option!(else_block) >>
+                (ExprIf {
+                    cond: Box::new(cond),
+                    if_true: Block {
+                        stmts: then_block.0,
+                        brace_token: then_block.1,
+                    },
+                    if_token: if_,
+                    else_token: else_block.as_ref().map(|p| Else((p.0).0)),
+                    if_false: else_block.map(|p| Box::new(p.1.into())),
+                })
+            }
+        }
+    }
 
-    named!(expr_if -> ExprKind, do_parse!(
-        keyword!("if") >>
-        cond: cond >>
-        then_block: delim!(Brace, within_block) >>
-        else_block: option!(preceded!(
-            keyword!("else"),
-            alt!(
-                expr_if
-                |
-                do_parse!(
-                    punct!("{") >>
-                    else_block: within_block >>
-                    punct!("}") >>
-                    (ExprKind::Block(ExprBlock {
-                        unsafety: Unsafety::Normal,
-                        block: Block {
-                            stmts: else_block,
-                            brace_token: tokens::Brace::default(),
-                        },
-                    }).into())
-                )
+    named!(else_block -> (Else, ExprKind), do_parse!(
+        else_: syn!(Else) >>
+        expr: alt!(
+            syn!(ExprIf) => { ExprKind::If }
+            |
+            syn!(ExprIfLet) => { ExprKind::IfLet }
+            |
+            do_parse!(
+                else_block: braces!(call!(Block::parse_within)) >>
+                (ExprKind::Block(ExprBlock {
+                    unsafety: Unsafety::Normal,
+                    block: Block {
+                        stmts: else_block.0,
+                        brace_token: else_block.1,
+                    },
+                }))
             )
-        )) >>
-        (match cond {
-            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(),
-        })
+        ) >>
+        (else_, expr)
     ));
 
-    named!(expr_for_loop -> ExprKind, do_parse!(
-        lbl: option!(terminated!(label, punct!(":"))) >>
-        keyword!("for") >>
-        pat: pat >>
-        keyword!("in") >>
-        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,
-            label: lbl,
-        }.into())
-    ));
 
-    named!(expr_loop -> ExprKind, do_parse!(
-        lbl: option!(terminated!(label, punct!(":"))) >>
-        keyword!("loop") >>
-        loop_block: block >>
-        (ExprLoop {
-            loop_token: tokens::Loop::default(),
-            colon_token: lbl.as_ref().map(|_| tokens::Colon::default()),
-            body: loop_block,
-            label: lbl,
-        }.into())
-    ));
+    impl Synom for ExprForLoop {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lbl: option!(tuple!(label, syn!(Colon))) >>
+                for_: syn!(For) >>
+                pat: syn!(Pat) >>
+                in_: syn!(In) >>
+                expr: expr_no_struct >>
+                loop_block: syn!(Block) >>
+                (ExprForLoop {
+                    for_token: for_,
+                    in_token: in_,
+                    pat: Box::new(pat),
+                    expr: Box::new(expr),
+                    body: loop_block,
+                    colon_token: lbl.as_ref().map(|p| Colon((p.1).0)),
+                    label: lbl.map(|p| p.0),
+                })
+            }
+        }
+    }
 
-    named!(expr_match -> ExprKind, do_parse!(
-        keyword!("match") >>
-        obj: expr_no_struct >>
-        res: delim!(Brace, do_parse!(
-            mut arms: many0!(do_parse!(
-                arm: match_arm >>
-                    cond!(arm_requires_comma(&arm), punct!(",")) >>
-                    cond!(!arm_requires_comma(&arm), option!(punct!(","))) >>
-                    (arm)
-            )) >>
-            last_arm: option!(match_arm) >>
-            (ExprKind::Match(Box::new(obj), {
-                arms.extend(last_arm);
-                arms
-            }))
-        )) >>
-        last_arm: option!(match_arm) >>
-        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());
+    impl Synom for ExprLoop {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lbl: option!(tuple!(label, syn!(Colon))) >>
+                loop_: syn!(Loop) >>
+                loop_block: syn!(Block) >>
+                (ExprLoop {
+                    loop_token: loop_,
+                    body: loop_block,
+                    colon_token: lbl.as_ref().map(|p| Colon((p.1).0)),
+                    label: lbl.map(|p| p.0),
+                })
+            }
+        }
+    }
+
+    impl Synom for ExprMatch {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                match_: syn!(Match) >>
+                obj: expr_no_struct >>
+                res: braces!(do_parse!(
+                    mut arms: many0!(do_parse!(
+                        arm: syn!(Arm) >>
+                            cond!(arm_requires_comma(&arm), syn!(Comma)) >>
+                            cond!(!arm_requires_comma(&arm), option!(syn!(Comma))) >>
+                            (arm)
+                    )) >>
+                    last_arm: option!(syn!(Arm)) >>
+                    ({
+                        arms.extend(last_arm);
+                        arms
+                    })
+                )) >>
+                ({
+                    let (mut arms, brace) = res;
+                    ExprMatch {
+                        expr: Box::new(obj),
+                        match_token: match_,
+                        brace_token: brace,
+                        arms: {
+                            for arm in &mut arms {
+                                if arm_requires_comma(arm) {
+                                    arm.comma = Some(tokens::Comma::default());
+                                }
+                            }
+                            arms
+                        },
                     }
-                }
-                arms.extend(last_arm);
-                arms
-            },
-        }.into())
-    ));
+                })
+            }
+        }
+    }
 
-    named!(expr_catch -> ExprKind, do_parse!(
-        keyword!("do") >>
-        keyword!("catch") >>
-        catch_block: block >>
-        (ExprCatch {
-            block: catch_block,
-            do_token: tokens::Do::default(),
-            catch_token: tokens::Catch::default(),
-        }.into())
-    ));
+    impl Synom for ExprCatch {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                do_: syn!(Do) >>
+                catch_: syn!(Catch) >>
+                catch_block: syn!(Block) >>
+                (ExprCatch {
+                    block: catch_block,
+                    do_token: do_,
+                    catch_token: catch_,
+                }.into())
+            }
+        }
+    }
 
     fn arm_requires_comma(arm: &Arm) -> bool {
         if let ExprKind::Block(ExprBlock { unsafety: Unsafety::Normal, .. }) = arm.body.node {
@@ -1066,45 +1099,48 @@
         }
     }
 
-    named!(match_arm -> Arm, do_parse!(
-        attrs: many0!(outer_attr) >>
-        pats: separated_nonempty_list!(map!(punct!("|"), |_| tokens::Or::default()),
-                                       pat) >>
-        guard: option!(preceded!(keyword!("if"), expr)) >>
-        punct!("=>") >>
-        body: alt!(
-            map!(block, |blk| {
-                ExprKind::Block(ExprBlock {
-                    unsafety: Unsafety::Normal,
-                    block: blk,
-                }).into()
-            })
-            |
-            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,
-        })
-    ));
+    impl Synom for Arm {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                attrs: many0!(call!(Attribute::parse_outer)) >>
+                pats: call!(Delimited::parse_separated_nonempty) >>
+                guard: option!(tuple!(syn!(If), syn!(Expr))) >>
+                rocket: syn!(Rocket) >>
+                body: alt!(
+                    map!(syn!(Block), |blk| {
+                        ExprKind::Block(ExprBlock {
+                            unsafety: Unsafety::Normal,
+                            block: blk,
+                        }).into()
+                    })
+                    |
+                    syn!(Expr)
+                ) >>
+                (Arm {
+                    rocket_token: rocket,
+                    if_token: guard.as_ref().map(|p| If((p.0).0)),
+                    attrs: attrs,
+                    pats: pats,
+                    guard: guard.map(|p| Box::new(p.1)),
+                    body: Box::new(body),
+                    comma: None,
+                })
+            }
+        }
+    }
 
     named_ambiguous_expr!(expr_closure -> ExprKind, allow_struct, do_parse!(
-        capture: capture_by >>
-        punct!("|") >>
-        inputs: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                 closure_arg) >>
-        punct!("|") >>
+        capture: syn!(CaptureBy) >>
+        or1: syn!(Or) >>
+        inputs: call!(Delimited::parse_terminated_with, fn_arg) >>
+        or2: syn!(Or) >>
         ret_and_body: alt!(
             do_parse!(
-                punct!("->") >>
-                ty: ty >>
-                body: block >>
-                (FunctionRetTy::Ty(ty, tokens::RArrow::default()),
+                arrow: syn!(RArrow) >>
+                ty: syn!(Ty) >>
+                body: syn!(Block) >>
+                (FunctionRetTy::Ty(ty, arrow),
                  ExprKind::Block(ExprBlock {
                     unsafety: Unsafety::Normal,
                     block: body,
@@ -1115,14 +1151,14 @@
         ) >>
         (ExprClosure {
             capture: capture,
-            or1_token: tokens::Or::default(),
-            or2_token: tokens::Or::default(),
+            or1_token: or1,
+            or2_token: or2,
             decl: Box::new(FnDecl {
                 inputs: inputs,
                 output: ret_and_body.0,
                 variadic: false,
                 dot_tokens: None,
-                fn_token: tokens::Fn::default(),
+                fn_token: tokens::Fn_::default(),
                 generics: Generics::default(),
                 paren_token: tokens::Paren::default(),
             }),
@@ -1130,274 +1166,356 @@
         }.into())
     ));
 
-    named!(closure_arg -> FnArg, do_parse!(
-        pat: pat >>
-        ty: option!(preceded!(punct!(":"), ty)) >>
-        (ArgCaptured {
-            pat: pat,
-            colon_token: tokens::Colon::default(),
-            ty: ty.unwrap_or_else(|| TyInfer {
-                underscore_token: tokens::Underscore::default(),
-            }.into()),
-        }.into())
-    ));
-
-    named!(expr_while -> ExprKind, do_parse!(
-        lbl: option!(terminated!(label, punct!(":"))) >>
-        keyword!("while") >>
-        cond: cond >>
-        while_block: block >>
-        (match cond {
-            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,
-            }.into(),
+    named!(fn_arg -> FnArg, do_parse!(
+        pat: syn!(Pat) >>
+        ty: option!(tuple!(syn!(Colon), syn!(Ty))) >>
+        ({
+            let (colon, ty) = ty.unwrap_or_else(|| {
+                (Colon::default(), TyInfer {
+                    underscore_token: Underscore::default(),
+                }.into())
+            });
+            ArgCaptured {
+                pat: pat,
+                colon_token: colon,
+                ty: ty,
+            }.into()
         })
     ));
 
-    named!(expr_continue -> ExprKind, do_parse!(
-        keyword!("continue") >>
-        lbl: option!(label) >>
-        (ExprContinue {
-            continue_token: tokens::Continue::default(),
-            label: lbl,
-        }.into())
-    ));
+    impl Synom for ExprWhile {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lbl: option!(tuple!(label, syn!(Colon))) >>
+                while_: syn!(While) >>
+                cond: expr_no_struct >>
+                while_block: syn!(Block) >>
+                (ExprWhile {
+                    while_token: while_,
+                    colon_token: lbl.as_ref().map(|p| Colon((p.1).0)),
+                    cond: Box::new(cond),
+                    body: while_block,
+                    label: lbl.map(|p| p.0),
+                })
+            }
+        }
+    }
+
+    impl Synom for ExprWhileLet {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lbl: option!(tuple!(label, syn!(Colon))) >>
+                while_: syn!(While) >>
+                let_: syn!(Let) >>
+                pat: syn!(Pat) >>
+                eq: syn!(Eq) >>
+                value: expr_no_struct >>
+                while_block: syn!(Block) >>
+                (ExprWhileLet {
+                    eq_token: eq,
+                    let_token: let_,
+                    while_token: while_,
+                    colon_token: lbl.as_ref().map(|p| Colon((p.1).0)),
+                    pat: Box::new(pat),
+                    expr: Box::new(value),
+                    body: while_block,
+                    label: lbl.map(|p| p.0),
+                })
+            }
+        }
+    }
+
+    impl Synom for ExprContinue {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                cont: syn!(Continue) >>
+                lbl: option!(label) >>
+                (ExprContinue {
+                    continue_token: cont,
+                    label: lbl,
+                })
+            }
+        }
+    }
 
     named_ambiguous_expr!(expr_break -> ExprKind, allow_struct, do_parse!(
-        keyword!("break") >>
+        break_: syn!(Break) >>
         lbl: option!(label) >>
         val: option!(call!(ambiguous_expr, allow_struct, false)) >>
         (ExprBreak {
             label: lbl,
             expr: val.map(Box::new),
-            break_token: tokens::Break::default(),
+            break_token: break_,
         }.into())
     ));
 
     named_ambiguous_expr!(expr_ret -> ExprKind, allow_struct, do_parse!(
-        keyword!("return") >>
+        return_: syn!(Return) >>
         ret_value: option!(ambiguous_expr!(allow_struct)) >>
         (ExprRet {
             expr: ret_value.map(Box::new),
-            return_token: tokens::Return::default(),
+            return_token: return_,
         }.into())
     ));
 
-    named!(expr_struct -> ExprKind, do_parse!(
-        path: path >>
-        punct!("{") >>
-        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                 field_value) >>
-        base: option!(
-            cond!(fields.is_empty() || fields.trailing_delim(),
+    impl Synom for ExprStruct {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                path: syn!(Path) >>
+                data: braces!(do_parse!(
+                    fields: call!(Delimited::parse_terminated) >>
+                    base: option!(
+                        cond!(fields.is_empty() || fields.trailing_delim(),
+                            do_parse!(
+                                dots: syn!(Dot2) >>
+                                base: syn!(Expr) >>
+                                (dots, base)
+                            )
+                        )
+                    ) >>
+                    (fields, base)
+                )) >>
+                ({
+                    let ((fields, base), brace) = data;
+                    let (dots, rest) = match base.and_then(|b| b) {
+                        Some((dots, base)) => (Some(dots), Some(base)),
+                        None => (None, None),
+                    };
+                    ExprStruct {
+                        brace_token: brace,
+                        path: path,
+                        fields: fields,
+                        dot2_token: dots,
+                        rest: rest.map(Box::new),
+                    }
+                })
+            }
+        }
+    }
+
+    impl Synom for FieldValue {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
                 do_parse!(
-                    punct!("..") >>
-                    base: expr >>
-                    (base)
+                    name: wordlike >>
+                    colon: syn!(Colon) >>
+                    value: syn!(Expr) >>
+                    (FieldValue {
+                        ident: name,
+                        expr: value,
+                        is_shorthand: false,
+                        attrs: Vec::new(),
+                        colon_token: Some(colon),
+                    })
                 )
-            )
-        ) >>
-        punct!("}") >>
-        (ExprStruct {
-            brace_token: tokens::Brace::default(),
-            path: path,
-            fields: fields,
-            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())
-    ));
+                |
+                map!(syn!(Ident), |name: Ident| FieldValue {
+                    ident: name.clone(),
+                    expr: ExprKind::Path(ExprPath { qself: None, path: name.into() }).into(),
+                    is_shorthand: true,
+                    attrs: Vec::new(),
+                    colon_token: None,
+                })
+            }
+        }
+    }
 
-    named!(field_value -> FieldValue, alt!(
-        do_parse!(
-            name: wordlike >>
-            punct!(":") >>
-            value: expr >>
-            (FieldValue {
-                ident: name,
-                expr: value,
-                is_shorthand: false,
-                attrs: Vec::new(),
-                colon_token: Some(tokens::Colon::default()),
-            })
-        )
-        |
-        map!(ident, |name: Ident| FieldValue {
-            ident: name.clone(),
-            expr: ExprKind::Path(ExprPath { qself: None, path: name.into() }).into(),
-            is_shorthand: true,
-            attrs: Vec::new(),
-            colon_token: None,
-        })
-    ));
+    impl Synom for ExprRepeat {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                data: brackets!(do_parse!(
+                    value: syn!(Expr) >>
+                    semi: syn!(Semi) >>
+                    times: syn!(Expr) >>
+                    (value, semi, times)
+                )) >>
+                (ExprRepeat {
+                    expr: Box::new((data.0).0),
+                    amt: Box::new((data.0).2),
+                    bracket_token: data.1,
+                    semi_token: (data.0).1,
+                })
+            }
+        }
+    }
 
-    named!(expr_repeat -> ExprKind, delim!(Bracket, do_parse!(
-        value: expr >>
-        punct!(";") >>
-        times: expr >>
-        punct!("]") >>
-        (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!(
-        rules: unsafety >>
-        b: block >>
-        (ExprBlock {
-            unsafety: rules,
-            block: b,
-        }.into())
-    ));
+    impl Synom for ExprBlock {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                rules: syn!(Unsafety) >>
+                b: syn!(Block) >>
+                (ExprBlock {
+                    unsafety: rules,
+                    block: b,
+                })
+            }
+        }
+    }
 
     named_ambiguous_expr!(expr_range -> ExprKind, allow_struct, do_parse!(
-        limits: range_limits >>
+        limits: syn!(RangeLimits) >>
         hi: option!(ambiguous_expr!(allow_struct)) >>
         (ExprRange { from: None, to: hi.map(Box::new), limits: limits }.into())
     ));
 
-    named!(range_limits -> RangeLimits, alt!(
-        punct!("...") => { |_| RangeLimits::Closed(tokens::Dot3::default()) }
-        |
-        punct!("..") => { |_| RangeLimits::HalfOpen(tokens::Dot2::default()) }
-    ));
+    impl Synom for RangeLimits {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
+                syn!(Dot3) => { RangeLimits::Closed }
+                |
+                syn!(Dot2) => { RangeLimits::HalfOpen }
+            }
+        }
+    }
 
-    named!(expr_path -> ExprKind, map!(qpath, |(qself, path)| {
-        ExprPath { qself: qself, path: path }.into()
-    }));
+    impl Synom for ExprPath {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                pair: qpath >>
+                (ExprPath {
+                    qself: pair.0,
+                    path: pair.1,
+                })
+            }
+        }
+    }
 
     named_ambiguous_expr!(expr_addr_of -> ExprKind, allow_struct, do_parse!(
-        punct!("&") >>
-        mutability: mutability >>
+        and: syn!(And) >>
+        mutability: syn!(Mutability) >>
         expr: ambiguous_expr!(allow_struct) >>
         (ExprAddrOf {
             mutbl: mutability,
             expr: Box::new(expr),
-            and_token: tokens::And::default(),
+            and_token: and,
         }.into())
     ));
 
-    named_ambiguous_expr!(and_assign -> (Expr, tokens::Eq), allow_struct, preceded!(
-        punct!("="),
-        map!(ambiguous_expr!(allow_struct), |t| (t, tokens::Eq::default()))
-    ));
+    named_ambiguous_expr!(and_assign -> (Expr, Eq), allow_struct,
+        map!(
+            tuple!(syn!(Eq), ambiguous_expr!(allow_struct)),
+            |(a, b)| (b, a)
+        )
+    );
 
     named_ambiguous_expr!(and_assign_op -> (BinOp, Expr), allow_struct, tuple!(
-        assign_op,
+        call!(BinOp::parse_assign_op),
         ambiguous_expr!(allow_struct)
     ));
 
-    named!(and_field -> (Ident, tokens::Dot),
-           preceded!(punct!("."), map!(ident, |t| (t, tokens::Dot::default()))));
+    named!(and_field -> (Ident, Dot),
+           map!(tuple!(syn!(Dot), syn!(Ident)), |(a, b)| (b, a)));
 
-    named!(and_tup_field -> (Lit, tokens::Dot),
-           preceded!(punct!("."), map!(lit, |l| (l, tokens::Dot::default()))));
+    named!(and_tup_field -> (Lit, Dot),
+           map!(tuple!(syn!(Dot), syn!(Lit)), |(a, b)| (b, a)));
 
-    named!(and_index -> (Expr, tokens::Bracket),
-           map!(delimited!(punct!("["), expr, punct!("]")),
-                |t| (t, tokens::Bracket::default())));
+    named!(and_index -> (Expr, tokens::Bracket), brackets!(syn!(Expr)));
 
     named_ambiguous_expr!(and_range -> (RangeLimits, Option<Expr>), allow_struct, tuple!(
-        range_limits,
+        syn!(RangeLimits),
         option!(call!(ambiguous_expr, allow_struct, false))
     ));
 
-    named!(pub block -> Block, do_parse!(
-        stmts: delim!(Brace, within_block) >>
-        (Block {
-            stmts: stmts,
-            brace_token: tokens::Brace::default(),
-        })
-    ));
-
-    named!(pub within_block -> Vec<Stmt>, do_parse!(
-        many0!(punct!(";")) >>
-        mut standalone: many0!(terminated!(stmt, many0!(punct!(";")))) >>
-        last: option!(expr) >>
-        (match last {
-            None => standalone,
-            Some(last) => {
-                standalone.push(Stmt::Expr(Box::new(last)));
-                standalone
+    impl Synom for Block {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                stmts: braces!(call!(Block::parse_within)) >>
+                (Block {
+                    stmts: stmts.0,
+                    brace_token: stmts.1,
+                })
             }
-        })
-    ));
+        }
+    }
 
-    named!(pub stmt -> Stmt, alt!(
-        stmt_mac
-        |
-        stmt_local
-        |
-        stmt_item
-        |
-        stmt_expr
-    ));
+    impl Block {
+        pub fn parse_within(input: &[TokenTree]) -> IResult<&[TokenTree], Vec<Stmt>> {
+            do_parse! {
+                input,
+                many0!(syn!(Semi)) >>
+                mut standalone: many0!(terminated!(syn!(Stmt), many0!(syn!(Semi)))) >>
+                last: option!(syn!(Expr)) >>
+                (match last {
+                    None => standalone,
+                    Some(last) => {
+                        standalone.push(Stmt::Expr(Box::new(last)));
+                        standalone
+                    }
+                })
+            }
+        }
+    }
+
+    impl Synom for Stmt {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
+                stmt_mac
+                |
+                stmt_local
+                |
+                stmt_item
+                |
+                stmt_expr
+            }
+        }
+    }
 
     named!(stmt_mac -> Stmt, do_parse!(
-        attrs: many0!(outer_attr) >>
-        what: path >>
-        punct!("!") >>
+        attrs: many0!(call!(Attribute::parse_outer)) >>
+        what: syn!(Path) >>
+        bang: syn!(Bang) >>
     // Only parse braces here; paren and bracket will get parsed as
     // expression statements
-        punct!("{") >>
-        ts: token_stream >>
-        punct!("}") >>
-        semi: option!(punct!(";")) >>
+        data: braces!(syn!(TokenStream)) >>
+        semi: option!(syn!(Semi)) >>
         (Stmt::Mac(Box::new((
             Mac {
                 path: what,
-                bang_token: tokens::Bang::default(),
+                bang_token: bang,
                 tokens: vec![TokenTree(proc_macro2::TokenTree {
-                    span: Default::default(),
-                    kind: TokenKind::Sequence(Delimiter::Brace, ts),
+                    span: ((data.1).0).0,
+                    kind: TokenKind::Sequence(Delimiter::Brace, data.0),
                 })],
             },
-            if semi.is_some() {
-                MacStmtStyle::Semicolon(tokens::Semi::default())
-            } else {
-                MacStmtStyle::Braces
+            match semi {
+                Some(semi) => MacStmtStyle::Semicolon(semi),
+                None => MacStmtStyle::Braces,
             },
             attrs,
         ))))
     ));
 
     named!(stmt_local -> Stmt, do_parse!(
-        attrs: many0!(outer_attr) >>
-        keyword!("let") >>
-        pat: pat >>
-        ty: option!(preceded!(punct!(":"), ty)) >>
-        init: option!(preceded!(punct!("="), expr)) >>
-        punct!(";") >>
+        attrs: many0!(call!(Attribute::parse_outer)) >>
+        let_: syn!(Let) >>
+        pat: syn!(Pat) >>
+        ty: option!(tuple!(syn!(Colon), syn!(Ty))) >>
+        init: option!(tuple!(syn!(Eq), syn!(Expr))) >>
+        semi: syn!(Semi) >>
         (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()),
+            let_token: let_,
+            semi_token: semi,
+            colon_token: ty.as_ref().map(|p| Colon((p.0).0)),
+            eq_token: init.as_ref().map(|p| Eq((p.0).0)),
             pat: Box::new(pat),
-            ty: ty.map(Box::new),
-            init: init.map(Box::new),
+            ty: ty.map(|p| Box::new(p.1)),
+            init: init.map(|p| Box::new(p.1)),
             attrs: attrs,
         })))
     ));
 
-    named!(stmt_item -> Stmt, map!(item, |i| Stmt::Item(Box::new(i))));
+    named!(stmt_item -> Stmt, map!(syn!(Item), |i| Stmt::Item(Box::new(i))));
 
     fn requires_semi(e: &Expr) -> bool {
         match e.node {
@@ -1415,13 +1533,13 @@
     }
 
     named!(stmt_expr -> Stmt, do_parse!(
-        attrs: many0!(outer_attr) >>
-        mut e: expr >>
-        semi: option!(punct!(";")) >>
+        attrs: many0!(call!(Attribute::parse_outer)) >>
+        mut e: syn!(Expr) >>
+        semi: option!(syn!(Semi)) >>
         ({
             e.attrs = attrs;
-            if semi.is_some() {
-                Stmt::Semi(Box::new(e), tokens::Semi::default())
+            if let Some(s) = semi {
+                Stmt::Semi(Box::new(e), s)
             } else if requires_semi(&e) {
                 return IResult::Error;
             } else {
@@ -1430,225 +1548,303 @@
         })
     ));
 
-    named!(pub pat -> Pat, alt!(
-        pat_wild // must be before pat_ident
-        |
-        pat_box // must be before pat_ident
-        |
-        pat_range // must be before pat_lit
-        |
-        pat_tuple_struct // must be before pat_ident
-        |
-        pat_struct // must be before pat_ident
-        |
-        pat_mac // must be before pat_ident
-        |
-        pat_lit // must be before pat_ident
-        |
-        pat_ident // must be before pat_path
-        |
-        pat_path
-        |
-        map!(pat_tuple, |t: PatTuple| t.into())
-        |
-        pat_ref
-        |
-        pat_slice
-    ));
+    impl Synom for Pat {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
+                syn!(PatWild) => { Pat::Wild } // must be before pat_ident
+                |
+                syn!(PatBox) => { Pat::Box }  // must be before pat_ident
+                |
+                syn!(PatRange) => { Pat::Range } // must be before pat_lit
+                |
+                syn!(PatTupleStruct) => { Pat::TupleStruct }  // must be before pat_ident
+                |
+                syn!(PatStruct) => { Pat::Struct } // must be before pat_ident
+                |
+                syn!(Mac) => { Pat::Mac } // must be before pat_ident
+                |
+                syn!(PatLit) => { Pat::Lit } // must be before pat_ident
+                |
+                syn!(PatIdent) => { Pat::Ident } // must be before pat_path
+                |
+                syn!(PatPath) => { Pat::Path }
+                |
+                syn!(PatTuple) => { Pat::Tuple }
+                |
+                syn!(PatRef) => { Pat::Ref }
+                |
+                syn!(PatSlice) => { Pat::Slice }
+            }
+        }
+    }
 
-    named!(pat_mac -> Pat, map!(mac, Pat::Mac));
+    impl Synom for PatWild {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            map! {
+                input,
+                syn!(Underscore),
+                |u| PatWild { underscore_token: u }
+            }
+        }
+    }
 
-    named!(pat_wild -> Pat, map!(keyword!("_"), |_| {
-        PatWild { underscore_token: tokens::Underscore::default() }.into()
-    }));
-
-    named!(pat_box -> Pat, do_parse!(
-        keyword!("box") >>
-        pat: pat >>
-        (PatBox {
-            pat: Box::new(pat),
-            box_token: tokens::Box::default(),
-        }.into())
-    ));
-
-    named!(pat_ident -> Pat, do_parse!(
-        mode: option!(keyword!("ref")) >>
-        mutability: mutability >>
-        name: alt!(
-            ident
-            |
-            keyword!("self") => { Into::into }
-        ) >>
-        not!(punct!("<")) >>
-        not!(punct!("::")) >>
-        subpat: option!(preceded!(punct!("@"), pat)) >>
-        (PatIdent {
-            mode: if mode.is_some() {
-                BindingMode::ByRef(tokens::Ref::default(), mutability)
-            } else {
-                BindingMode::ByValue(mutability)
-            },
-            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 >>
-        (PatTupleStruct {
-            path: path,
-            pat: tuple,
-        }.into())
-    ));
-
-    named!(pat_struct -> Pat, do_parse!(
-        path: path >>
-        punct!("{") >>
-        fields: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                 field_pat) >>
-        base: option!(
-            cond!(fields.is_empty() || fields.trailing_delim(),
-                  punct!(".."))
-        ) >>
-        punct!("}") >>
-        (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!(
-        do_parse!(
-            ident: wordlike >>
-            punct!(":") >>
-            pat: pat >>
-            (FieldPat {
-                ident: ident,
-                pat: Box::new(pat),
-                is_shorthand: false,
-                attrs: Vec::new(),
-                colon_token: Some(tokens::Colon::default()),
-            })
-        )
-        |
-        do_parse!(
-            boxed: option!(keyword!("box")) >>
-            mode: option!(keyword!("ref")) >>
-            mutability: mutability >>
-            ident: ident >>
-            ({
-                let mut pat: Pat = PatIdent {
-                    mode: if mode.is_some() {
-                        BindingMode::ByRef(tokens::Ref::default(), mutability)
-                    } else {
-                        BindingMode::ByValue(mutability)
-                    },
-                    ident: ident.clone(),
-                    subpat: None,
-                    at_token: None,
-                }.into();
-                if boxed.is_some() {
-                    pat = PatBox {
-                        pat: Box::new(pat),
-                        box_token: tokens::Box::default(),
-                    }.into();
-                }
-                FieldPat {
-                    ident: ident,
+    impl Synom for PatBox {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                boxed: syn!(Box_) >>
+                pat: syn!(Pat) >>
+                (PatBox {
                     pat: Box::new(pat),
-                    is_shorthand: true,
-                    attrs: Vec::new(),
-                    colon_token: None,
+                    box_token: boxed,
+                })
+            }
+        }
+    }
+
+    impl Synom for PatIdent {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                mode: option!(syn!(Ref)) >>
+                mutability: syn!(Mutability) >>
+                name: alt!(
+                    syn!(Ident)
+                    |
+                    syn!(Self_) => { Into::into }
+                ) >>
+                not!(syn!(Lt)) >>
+                not!(syn!(Colon2)) >>
+                subpat: option!(tuple!(syn!(At), syn!(Pat))) >>
+                (PatIdent {
+                    mode: match mode {
+                        Some(mode) => BindingMode::ByRef(mode, mutability),
+                        None => BindingMode::ByValue(mutability),
+                    },
+                    ident: name,
+                    at_token: subpat.as_ref().map(|p| At((p.0).0)),
+                    subpat: subpat.map(|p| Box::new(p.1)),
+                })
+            }
+        }
+    }
+
+    impl Synom for PatTupleStruct {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                path: syn!(Path) >>
+                tuple: syn!(PatTuple) >>
+                (PatTupleStruct {
+                    path: path,
+                    pat: tuple,
+                })
+            }
+        }
+    }
+
+    impl Synom for PatStruct {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                path: syn!(Path) >>
+                data: braces!(do_parse!(
+                    fields: call!(Delimited::parse_terminated) >>
+                    base: option!(
+                        cond!(fields.is_empty() || fields.trailing_delim(),
+                              syn!(Dot2))
+                    ) >>
+                    (fields, base)
+                )) >>
+                (PatStruct {
+                    path: path,
+                    fields: (data.0).0,
+                    brace_token: data.1,
+                    dot2_token: (data.0).1.and_then(|m| m),
+                })
+            }
+        }
+    }
+
+    impl Synom for FieldPat {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
+                do_parse!(
+                    ident: wordlike >>
+                    colon: syn!(Colon) >>
+                    pat: syn!(Pat) >>
+                    (FieldPat {
+                        ident: ident,
+                        pat: Box::new(pat),
+                        is_shorthand: false,
+                        attrs: Vec::new(),
+                        colon_token: Some(colon),
+                    })
+                )
+                |
+                do_parse!(
+                    boxed: option!(syn!(Box_)) >>
+                    mode: option!(syn!(Ref)) >>
+                    mutability: syn!(Mutability) >>
+                    ident: syn!(Ident) >>
+                    ({
+                        let mut pat: Pat = PatIdent {
+                            mode: if let Some(mode) = mode {
+                                BindingMode::ByRef(mode, mutability)
+                            } else {
+                                BindingMode::ByValue(mutability)
+                            },
+                            ident: ident.clone(),
+                            subpat: None,
+                            at_token: None,
+                        }.into();
+                        if let Some(boxed) = boxed {
+                            pat = PatBox {
+                                pat: Box::new(pat),
+                                box_token: boxed,
+                            }.into();
+                        }
+                        FieldPat {
+                            ident: ident,
+                            pat: Box::new(pat),
+                            is_shorthand: true,
+                            attrs: Vec::new(),
+                            colon_token: None,
+                        }
+                    })
+                )
+            }
+        }
+    }
+
+    named!(wordlike -> Ident, alt!(
+        syn!(Ident)
+        |
+        do_parse!(
+            lit: syn!(Lit) >>
+            ({
+                let s = lit.value.to_string();
+                if s.parse::<u32>().is_ok() {
+                    Ident::new(s.into(), lit.span)
+                } else {
+                    return IResult::Error
                 }
             })
         )
     ));
 
-    named!(pat_path -> Pat, map!(qpath, |(qself, path)| {
-        PatPath { qself: qself, path: path }.into()
-    }));
+    impl Synom for PatPath {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            map! {
+                input,
+                syn!(ExprPath),
+                |p: ExprPath| PatPath { qself: p.qself, path: p.path }
+            }
+        }
+    }
 
-    named!(pat_tuple -> PatTuple, do_parse!(
-        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!(")") >>
-        (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);
+    impl Synom for PatTuple {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                data: parens!(do_parse!(
+                    elems: call!(Delimited::parse_terminated) >>
+                    dotdot: map!(cond!(
+                        elems.is_empty() || elems.trailing_delim(),
+                        option!(do_parse!(
+                            dots: syn!(Dot2) >>
+                            trailing: option!(syn!(Comma)) >>
+                            (dots, trailing)
+                        ))
+                    ), |x: Option<_>| x.and_then(|x| x)) >>
+                    rest: cond!(match dotdot {
+                                    Some((_, Some(_))) => true,
+                                    _ => false,
+                                },
+                                call!(Delimited::parse_terminated)) >>
+                    (elems, dotdot, rest)
+                )) >>
+                ({
+                    let ((mut elems, dotdot, rest), parens) = data;
+                    let (dotdot, trailing) = match dotdot {
+                        Some((a, b)) => (Some(a), Some(b)),
+                        None => (None, None),
+                    };
+                    PatTuple {
+                        paren_token: parens,
+                        dots_pos: dotdot.as_ref().map(|_| elems.len()),
+                        dot2_token: dotdot,
+                        comma_token: trailing.and_then(|b| b),
+                        pats: {
+                            if let Some(rest) = rest {
+                                for elem in rest {
+                                    elems.push(elem);
+                                }
+                            }
+                            elems
+                        },
                     }
-                }
-                elems
-            },
-        })
-    )));
+                })
+            }
+        }
+    }
 
-    named!(pat_ref -> Pat, do_parse!(
-        punct!("&") >>
-        mutability: mutability >>
-        pat: pat >>
-        (PatRef {
-            pat: Box::new(pat),
-            mutbl: mutability,
-            and_token: tokens::And::default(),
-        }.into())
-    ));
+    impl Synom for PatRef {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                and: syn!(And) >>
+                mutability: syn!(Mutability) >>
+                pat: syn!(Pat) >>
+                (PatRef {
+                    pat: Box::new(pat),
+                    mutbl: mutability,
+                    and_token: and,
+                })
+            }
+        }
+    }
 
-    named!(pat_lit -> Pat, do_parse!(
-        lit: pat_lit_expr >>
-        (if let ExprKind::Path(_) = lit.node {
-            return IResult::Error; // these need to be parsed by pat_path
-        } else {
-            PatLit {
-                expr: Box::new(lit),
-            }.into()
-        })
-    ));
+    impl Synom for PatLit {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lit: pat_lit_expr >>
+                (if let ExprKind::Path(_) = lit.node {
+                    return IResult::Error; // these need to be parsed by pat_path
+                } else {
+                    PatLit {
+                        expr: Box::new(lit),
+                    }
+                })
+            }
+        }
+    }
 
-    named!(pat_range -> Pat, do_parse!(
-        lo: pat_lit_expr >>
-        limits: range_limits >>
-        hi: pat_lit_expr >>
-        (PatRange {
-            lo: Box::new(lo),
-            hi: Box::new(hi),
-            limits: limits,
-        }.into())
-    ));
+    impl Synom for PatRange {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            do_parse! {
+                input,
+                lo: pat_lit_expr >>
+                limits: syn!(RangeLimits) >>
+                hi: pat_lit_expr >>
+                (PatRange {
+                    lo: Box::new(lo),
+                    hi: Box::new(hi),
+                    limits: limits,
+                })
+            }
+        }
+    }
 
     named!(pat_lit_expr -> Expr, do_parse!(
-        neg: option!(punct!("-")) >>
+        neg: option!(syn!(Sub)) >>
         v: alt!(
-            lit => { ExprKind::Lit }
+            syn!(Lit) => { ExprKind::Lit }
             |
-            path => { |p| ExprPath { qself: None, path: p }.into() }
+            syn!(ExprPath) => { ExprKind::Path }
         ) >>
         (if neg.is_some() {
             ExprKind::Unary(ExprUnary {
@@ -1660,50 +1856,63 @@
         })
     ));
 
-    named!(pat_slice -> Pat, do_parse!(
-        punct!("[") >>
-        mut before: terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                                 pat) >>
-        middle: option!(do_parse!(
-            punct!("..") >>
-            trailing: option!(punct!(",")) >>
-            (trailing.is_some())
-        )) >>
-        after: cond!(
-            match middle {
-                Some(trailing) => trailing,
-                _ => false,
-            },
-            terminated_list!(map!(punct!(","), |_| tokens::Comma::default()),
-                             pat)
-        ) >>
-        punct!("]") >>
-        (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
+    impl Synom for PatSlice {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            map! {
+                input,
+                brackets!(do_parse!(
+                    before: call!(Delimited::parse_terminated) >>
+                    middle: option!(do_parse!(
+                        dots: syn!(Dot2) >>
+                        trailing: option!(syn!(Comma)) >>
+                        (dots, trailing)
+                    )) >>
+                    after: cond!(
+                        match middle {
+                            Some((_, ref trailing)) => trailing.is_some(),
+                            _ => false,
+                        },
+                        call!(Delimited::parse_terminated)
+                    ) >>
+                    (before, middle, after)
+                )),
+                |((before, middle, after), brackets)| {
+                    let mut before: Delimited<Pat, tokens::Comma> = before;
+                    let after: Option<Delimited<Pat, tokens::Comma>> = after;
+                    let middle: Option<(Dot2, Option<Comma>)> = middle;
+                    PatSlice {
+                        dot2_token: middle.as_ref().map(|m| Dot2((m.0).0)),
+                        comma_token: middle.as_ref().and_then(|m| {
+                            m.1.as_ref().map(|m| Comma(m.0))
+                        }),
+                        bracket_token: brackets,
+                        middle: middle.and_then(|_| {
+                            if !before.is_empty() && !before.trailing_delim() {
+                                Some(Box::new(before.pop().unwrap().into_item()))
+                            } else {
+                                None
+                            }
+                        }),
+                        front: before,
+                        back: after.unwrap_or_default(),
+                    }
                 }
-            }),
-            front: before,
-            back: after.unwrap_or_default(),
-        }.into())
-    ));
+            }
+        }
+    }
 
-    named!(capture_by -> CaptureBy, alt!(
-        keyword!("move") => { |_| CaptureBy::Value(tokens::Move::default()) }
-        |
-        epsilon!() => { |_| CaptureBy::Ref }
-    ));
+    impl Synom for CaptureBy {
+        fn parse(input: &[TokenTree]) -> IResult<&[TokenTree], Self> {
+            alt! {
+                input,
+                syn!(Move) => { CaptureBy::Value }
+                |
+                epsilon!() => { |_| CaptureBy::Ref }
+            }
+        }
+    }
 
-    named!(label -> Ident, map!(lifetime, |lt: Lifetime| lt.ident));
+    named!(label -> Ident, map!(syn!(Lifetime), |lt: Lifetime| lt.ident));
 }
 
 #[cfg(feature = "printing")]