[][src]Macro nom::alt

macro_rules! alt {
    (__impl $i:expr, $submac:ident!( $($args:tt)* ), $($rest:tt)* ) => { ... };
    (__impl $i:expr, $e:path, $($rest:tt)* ) => { ... };
    (__impl $i:expr, $e:path | $($rest:tt)*) => { ... };
    (__impl $i:expr, $subrule:ident!( $($args:tt)*) | $($rest:tt)*) => { ... };
    (__impl $i:expr, $subrule:ident!( $($args:tt)* ) => { $gen:expr } | $($rest:tt)*) => { ... };
    (__impl $i:expr, $e:path => { $gen:expr } | $($rest:tt)*) => { ... };
    (__impl $i:expr, __end) => { ... };
    ($i:expr, $($rest:tt)*) => { ... };
}

Try a list of parsers and return the result of the first successful one

This example is not tested
alt!(I -> IResult<I,O> | I -> IResult<I,O> | ... | I -> IResult<I,O> ) => I -> IResult<I, O>

All the parsers must have the same return type.

If one of the parsers 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!.

The alt! combinator is used in the following way:

This example is not tested
alt!(parser_1 | parser_2 | ... | parser_n)

Basic example

 // Create a parser that will match either "dragon" or "beast"
 named!( dragon_or_beast, alt!( tag!( "dragon" ) | tag!( "beast" ) ) );

 // Given the input "dragon slayer", the parser will match "dragon"
 // and the rest will be " slayer"
 let (rest, result) = dragon_or_beast(b"dragon slayer").unwrap();
 assert_eq!(result, b"dragon");
 assert_eq!(rest, b" slayer");

 // Given the input "beast of Gevaudan", the parser will match "beast"
 // and the rest will be " of Gevaudan"
 let (rest, result) = dragon_or_beast(&b"beast of Gevaudan"[..]).unwrap();
 assert_eq!(result, b"beast");
 assert_eq!(rest, b" of Gevaudan");

Manipulate results

There exists another syntax for alt! that gives you the ability to manipulate the result from each parser:

// We create an enum to represent our creatures
#[derive(Debug,PartialEq,Eq)]
enum Creature {
    Dragon,
    Beast,
    Unknown(usize)
}

// Let's make a helper function that returns true when not a space
// we are required to do this because the `take_while!` macro is limited
// to idents, so we can't negate `ìs_space` at the call site
fn is_not_space(c: u8) -> bool { ! nom::character::is_space(c) }

// Our parser will return the `Dragon` variant when matching "dragon",
// the `Beast` variant when matching "beast" and otherwise it will consume
// the input until a space is found and return an `Unknown` creature with
// the size of it's name.
named!(creature<Creature>, alt!(
    tag!("dragon")            => { |_| Creature::Dragon } |
    tag!("beast")             => { |_| Creature::Beast }  |
    take_while!(is_not_space) => { |r: &[u8]| Creature::Unknown(r.len()) }
    // the closure takes the result as argument if the parser is successful
));

// Given the input "dragon slayer" the parser will return `Creature::Dragon`
// and the rest will be " slayer"
let (rest, result) = creature(b"dragon slayer").unwrap();
assert_eq!(result, Creature::Dragon);
assert_eq!(rest, b" slayer");

// Given the input "beast of Gevaudan" the parser will return `Creature::Beast`
// and the rest will be " of Gevaudan"
let (rest, result) = creature(b"beast of Gevaudan").unwrap();
assert_eq!(result, Creature::Beast);
assert_eq!(rest, b" of Gevaudan");

// Given the input "demon hunter" the parser will return `Creature::Unknown(5)`
// and the rest will be " hunter"
let (rest, result) = creature(b"demon hunter").unwrap();
assert_eq!(result, Creature::Unknown(5));
assert_eq!(rest, b" hunter");

Behaviour of alt!

BE CAREFUL there is a case where the behaviour of alt! can be confusing:

When the alternatives have different lengths, like this case:

This example is not tested
 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:

This example is not tested
 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:

This example is not tested
 named!( test,
   alt!(
     complete!( tag!( "abcd" ) ) |
     complete!( tag!( "ef"   ) ) |
     complete!( tag!( "ghi"  ) ) |
     complete!( tag!( "kl"   ) )
   )
 );

This behaviour of alt! can get especially confusing if multiple alternatives have different sizes but a common prefix, like this:

This example is not tested
 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:

This example is not tested
 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.