pub fn choice<T, E>(parsers: T) -> Choice<T, E>
Expand description
Parse using a tuple or array of many parsers, producing the output of the first to successfully parse.
This primitive has a twofold improvement over a chain of Parser::or
calls:
-
Rust’s trait solver seems to resolve the
Parser
impl for this type much faster, significantly reducing compilation times. -
Parsing is likely a little faster in some cases because the resulting parser is ‘less careful’ about error routing, and doesn’t perform the same fine-grained error prioritisation that
Parser::or
does.
These qualities make this parser ideal for lexers.
The output type of this parser is the output type of the inner parsers.
Examples
#[derive(Clone, Debug, PartialEq)]
enum Token {
If,
For,
While,
Fn,
Int(u64),
Ident(String),
}
let tokens = choice::<_, Simple<char>>((
text::keyword("if").to(Token::If),
text::keyword("for").to(Token::For),
text::keyword("while").to(Token::While),
text::keyword("fn").to(Token::Fn),
text::int(10).from_str().unwrapped().map(Token::Int),
text::ident().map(Token::Ident),
))
.padded()
.repeated();
use Token::*;
assert_eq!(
tokens.parse("if 56 for foo while 42 fn bar"),
Ok(vec![If, Int(56), For, Ident("foo".to_string()), While, Int(42), Fn, Ident("bar".to_string())]),
);
If you have more than 26 choices, the array-form of choice will work for any length. The downside being that the contained parsers must all be of the same type.
#[derive(Clone, Debug, PartialEq)]
enum Token {
If,
For,
While,
Fn,
Def,
}
let tokens = choice::<_, Simple<char>>([
text::keyword("if").to(Token::If),
text::keyword("for").to(Token::For),
text::keyword("while").to(Token::While),
text::keyword("fn").to(Token::Fn),
text::keyword("def").to(Token::Def),
])
.padded()
.repeated();
use Token::*;
assert_eq!(
tokens.parse("def fn while if for"),
Ok(vec![Def, Fn, While, If, For]),
);