Parse paths
diff --git a/src/data.rs b/src/data.rs
index b87eaf1..36ba136 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -303,13 +303,7 @@
         }
 
         fn parse_crate(input: ParseStream) -> Result<Self> {
-            let followed_by_colons = {
-                let ahead = input.fork();
-                ahead.parse::<Token![crate]>()?;
-                ahead.peek(Token![::])
-            };
-
-            if followed_by_colons {
+            if input.peek2(Token![::]) {
                 Ok(Visibility::Inherited)
             } else {
                 Ok(Visibility::Crate(VisCrate {
diff --git a/src/derive.rs b/src/derive.rs
index 7a1e406..7a8b94b 100644
--- a/src/derive.rs
+++ b/src/derive.rs
@@ -183,7 +183,13 @@
         }
     }
 
-    fn data_enum(input: ParseStream) -> Result<(Option<WhereClause>, token::Brace, Punctuated<Variant, Token![,]>)> {
+    fn data_enum(
+        input: ParseStream,
+    ) -> Result<(
+        Option<WhereClause>,
+        token::Brace,
+        Punctuated<Variant, Token![,]>,
+    )> {
         let where_clause = if input.peek(Token![where]) {
             Some(input.parse_synom(WhereClause::parse)?)
         } else {
diff --git a/src/ident.rs b/src/ident.rs
new file mode 100644
index 0000000..df4386b
--- /dev/null
+++ b/src/ident.rs
@@ -0,0 +1,11 @@
+#[cfg(feature = "parsing")]
+use lookahead;
+
+pub use proc_macro2::Ident;
+
+#[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Ident(marker: lookahead::TokenMarker) -> Ident {
+    match marker {}
+}
diff --git a/src/lib.rs b/src/lib.rs
index 54d81b2..266d7b8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -316,7 +316,8 @@
 #[macro_use]
 pub mod token;
 
-pub use proc_macro2::Ident;
+mod ident;
+pub use ident::Ident;
 
 #[cfg(any(feature = "full", feature = "derive"))]
 mod attr;
diff --git a/src/lifetime.rs b/src/lifetime.rs
index 4710ec5..c8101eb 100644
--- a/src/lifetime.rs
+++ b/src/lifetime.rs
@@ -13,6 +13,8 @@
 use proc_macro2::{Ident, Span};
 use unicode_xid::UnicodeXID;
 
+#[cfg(feature = "parsing")]
+use lookahead;
 use token::Apostrophe;
 
 /// A Rust lifetime: `'a`.
@@ -107,6 +109,13 @@
 }
 
 #[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Lifetime(marker: lookahead::TokenMarker) -> Lifetime {
+    match marker {}
+}
+
+#[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
     use parse::{Error, Parse, ParseStream, Result};
diff --git a/src/lit.rs b/src/lit.rs
index 299704d..a25d2a3 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -22,6 +22,9 @@
 #[cfg(feature = "extra-traits")]
 use std::hash::{Hash, Hasher};
 
+#[cfg(feature = "parsing")]
+use lookahead;
+
 ast_enum_of_structs! {
     /// A Rust literal such as a string or integer or boolean.
     ///
@@ -411,45 +414,49 @@
 }
 
 #[cfg(feature = "parsing")]
+#[doc(hidden)]
+#[allow(non_snake_case)]
+pub fn Lit(marker: lookahead::TokenMarker) -> Lit {
+    match marker {}
+}
+
+#[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use buffer::Cursor;
+    use parse::{Parse, ParseStream, Result};
     use parse_error;
-    use synom::PResult;
     use synom::Synom;
 
-    impl Synom for Lit {
-        fn parse(input: Cursor) -> PResult<Self> {
-            match input.literal() {
-                Some((lit, rest)) => {
-                    if lit.to_string().starts_with('/') {
-                        // Doc comment literal which is not a Syn literal
-                        parse_error()
-                    } else {
-                        Ok((Lit::new(lit), rest))
+    impl Parse for Lit {
+        fn parse(input: ParseStream) -> Result<Self> {
+            input.step_cursor(|cursor| {
+                match cursor.literal() {
+                    Some((lit, rest)) => {
+                        if lit.to_string().starts_with('/') {
+                            // Doc comment literal which is not a Syn literal
+                            parse_error()
+                        } else {
+                            Ok((Lit::new(lit), rest))
+                        }
                     }
+                    _ => match cursor.ident() {
+                        Some((ident, rest)) => Ok((
+                            Lit::Bool(LitBool {
+                                value: if ident == "true" {
+                                    true
+                                } else if ident == "false" {
+                                    false
+                                } else {
+                                    return parse_error();
+                                },
+                                span: ident.span(),
+                            }),
+                            rest,
+                        )),
+                        _ => parse_error(),
+                    },
                 }
-                _ => match input.ident() {
-                    Some((ident, rest)) => Ok((
-                        Lit::Bool(LitBool {
-                            value: if ident == "true" {
-                                true
-                            } else if ident == "false" {
-                                false
-                            } else {
-                                return parse_error();
-                            },
-                            span: ident.span(),
-                        }),
-                        rest,
-                    )),
-                    _ => parse_error(),
-                },
-            }
-        }
-
-        fn description() -> Option<&'static str> {
-            Some("literal")
+            })
         }
     }
 
diff --git a/src/parse.rs b/src/parse.rs
index aa3043d..c833bb7 100644
--- a/src/parse.rs
+++ b/src/parse.rs
@@ -13,6 +13,7 @@
 use error;
 use punctuated::Punctuated;
 use synom::PResult;
+use token::Token;
 
 pub use error::{Error, Result};
 pub use lookahead::{Lookahead1, Peek};
@@ -79,8 +80,6 @@
         unsafe { mem::transmute::<Cursor<'c>, Cursor<'a>>(other) }
     }
 
-    // Not public API.
-    #[doc(hidden)]
     pub fn error<T: Display>(self, message: T) -> Error {
         error::new_at(self.scope, self.cursor, message)
     }
@@ -124,6 +123,25 @@
         self.lookahead1().peek(token)
     }
 
+    pub fn peek2<T: Peek>(&self, token: T) -> bool {
+        if self.is_empty() {
+            return false;
+        }
+        let ahead = self.fork();
+        ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
+        ahead.peek(token)
+    }
+
+    pub fn peek3<T: Peek>(&self, token: T) -> bool {
+        if self.is_empty() {
+            return false;
+        }
+        let ahead = self.fork();
+        ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
+        ahead.step_cursor(|cursor| Ok(cursor.token_tree().unwrap())).unwrap();
+        ahead.peek(token)
+    }
+
     pub fn parse_terminated<T, P: Parse>(
         &self,
         parser: fn(ParseStream) -> Result<T>,
@@ -135,6 +153,10 @@
         self.clone()
     }
 
+    pub fn error<T: Display>(&self, message: T) -> Error {
+        error::new_at(self.scope, self.cursor(), message)
+    }
+
     // Not public API.
     #[doc(hidden)]
     pub fn step_cursor<F, R>(&self, function: F) -> Result<R>
@@ -200,14 +222,12 @@
     }
 }
 
-// In reality the impl would be for Punctuated.
-impl<T: Parse> Parse for Vec<T> {
+impl<T: Parse + Token> Parse for Option<T> {
     fn parse(input: ParseStream) -> Result<Self> {
-        let mut vec = Vec::new();
-        while !input.is_empty() {
-            let t = input.parse::<T>()?;
-            vec.push(t);
+        if T::peek(&input.lookahead1()) {
+            Ok(Some(input.parse()?))
+        } else {
+            Ok(None)
         }
-        Ok(vec)
     }
 }
diff --git a/src/path.rs b/src/path.rs
index a848944..12c7549 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -227,122 +227,120 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
+    use parse::{Parse, ParseStream, Result};
+    use synom::ext::IdentExt;
     use synom::Synom;
 
-    impl Synom for Path {
-        named!(parse -> Self, do_parse!(
-            colon: option!(punct!(::)) >>
-            segments: call!(Punctuated::<PathSegment, Token![::]>::parse_separated_nonempty) >>
-            cond_reduce!(segments.first().map_or(true, |seg| seg.value().ident != "dyn")) >>
-            (Path {
-                leading_colon: colon,
-                segments: segments,
+    impl Parse for Path {
+        fn parse(input: ParseStream) -> Result<Self> {
+            if input.peek(Token![dyn]) {
+                return Err(input.error("expected path"));
+            }
+
+            Ok(Path {
+                leading_colon: input.parse()?,
+                segments: input.parse_synom(Punctuated::parse_separated_nonempty)?,
             })
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("path")
         }
     }
 
-    #[cfg(not(feature = "full"))]
-    impl Synom for GenericArgument {
-        named!(parse -> Self, alt!(
-            call!(ty_no_eq_after) => { GenericArgument::Type }
-            |
-            syn!(Lifetime) => { GenericArgument::Lifetime }
-            |
-            syn!(Binding) => { GenericArgument::Binding }
-        ));
-    }
+    impl Parse for GenericArgument {
+        fn parse(input: ParseStream) -> Result<Self> {
+            if input.peek(Lifetime) && !input.peek3(Token![+]) {
+                return Ok(GenericArgument::Lifetime(input.parse()?));
+            }
 
-    #[cfg(feature = "full")]
-    impl Synom for GenericArgument {
-        named!(parse -> Self, alt!(
-            call!(ty_no_eq_after) => { GenericArgument::Type }
-            |
-            syn!(Lifetime) => { GenericArgument::Lifetime }
-            |
-            syn!(Binding) => { GenericArgument::Binding }
-            |
-            syn!(ExprLit) => { |l| GenericArgument::Const(Expr::Lit(l)) }
-            |
-            syn!(ExprBlock) => { |b| GenericArgument::Const(Expr::Block(b)) }
-        ));
+            if input.peek(Ident) && input.peek2(Token![=]) {
+                return Ok(GenericArgument::Binding(input.parse()?));
+            }
 
-        fn description() -> Option<&'static str> {
-            Some("generic argument")
+            #[cfg(feature = "full")]
+            {
+                if input.peek(Lit) {
+                    let lit = input.parse_synom(ExprLit::parse)?;
+                    return Ok(GenericArgument::Const(Expr::Lit(lit)));
+                }
+
+                if input.peek(token::Brace) {
+                    let block = input.parse_synom(ExprBlock::parse)?;
+                    return Ok(GenericArgument::Const(Expr::Block(block)));
+                }
+            }
+
+            Ok(GenericArgument::Type(input.parse_synom(ty_no_eq_after)?))
         }
     }
 
-    impl Synom for AngleBracketedGenericArguments {
-        named!(parse -> Self, do_parse!(
-            colon2: option!(punct!(::)) >>
-            lt: punct!(<) >>
-            args: call!(Punctuated::parse_terminated) >>
-            gt: punct!(>) >>
-            (AngleBracketedGenericArguments {
-                colon2_token: colon2,
-                lt_token: lt,
-                args: args,
-                gt_token: gt,
+    impl Parse for AngleBracketedGenericArguments {
+        fn parse(input: ParseStream) -> Result<Self> {
+            Ok(AngleBracketedGenericArguments {
+                colon2_token: input.parse()?,
+                lt_token: input.parse()?,
+                args: {
+                    let mut args = Punctuated::new();
+                    loop {
+                        if input.peek(Token![>]) {
+                            break;
+                        }
+                        let value = input.parse()?;
+                        args.push_value(value);
+                        if input.peek(Token![>]) {
+                            break;
+                        }
+                        let punct = input.parse()?;
+                        args.push_punct(punct);
+                    }
+                    args
+                },
+                gt_token: input.parse()?,
             })
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("angle bracketed generic arguments")
         }
     }
 
-    impl Synom for ParenthesizedGenericArguments {
-        named!(parse -> Self, do_parse!(
-            data: parens!(Punctuated::parse_terminated) >>
-            output: call!(ReturnType::without_plus) >>
-            (ParenthesizedGenericArguments {
-                paren_token: data.0,
-                inputs: data.1,
-                output: output,
+    impl Parse for ParenthesizedGenericArguments {
+        fn parse(input: ParseStream) -> Result<Self> {
+            let content;
+            Ok(ParenthesizedGenericArguments {
+                paren_token: parenthesized!(content in input),
+                inputs: content.parse_synom(Punctuated::parse_terminated)?,
+                output: input.parse_synom(ReturnType::without_plus)?,
             })
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("parenthesized generic arguments: `Foo(A, B, ..) -> T`")
         }
     }
 
-    impl Synom for PathSegment {
-        named!(parse -> Self, alt!(
-            do_parse!(
-                ident: syn!(Ident) >>
-                arguments: syn!(AngleBracketedGenericArguments) >>
-                (PathSegment {
+    impl Parse for PathSegment {
+        fn parse(input: ParseStream) -> Result<Self> {
+            if input.peek(Token![super])
+                || input.peek(Token![self])
+                || input.peek(Token![Self])
+                || input.peek(Token![crate])
+                || input.peek(Token![extern])
+            {
+                let ident = input.parse_synom(Ident::parse_any)?;
+                return Ok(PathSegment::from(ident));
+            }
+
+            let ident = input.parse()?;
+            if input.peek(Token![<]) && !input.peek2(Token![=])
+                || input.peek(Token![::]) && input.peek3(Token![<])
+            {
+                Ok(PathSegment {
                     ident: ident,
-                    arguments: PathArguments::AngleBracketed(arguments),
+                    arguments: PathArguments::AngleBracketed(input.parse()?),
                 })
-            )
-            |
-            mod_style_path_segment
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("path segment")
+            } else {
+                Ok(PathSegment::from(ident))
+            }
         }
     }
 
-    impl Synom for Binding {
-        named!(parse -> Self, do_parse!(
-            id: syn!(Ident) >>
-            eq: punct!(=) >>
-            ty: syn!(Type) >>
-            (Binding {
-                ident: id,
-                eq_token: eq,
-                ty: ty,
+    impl Parse for Binding {
+        fn parse(input: ParseStream) -> Result<Self> {
+            Ok(Binding {
+                ident: input.parse()?,
+                eq_token: input.parse()?,
+                ty: input.parse_synom(Type::parse)?,
             })
-        ));
-
-        fn description() -> Option<&'static str> {
-            Some("associated type binding")
         }
     }
 
diff --git a/src/token.rs b/src/token.rs
index 0dd00a2..3ffe827 100644
--- a/src/token.rs
+++ b/src/token.rs
@@ -122,6 +122,10 @@
 #[cfg(feature = "parsing")]
 use error::Result;
 #[cfg(feature = "parsing")]
+use lifetime::Lifetime;
+#[cfg(feature = "parsing")]
+use lit::Lit;
+#[cfg(feature = "parsing")]
 use lookahead;
 #[cfg(feature = "parsing")]
 use parse::{Lookahead1, Parse, ParseBuffer, ParseStream};
@@ -147,7 +151,7 @@
 }
 
 macro_rules! impl_token {
-    ($token:tt $name:ident) => {
+    ($name:ident $display:expr) => {
         #[cfg(feature = "parsing")]
         impl Token for $name {
             fn peek(lookahead: &Lookahead1) -> bool {
@@ -161,7 +165,7 @@
             }
 
             fn display() -> String {
-                concat!("`", $token, "`").to_owned()
+                $display.to_owned()
             }
         }
 
@@ -170,6 +174,10 @@
     };
 }
 
+impl_token!(Ident "identifier");
+impl_token!(Lifetime "lifetime");
+impl_token!(Lit "literal");
+
 macro_rules! define_keywords {
     ($($token:tt pub struct $name:ident #[$doc:meta])*) => {
         $(
@@ -192,7 +200,7 @@
                 }
             }
 
-            impl_token!($token $name);
+            impl_token!($name concat!("`", $token, "`"));
 
             impl std::default::Default for $name {
                 fn default() -> Self {
@@ -261,7 +269,7 @@
                 }
             }
 
-            impl_token!($token $name);
+            impl_token!($name concat!("`", $token, "`"));
 
             impl std::default::Default for $name {
                 fn default() -> Self {