nom::alt
[−]
[src]
macro_rules! alt { ($i:expr, $($rest:tt)*) => { ... }; }
alt!(I -> IResult<I,O> | I -> IResult<I,O> | ... | I -> IResult<I,O> ) => I -> IResult<I, O>
try a list of parsers, return the result of the first successful one
If one of the parser returns Incomplete, alt will return Incomplete, to retry once you get more input. Note that it is better for performance to know the minimum size of data you need before you get into alt.
named!( test, alt!( tag!( "abcd" ) | tag!( "efgh" ) ) ); let r1 = test(b"abcdefgh"); assert_eq!(r1, Done(&b"efgh"[..], &b"abcd"[..])); let r2 = test(&b"efghijkl"[..]); assert_eq!(r2, Done(&b"ijkl"[..], &b"efgh"[..]));
There is another syntax for alt allowing a block to manipulate the result:
#[derive(Debug,PartialEq,Eq)] enum Tagged { Abcd, Efgh, Took(usize) } named!(test<Tagged>, alt!( tag!("abcd") => { |_| Tagged::Abcd } | tag!("efgh") => { |_| Tagged::Efgh } | take!(5) => { |res: &[u8]| Tagged::Took(res.len()) } // the closure takes the result as argument if the parser is successful )); let r1 = test(b"abcdefgh"); assert_eq!(r1, Done(&b"efgh"[..], Tagged::Abcd)); let r2 = test(&b"efghijkl"[..]); assert_eq!(r2, Done(&b"ijkl"[..], Tagged::Efgh)); let r3 = test(&b"mnopqrst"[..]); assert_eq!(r3, Done(&b"rst"[..], Tagged::Took(5)));
BE CAREFUL there is a case where the behaviour of alt!
can be confusing:
when the alternatives have different lengths, like this case:
named!( test, alt!( tag!( "abcd" ) | tag!( "ef" ) | tag!( "ghi" ) | tag!( "kl" ) ) );
With this parser, if you pass "abcd"
as input, the first alternative parses it correctly,
but if you pass "efg"
, the first alternative will return Incomplete
, since it needs an input
of 4 bytes. This behaviour of alt!
is expected: if you get a partial input that isn't matched
by the first alternative, but would match if the input was complete, you want alt!
to indicate
that it cannot decide with limited information.
There are two ways to fix this behaviour. The first one consists in ordering the alternatives by size, like this:
named!( test, alt!( tag!( "ef" ) | tag!( "kl") | tag!( "ghi" ) | tag!( "abcd" ) ) );
With this solution, the largest alternative will be tested last.
The other solution uses the complete!
combinator, which transforms an Incomplete
in an
Error
. If one of the alternatives returns Incomplete
but is wrapped by complete!
,
alt!
will try the next alternative. This is useful when you know that
you will not get partial input:
named!( test, alt!( complete!( tag!( "abcd" ) ) | complete!( tag!( "ef" ) ) | complete!( tag!( "ghi" ) ) | complete!( tag!( "kl" ) ) ) );
If you want the complete!
combinator to be applied to all rules then use the convenience
alt_complete!
macro (see below).
This behaviour of alt!
can get especially confusing if multiple alternatives have different
sizes but a common prefix, like this:
named!( test, alt!( tag!( "abcd" ) | tag!( "ab" ) | tag!( "ef" ) ) );
in that case, if you order by size, passing "abcd"
as input will always be matched by the
smallest parser, so the solution using complete!
is better suited.
You can also nest multiple alt!
, like this:
named!( test, alt!( preceded!( tag!("ab"), alt!( tag!( "cd" ) | eof ) ) | tag!( "ef" ) ) );
preceded!
will first parse "ab"
then, if successful, try the alternatives "cd",
or empty input (End Of File). If none of them work, preceded!
will fail and
"ef" will be tested.