Parse based on proc-macro2
diff --git a/src/attr.rs b/src/attr.rs
index 0a2b016..fa550dd 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -210,19 +210,43 @@
     use lit::{Lit, StrStyle};
     use mac::{Token, TokenTree};
     use mac::parsing::token_trees;
-    use synom::space::{block_comment, whitespace};
     use ty::parsing::mod_style_path;
+    use synom::{TokenKind, IResult};
+
+    pub fn inner_doc_comment(i: &[synom::TokenTree]) -> IResult<&[synom::TokenTree], String> {
+        match i.first() {
+            Some(&synom::TokenTree { kind: TokenKind::Literal(ref lit), .. }) => {
+                let s = lit.to_string();
+                if s.starts_with("//!") || s.starts_with("/*!") {
+                    IResult::Done(&i[1..], s)
+                } else {
+                    IResult::Error
+                }
+            }
+            _ => IResult::Error,
+        }
+    }
+
+    pub fn outer_doc_comment(i: &[synom::TokenTree]) -> IResult<&[synom::TokenTree], String> {
+        match i.first() {
+            Some(&synom::TokenTree { kind: TokenKind::Literal(ref lit), .. }) => {
+                let s = lit.to_string();
+                if s.starts_with("///") || s.starts_with("/**") {
+                    IResult::Done(&i[1..], s)
+                } else {
+                    IResult::Error
+                }
+            }
+            _ => IResult::Error,
+        }
+    }
 
     #[cfg(feature = "full")]
     named!(pub inner_attr -> Attribute, alt!(
         do_parse!(
             punct!("#") >>
             punct!("!") >>
-            path_and_tts: delimited!(
-                punct!("["),
-                tuple!(mod_style_path, token_trees),
-                punct!("]")
-            ) >>
+            path_and_tts: delim!(Bracket, tuple!(mod_style_path, token_trees)) >>
             ({
                 let (path, tts) = path_and_tts;
 
@@ -236,29 +260,13 @@
         )
         |
         do_parse!(
-            punct!("//!") >>
-            content: take_until!("\n") >>
+            comment: inner_doc_comment >>
             (Attribute {
                 style: AttrStyle::Inner,
                 path: "doc".into(),
                 tts: vec![
                     TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(format!("//!{}", content).into(), StrStyle::Cooked))),
-                ],
-                is_sugared_doc: true,
-            })
-        )
-        |
-        do_parse!(
-            option!(whitespace) >>
-            peek!(tag!("/*!")) >>
-            com: block_comment >>
-            (Attribute {
-                style: AttrStyle::Inner,
-                path: "doc".into(),
-                tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+                    TokenTree::Token(Token::Literal(Lit::Str(comment.into(), StrStyle::Cooked))),
                 ],
                 is_sugared_doc: true,
             })
@@ -268,11 +276,7 @@
     named!(pub outer_attr -> Attribute, alt!(
         do_parse!(
             punct!("#") >>
-            path_and_tts: delimited!(
-                punct!("["),
-                tuple!(mod_style_path, token_trees),
-                punct!("]")
-            ) >>
+            path_and_tts: delim!(Bracket, tuple!(mod_style_path, token_trees)) >>
             ({
                 let (path, tts) = path_and_tts;
 
@@ -286,30 +290,13 @@
         )
         |
         do_parse!(
-            punct!("///") >>
-            not!(tag!("/")) >>
-            content: take_until!("\n") >>
+            comment: outer_doc_comment >>
             (Attribute {
                 style: AttrStyle::Outer,
                 path: "doc".into(),
                 tts: vec![
                     TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(format!("///{}", content).into(), StrStyle::Cooked))),
-                ],
-                is_sugared_doc: true,
-            })
-        )
-        |
-        do_parse!(
-            option!(whitespace) >>
-            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
-            com: block_comment >>
-            (Attribute {
-                style: AttrStyle::Outer,
-                path: "doc".into(),
-                tts: vec![
-                    TokenTree::Token(Token::Eq),
-                    TokenTree::Token(Token::Literal(Lit::Str(com.into(), StrStyle::Cooked))),
+                    TokenTree::Token(Token::Literal(Lit::Str(comment.into(), StrStyle::Cooked))),
                 ],
                 is_sugared_doc: true,
             })
diff --git a/src/constant.rs b/src/constant.rs
index ad0d325..037b524 100644
--- a/src/constant.rs
+++ b/src/constant.rs
@@ -89,9 +89,7 @@
     ));
 
     named!(and_call -> Vec<ConstExpr>, do_parse!(
-        punct!("(") >>
-        args: terminated_list!(punct!(","), const_expr) >>
-        punct!(")") >>
+        args: delim!(Parenthesis, terminated_list!(punct!(","), const_expr)) >>
         (args)
     ));
 
@@ -107,12 +105,10 @@
 
     named!(expr_path -> ConstExpr, map!(path, ConstExpr::Path));
 
-    named!(and_index -> ConstExpr, delimited!(punct!("["), const_expr, punct!("]")));
+    named!(and_index -> ConstExpr, delim!(Brace, const_expr));
 
     named!(expr_paren -> ConstExpr, do_parse!(
-        punct!("(") >>
-        e: const_expr >>
-        punct!(")") >>
+        e: delim!(Parenthesis, const_expr) >>
         (ConstExpr::Paren(Box::new(e)))
     ));
 
diff --git a/src/data.rs b/src/data.rs
index 69df303..2174617 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -122,9 +122,7 @@
 
     named!(pub enum_body -> (WhereClause, Vec<Variant>), do_parse!(
         wh: where_clause >>
-        punct!("{") >>
-        variants: terminated_list!(punct!(","), variant) >>
-        punct!("}") >>
+        variants: delim!(Brace, terminated_list!(punct!(","), variant)) >>
         (wh, variants)
     ));
 
@@ -157,20 +155,26 @@
         terminated!(expr, after_discriminant) => { ConstExpr::Other }
     ));
 
+    // XXX: HACKY
     #[cfg(feature = "full")]
-    named!(after_discriminant -> &str, peek!(alt!(punct!(",") | punct!("}"))));
+    pub fn eof(input: &[synom::TokenTree]) -> synom::IResult<&[synom::TokenTree], &'static str> {
+        if input.is_empty() {
+            synom::IResult::Done(&[], "")
+        } else {
+            synom::IResult::Error
+        }
+    }
+
+    #[cfg(feature = "full")]
+    named!(after_discriminant -> &str, peek!(alt!(punct!(",") | input_end!())));
 
     named!(pub struct_like_body -> Vec<Field>, do_parse!(
-        punct!("{") >>
-        fields: terminated_list!(punct!(","), struct_field) >>
-        punct!("}") >>
+        fields: delim!(Brace, terminated_list!(punct!(","), struct_field)) >>
         (fields)
     ));
 
     named!(tuple_like_body -> Vec<Field>, do_parse!(
-        punct!("(") >>
-        fields: terminated_list!(punct!(","), tuple_field) >>
-        punct!(")") >>
+        fields: delim!(Parenthesis, terminated_list!(punct!(","), tuple_field)) >>
         (fields)
     ));
 
@@ -203,34 +207,25 @@
     named!(pub visibility -> Visibility, alt!(
         do_parse!(
             keyword!("pub") >>
-            punct!("(") >>
-            keyword!("crate") >>
-            punct!(")") >>
+            delim!(Parenthesis, keyword!("crate")) >>
             (Visibility::Crate)
         )
         |
         do_parse!(
             keyword!("pub") >>
-            punct!("(") >>
-            keyword!("self") >>
-            punct!(")") >>
+            delim!(Parenthesis, keyword!("self")) >>
             (Visibility::Restricted(Box::new("self".into())))
         )
         |
         do_parse!(
             keyword!("pub") >>
-            punct!("(") >>
-            keyword!("super") >>
-            punct!(")") >>
+            delim!(Parenthesis, keyword!("super")) >>
             (Visibility::Restricted(Box::new("super".into())))
         )
         |
         do_parse!(
             keyword!("pub") >>
-            punct!("(") >>
-            keyword!("in") >>
-            restricted: mod_style_path >>
-            punct!(")") >>
+            restricted: delim!(Parenthesis, preceded!(keyword!("in"), mod_style_path)) >>
             (Visibility::Restricted(Box::new(restricted)))
         )
         |
diff --git a/src/escape.rs b/src/escape.rs
deleted file mode 100644
index c17a158..0000000
--- a/src/escape.rs
+++ /dev/null
@@ -1,294 +0,0 @@
-use std::{char, str};
-use std::num::ParseIntError;
-use synom::IResult;
-
-pub fn cooked_string(input: &str) -> IResult<&str, String> {
-    let mut s = String::new();
-    let mut chars = input.char_indices().peekable();
-    while let Some((byte_offset, ch)) = chars.next() {
-        match ch {
-            '"' => {
-                return IResult::Done(&input[byte_offset..], s);
-            }
-            '\r' => {
-                if let Some((_, '\n')) = chars.next() {
-                    s.push('\n');
-                } else {
-                    break;
-                }
-            }
-            '\\' => {
-                match chars.next() {
-                    Some((_, 'x')) => {
-                        match backslash_x_char(&mut chars) {
-                            Some(ch) => s.push(ch),
-                            None => break,
-                        }
-                    }
-                    Some((_, 'n')) => s.push('\n'),
-                    Some((_, 'r')) => s.push('\r'),
-                    Some((_, 't')) => s.push('\t'),
-                    Some((_, '\\')) => s.push('\\'),
-                    Some((_, '0')) => s.push('\0'),
-                    Some((_, 'u')) => {
-                        match backslash_u(&mut chars) {
-                            Some(ch) => s.push(ch),
-                            None => break,
-                        }
-                    }
-                    Some((_, '\'')) => s.push('\''),
-                    Some((_, '"')) => s.push('"'),
-                    Some((_, '\n')) | Some((_, '\r')) => {
-                        while let Some(&(_, ch)) = chars.peek() {
-                            if ch.is_whitespace() {
-                                chars.next();
-                            } else {
-                                break;
-                            }
-                        }
-                    }
-                    _ => break,
-                }
-            }
-            ch => {
-                s.push(ch);
-            }
-        }
-    }
-    IResult::Error
-}
-
-pub fn cooked_byte_string(mut input: &str) -> IResult<&str, Vec<u8>> {
-    let mut vec = Vec::new();
-    let mut bytes = input.bytes().enumerate();
-    'outer: while let Some((offset, b)) = bytes.next() {
-        match b {
-            b'"' => {
-                return IResult::Done(&input[offset..], vec);
-            }
-            b'\r' => {
-                if let Some((_, b'\n')) = bytes.next() {
-                    vec.push(b'\n');
-                } else {
-                    break;
-                }
-            }
-            b'\\' => {
-                match bytes.next() {
-                    Some((_, b'x')) => {
-                        match backslash_x_byte(&mut bytes) {
-                            Some(b) => vec.push(b),
-                            None => break,
-                        }
-                    }
-                    Some((_, b'n')) => vec.push(b'\n'),
-                    Some((_, b'r')) => vec.push(b'\r'),
-                    Some((_, b't')) => vec.push(b'\t'),
-                    Some((_, b'\\')) => vec.push(b'\\'),
-                    Some((_, b'0')) => vec.push(b'\0'),
-                    Some((_, b'\'')) => vec.push(b'\''),
-                    Some((_, b'"')) => vec.push(b'"'),
-                    Some((newline, b'\n')) |
-                    Some((newline, b'\r')) => {
-                        let rest = &input[newline + 1..];
-                        for (offset, ch) in rest.char_indices() {
-                            if !ch.is_whitespace() {
-                                input = &rest[offset..];
-                                bytes = input.bytes().enumerate();
-                                continue 'outer;
-                            }
-                        }
-                        break;
-                    }
-                    _ => break,
-                }
-            }
-            b if b < 0x80 => {
-                vec.push(b);
-            }
-            _ => break,
-        }
-    }
-    IResult::Error
-}
-
-pub fn cooked_char(input: &str) -> IResult<&str, char> {
-    let mut chars = input.char_indices();
-    let ch = match chars.next().map(|(_, ch)| ch) {
-        Some('\\') => {
-            match chars.next().map(|(_, ch)| ch) {
-                Some('x') => backslash_x_char(&mut chars),
-                Some('n') => Some('\n'),
-                Some('r') => Some('\r'),
-                Some('t') => Some('\t'),
-                Some('\\') => Some('\\'),
-                Some('0') => Some('\0'),
-                Some('u') => backslash_u(&mut chars),
-                Some('\'') => Some('\''),
-                Some('"') => Some('"'),
-                _ => None,
-            }
-        }
-        ch => ch,
-    };
-    match ch {
-        Some(ch) => IResult::Done(chars.as_str(), ch),
-        None => IResult::Error,
-    }
-}
-
-pub fn cooked_byte(input: &str) -> IResult<&str, u8> {
-    let mut bytes = input.bytes().enumerate();
-    let b = match bytes.next().map(|(_, b)| b) {
-        Some(b'\\') => {
-            match bytes.next().map(|(_, b)| b) {
-                Some(b'x') => backslash_x_byte(&mut bytes),
-                Some(b'n') => Some(b'\n'),
-                Some(b'r') => Some(b'\r'),
-                Some(b't') => Some(b'\t'),
-                Some(b'\\') => Some(b'\\'),
-                Some(b'0') => Some(b'\0'),
-                Some(b'\'') => Some(b'\''),
-                Some(b'"') => Some(b'"'),
-                _ => None,
-            }
-        }
-        b => b,
-    };
-    match b {
-        Some(b) => {
-            match bytes.next() {
-                Some((offset, _)) => IResult::Done(&input[offset..], b),
-                None => IResult::Done("", b),
-            }
-        }
-        None => IResult::Error,
-    }
-}
-
-pub fn raw_string(input: &str) -> IResult<&str, (String, usize)> {
-    let mut chars = input.char_indices();
-    let mut n = 0;
-    while let Some((byte_offset, ch)) = chars.next() {
-        match ch {
-            '"' => {
-                n = byte_offset;
-                break;
-            }
-            '#' => {}
-            _ => return IResult::Error,
-        }
-    }
-    let mut s = String::new();
-    for (byte_offset, ch) in chars {
-        match ch {
-            '"' if input[byte_offset + 1..].starts_with(&input[..n]) => {
-                let rest = &input[byte_offset + 1 + n..];
-                return IResult::Done(rest, (s, n));
-            }
-            '\r' => {}
-            _ => s.push(ch),
-        }
-    }
-    IResult::Error
-}
-
-macro_rules! next_ch {
-    ($chars:ident @ $pat:pat $(| $rest:pat)*) => {
-        match $chars.next() {
-            Some((_, ch)) => match ch {
-                $pat $(| $rest)*  => ch,
-                _ => return None,
-            },
-            None => return None,
-        }
-    };
-}
-
-trait FromStrRadix: Sized {
-    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError>;
-}
-
-impl FromStrRadix for u8 {
-    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-        u8::from_str_radix(src, radix)
-    }
-}
-
-impl FromStrRadix for u32 {
-    fn from_str_radix(src: &str, radix: u32) -> Result<Self, ParseIntError> {
-        u32::from_str_radix(src, radix)
-    }
-}
-
-macro_rules! from_hex {
-    ($($ch:ident)+) => {{
-        let hex_bytes = &[$($ch as u8),*];
-        let hex_str = str::from_utf8(hex_bytes).unwrap();
-        FromStrRadix::from_str_radix(hex_str, 16).unwrap()
-    }};
-}
-
-#[cfg_attr(feature = "cargo-clippy", allow(diverging_sub_expression))]
-fn backslash_x_char<I>(chars: &mut I) -> Option<char>
-    where I: Iterator<Item = (usize, char)>
-{
-    let a = next_ch!(chars @ '0'...'7');
-    let b = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
-    char::from_u32(from_hex!(a b))
-}
-
-#[cfg_attr(feature = "cargo-clippy", allow(diverging_sub_expression))]
-fn backslash_x_byte<I>(chars: &mut I) -> Option<u8>
-    where I: Iterator<Item = (usize, u8)>
-{
-    let a = next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
-    let b = next_ch!(chars @ b'0'...b'9' | b'a'...b'f' | b'A'...b'F');
-    Some(from_hex!(a b))
-}
-
-#[cfg_attr(feature = "cargo-clippy", allow(diverging_sub_expression, many_single_char_names))]
-fn backslash_u<I>(chars: &mut I) -> Option<char>
-    where I: Iterator<Item = (usize, char)>
-{
-    next_ch!(chars @ '{');
-    let a = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F');
-    let b = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
-    if b == '}' {
-        return char::from_u32(from_hex!(a));
-    }
-    let c = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
-    if c == '}' {
-        return char::from_u32(from_hex!(a b));
-    }
-    let d = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
-    if d == '}' {
-        return char::from_u32(from_hex!(a b c));
-    }
-    let e = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
-    if e == '}' {
-        return char::from_u32(from_hex!(a b c d));
-    }
-    let f = next_ch!(chars @ '0'...'9' | 'a'...'f' | 'A'...'F' | '}');
-    if f == '}' {
-        return char::from_u32(from_hex!(a b c d e));
-    }
-    next_ch!(chars @ '}');
-    char::from_u32(from_hex!(a b c d e f))
-}
-
-#[test]
-fn test_cooked_string() {
-    let input = "\\x62 \\\n \\u{7} \\u{64} \\u{bf5} \\u{12ba} \\u{1F395} \\u{102345}\"";
-    let expected = "\x62 \u{7} \u{64} \u{bf5} \u{12ba} \u{1F395} \u{102345}";
-    assert_eq!(cooked_string(input),
-               IResult::Done("\"", expected.to_string()));
-}
-
-#[test]
-fn test_cooked_byte_string() {
-    let input = "\\x62 \\\n \\xEF\"";
-    let expected = b"\x62 \xEF";
-    assert_eq!(cooked_byte_string(input),
-               IResult::Done("\"", expected.to_vec()));
-}
diff --git a/src/expr.rs b/src/expr.rs
index fae3e65..90b6538 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -369,15 +369,16 @@
     use item::parsing::item;
     use lit::parsing::{digits, lit};
     use mac::parsing::{mac, token_trees};
-    use synom::IResult::{self, Error};
     use op::parsing::{assign_op, binop, unop};
     use ty::parsing::{mutability, path, qpath, ty, unsafety};
+    use synom::{self, IResult};
 
     // Struct literals are ambiguous in certain positions
     // https://github.com/rust-lang/rfcs/pull/92
     macro_rules! named_ambiguous_expr {
         ($name:ident -> $o:ty, $allow_struct:ident, $submac:ident!( $($args:tt)* )) => {
-            fn $name(i: &str, $allow_struct: bool) -> $crate::synom::IResult<&str, $o> {
+            fn $name(i: &[$crate::synom::TokenTree], $allow_struct: bool)
+                     -> $crate::synom::IResult<&[$crate::synom::TokenTree], $o> {
                 $submac!(i, $($args)*)
             }
         };
@@ -394,7 +395,10 @@
     named!(expr_no_struct -> Expr, ambiguous_expr!(false));
 
     #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
-    fn ambiguous_expr(i: &str, allow_struct: bool, allow_block: bool) -> IResult<&str, Expr> {
+    fn ambiguous_expr(i: &[synom::TokenTree],
+                      allow_struct: bool,
+                      allow_block: bool)
+                      -> IResult<&[synom::TokenTree], Expr> {
         do_parse!(
             i,
             mut e: alt!(
@@ -507,9 +511,7 @@
     named!(expr_mac -> ExprKind, map!(mac, ExprKind::Mac));
 
     named!(expr_paren -> ExprKind, do_parse!(
-        punct!("(") >>
-        e: expr >>
-        punct!(")") >>
+        e: delim!(Parenthesis, expr) >>
         (ExprKind::Paren(Box::new(e)))
     ));
 
@@ -522,9 +524,7 @@
     named!(expr_in_place -> ExprKind, do_parse!(
         keyword!("in") >>
         place: expr_no_struct >>
-        punct!("{") >>
-        value: within_block >>
-        punct!("}") >>
+        value: delim!(Brace, within_block) >>
         (ExprKind::InPlace(
             Box::new(place),
             Box::new(ExprKind::Block(Unsafety::Normal, Block {
@@ -533,17 +533,13 @@
         ))
     ));
 
-    named!(expr_array -> ExprKind, do_parse!(
-        punct!("[") >>
+    named!(expr_array -> ExprKind, delim!(Bracket, do_parse!(
         elems: terminated_list!(punct!(","), expr) >>
-        punct!("]") >>
         (ExprKind::Array(elems))
-    ));
+    )));
 
     named!(and_call -> Vec<Expr>, do_parse!(
-        punct!("(") >>
-        args: terminated_list!(punct!(","), expr) >>
-        punct!(")") >>
+        args: delim!(Parenthesis, terminated_list!(punct!(","), expr)) >>
         (args)
     ));
 
@@ -558,16 +554,12 @@
                 punct!(">")
             )
         )) >>
-        punct!("(") >>
-        args: terminated_list!(punct!(","), expr) >>
-        punct!(")") >>
+        args: delim!(Parenthesis, terminated_list!(punct!(","), expr)) >>
         (method, ascript, args)
     ));
 
     named!(expr_tup -> ExprKind, do_parse!(
-        punct!("(") >>
-        elems: terminated_list!(punct!(","), expr) >>
-        punct!(")") >>
+        elems: delim!(Parenthesis, terminated_list!(punct!(","), expr)) >>
         (ExprKind::Tup(elems))
     ));
 
@@ -612,18 +604,14 @@
     named!(expr_if -> ExprKind, do_parse!(
         keyword!("if") >>
         cond: cond >>
-        punct!("{") >>
-        then_block: within_block >>
-        punct!("}") >>
+        then_block: delim!(Brace, within_block) >>
         else_block: option!(preceded!(
             keyword!("else"),
             alt!(
                 expr_if
                 |
                 do_parse!(
-                    punct!("{") >>
-                    else_block: within_block >>
-                    punct!("}") >>
+                    else_block: delim!(Brace, within_block) >>
                     (ExprKind::Block(Unsafety::Normal, Block {
                         stmts: else_block,
                     }).into())
@@ -669,19 +657,20 @@
     named!(expr_match -> ExprKind, do_parse!(
         keyword!("match") >>
         obj: expr_no_struct >>
-        punct!("{") >>
-        mut arms: many0!(do_parse!(
-            arm: match_arm >>
-            cond!(arm_requires_comma(&arm), punct!(",")) >>
-            cond!(!arm_requires_comma(&arm), option!(punct!(","))) >>
-            (arm)
+        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!("}") >>
-        (ExprKind::Match(Box::new(obj), {
-            arms.extend(last_arm);
-            arms
-        }))
+        (res)
     ));
 
     named!(expr_catch -> ExprKind, do_parse!(
@@ -790,17 +779,18 @@
 
     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)
+        res: delim!(Brace, do_parse!(
+            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!(","))) >>
+            (ExprKind::Struct(path, fields, base.map(Box::new)))
         )) >>
-        cond!(!fields.is_empty() && base.is_none(), option!(punct!(","))) >>
-        punct!("}") >>
-        (ExprKind::Struct(path, fields, base.map(Box::new)))
+        (res)
     ));
 
     named!(field_value -> FieldValue, alt!(
@@ -824,14 +814,12 @@
         })
     ));
 
-    named!(expr_repeat -> ExprKind, do_parse!(
-        punct!("[") >>
+    named!(expr_repeat -> ExprKind, delim!(Bracket, do_parse!(
         value: expr >>
         punct!(";") >>
         times: expr >>
-        punct!("]") >>
         (ExprKind::Repeat(Box::new(value), Box::new(times)))
-    ));
+    )));
 
     named!(expr_block -> ExprKind, do_parse!(
         rules: unsafety >>
@@ -876,7 +864,7 @@
 
     named!(and_tup_field -> u64, preceded!(punct!("."), digits));
 
-    named!(and_index -> Expr, delimited!(punct!("["), expr, punct!("]")));
+    named!(and_index -> Expr, delim!(Bracket, expr));
 
     named_ambiguous_expr!(and_range -> (RangeLimits, Option<Expr>), allow_struct, tuple!(
         range_limits,
@@ -884,9 +872,7 @@
     ));
 
     named!(pub block -> Block, do_parse!(
-        punct!("{") >>
-        stmts: within_block >>
-        punct!("}") >>
+        stmts: delim!(Brace, within_block) >>
         (Block {
             stmts: stmts,
         })
@@ -921,9 +907,7 @@
         punct!("!") >>
     // Only parse braces here; paren and bracket will get parsed as
     // expression statements
-        punct!("{") >>
-        tts: token_trees >>
-        punct!("}") >>
+        tts: delim!(Brace, token_trees) >>
         semi: option!(punct!(";")) >>
         (Stmt::Mac(Box::new((
             Mac {
@@ -983,7 +967,7 @@
             if semi.is_some() {
                 Stmt::Semi(Box::new(e))
             } else if requires_semi(&e) {
-                return Error;
+                return IResult::Error;
             } else {
                 Stmt::Expr(Box::new(e))
             }
@@ -1056,15 +1040,16 @@
 
     named!(pat_struct -> Pat, do_parse!(
         path: path >>
-        punct!("{") >>
-        fields: separated_list!(punct!(","), field_pat) >>
-        more: option!(preceded!(
-            cond!(!fields.is_empty(), punct!(",")),
-            punct!("..")
+        res: delim!(Brace, do_parse!(
+            fields: separated_list!(punct!(","), field_pat) >>
+            more: option!(preceded!(
+                cond!(!fields.is_empty(), punct!(",")),
+                punct!("..")
+            )) >>
+            cond!(!fields.is_empty() && more.is_none(), option!(punct!(","))) >>
+            (Pat::Struct(path, fields, more.is_some()))
         )) >>
-        cond!(!fields.is_empty() && more.is_none(), option!(punct!(","))) >>
-        punct!("}") >>
-        (Pat::Struct(path, fields, more.is_some()))
+        (res)
     ));
 
     named!(field_pat -> FieldPat, alt!(
@@ -1115,8 +1100,7 @@
         |(pats, dotdot)| Pat::Tuple(pats, dotdot)
     ));
 
-    named!(pat_tuple_helper -> (Vec<Pat>, Option<usize>), do_parse!(
-        punct!("(") >>
+    named!(pat_tuple_helper -> (Vec<Pat>, Option<usize>), delim!(Parenthesis, do_parse!(
         mut elems: separated_list!(punct!(","), pat) >>
         dotdot: option!(do_parse!(
             cond!(!elems.is_empty(), punct!(",")) >>
@@ -1126,7 +1110,6 @@
             (rest)
         )) >>
         cond!(!elems.is_empty() && dotdot.is_none(), option!(punct!(","))) >>
-        punct!(")") >>
         (match dotdot {
             Some(rest) => {
                 let pos = elems.len();
@@ -1135,7 +1118,7 @@
             }
             None => (elems, None),
         })
-    ));
+    )));
 
     named!(pat_ref -> Pat, do_parse!(
         punct!("&") >>
@@ -1174,8 +1157,7 @@
         })
     ));
 
-    named!(pat_slice -> Pat, do_parse!(
-        punct!("[") >>
+    named!(pat_slice -> Pat, delim!(Bracket, do_parse!(
         mut before: separated_list!(punct!(","), pat) >>
         after: option!(do_parse!(
             comma_before_dots: option!(cond_reduce!(!before.is_empty(), punct!(","))) >>
@@ -1185,7 +1167,6 @@
             (comma_before_dots.is_some(), after)
         )) >>
         cond!(after.is_none(), option!(punct!(","))) >>
-        punct!("]") >>
         (match after {
             None => Pat::Slice(before, None, Vec::new()),
             Some((true, after)) => {
@@ -1199,7 +1180,7 @@
                 Pat::Slice(before, Some(Box::new(rest)), after)
             }
         })
-    ));
+    )));
 
     named!(capture_by -> CaptureBy, alt!(
         keyword!("move") => { |_| CaptureBy::Value }
diff --git a/src/generics.rs b/src/generics.rs
index fbb89b1..2e3b7b9 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -191,6 +191,7 @@
     use attr::parsing::outer_attr;
     use ident::parsing::ident;
     use ty::parsing::{ty, poly_trait_ref};
+    use synom::{TokenTree, IResult};
 
     named!(pub generics -> Generics, map!(
         alt!(
@@ -215,18 +216,21 @@
         }
     ));
 
-    named!(pub lifetime -> Lifetime, preceded!(
-        punct!("'"),
-        alt!(
-            map!(ident, |id| Lifetime {
-                ident: format!("'{}", id).into(),
-            })
-            |
-            map!(keyword!("static"), |_| Lifetime {
-                ident: "'static".into(),
-            })
-        )
-    ));
+    pub fn lifetime(input: &[TokenTree]) -> IResult<&[TokenTree], Lifetime> {
+        use synom::*;
+        if let Some(&TokenTree { kind: TokenKind::Word(ref id), .. }) = input.first() {
+            // Check if this word is _actually_ a lifetime, and treat that differently
+            if id.chars().next().unwrap() == '\'' {
+                IResult::Done(&input[1..], Lifetime {
+                    ident: id.to_string().into()
+                })
+            } else {
+                IResult::Error
+            }
+        } else {
+            IResult::Error
+        }
+    }
 
     named!(pub lifetime_def -> LifetimeDef, do_parse!(
         attrs: many0!(outer_attr) >>
diff --git a/src/ident.rs b/src/ident.rs
index 8f698be..fbdce4f 100644
--- a/src/ident.rs
+++ b/src/ident.rs
@@ -57,63 +57,47 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use synom::IResult;
-    use synom::space::skip_whitespace;
-    use unicode_xid::UnicodeXID;
+    use synom::{TokenTree, TokenKind, IResult};
+    #[cfg(feature = "full")]
+    use lit::parsing::int;
 
-    pub fn ident(input: &str) -> IResult<&str, Ident> {
-        let (rest, id) = match word(input) {
-            IResult::Done(rest, id) => (rest, id),
-            IResult::Error => return IResult::Error,
-        };
-
-        match id.as_ref() {
-            // From https://doc.rust-lang.org/grammar.html#keywords
-            "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
-            "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
-            "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
-            "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
-            "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
-            "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
-            "while" | "yield" => IResult::Error,
-            _ => IResult::Done(rest, id),
+    pub fn ident(input: &[TokenTree]) -> IResult<&[TokenTree], Ident> {
+        if let IResult::Done(rest, id) = word(input) {
+            match id.as_ref() {
+                // From https://doc.rust-lang.org/grammar.html#keywords
+                "abstract" | "alignof" | "as" | "become" | "box" | "break" | "const" | "continue" |
+                "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" |
+                "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" |
+                "mut" | "offsetof" | "override" | "priv" | "proc" | "pub" | "pure" | "ref" |
+                "return" | "Self" | "self" | "sizeof" | "static" | "struct" | "super" | "trait" |
+                "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" |
+                "while" | "yield" => IResult::Error,
+                _ => IResult::Done(rest, id),
+            }
+        } else {
+            IResult::Error
         }
     }
 
-    pub fn word(mut input: &str) -> IResult<&str, Ident> {
-        input = skip_whitespace(input);
-
-        let mut chars = input.char_indices();
-        match chars.next() {
-            Some((_, ch)) if UnicodeXID::is_xid_start(ch) || ch == '_' => {}
-            _ => return IResult::Error,
-        }
-
-        for (i, ch) in chars {
-            if !UnicodeXID::is_xid_continue(ch) {
-                return IResult::Done(&input[i..], input[..i].into());
+    pub fn word(input: &[TokenTree]) -> IResult<&[TokenTree], Ident> {
+        if let Some(&TokenTree { kind: TokenKind::Word(ref id), .. }) = input.first() {
+            // Check if this word is _actually_ a lifetime, and treat that differently
+            if id.chars().next().unwrap() == '\'' {
+                IResult::Error
+            } else {
+                IResult::Done(&input[1..], Ident(id.to_string()))
             }
+        } else {
+            IResult::Error
         }
-
-        IResult::Done("", input.into())
     }
 
     #[cfg(feature = "full")]
-    pub fn wordlike(mut input: &str) -> IResult<&str, Ident> {
-        input = skip_whitespace(input);
-
-        for (i, ch) in input.char_indices() {
-            if !UnicodeXID::is_xid_start(ch) && !UnicodeXID::is_xid_continue(ch) {
-                return if i == 0 {
-                           IResult::Error
-                       } else {
-                           IResult::Done(&input[i..], input[..i].into())
-                       };
-            }
-        }
-
-        IResult::Done("", input.into())
-    }
+    named!(pub wordlike -> Ident, alt!(
+        word
+        |
+        int => { |d| format!("{}", d).into() }
+    ));
 }
 
 #[cfg(feature = "printing")]
diff --git a/src/item.rs b/src/item.rs
index 4cbac33..8d55f5c 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -365,17 +365,13 @@
     named!(view_path_list -> ViewPath, do_parse!(
         path: path >>
         punct!("::") >>
-        punct!("{") >>
-        items: terminated_list!(punct!(","), path_list_item) >>
-        punct!("}") >>
+        items: delim!(Brace, terminated_list!(punct!(","), path_list_item)) >>
         (ViewPath::List(path, items))
     ));
 
     named!(view_path_list_root -> ViewPath, do_parse!(
         global: option!(punct!("::")) >>
-        punct!("{") >>
-        items: terminated_list!(punct!(","), path_list_item) >>
-        punct!("}") >>
+        items: delim!(Brace, terminated_list!(punct!(","), path_list_item)) >>
         (ViewPath::List(Path {
             global: global.is_some(),
             segments: Vec::new(),
@@ -441,21 +437,18 @@
         keyword!("fn") >>
         name: ident >>
         generics: generics >>
-        punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
-        punct!(")") >>
+        inputs: delim!(Parenthesis, terminated_list!(punct!(","), fn_arg)) >>
         ret: option!(preceded!(punct!("->"), ty)) >>
         where_clause: where_clause >>
-        punct!("{") >>
-        inner_attrs: many0!(inner_attr) >>
-        stmts: within_block >>
-        punct!("}") >>
+        inner_attrs_stmts: delim!(Brace, tuple!(
+            many0!(inner_attr), within_block
+        )) >>
         (Item {
             ident: name,
             vis: vis,
             attrs: {
                 let mut attrs = outer_attrs;
-                attrs.extend(inner_attrs);
+                attrs.extend(inner_attrs_stmts.0);
                 attrs
             },
             node: ItemKind::Fn(
@@ -472,7 +465,7 @@
                     .. generics
                 },
                 Box::new(Block {
-                    stmts: stmts,
+                    stmts: inner_attrs_stmts.1,
                 }),
             ),
         })
@@ -513,13 +506,12 @@
         content: alt!(
             punct!(";") => { |_| None }
             |
-            delimited!(
-                punct!("{"),
+            delim!(
+                Brace,
                 tuple!(
                     many0!(inner_attr),
                     items
-                ),
-                punct!("}")
+                )
             ) => { Some }
         ) >>
         (match content {
@@ -545,9 +537,7 @@
     named!(item_foreign_mod -> Item, do_parse!(
         attrs: many0!(outer_attr) >>
         abi: abi >>
-        punct!("{") >>
-        items: many0!(foreign_item) >>
-        punct!("}") >>
+        items: delim!(Brace, many0!(foreign_item)) >>
         (Item {
             ident: "".into(),
             vis: Visibility::Inherited,
@@ -571,11 +561,12 @@
         keyword!("fn") >>
         name: ident >>
         generics: generics >>
-        punct!("(") >>
-        inputs: separated_list!(punct!(","), fn_arg) >>
-        trailing_comma: option!(punct!(",")) >>
-        variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
-        punct!(")") >>
+        inputs_and_variadic: delim!(Parenthesis, do_parse!(
+            inputs: separated_list!(punct!(","), fn_arg) >>
+            trailing_comma: option!(punct!(",")) >>
+            variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
+            ((inputs, variadic.is_some()))
+        )) >>
         ret: option!(preceded!(punct!("->"), ty)) >>
         where_clause: where_clause >>
         punct!(";") >>
@@ -584,9 +575,9 @@
             attrs: attrs,
             node: ForeignItemKind::Fn(
                 Box::new(FnDecl {
-                    inputs: inputs,
+                    inputs: inputs_and_variadic.0,
                     output: ret.map(FunctionRetTy::Ty).unwrap_or(FunctionRetTy::Default),
-                    variadic: variadic.is_some(),
+                    variadic: inputs_and_variadic.1,
                 }),
                 Generics {
                     where_clause: where_clause,
@@ -689,9 +680,7 @@
             separated_nonempty_list!(punct!("+"), ty_param_bound)
         )) >>
         where_clause: where_clause >>
-        punct!("{") >>
-        body: many0!(trait_item) >>
-        punct!("}") >>
+        body: delim!(Brace, many0!(trait_item)) >>
         (Item {
             ident: id,
             vis: vis,
@@ -715,8 +704,7 @@
         path: path >>
         keyword!("for") >>
         punct!("..") >>
-        punct!("{") >>
-        punct!("}") >>
+        delim!(Brace, epsilon!()) >>
         (Item {
             ident: "".into(),
             vis: Visibility::Inherited,
@@ -758,15 +746,12 @@
         keyword!("fn") >>
         name: ident >>
         generics: generics >>
-        punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
-        punct!(")") >>
+        inputs: delim!(Parenthesis, terminated_list!(punct!(","), fn_arg)) >>
         ret: option!(preceded!(punct!("->"), ty)) >>
         where_clause: where_clause >>
-        body: option!(delimited!(
-            punct!("{"),
-            tuple!(many0!(inner_attr), within_block),
-            punct!("}")
+        body: option!(delim!(
+            Brace,
+            tuple!(many0!(inner_attr), within_block)
         )) >>
         cond!(body.is_none(), punct!(";")) >>
         ({
@@ -855,9 +840,7 @@
         ) >>
         self_ty: ty >>
         where_clause: where_clause >>
-        punct!("{") >>
-        body: many0!(impl_item) >>
-        punct!("}") >>
+        body: delim!(Brace, many0!(impl_item)) >>
         (Item {
             ident: "".into(),
             vis: Visibility::Inherited,
@@ -916,22 +899,19 @@
         keyword!("fn") >>
         name: ident >>
         generics: generics >>
-        punct!("(") >>
-        inputs: terminated_list!(punct!(","), fn_arg) >>
-        punct!(")") >>
+        inputs: delim!(Parenthesis, terminated_list!(punct!(","), fn_arg)) >>
         ret: option!(preceded!(punct!("->"), ty)) >>
         where_clause: where_clause >>
-        punct!("{") >>
-        inner_attrs: many0!(inner_attr) >>
-        stmts: within_block >>
-        punct!("}") >>
+        inner_attrs_stmts: delim!(Brace, tuple!(
+            many0!(inner_attr), within_block
+        )) >>
         (ImplItem {
             ident: name,
             vis: vis,
             defaultness: defaultness,
             attrs: {
                 let mut attrs = outer_attrs;
-                attrs.extend(inner_attrs);
+                attrs.extend(inner_attrs_stmts.0);
                 attrs
             },
             node: ImplItemKind::Method(
@@ -950,7 +930,7 @@
                     },
                 },
                 Block {
-                    stmts: stmts,
+                    stmts: inner_attrs_stmts.1,
                 },
             ),
         })
diff --git a/src/krate.rs b/src/krate.rs
index 077a36d..9bef3df 100644
--- a/src/krate.rs
+++ b/src/krate.rs
@@ -14,25 +14,28 @@
     use item::parsing::items;
 
     named!(pub krate -> Crate, do_parse!(
-        option!(byte_order_mark) >>
-        shebang: option!(shebang) >>
+        // NOTE: The byte order mark and shebang are not tokens which can appear
+        // in a TokenStream, so we can't parse them anymore.
+
+        //option!(byte_order_mark) >>
+        //shebang: option!(shebang) >>
         attrs: many0!(inner_attr) >>
         items: items >>
         (Crate {
-            shebang: shebang,
+            shebang: None,
             attrs: attrs,
             items: items,
         })
     ));
 
-    named!(byte_order_mark -> &str, tag!("\u{feff}"));
+    // named!(byte_order_mark -> &str, tag!("\u{feff}"));
 
-    named!(shebang -> String, do_parse!(
-        tag!("#!") >>
-        not!(tag!("[")) >>
-        content: take_until!("\n") >>
-        (format!("#!{}", content))
-    ));
+    // named!(shebang -> String, do_parse!(
+    //     tag!("#!") >>
+    //     not!(tag!("[")) >>
+    //     content: take_until!("\n") >>
+    //     (format!("#!{}", content))
+    // ));
 }
 
 #[cfg(feature = "printing")]
diff --git a/src/lib.rs b/src/lib.rs
index 3f7f0df..7e9533c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,7 +6,7 @@
 extern crate quote;
 
 #[cfg(feature = "parsing")]
-extern crate unicode_xid;
+extern crate relex;
 
 #[cfg(feature = "parsing")]
 #[macro_use]
@@ -24,9 +24,6 @@
 mod data;
 pub use data::{Field, Variant, VariantData, Visibility};
 
-#[cfg(feature = "parsing")]
-mod escape;
-
 #[cfg(feature = "full")]
 mod expr;
 #[cfg(feature = "full")]
@@ -92,59 +89,108 @@
 
     use super::*;
     use {derive, generics, ident, mac, ty, attr};
-    use synom::{space, IResult};
+    use synom::{IResult, TokenStream};
+
+    use std::convert::From;
+    use std::error::Error;
+    use std::fmt;
 
     #[cfg(feature = "full")]
     use {expr, item, krate};
 
+    #[derive(Debug)]
+    pub struct ParseError(String);
+
+    impl Error for ParseError {
+        fn description(&self) -> &str {
+            &self.0
+        }
+    }
+
+    impl fmt::Display for ParseError {
+        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+            <String as fmt::Display>::fmt(&self.0, f)
+        }
+    }
+
+    impl From<synom::LexError> for ParseError {
+        fn from(_: synom::LexError) -> ParseError {
+            ParseError("error while lexing input string".to_owned())
+        }
+    }
+
     /// Parse the stringified representation of a struct or enum passed
     /// to a `proc_macro_derive` function.
-    pub fn parse_derive_input(input: &str) -> Result<DeriveInput, String> {
+    pub fn parse_derive_input(input: TokenStream) -> Result<DeriveInput, ParseError> {
         unwrap("derive input", derive::parsing::derive_input, input)
     }
 
+    /// Parse an entire crate into an AST. This function takes a string as input
+    /// instead of a TokenStream, as we need to handle parsing the BOM and
+    /// shebang from the string.
     #[cfg(feature = "full")]
-    pub fn parse_crate(input: &str) -> Result<Crate, String> {
-        unwrap("crate", krate::parsing::krate, input)
+    pub fn parse_crate(mut input: &str) -> Result<Crate, ParseError> {
+        // Strip the BOM if it is present
+        const BOM: &str = "\u{feff}";
+        if input.starts_with(BOM) {
+            input = &input[BOM.len()..];
+        }
+
+        let mut shebang = None;
+        if input.starts_with("#!") && !input.starts_with("#![") {
+            if let Some(idx) = input.find('\n') {
+                shebang = Some(input[..idx].to_string());
+                input = &input[idx..];
+            } else {
+                shebang = Some(input.to_string());
+                input = "";
+            }
+        }
+
+        let mut krate = unwrap("crate", krate::parsing::krate,
+                           input.parse()?)?;
+        krate.shebang = shebang;
+        Ok(krate)
+
     }
 
     #[cfg(feature = "full")]
-    pub fn parse_item(input: &str) -> Result<Item, String> {
+    pub fn parse_item(input: TokenStream) -> Result<Item, ParseError> {
         unwrap("item", item::parsing::item, input)
     }
 
     #[cfg(feature = "full")]
-    pub fn parse_items(input: &str) -> Result<Vec<Item>, String> {
+    pub fn parse_items(input: TokenStream) -> Result<Vec<Item>, ParseError> {
         unwrap("items", item::parsing::items, input)
     }
 
     #[cfg(feature = "full")]
-    pub fn parse_expr(input: &str) -> Result<Expr, String> {
+    pub fn parse_expr(input: TokenStream) -> Result<Expr, ParseError> {
         unwrap("expression", expr::parsing::expr, input)
     }
 
-    pub fn parse_type(input: &str) -> Result<Ty, String> {
+    pub fn parse_type(input: TokenStream) -> Result<Ty, ParseError> {
         unwrap("type", ty::parsing::ty, input)
     }
 
     /// Parse a path, such as `std::str::FromStr` or `::syn::parse_path`.
-    pub fn parse_path(input: &str) -> Result<Path, String> {
+    pub fn parse_path(input: TokenStream) -> Result<Path, ParseError> {
         unwrap("path", ty::parsing::path, input)
     }
 
-    pub fn parse_where_clause(input: &str) -> Result<WhereClause, String> {
+    pub fn parse_where_clause(input: TokenStream) -> Result<WhereClause, ParseError> {
         unwrap("where clause", generics::parsing::where_clause, input)
     }
 
-    pub fn parse_token_trees(input: &str) -> Result<Vec<TokenTree>, String> {
+    pub fn parse_token_trees(input: TokenStream) -> Result<Vec<TokenTree>, ParseError> {
         unwrap("token trees", mac::parsing::token_trees, input)
     }
 
-    pub fn parse_ident(input: &str) -> Result<Ident, String> {
+    pub fn parse_ident(input: TokenStream) -> Result<Ident, ParseError> {
         unwrap("identifier", ident::parsing::ident, input)
     }
 
-    pub fn parse_ty_param_bound(input: &str) -> Result<TyParamBound, String> {
+    pub fn parse_ty_param_bound(input: TokenStream) -> Result<TyParamBound, ParseError> {
         unwrap("type parameter bound",
                generics::parsing::ty_param_bound,
                input)
@@ -152,7 +198,7 @@
 
     /// Parse an attribute declared outside the item it annotates, such as
     /// a struct annotation. They are written as `#[...]`.
-    pub fn parse_outer_attr(input: &str) -> Result<Attribute, String> {
+    pub fn parse_outer_attr(input: TokenStream) -> Result<Attribute, ParseError> {
         unwrap("outer attribute", attr::parsing::outer_attr, input)
     }
 
@@ -160,30 +206,30 @@
     /// for crate annotations or for mod-level declarations when modules are in
     /// their own files. They are written as `#![...]`.
     #[cfg(feature = "full")]
-    pub fn parse_inner_attr(input: &str) -> Result<Attribute, String> {
+    pub fn parse_inner_attr(input: TokenStream) -> Result<Attribute, ParseError> {
         unwrap("inner attribute", attr::parsing::inner_attr, input)
     }
 
     /// Deprecated: Use `parse_derive_input` instead.
     #[doc(hidden)]
     #[deprecated(since="0.11.0", note = "Use `parse_derive_input` instead")]
-    pub fn parse_macro_input(input: &str) -> Result<MacroInput, String> {
+    pub fn parse_macro_input(input: TokenStream) -> Result<MacroInput, ParseError> {
         parse_derive_input(input)
     }
 
     /// Alias for `syn::parse_derive_input`.
     impl FromStr for DeriveInput {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_derive_input(s)
+            parse_derive_input(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_crate`.
     #[cfg(feature = "full")]
     impl FromStr for Crate {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
             parse_crate(s)
@@ -193,85 +239,85 @@
     /// Alias for `syn::parse_item`.
     #[cfg(feature = "full")]
     impl FromStr for Item {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_item(s)
+            parse_item(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_expr`.
     #[cfg(feature = "full")]
     impl FromStr for Expr {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_expr(s)
+            parse_expr(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_type`.
     impl FromStr for Ty {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_type(s)
+            parse_type(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_path`.
     impl FromStr for Path {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_path(s)
+            parse_path(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_where_clause`.
     impl FromStr for WhereClause {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_where_clause(s)
+            parse_where_clause(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_ident`.
     impl FromStr for Ident {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_ident(s)
+            parse_ident(s.parse()?)
         }
     }
 
     /// Alias for `syn::parse_ty_param_bound`.
     impl FromStr for TyParamBound {
-        type Err = String;
+        type Err = ParseError;
 
         fn from_str(s: &str) -> Result<Self, Self::Err> {
-            parse_ty_param_bound(s)
+            parse_ty_param_bound(s.parse()?)
         }
     }
 
     fn unwrap<T>(name: &'static str,
-                 f: fn(&str) -> IResult<&str, T>,
-                 input: &str)
-                 -> Result<T, String> {
-        match f(input) {
-            IResult::Done(mut rest, t) => {
-                rest = space::skip_whitespace(rest);
+                 f: fn(&[synom::TokenTree]) -> IResult<&[synom::TokenTree], T>,
+                 input: TokenStream)
+                 -> Result<T, ParseError> {
+        let input = synom::InputBuf::new(input);
+        match f(&input) {
+            IResult::Done(rest, t) => {
                 if rest.is_empty() {
                     Ok(t)
                 } else if rest.len() == input.len() {
                     // parsed nothing
-                    Err(format!("failed to parse {}: {:?}", name, rest))
+                    Err(ParseError(format!("failed to parse {}", name)))
                 } else {
-                    Err(format!("unparsed tokens after {}: {:?}", name, rest))
+                    Err(ParseError(format!("unparsed tokens after {}", name)))
                 }
             }
-            IResult::Error => Err(format!("failed to parse {}: {:?}", name, input)),
+            IResult::Error => Err(ParseError(format!("failed to parse {}", name))),
         }
     }
 }
diff --git a/src/lit.rs b/src/lit.rs
index 81be285..4aeec28 100644
--- a/src/lit.rs
+++ b/src/lit.rs
@@ -157,244 +157,159 @@
 #[cfg(feature = "parsing")]
 pub mod parsing {
     use super::*;
-    use escape::{cooked_byte, cooked_byte_string, cooked_char, cooked_string, raw_string};
-    use synom::space::skip_whitespace;
-    use synom::IResult;
-    use unicode_xid::UnicodeXID;
+    use synom::{IResult, TokenTree, TokenKind};
+    use relex;
 
-    named!(pub lit -> Lit, alt!(
-        string => { |StrLit { value, style }| Lit::Str(value, style) }
-        |
-        byte_string => { |ByteStrLit { value, style }| Lit::ByteStr(value, style) }
-        |
-        byte => { |b| Lit::Byte(b) }
-        |
-        character => { |ch| Lit::Char(ch) }
-        |
-        float => { |FloatLit { value, suffix }| Lit::Float(value, suffix) } // must be before int
-        |
-        int => { |IntLit { value, suffix }| Lit::Int(value, suffix) }
-        |
-        boolean => { |value| Lit::Bool(value) }
-    ));
-
-    named!(pub string -> StrLit, alt!(
-        quoted_string => { |s| StrLit { value: s, style: StrStyle::Cooked } }
-        |
-        preceded!(
-            punct!("r"),
-            raw_string
-        ) => { |(s, n)| StrLit { value: s, style: StrStyle::Raw(n) }}
-    ));
-
-    named!(pub quoted_string -> String, delimited!(
-        punct!("\""),
-        cooked_string,
-        tag!("\"")
-    ));
-
-    named!(pub byte_string -> ByteStrLit, alt!(
-        delimited!(
-            punct!("b\""),
-            cooked_byte_string,
-            tag!("\"")
-        ) => { |vec| ByteStrLit { value: vec, style: StrStyle::Cooked } }
-        |
-        preceded!(
-            punct!("br"),
-            raw_string
-        ) => { |(s, n): (String, _)| ByteStrLit { value: s.into_bytes(), style: StrStyle::Raw(n) } }
-    ));
-
-    named!(pub byte -> u8, do_parse!(
-        punct!("b") >>
-        tag!("'") >>
-        b: cooked_byte >>
-        tag!("'") >>
-        (b)
-    ));
-
-    named!(pub character -> char, do_parse!(
-        punct!("'") >>
-        ch: cooked_char >>
-        tag!("'") >>
-        (ch)
-    ));
-
-    named!(pub float -> FloatLit, do_parse!(
-        value: float_string >>
-        suffix: alt!(
-            tag!("f32") => { |_| FloatTy::F32 }
-            |
-            tag!("f64") => { |_| FloatTy::F64 }
-            |
-            epsilon!() => { |_| FloatTy::Unsuffixed }
-        ) >>
-        (FloatLit { value: value, suffix: suffix })
-    ));
-
-    named!(pub int -> IntLit, do_parse!(
-        value: digits >>
-        suffix: alt!(
-            tag!("isize") => { |_| IntTy::Isize }
-            |
-            tag!("i8") => { |_| IntTy::I8 }
-            |
-            tag!("i16") => { |_| IntTy::I16 }
-            |
-            tag!("i32") => { |_| IntTy::I32 }
-            |
-            tag!("i64") => { |_| IntTy::I64 }
-            |
-            tag!("usize") => { |_| IntTy::Usize }
-            |
-            tag!("u8") => { |_| IntTy::U8 }
-            |
-            tag!("u16") => { |_| IntTy::U16 }
-            |
-            tag!("u32") => { |_| IntTy::U32 }
-            |
-            tag!("u64") => { |_| IntTy::U64 }
-            |
-            epsilon!() => { |_| IntTy::Unsuffixed }
-        ) >>
-        (IntLit { value: value, suffix: suffix })
-    ));
-
-    named!(pub boolean -> bool, alt!(
-        keyword!("true") => { |_| true }
-        |
-        keyword!("false") => { |_| false }
-    ));
-
-    fn float_string(mut input: &str) -> IResult<&str, String> {
-        input = skip_whitespace(input);
-
-        let mut chars = input.chars().peekable();
-        match chars.next() {
-            Some(ch) if ch >= '0' && ch <= '9' => {}
-            _ => return IResult::Error,
-        }
-
-        let mut len = 1;
-        let mut has_dot = false;
-        let mut has_exp = false;
-        while let Some(&ch) = chars.peek() {
-            match ch {
-                '0'...'9' | '_' => {
-                    chars.next();
-                    len += 1;
-                }
-                '.' => {
-                    if has_dot {
-                        break;
+    pub fn lit(i: &[TokenTree]) -> IResult<&[TokenTree], Lit> {
+        match i.first() {
+            Some(&TokenTree{ kind: TokenKind::Literal(ref l), .. }) => {
+                // XXX: I'm using my lexer for this temporarially, as it makes
+                // my life easier. A final version shouldn't be this hacky,
+                // though we'll probably want `proc_macro::Literal` -> actual
+                // literal value conversions to be in a separate crate, rather
+                // than requiring syn (which seems a bit heavyweight for that).
+                let tok = if let Ok(tok) = relex::relex_literal(&l.to_string()) {
+                    tok
+                } else {
+                    return IResult::Error
+                };
+                let lit = match tok {
+                    relex::LToken::Lit(relex::Lit::Byte(b)) => {
+                        Lit::Byte(b)
                     }
-                    chars.next();
-                    if chars.peek()
-                           .map(|&ch| ch == '.' || UnicodeXID::is_xid_start(ch))
-                           .unwrap_or(false) {
-                        return IResult::Error;
+                    relex::LToken::Lit(relex::Lit::Char(c)) => {
+                        Lit::Char(c)
                     }
-                    len += 1;
-                    has_dot = true;
-                }
-                'e' | 'E' => {
-                    chars.next();
-                    len += 1;
-                    has_exp = true;
-                    break;
-                }
-                _ => break,
+                    relex::LToken::Lit(relex::Lit::Integer(v, suffix)) => {
+                        let suffix = match suffix {
+                            relex::IntSuffix::Unsuffixed =>
+                                IntTy::Unsuffixed,
+                            relex::IntSuffix::Isize =>
+                                IntTy::Isize,
+                            relex::IntSuffix::Usize =>
+                                IntTy::Usize,
+                            relex::IntSuffix::I8 =>
+                                IntTy::I8,
+                            relex::IntSuffix::U8 =>
+                                IntTy::U8,
+                            relex::IntSuffix::I16 =>
+                                IntTy::I16,
+                            relex::IntSuffix::U16 =>
+                                IntTy::U16,
+                            relex::IntSuffix::I32 =>
+                                IntTy::I32,
+                            relex::IntSuffix::U32 =>
+                                IntTy::U32,
+                            relex::IntSuffix::I64 =>
+                                IntTy::I64,
+                            relex::IntSuffix::U64 =>
+                                IntTy::U64,
+                        };
+                        Lit::Int(v, suffix)
+                    }
+                    relex::LToken::Lit(relex::Lit::Float(v, suffix)) => {
+                        let suffix = match suffix {
+                            relex::FloatSuffix::Unsuffixed =>
+                                FloatTy::Unsuffixed,
+                            relex::FloatSuffix::F32 =>
+                                FloatTy::F32,
+                            relex::FloatSuffix::F64 =>
+                                FloatTy::F64,
+                        };
+                        Lit::Float(v, suffix)
+                    }
+                    relex::LToken::Lit(relex::Lit::Str(s, relex::StrStyle::Cooked)) => {
+                        Lit::Str(s, StrStyle::Cooked)
+                    }
+                    relex::LToken::Lit(relex::Lit::Str(s, relex::StrStyle::Raw(n))) => {
+                        Lit::Str(s, StrStyle::Raw(n))
+                    }
+                    relex::LToken::Lit(relex::Lit::ByteStr(s, relex::StrStyle::Cooked)) => {
+                        Lit::ByteStr(s, StrStyle::Cooked)
+                    }
+                    relex::LToken::Lit(relex::Lit::ByteStr(s, relex::StrStyle::Raw(n))) => {
+                        Lit::ByteStr(s, StrStyle::Raw(n))
+                    }
+                    _ => return IResult::Error
+                };
+
+                IResult::Done(&i[1..], lit)
             }
-        }
-
-        let rest = &input[len..];
-        if !(has_dot || has_exp || rest.starts_with("f32") || rest.starts_with("f64")) {
-            return IResult::Error;
-        }
-
-        if has_exp {
-            let mut has_exp_value = false;
-            while let Some(&ch) = chars.peek() {
-                match ch {
-                    '+' | '-' => {
-                        if has_exp_value {
-                            break;
-                        }
-                        chars.next();
-                        len += 1;
-                    }
-                    '0'...'9' => {
-                        chars.next();
-                        len += 1;
-                        has_exp_value = true;
-                    }
-                    '_' => {
-                        chars.next();
-                        len += 1;
-                    }
-                    _ => break,
+            Some(&TokenTree{ kind: TokenKind::Word(ref w), .. }) => {
+                if &**w == "true" {
+                    IResult::Done(&i[1..], Lit::Bool(true))
+                } else if &**w == "false" {
+                    IResult::Done(&i[1..], Lit::Bool(false))
+                } else {
+                    IResult::Error
                 }
             }
-            if !has_exp_value {
-                return IResult::Error;
-            }
+            _ => IResult::Error
         }
-
-        IResult::Done(&input[len..], input[..len].replace("_", ""))
     }
 
-    pub fn digits(mut input: &str) -> IResult<&str, u64> {
-        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
+    #[cfg(feature = "full")]
+    pub fn digits(i: &[TokenTree]) -> IResult<&[TokenTree], u64> {
+        if let IResult::Done(r, Lit::Int(v, IntTy::Unsuffixed)) = lit(i) {
+            IResult::Done(r, v)
         } else {
-            10
-        };
-
-        let mut value = 0u64;
-        let mut len = 0;
-        let mut empty = true;
-        for b in input.bytes() {
-            let digit = match b {
-                b'0'...b'9' => (b - b'0') as u64,
-                b'a'...b'f' => 10 + (b - b'a') as u64,
-                b'A'...b'F' => 10 + (b - b'A') as u64,
-                b'_' => {
-                    if empty && base == 10 {
-                        return IResult::Error;
-                    }
-                    len += 1;
-                    continue;
-                }
-                _ => break,
-            };
-            if digit >= base {
-                return IResult::Error;
-            }
-            value = match value.checked_mul(base) {
-                Some(value) => value,
-                None => return IResult::Error,
-            };
-            value = match value.checked_add(digit) {
-                Some(value) => value,
-                None => return IResult::Error,
-            };
-            len += 1;
-            empty = false;
-        }
-        if empty {
             IResult::Error
+        }
+    }
+
+    pub fn string(i: &[TokenTree]) -> IResult<&[TokenTree], String> {
+        if let IResult::Done(r, Lit::Str(v, _)) = lit(i) {
+            IResult::Done(r, v)
         } else {
-            IResult::Done(&input[len..], value)
+            IResult::Error
+        }
+    }
+
+    pub fn byte_string(i: &[TokenTree]) -> IResult<&[TokenTree], Vec<u8>> {
+        if let IResult::Done(r, Lit::ByteStr(v, _)) = lit(i) {
+            IResult::Done(r, v)
+        } else {
+            IResult::Error
+        }
+    }
+
+    pub fn byte(i: &[TokenTree]) -> IResult<&[TokenTree], u8> {
+        if let IResult::Done(r, Lit::Byte(b)) = lit(i) {
+            IResult::Done(r, b)
+        } else {
+            IResult::Error
+        }
+    }
+
+    pub fn character(i: &[TokenTree]) -> IResult<&[TokenTree], char> {
+        if let IResult::Done(r, Lit::Char(c)) = lit(i) {
+            IResult::Done(r, c)
+        } else {
+            IResult::Error
+        }
+    }
+
+    pub fn float(i: &[TokenTree]) -> IResult<&[TokenTree], String> {
+        if let IResult::Done(r, Lit::Float(f, _)) = lit(i) {
+            IResult::Done(r, f)
+        } else {
+            IResult::Error
+        }
+    }
+
+    pub fn int(i: &[TokenTree]) -> IResult<&[TokenTree], u64> {
+        if let IResult::Done(r, Lit::Int(v, _)) = lit(i) {
+            IResult::Done(r, v)
+        } else {
+            IResult::Error
+        }
+    }
+
+    pub fn boolean(i: &[TokenTree]) -> IResult<&[TokenTree], bool> {
+        if let IResult::Done(r, Lit::Bool(b)) = lit(i) {
+            IResult::Done(r, b)
+        } else {
+            IResult::Error
         }
     }
 }
diff --git a/src/mac.rs b/src/mac.rs
index 26b3c61..a5d781f 100644
--- a/src/mac.rs
+++ b/src/mac.rs
@@ -116,8 +116,8 @@
     use generics::parsing::lifetime;
     use ident::parsing::word;
     use lit::parsing::lit;
-    use synom::space::{block_comment, whitespace};
     use ty::parsing::path;
+    use attr::parsing::{inner_doc_comment, outer_doc_comment};
 
     named!(pub mac -> Mac, do_parse!(
         what: path >>
@@ -132,22 +132,19 @@
     named!(pub token_trees -> Vec<TokenTree>, many0!(token_tree));
 
     named!(pub delimited -> Delimited, alt!(
-        delimited!(
-            punct!("("),
-            token_trees,
-            punct!(")")
+        delim!(
+            Parenthesis,
+            token_trees
         ) => { |tts| Delimited { delim: DelimToken::Paren, tts: tts } }
         |
-        delimited!(
-            punct!("["),
-            token_trees,
-            punct!("]")
+        delim!(
+            Bracket,
+            token_trees
         ) => { |tts| Delimited { delim: DelimToken::Bracket, tts: tts } }
         |
-        delimited!(
-            punct!("{"),
-            token_trees,
-            punct!("}")
+        delim!(
+            Brace,
+            token_trees
         ) => { |tts| Delimited { delim: DelimToken::Brace, tts: tts } }
     ));
 
@@ -268,32 +265,9 @@
     ));
 
     named!(doc_comment -> String, alt!(
-        do_parse!(
-            punct!("//!") >>
-            content: take_until!("\n") >>
-            (format!("//!{}", content))
-        )
+        inner_doc_comment
         |
-        do_parse!(
-            option!(whitespace) >>
-            peek!(tag!("/*!")) >>
-            com: block_comment >>
-            (com.to_owned())
-        )
-        |
-        do_parse!(
-            punct!("///") >>
-            not!(tag!("/")) >>
-            content: take_until!("\n") >>
-            (format!("///{}", content))
-        )
-        |
-        do_parse!(
-            option!(whitespace) >>
-            peek!(tuple!(tag!("/**"), not!(tag!("*")))) >>
-            com: block_comment >>
-            (com.to_owned())
-        )
+        outer_doc_comment
     ));
 }
 
diff --git a/src/ty.rs b/src/ty.rs
index 7b7d3af..2440a28 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -240,9 +240,10 @@
     use expr::parsing::expr;
     use generics::parsing::{lifetime, lifetime_def, 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;
+    #[cfg(feature = "full")]
+    use synom::{IResult, TokenTree};
 
     named!(pub ty -> Ty, alt!(
         ty_paren // must be before ty_tup
@@ -272,35 +273,28 @@
 
     named!(ty_mac -> Ty, map!(mac, Ty::Mac));
 
-    named!(ty_vec -> Ty, do_parse!(
-        punct!("[") >>
+    named!(ty_vec -> Ty, delim!(Bracket, do_parse!(
         elem: ty >>
-        punct!("]") >>
         (Ty::Slice(Box::new(elem)))
-    ));
+    )));
 
-    named!(ty_array -> Ty, do_parse!(
-        punct!("[") >>
+    named!(ty_array -> Ty, delim!(Bracket, do_parse!(
         elem: ty >>
         punct!(";") >>
         len: array_len >>
-        punct!("]") >>
         (Ty::Array(Box::new(elem), len))
-    ));
+    )));
 
     #[cfg(not(feature = "full"))]
     use constant::parsing::const_expr as array_len;
 
     #[cfg(feature = "full")]
     named!(array_len -> ConstExpr, alt!(
-        terminated!(const_expr, after_array_len)
+        terminated!(const_expr, input_end!())
         |
-        terminated!(expr, after_array_len) => { ConstExpr::Other }
+        terminated!(expr, input_end!()) => { ConstExpr::Other }
     ));
 
-    #[cfg(feature = "full")]
-    named!(after_array_len -> &str, peek!(punct!("]")));
-
     named!(ty_ptr -> Ty, do_parse!(
         punct!("*") >>
         mutability: alt!(
@@ -337,11 +331,12 @@
         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!("..."))) >>
-        punct!(")") >>
+        inputs_and_variadic: delim!(Parenthesis, do_parse!(
+            inputs: separated_list!(punct!(","), fn_arg) >>
+            trailing_comma: option!(punct!(",")) >>
+            variadic: option!(cond_reduce!(trailing_comma.is_some(), punct!("..."))) >>
+            ((inputs, variadic.is_some()))
+        )) >>
         output: option!(preceded!(
             punct!("->"),
             ty
@@ -350,21 +345,19 @@
             unsafety: unsafety,
             abi: abi,
             lifetimes: lifetimes,
-            inputs: inputs,
+            inputs: inputs_and_variadic.0,
             output: match output {
                 Some(ty) => FunctionRetTy::Ty(ty),
                 None => FunctionRetTy::Default,
             },
-            variadic: variadic.is_some(),
+            variadic: inputs_and_variadic.1,
         })))
     ));
 
     named!(ty_never -> Ty, map!(punct!("!"), |_| Ty::Never));
 
     named!(ty_tup -> Ty, do_parse!(
-        punct!("(") >>
-        elems: terminated_list!(punct!(","), ty) >>
-        punct!(")") >>
+        elems: delim!(Parenthesis, terminated_list!(punct!(","), ty)) >>
         (Ty::Tup(elems))
     ));
 
@@ -397,9 +390,7 @@
     ));
 
     named!(parenthesized_parameter_data -> PathParameters, do_parse!(
-        punct!("(") >>
-        inputs: terminated_list!(punct!(","), ty) >>
-        punct!(")") >>
+        inputs: delim!(Parenthesis, terminated_list!(punct!(","), ty)) >>
         output: option!(preceded!(
             punct!("->"),
             ty
@@ -457,9 +448,7 @@
     ));
 
     named!(ty_paren -> Ty, do_parse!(
-        punct!("(") >>
-        elem: ty >>
-        punct!(")") >>
+        elem: delim!(Parenthesis, ty) >>
         (Ty::Paren(Box::new(elem)))
     ));
 
@@ -572,8 +561,8 @@
     named!(pub fn_arg -> BareFnArg, do_parse!(
         name: option!(do_parse!(
             name: ident >>
+            not!(punct!("::")) >>
             punct!(":") >>
-            not!(tag!(":")) >> // not ::
             (name)
         )) >>
         ty: ty >>
@@ -591,7 +580,7 @@
 
     named!(pub abi -> Abi, do_parse!(
         keyword!("extern") >>
-        name: option!(quoted_string) >>
+        name: option!(string) >>
         (match name {
             Some(name) => Abi::Named(name),
             None => Abi::Rust,