macro_rules! select {
($($p:pat $(= $extra:ident)? $(if $guard:expr)? $(=> $out:expr)?),+ $(,)?) => { ... };
}Expand description
Create a parser that selects one or more input patterns and map them to an output value.
This is most useful when turning the tokens of a previous compilation pass (such as lexing) into data that can be
used for parsing, although it can also generally be used to select inputs and map them to outputs. Any unmapped
input patterns will become syntax errors, just as with Parser::filter.
Internally, select! is very similar to a single-token Parser::filter and thinking of it as such might make
it less confusing.
select! requires that tokens implement Clone and the input type implements ValueInput. If you’re trying
to access tokens referentially (for the sake of nested parsing, or simply because you want to avoid cloning the
token), see select_ref!.
§Examples
select! is syntactically similar to a match expression and has support for
pattern guards:
#[derive(Clone)]
enum Token<'src> { Ident(&'src str) }
enum Expr<'src> { Local(&'src str), Null, True, False }
select! {
Token::Ident(s) if s == "true" => Expr::True,
Token::Ident(s) if s == "false" => Expr::False,
Token::Ident(s) if s == "null" => Expr::Null,
Token::Ident(s) => Expr::Local(s),
}If you require access to the token’s span or other metadata, you may add an argument after a pattern to gain access
to it (see the docs for Parser::map_with and MapExtra):
#[derive(Clone)]
enum Token<'src> { Num(f64), Str(&'src str) }
enum Expr<'src> { Num(f64), Str(&'src str) }
type Span = SimpleSpan<usize>;
impl<'src> Expr<'src> {
fn spanned(self, span: Span) -> (Self, Span) { (self, span) }
}
select! {
Token::Num(x) = e => Expr::Num(x).spanned(e.span()),
Token::Str(s) = e => Expr::Str(s).spanned(e.span()),
}// The type of our parser's input (tokens like this might be emitted by your compiler's lexer)
#[derive(Clone, Debug, PartialEq)]
enum Token {
Num(u64),
Bool(bool),
LParen,
RParen,
}
// The type of our parser's output, a syntax tree
#[derive(Debug, PartialEq)]
enum Ast {
Num(u64),
Bool(bool),
List(Vec<Ast>),
}
// Our parser converts a stream of input tokens into an AST
// `select!` is used to deconstruct some of the tokens and turn them into AST nodes
let ast = recursive::<_, _, extra::Err<Simple<Token>>, _, _>(|ast| {
let literal = select! {
Token::Num(x) => Ast::Num(x),
Token::Bool(x) => Ast::Bool(x),
};
literal.or(ast
.repeated()
.collect()
.delimited_by(just(Token::LParen), just(Token::RParen))
.map(Ast::List))
});
use Token::*;
assert_eq!(
ast.parse(&[LParen, Num(5), LParen, Bool(false), Num(42), RParen, RParen]).into_result(),
Ok(Ast::List(vec![
Ast::Num(5),
Ast::List(vec![
Ast::Bool(false),
Ast::Num(42),
]),
])),
);