Add keyword parser
diff --git a/src/data.rs b/src/data.rs
index 64c893d..30edc8b 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -53,7 +53,6 @@
     use ident::parsing::ident;
     use lit::parsing::int;
     use ty::parsing::ty;
-    use nom::multispace;
 
     named!(pub struct_body -> VariantData, alt!(
         struct_like_body => { VariantData::Struct }
@@ -134,8 +133,7 @@
 
     named!(pub visibility -> Visibility, alt!(
         do_parse!(
-            punct!("pub") >>
-            multispace >>
+            keyword!("pub") >>
             (Visibility::Public)
         )
         |
diff --git a/src/expr.rs b/src/expr.rs
index c2310ce..10e429f 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -340,7 +340,6 @@
     use generics::parsing::lifetime;
     use ident::parsing::ident;
     use lit::parsing::lit;
-    use nom::multispace;
     use ty::parsing::ty;
 
     named!(pub expr -> Expr, do_parse!(
@@ -414,8 +413,7 @@
     ));
 
     named!(expr_box -> Expr, do_parse!(
-        punct!("box") >>
-        multispace >>
+        keyword!("box") >>
         inner: expr >>
         (Expr::Box(Box::new(inner)))
     ));
@@ -511,8 +509,7 @@
     named!(expr_lit -> Expr, map!(lit, Expr::Lit));
 
     named!(and_cast -> Ty, do_parse!(
-        punct!("as") >>
-        multispace >>
+        keyword!("as") >>
         ty: ty >>
         (ty)
     ));
@@ -520,14 +517,13 @@
     named!(and_ascription -> Ty, preceded!(punct!(":"), ty));
 
     named!(expr_if -> Expr, do_parse!(
-        punct!("if") >>
-        multispace >>
+        keyword!("if") >>
         cond: expr >>
         punct!("{") >>
         then_block: within_block >>
         punct!("}") >>
         else_block: option!(preceded!(
-            punct!("else"),
+            keyword!("else"),
             alt!(
                 expr_if
                 |
@@ -554,7 +550,7 @@
 
     named!(expr_loop -> Expr, do_parse!(
         lt: option!(terminated!(lifetime, punct!(":"))) >>
-        punct!("loop") >>
+        keyword!("loop") >>
         loop_block: block >>
         (Expr::Loop(
             Box::new(loop_block),
@@ -588,7 +584,7 @@
     ));
 
     named!(block_check_mode -> BlockCheckMode, alt!(
-        punct!("unsafe") => { |_| BlockCheckMode::Unsafe }
+        keyword!("unsafe") => { |_| BlockCheckMode::Unsafe }
         |
         epsilon!() => { |_| BlockCheckMode::Default }
     ));
diff --git a/src/generics.rs b/src/generics.rs
index e7cc873..c0d5c94 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -88,7 +88,6 @@
     use super::*;
     use ident::parsing::ident;
     use ty::parsing::{ty, poly_trait_ref};
-    use nom::multispace;
 
     named!(pub generics -> Generics, do_parse!(
         bracketed: alt!(
@@ -133,7 +132,7 @@
     ));
 
     named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
-        punct!("for") >>
+        keyword!("for") >>
         punct!("<") >>
         lifetimes: separated_list!(punct!(","), lifetime_def) >>
         punct!(">") >>
@@ -171,8 +170,7 @@
 
     named!(pub where_clause -> WhereClause, alt!(
         do_parse!(
-            punct!("where") >>
-            multispace >>
+            keyword!("where") >>
             predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
             option!(punct!(",")) >>
             (WhereClause { predicates: predicates })
diff --git a/src/helper.rs b/src/helper.rs
index 2a429e9..de8b715 100644
--- a/src/helper.rs
+++ b/src/helper.rs
@@ -1,6 +1,7 @@
 #![cfg(feature = "parsing")]
 
 use nom::IResult;
+use unicode_xid::UnicodeXID;
 
 macro_rules! punct {
     ($i:expr, $punct:expr) => {
@@ -12,8 +13,7 @@
     for (i, ch) in input.char_indices() {
         if !ch.is_whitespace() {
             return if input[i..].starts_with(token) {
-                let end = i + token.len();
-                IResult::Done(&input[end..], &input[i..end])
+                IResult::Done(&input[i + token.len()..], token)
             } else {
                 IResult::Error
             };
@@ -22,6 +22,35 @@
     IResult::Error
 }
 
+macro_rules! keyword {
+    ($i:expr, $keyword:expr) => {
+        $crate::helper::keyword($i, $keyword)
+    };
+}
+
+pub fn keyword<'a>(input: &'a str, token: &'static str) -> IResult<&'a str, &'a str> {
+    match punct(input, token) {
+        IResult::Done(rest, _) => {
+            match word_break(rest) {
+                IResult::Done(_, _) => IResult::Done(rest, token),
+                IResult::Error => IResult::Error,
+            }
+        }
+        IResult::Error => IResult::Error,
+    }
+}
+
+pub fn word_break<'a>(input: &'a str) -> IResult<&'a str, ()> {
+    match input.chars().next() {
+        Some(ch) if UnicodeXID::is_xid_continue(ch) => {
+            IResult::Error
+        }
+        Some(_) | None => {
+            IResult::Done(input, ())
+        }
+    }
+}
+
 macro_rules! option {
     ($i:expr, $submac:ident!( $($args:tt)* )) => {
         match $submac!($i, $($args)*) {
diff --git a/src/item.rs b/src/item.rs
index b91af03..d8488c8 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -214,7 +214,6 @@
     use ident::parsing::ident;
     use macro_input::{Body, MacroInput};
     use macro_input::parsing::macro_input;
-    use nom::multispace;
 
     named!(pub item -> Item, alt!(
         item_extern_crate
@@ -237,13 +236,11 @@
     named!(item_extern_crate -> Item, do_parse!(
         attrs: many0!(attribute) >>
         vis: visibility >>
-        punct!("extern") >>
-        multispace >>
-        punct!("crate") >>
-        multispace >>
+        keyword!("extern") >>
+        keyword!("crate") >>
         id: ident >>
         rename: option!(preceded!(
-            tuple!(punct!("as"), multispace),
+            keyword!("as"),
             ident
         )) >>
         punct!(";") >>
diff --git a/src/lib.rs b/src/lib.rs
index 0841f17..df62d75 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,9 @@
 extern crate quote;
 
 #[cfg(feature = "parsing")]
+extern crate unicode_xid;
+
+#[cfg(feature = "parsing")]
 #[macro_use]
 mod nom;
 
diff --git a/src/macro_input.rs b/src/macro_input.rs
index 64a735e..848e609 100644
--- a/src/macro_input.rs
+++ b/src/macro_input.rs
@@ -27,8 +27,7 @@
     named!(pub macro_input -> MacroInput, do_parse!(
         attrs: many0!(attribute) >>
         vis: visibility >>
-        which: alt!(punct!("struct") | punct!("enum")) >>
-        multispace >>
+        which: alt!(keyword!("struct") | keyword!("enum")) >>
         id: ident >>
         generics: generics >>
         item: switch!(value!(which),
diff --git a/src/ty.rs b/src/ty.rs
index 0dc6eaf..35b640d 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -239,9 +239,9 @@
     named!(ty_ptr -> Ty, do_parse!(
         punct!("*") >>
         mutability: alt!(
-            punct!("const") => { |_| Mutability::Immutable }
+            keyword!("const") => { |_| Mutability::Immutable }
             |
-            punct!("mut") => { |_| Mutability::Mutable }
+            keyword!("mut") => { |_| Mutability::Mutable }
         ) >>
         target: ty >>
         (Ty::Ptr(Box::new(MutTy {
@@ -262,8 +262,7 @@
     ));
 
     named!(ty_bare_fn -> Ty, do_parse!(
-        punct!("fn") >>
-        multispace >>
+        keyword!("fn") >>
         lifetimes: opt_vec!(delimited!(
             punct!("<"),
             separated_list!(punct!(","), lifetime_def),
@@ -303,7 +302,7 @@
         punct!("<") >>
         this: map!(ty, Box::new) >>
         path: option!(preceded!(
-            tuple!(punct!("as"), multispace),
+            keyword!("as"),
             path
         )) >>
         punct!(">") >>
@@ -327,8 +326,7 @@
     ));
 
     named!(ty_impl_trait -> Ty, do_parse!(
-        punct!("impl") >>
-        multispace >>
+        keyword!("impl") >>
         elem: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
         (Ty::ImplTrait(elem))
     ));
@@ -342,8 +340,7 @@
 
     named!(mutability -> Mutability, alt!(
         do_parse!(
-            punct!("mut") >>
-            multispace >>
+            keyword!("mut") >>
             (Mutability::Mutable)
         )
         |