diff --git a/src/attr.rs b/src/attr.rs index 2862baef..387759a1 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -32,7 +32,7 @@ pub mod parsing { use helper::escaped_string; use nom::multispace; - named!(pub attribute<&str, Attribute>, alt!( + named!(pub attribute<&str, Attribute>, alt_complete!( do_parse!( punct!("#") >> punct!("[") >> @@ -64,7 +64,7 @@ pub mod parsing { tag_s!("\"") )); - named!(meta_item<&str, MetaItem>, alt!( + named!(meta_item<&str, MetaItem>, alt_complete!( do_parse!( ident: word >> punct!("(") >> diff --git a/src/common.rs b/src/common.rs index f6cec606..f2db35c3 100644 --- a/src/common.rs +++ b/src/common.rs @@ -42,23 +42,25 @@ pub enum Visibility { #[cfg(feature = "parsing")] pub mod parsing { use super::*; + use nom::multispace; fn ident_ch(ch: char) -> bool { ch.is_alphanumeric() || ch == '_' } named!(pub word<&str, Ident>, preceded!( - opt!(call!(::nom::multispace)), + option!(multispace), map!(take_while1_s!(ident_ch), Into::into) )); - named!(pub visibility<&str, Visibility>, preceded!( - opt!(call!(::nom::multispace)), - alt!( - terminated!(tag_s!("pub"), call!(::nom::multispace)) => { |_| Visibility::Public } - | - epsilon!() => { |_| Visibility::Inherited } + named!(pub visibility<&str, Visibility>, alt_complete!( + do_parse!( + punct!("pub") >> + multispace >> + (Visibility::Public) ) + | + epsilon!() => { |_| Visibility::Inherited } )); } diff --git a/src/generics.rs b/src/generics.rs index 04475ddb..2a00787b 100644 --- a/src/generics.rs +++ b/src/generics.rs @@ -71,7 +71,7 @@ pub mod parsing { use nom::multispace; named!(pub generics<&str, Generics>, do_parse!( - bracketed: alt!( + bracketed: alt_complete!( do_parse!( punct!("<") >> lifetimes: separated_list!(punct!(","), lifetime_def) >> @@ -89,7 +89,7 @@ pub mod parsing { punct!("where") >> multispace >> predicates: separated_nonempty_list!(punct!(","), where_predicate) >> - opt!(punct!(",")) >> + option!(punct!(",")) >> (predicates) )) >> (Generics { @@ -132,7 +132,7 @@ pub mod parsing { punct!(":"), separated_nonempty_list!(punct!("+"), ty_param_bound) )) >> - default: opt!(preceded!( + default: option!(preceded!( punct!("="), ty )) >> @@ -143,7 +143,7 @@ pub mod parsing { }) )); - named!(pub ty_param_bound<&str, TyParamBound>, alt!( + named!(pub ty_param_bound<&str, TyParamBound>, alt_complete!( tuple!(punct!("?"), punct!("Sized")) => { |_| TyParamBound::MaybeSized } | lifetime => { TyParamBound::Region } @@ -151,7 +151,7 @@ pub mod parsing { poly_trait_ref => { TyParamBound::Trait } )); - named!(where_predicate<&str, WherePredicate>, alt!( + named!(where_predicate<&str, WherePredicate>, alt_complete!( do_parse!( ident: lifetime >> punct!(":") >> diff --git a/src/helper.rs b/src/helper.rs index 6c9f6e2e..eec26d69 100644 --- a/src/helper.rs +++ b/src/helper.rs @@ -4,16 +4,29 @@ use nom::{self, IResult}; macro_rules! punct { ($i:expr, $punct:expr) => { - tuple!($i, opt!(call!(::nom::multispace)), tag_s!($punct)) + complete!($i, preceded!(opt!(call!(::nom::multispace)), tag_s!($punct))) }; } +macro_rules! option ( + ($i:expr, $submac:ident!( $($args:tt)* )) => ({ + match $submac!($i, $($args)*) { + ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, Some(o)), + ::nom::IResult::Error(_) => ::nom::IResult::Done($i, None), + ::nom::IResult::Incomplete(_) => ::nom::IResult::Done($i, None), + } + }); + ($i:expr, $f:expr) => ( + option!($i, call!($f)); + ); +); + macro_rules! opt_vec ( ($i:expr, $submac:ident!( $($args:tt)* )) => ({ match $submac!($i, $($args)*) { ::nom::IResult::Done(i, o) => ::nom::IResult::Done(i, o), ::nom::IResult::Error(_) => ::nom::IResult::Done($i, Vec::new()), - ::nom::IResult::Incomplete(i) => ::nom::IResult::Incomplete(i) + ::nom::IResult::Incomplete(_) => ::nom::IResult::Done($i, Vec::new()), } }); ); diff --git a/src/item.rs b/src/item.rs index aad903aa..7b4a9558 100644 --- a/src/item.rs +++ b/src/item.rs @@ -50,7 +50,7 @@ pub mod parsing { named!(pub item<&str, Item>, do_parse!( attrs: many0!(attribute) >> vis: visibility >> - which: alt!(tag_s!("struct") | tag_s!("enum")) >> + which: alt_complete!(punct!("struct") | punct!("enum")) >> multispace >> ident: word >> generics: generics >> @@ -71,11 +71,11 @@ pub mod parsing { body: body, }) ) >> - opt!(multispace) >> + option!(multispace) >> (item) )); - named!(struct_body<&str, (Style, Vec)>, alt!( + named!(struct_body<&str, (Style, Vec)>, alt_complete!( struct_like_body => { |fields| (Style::Struct, fields) } | terminated!(tuple_like_body, punct!(";")) => { |fields| (Style::Tuple, fields) } @@ -86,7 +86,7 @@ pub mod parsing { named!(enum_body<&str, Body>, do_parse!( punct!("{") >> variants: separated_list!(punct!(","), variant) >> - opt!(punct!(",")) >> + option!(punct!(",")) >> punct!("}") >> (Body::Enum(variants)) )); @@ -94,7 +94,7 @@ pub mod parsing { named!(variant<&str, Variant>, do_parse!( attrs: many0!(attribute) >> ident: word >> - body: alt!( + body: alt_complete!( struct_like_body => { |fields| (Style::Struct, fields) } | tuple_like_body => { |fields| (Style::Tuple, fields) } @@ -112,7 +112,7 @@ pub mod parsing { named!(struct_like_body<&str, Vec >, do_parse!( punct!("{") >> fields: separated_list!(punct!(","), struct_field) >> - opt!(punct!(",")) >> + option!(punct!(",")) >> punct!("}") >> (fields) )); @@ -120,7 +120,7 @@ pub mod parsing { named!(tuple_like_body<&str, Vec >, do_parse!( punct!("(") >> fields: separated_list!(punct!(","), tuple_field) >> - opt!(punct!(",")) >> + option!(punct!(",")) >> punct!(")") >> (fields) )); diff --git a/src/ty.rs b/src/ty.rs index ac680fec..18502580 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -188,7 +188,7 @@ pub mod parsing { use nom::{digit, multispace}; use std::str; - named!(pub ty<&str, Ty>, alt!( + named!(pub ty<&str, Ty>, alt_complete!( ty_vec | ty_fixed_length_vec @@ -223,14 +223,14 @@ pub mod parsing { punct!("[") >> elem: ty >> punct!(";") >> - opt!(multispace) >> + option!(multispace) >> size: map_res!(digit, str::parse) >> (Ty::FixedLengthVec(Box::new(elem), size)) )); named!(ty_ptr<&str, Ty>, do_parse!( punct!("*") >> - mutability: alt!( + mutability: alt_complete!( punct!("const") => { |_| Mutability::Immutable } | punct!("mut") => { |_| Mutability::Mutable } @@ -244,7 +244,7 @@ pub mod parsing { named!(ty_rptr<&str, Ty>, do_parse!( punct!("&") >> - life: opt!(lifetime) >> + life: option!(lifetime) >> mutability: mutability >> target: ty >> (Ty::Rptr(life, Box::new(MutTy { @@ -264,7 +264,7 @@ pub mod parsing { punct!("(") >> inputs: separated_list!(punct!(","), fn_arg) >> punct!(")") >> - output: opt!(preceded!( + output: option!(preceded!( punct!("->"), ty )) >> @@ -294,7 +294,7 @@ pub mod parsing { named!(ty_qpath<&str, Ty>, do_parse!( punct!("<") >> this: map!(ty, Box::new) >> - path: opt!(preceded!( + path: option!(preceded!( tuple!(punct!("as"), multispace), path )) >> @@ -332,17 +332,18 @@ pub mod parsing { (Ty::Paren(Box::new(elem))) )); - named!(mutability<&str, Mutability>, preceded!( - opt!(multispace), - alt!( - terminated!(tag_s!("mut"), multispace) => { |_| Mutability::Mutable } - | - epsilon!() => { |_| Mutability::Immutable } + named!(mutability<&str, Mutability>, alt_complete!( + do_parse!( + punct!("mut") >> + multispace >> + (Mutability::Mutable) ) + | + epsilon!() => { |_| Mutability::Immutable } )); named!(path<&str, Path>, do_parse!( - global: opt!(punct!("::")) >> + global: option!(punct!("::")) >> segments: separated_nonempty_list!(punct!("::"), path_segment) >> (Path { global: global.is_some(), @@ -350,7 +351,7 @@ pub mod parsing { }) )); - named!(path_segment<&str, PathSegment>, alt!( + named!(path_segment<&str, PathSegment>, alt_complete!( do_parse!( ident: word >> punct!("<") >> @@ -402,7 +403,7 @@ pub mod parsing { )); named!(fn_arg<&str, Arg>, do_parse!( - pat: opt!(terminated!(word, punct!(":"))) >> + pat: option!(terminated!(word, punct!(":"))) >> ty: ty >> (Arg { pat: pat, diff --git a/tests/test.rs b/tests/test.rs index 290a300b..82b2716d 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -8,6 +8,21 @@ fn simple_ty(ident: &str) -> Ty { }) } +#[test] +fn test_unit() { + let raw = "struct Unit;"; + + let expected = Item { + ident: "Unit".into(), + vis: Visibility::Inherited, + attrs: Vec::new(), + generics: Generics::default(), + body: Body::Struct(Style::Unit, Vec::new()), + }; + + assert_eq!(expected, parse(raw)); +} + #[test] fn test_struct() { let raw = "