Switch from chain to do_parse
diff --git a/src/attr.rs b/src/attr.rs
index a5d7c7d..266bbb4 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -30,28 +30,28 @@
 }
 
 named!(pub attribute<&str, Attribute>, alt!(
-    chain!(
-        punct!("#") ~
-        punct!("[") ~
-        meta_item: meta_item ~
-        punct!("]"),
-        move || Attribute {
+    do_parse!(
+        punct!("#") >>
+        punct!("[") >>
+        meta_item: meta_item >>
+        punct!("]") >>
+        (Attribute {
             value: meta_item,
             is_sugared_doc: false,
-        }
+        })
     )
     |
-    chain!(
-        punct!("///") ~
-        space: multispace ~
-        content: take_until_s!("\n"),
-        move || Attribute {
+    do_parse!(
+        punct!("///") >>
+        space: multispace >>
+        content: take_until_s!("\n") >>
+        (Attribute {
             value: MetaItem::NameValue(
                 "doc".to_string(),
                 format!("///{}{}", space, content),
             ),
             is_sugared_doc: true,
-        }
+        })
     )
 ));
 
@@ -62,19 +62,19 @@
 ));
 
 named!(meta_item<&str, MetaItem>, alt!(
-    chain!(
-        ident: word ~
-        punct!("(") ~
-        inner: separated_list!(punct!(","), meta_item) ~
-        punct!(")"),
-        move || MetaItem::List(ident, inner)
+    do_parse!(
+        ident: word >>
+        punct!("(") >>
+        inner: separated_list!(punct!(","), meta_item) >>
+        punct!(")") >>
+        (MetaItem::List(ident, inner))
     )
     |
-    chain!(
-        ident: word ~
-        punct!("=") ~
-        string: quoted,
-        move || MetaItem::NameValue(ident, string)
+    do_parse!(
+        ident: word >>
+        punct!("=") >>
+        string: quoted >>
+        (MetaItem::NameValue(ident, string))
     )
     |
     map!(word, MetaItem::Word)
diff --git a/src/do_parse.rs b/src/do_parse.rs
new file mode 100644
index 0000000..d56461c
--- /dev/null
+++ b/src/do_parse.rs
@@ -0,0 +1,101 @@
+// Copied from nom master:
+// https://github.com/Geal/nom/blob/a38188f333c29d00c32a3082bec5491d2eefa33f/src/sequence.rs#L591-L687
+// Will be released in nom 2.0.
+
+#[macro_export]
+macro_rules! do_parse (
+  ($i:expr, $($rest:tt)*) => (
+    {
+      do_parse_impl!($i, 0usize, $($rest)*)
+    }
+  );
+);
+
+/// Internal parser, do not use directly
+#[doc(hidden)]
+#[macro_export]
+macro_rules! do_parse_impl (
+
+  ($i:expr, $consumed:expr, ( $($rest:expr),* )) => (
+    ::nom::IResult::Done($i, ( $($rest),* ))
+  );
+
+  ($i:expr, $consumed:expr, $e:ident >> $($rest:tt)*) => (
+    do_parse_impl!($i, $consumed, call!($e) >> $($rest)*);
+  );
+  ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => (
+    {
+      match $submac!($i, $($args)*) {
+        ::nom::IResult::Error(e)      => ::nom::IResult::Error(e),
+        ::nom::IResult::Incomplete(::nom::Needed::Unknown) =>
+          ::nom::IResult::Incomplete(::nom::Needed::Unknown),
+        ::nom::IResult::Incomplete(::nom::Needed::Size(i)) =>
+          ::nom::IResult::Incomplete(::nom::Needed::Size($consumed + i)),
+        ::nom::IResult::Done(i,_)     => {
+          do_parse_impl!(i,
+            $consumed + (::nom::InputLength::input_len(&($i)) -
+                         ::nom::InputLength::input_len(&i)), $($rest)*)
+        },
+      }
+    }
+  );
+
+  ($i:expr, $consumed:expr, $field:ident : $e:ident >> $($rest:tt)*) => (
+    do_parse_impl!($i, $consumed, $field: call!($e) >> $($rest)*);
+  );
+
+  ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> $($rest:tt)*) => (
+    {
+      match  $submac!($i, $($args)*) {
+        ::nom::IResult::Error(e)      => ::nom::IResult::Error(e),
+        ::nom::IResult::Incomplete(::nom::Needed::Unknown) =>
+          ::nom::IResult::Incomplete(::nom::Needed::Unknown),
+        ::nom::IResult::Incomplete(::nom::Needed::Size(i)) =>
+          ::nom::IResult::Incomplete(::nom::Needed::Size($consumed + i)),
+        ::nom::IResult::Done(i,o)     => {
+          let $field = o;
+          do_parse_impl!(i,
+            $consumed + (::nom::InputLength::input_len(&($i)) -
+                         ::nom::InputLength::input_len(&i)), $($rest)*)
+        },
+      }
+    }
+  );
+
+  // ending the chain
+  ($i:expr, $consumed:expr, $e:ident >> ( $($rest:tt)* )) => (
+    do_parse_impl!($i, $consumed, call!($e) >> ( $($rest)* ));
+  );
+
+  ($i:expr, $consumed:expr, $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => (
+    match $submac!($i, $($args)*) {
+      ::nom::IResult::Error(e)      => ::nom::IResult::Error(e),
+      ::nom::IResult::Incomplete(::nom::Needed::Unknown) =>
+        ::nom::IResult::Incomplete(::nom::Needed::Unknown),
+      ::nom::IResult::Incomplete(::nom::Needed::Size(i)) =>
+        ::nom::IResult::Incomplete(::nom::Needed::Size($consumed + i)),
+      ::nom::IResult::Done(i,_)     => {
+        ::nom::IResult::Done(i, ( $($rest)* ))
+      },
+    }
+  );
+
+  ($i:expr, $consumed:expr, $field:ident : $e:ident >> ( $($rest:tt)* )) => (
+    do_parse_impl!($i, $consumed, $field: call!($e) >> ( $($rest)* ) );
+  );
+
+  ($i:expr, $consumed:expr, $field:ident : $submac:ident!( $($args:tt)* ) >> ( $($rest:tt)* )) => (
+    match $submac!($i, $($args)*) {
+      ::nom::IResult::Error(e)      => ::nom::IResult::Error(e),
+      ::nom::IResult::Incomplete(::nom::Needed::Unknown) =>
+        ::nom::IResult::Incomplete(::nom::Needed::Unknown),
+      ::nom::IResult::Incomplete(::nom::Needed::Size(i)) =>
+        ::nom::IResult::Incomplete(::nom::Needed::Size($consumed + i)),
+      ::nom::IResult::Done(i,o)     => {
+        let $field = o;
+        ::nom::IResult::Done(i, ( $($rest)* ))
+      },
+    }
+  );
+
+);
diff --git a/src/generics.rs b/src/generics.rs
index 92a6a1d..425228d 100644
--- a/src/generics.rs
+++ b/src/generics.rs
@@ -67,33 +67,33 @@
     pub bounds: Vec<Lifetime>,
 }
 
-named!(pub generics<&str, Generics>, chain!(
+named!(pub generics<&str, Generics>, do_parse!(
     bracketed: alt!(
-        chain!(
-            punct!("<") ~
-            lifetimes: separated_list!(punct!(","), lifetime_def) ~
+        do_parse!(
+            punct!("<") >>
+            lifetimes: separated_list!(punct!(","), lifetime_def) >>
             ty_params: opt_vec!(preceded!(
                 cond!(!lifetimes.is_empty(), punct!(",")),
                 separated_nonempty_list!(punct!(","), ty_param)
-            )) ~
-            punct!(">"),
-            move || (lifetimes, ty_params)
+            )) >>
+            punct!(">") >>
+            (lifetimes, ty_params)
         )
         |
         epsilon!() => { |_| (Vec::new(), Vec::new()) }
-    ) ~
-    where_clause: opt_vec!(chain!(
-        punct!("where") ~
-        multispace ~
-        predicates: separated_nonempty_list!(punct!(","), where_predicate) ~
-        punct!(",")? ~
-        move || predicates
-    )),
-    move || Generics {
+    ) >>
+    where_clause: opt_vec!(do_parse!(
+        punct!("where") >>
+        multispace >>
+        predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
+        opt!(punct!(",")) >>
+        (predicates)
+    )) >>
+    (Generics {
         lifetimes: bracketed.0,
         ty_params: bracketed.1,
         where_clause: where_clause,
-    }
+    })
 ));
 
 named!(pub lifetime<&str, Lifetime>, preceded!(
@@ -101,41 +101,41 @@
     map!(word, |ident| Lifetime { ident: ident })
 ));
 
-named!(pub lifetime_def<&str, LifetimeDef>, chain!(
-    life: lifetime ~
+named!(pub lifetime_def<&str, LifetimeDef>, do_parse!(
+    life: lifetime >>
     bounds: opt_vec!(preceded!(
         punct!(":"),
         separated_nonempty_list!(punct!(","), lifetime)
-    )),
-    move || LifetimeDef {
+    )) >>
+    (LifetimeDef {
         lifetime: life,
         bounds: bounds,
-    }
+    })
 ));
 
-named!(pub bound_lifetimes<&str, Vec<LifetimeDef> >, opt_vec!(chain!(
-    punct!("for") ~
-    punct!("<") ~
-    lifetimes: separated_list!(punct!(","), lifetime_def) ~
-    punct!(">"),
-    move || lifetimes
+named!(pub bound_lifetimes<&str, Vec<LifetimeDef> >, opt_vec!(do_parse!(
+    punct!("for") >>
+    punct!("<") >>
+    lifetimes: separated_list!(punct!(","), lifetime_def) >>
+    punct!(">") >>
+    (lifetimes)
 )));
 
-named!(ty_param<&str, TyParam>, chain!(
-    ident: word ~
+named!(ty_param<&str, TyParam>, do_parse!(
+    ident: word >>
     bounds: opt_vec!(preceded!(
         punct!(":"),
         separated_nonempty_list!(punct!("+"), ty_param_bound)
-    )) ~
+    )) >>
     default: opt!(preceded!(
         punct!("="),
         ty
-    )) ~
-    move || TyParam {
+    )) >>
+    (TyParam {
         ident: ident,
         bounds: bounds,
         default: default,
-    }
+    })
 ));
 
 named!(pub ty_param_bound<&str, TyParamBound>, alt!(
@@ -147,25 +147,25 @@
 ));
 
 named!(where_predicate<&str, WherePredicate>, alt!(
-    chain!(
-        ident: lifetime ~
-        punct!(":") ~
-        bounds: separated_nonempty_list!(punct!("+"), lifetime),
-        move || WherePredicate::RegionPredicate(WhereRegionPredicate {
+    do_parse!(
+        ident: lifetime >>
+        punct!(":") >>
+        bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
+        (WherePredicate::RegionPredicate(WhereRegionPredicate {
             lifetime: ident,
             bounds: bounds,
-        })
+        }))
     )
     |
-    chain!(
-        bound_lifetimes: bound_lifetimes ~
-        bounded_ty: ty ~
-        punct!(":") ~
-        bounds: separated_nonempty_list!(punct!("+"), ty_param_bound),
-        move || WherePredicate::BoundPredicate(WhereBoundPredicate {
+    do_parse!(
+        bound_lifetimes: bound_lifetimes >>
+        bounded_ty: ty >>
+        punct!(":") >>
+        bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
+        (WherePredicate::BoundPredicate(WhereBoundPredicate {
             bound_lifetimes: bound_lifetimes,
             bounded_ty: bounded_ty,
             bounds: bounds,
-        })
+        }))
     )
 ));
diff --git a/src/item.rs b/src/item.rs
index cab2685..544b55f 100644
--- a/src/item.rs
+++ b/src/item.rs
@@ -44,13 +44,13 @@
     pub ty: Ty,
 }
 
-named!(pub item<&str, Item>, chain!(
-    attrs: many0!(attribute) ~
-    vis: visibility ~
-    which: alt!(tag_s!("struct") | tag_s!("enum")) ~
-    multispace ~
-    ident: word ~
-    generics: generics ~
+named!(pub item<&str, Item>, do_parse!(
+    attrs: many0!(attribute) >>
+    vis: visibility >>
+    which: alt!(tag_s!("struct") | tag_s!("enum")) >>
+    multispace >>
+    ident: word >>
+    generics: generics >>
     item: switch!(value!(which),
         "struct" => map!(struct_body, move |(style, fields)| Item {
             ident: ident,
@@ -67,9 +67,9 @@
             generics: generics,
             body: body,
         })
-    ) ~
-    multispace?,
-    move || item
+    ) >>
+    opt!(multispace) >>
+    (item)
 ));
 
 named!(struct_body<&str, (Style, Vec<Field>)>, alt!(
@@ -80,70 +80,70 @@
     punct!(";") => { |_| (Style::Unit, Vec::new()) }
 ));
 
-named!(enum_body<&str, Body>, chain!(
-    punct!("{") ~
-    variants: separated_list!(punct!(","), variant) ~
-    punct!(",")? ~
-    punct!("}"),
-    move || Body::Enum(variants)
+named!(enum_body<&str, Body>, do_parse!(
+    punct!("{") >>
+    variants: separated_list!(punct!(","), variant) >>
+    opt!(punct!(",")) >>
+    punct!("}") >>
+    (Body::Enum(variants))
 ));
 
-named!(variant<&str, Variant>, chain!(
-    attrs: many0!(attribute) ~
-    ident: word ~
+named!(variant<&str, Variant>, do_parse!(
+    attrs: many0!(attribute) >>
+    ident: word >>
     body: alt!(
         struct_like_body => { |fields| (Style::Struct, fields) }
         |
         tuple_like_body => { |fields| (Style::Tuple, fields) }
         |
         epsilon!() => { |_| (Style::Unit, Vec::new()) }
-    ),
-    move || Variant {
+    ) >>
+    (Variant {
         ident: ident,
         attrs: attrs,
         style: body.0,
         fields: body.1,
-    }
+    })
 ));
 
-named!(struct_like_body<&str, Vec<Field> >, chain!(
-    punct!("{") ~
-    fields: separated_list!(punct!(","), struct_field) ~
-    punct!(",")? ~
-    punct!("}"),
-    move || fields
+named!(struct_like_body<&str, Vec<Field> >, do_parse!(
+    punct!("{") >>
+    fields: separated_list!(punct!(","), struct_field) >>
+    opt!(punct!(",")) >>
+    punct!("}") >>
+    (fields)
 ));
 
-named!(tuple_like_body<&str, Vec<Field> >, chain!(
-    punct!("(") ~
-    fields: separated_list!(punct!(","), tuple_field) ~
-    punct!(",")? ~
-    punct!(")"),
-    move || fields
+named!(tuple_like_body<&str, Vec<Field> >, do_parse!(
+    punct!("(") >>
+    fields: separated_list!(punct!(","), tuple_field) >>
+    opt!(punct!(",")) >>
+    punct!(")") >>
+    (fields)
 ));
 
-named!(struct_field<&str, Field>, chain!(
-    attrs: many0!(attribute) ~
-    vis: visibility ~
-    ident: word ~
-    punct!(":") ~
-    ty: ty,
-    move || Field {
+named!(struct_field<&str, Field>, do_parse!(
+    attrs: many0!(attribute) >>
+    vis: visibility >>
+    ident: word >>
+    punct!(":") >>
+    ty: ty >>
+    (Field {
         ident: Some(ident),
         vis: vis,
         attrs: attrs,
         ty: ty,
-    }
+    })
 ));
 
-named!(tuple_field<&str, Field>, chain!(
-    attrs: many0!(attribute) ~
-    vis: visibility ~
-    ty: ty,
-    move || Field {
+named!(tuple_field<&str, Field>, do_parse!(
+    attrs: many0!(attribute) >>
+    vis: visibility >>
+    ty: ty >>
+    (Field {
         ident: None,
         vis: vis,
         attrs: attrs,
         ty: ty,
-    }
+    })
 ));
diff --git a/src/lib.rs b/src/lib.rs
index de2418c..ebd3c8e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,6 +2,9 @@
 extern crate nom;
 
 #[macro_use]
+mod do_parse;
+
+#[macro_use]
 mod helper;
 
 mod attr;
diff --git a/src/ty.rs b/src/ty.rs
index 4aa3199..7393719 100644
--- a/src/ty.rs
+++ b/src/ty.rs
@@ -193,56 +193,56 @@
         punct!("]")
     ) => { |elem| Ty::Vec(Box::new(elem)) }
     |
-    chain!(
-        punct!("[") ~
-        elem: ty ~
-        punct!(";") ~
-        multispace? ~
-        size: map_res!(digit, str::parse),
-        move || Ty::FixedLengthVec(Box::new(elem), size)
+    do_parse!(
+        punct!("[") >>
+        elem: ty >>
+        punct!(";") >>
+        opt!(multispace) >>
+        size: map_res!(digit, str::parse) >>
+        (Ty::FixedLengthVec(Box::new(elem), size))
     )
     |
-    chain!(
-        punct!("*") ~
+    do_parse!(
+        punct!("*") >>
         mutability: alt!(
             punct!("const") => { |_| Mutability::Immutable }
             |
             punct!("mut") => { |_| Mutability::Mutable }
-        ) ~
-        target: ty,
-        move || Ty::Ptr(Box::new(MutTy {
+        ) >>
+        target: ty >>
+        (Ty::Ptr(Box::new(MutTy {
             ty: target,
             mutability: mutability,
-        }))
+        })))
     )
     |
-    chain!(
-        punct!("&") ~
-        life: lifetime? ~
-        mutability: mutability ~
-        target: ty,
-        move || Ty::Rptr(life, Box::new(MutTy {
+    do_parse!(
+        punct!("&") >>
+        life: opt!(lifetime) >>
+        mutability: mutability >>
+        target: ty >>
+        (Ty::Rptr(life, Box::new(MutTy {
             ty: target,
             mutability: mutability,
-        }))
+        })))
     )
     |
-    chain!(
-        punct!("fn") ~
-        multispace ~
+    do_parse!(
+        punct!("fn") >>
+        multispace >>
         lifetimes: opt_vec!(delimited!(
             punct!("<"),
             separated_list!(punct!(","), lifetime_def),
             punct!(">")
-        )) ~
-        punct!("(") ~
-        inputs: separated_list!(punct!(","), fn_arg) ~
-        punct!(")") ~
+        )) >>
+        punct!("(") >>
+        inputs: separated_list!(punct!(","), fn_arg) >>
+        punct!(")") >>
         output: opt!(preceded!(
             punct!("->"),
             ty
-        )),
-        move || Ty::BareFn(Box::new(BareFnTy {
+        )) >>
+        (Ty::BareFn(Box::new(BareFnTy {
             lifetimes: lifetimes,
             decl: FnDecl {
                 inputs: inputs,
@@ -251,7 +251,7 @@
                     None => FunctionRetTy::Default,
                 },
             },
-        }))
+        })))
     )
     |
     punct!("!") => { |_| Ty::Never }
@@ -264,17 +264,17 @@
     |
     path => { |p| Ty::Path(None, p) }
     |
-    chain!(
-        punct!("<") ~
-        this: map!(ty, Box::new) ~
+    do_parse!(
+        punct!("<") >>
+        this: map!(ty, Box::new) >>
         path: opt!(preceded!(
             tuple!(punct!("as"), multispace),
             path
-        )) ~
-        punct!(">") ~
-        punct!("::") ~
-        rest: separated_nonempty_list!(punct!("::"), path_segment),
-        move || {
+        )) >>
+        punct!(">") >>
+        punct!("::") >>
+        rest: separated_nonempty_list!(punct!("::"), path_segment) >>
+        ({
             match path {
                 Some(mut path) => {
                     let pos = path.segments.len();
@@ -288,7 +288,7 @@
                     })
                 }
             }
-        }
+        })
     )
     |
     preceded!(
@@ -312,33 +312,33 @@
     )
 ));
 
-named!(path<&str, Path>, chain!(
-    global: punct!("::")? ~
-    segments: separated_nonempty_list!(punct!("::"), path_segment),
-    move || Path {
+named!(path<&str, Path>, do_parse!(
+    global: opt!(punct!("::")) >>
+    segments: separated_nonempty_list!(punct!("::"), path_segment) >>
+    (Path {
         global: global.is_some(),
         segments: segments,
-    }
+    })
 ));
 
 named!(path_segment<&str, PathSegment>, alt!(
-    chain!(
-        ident: word ~
-        punct!("<") ~
-        lifetimes: separated_list!(punct!(","), lifetime) ~
+    do_parse!(
+        ident: word >>
+        punct!("<") >>
+        lifetimes: separated_list!(punct!(","), lifetime) >>
         types: opt_vec!(preceded!(
             cond!(!lifetimes.is_empty(), punct!(",")),
             separated_nonempty_list!(
                 punct!(","),
                 terminated!(ty, not!(peek!(punct!("="))))
             )
-        )) ~
+        )) >>
         bindings: opt_vec!(preceded!(
             cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
             separated_nonempty_list!(punct!(","), type_binding)
-        )) ~
-        punct!(">"),
-        move || PathSegment {
+        )) >>
+        punct!(">") >>
+        (PathSegment {
             ident: ident,
             parameters: PathParameters::AngleBracketed(
                 AngleBracketedParameterData {
@@ -347,36 +347,36 @@
                     bindings: bindings,
                 }
             ),
-        }
+        })
     )
     |
     map!(word, PathSegment::ident)
 ));
 
-named!(type_binding<&str, TypeBinding>, chain!(
-    ident: word ~
-    punct!("=") ~
-    ty: ty,
-    move || TypeBinding {
+named!(type_binding<&str, TypeBinding>, do_parse!(
+    ident: word >>
+    punct!("=") >>
+    ty: ty >>
+    (TypeBinding {
         ident: ident,
         ty: ty,
-    }
+    })
 ));
 
-named!(pub poly_trait_ref<&str, PolyTraitRef>, chain!(
-    bound_lifetimes: bound_lifetimes ~
-    trait_ref: path,
-    move || PolyTraitRef {
+named!(pub poly_trait_ref<&str, PolyTraitRef>, do_parse!(
+    bound_lifetimes: bound_lifetimes >>
+    trait_ref: path >>
+    (PolyTraitRef {
         bound_lifetimes: bound_lifetimes,
         trait_ref: trait_ref,
-    }
+    })
 ));
 
-named!(fn_arg<&str, Arg>, chain!(
-    pat: opt!(terminated!(word, punct!(":"))) ~
-    ty: ty,
-    move || Arg {
+named!(fn_arg<&str, Arg>, do_parse!(
+    pat: opt!(terminated!(word, punct!(":"))) >>
+    ty: ty >>
+    (Arg {
         pat: pat,
         ty: ty,
-    }
+    })
 ));