macro_rules! select { (|$span:ident| $($p:pat $(if $guard:expr)? => $out:expr),+ $(,)?) => { ... }; ($($p:pat $(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 filter
.
The macro is semantically similar to a match
expression and so supports
pattern guards too.
ⓘ
select! {
Token::Bool(x) if x => Expr::True,
Token::Bool(x) if !x => Expr::False,
}
If you require access to the input’s span, you may add an argument before the patterns to gain access to it.
ⓘ
select! { |span|
Token::Num(x) => Expr::Num(x).spanned(span),
Token::Str(s) => Expr::Str(s).spanned(span),
}
Internally, select!
is a loose wrapper around filter_map
and thinking of it as such might make it less
confusing.
Examples
// 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::<_, _, _, _, Cheap<Token>>(|ast| {
let literal = select! {
Token::Num(x) => Ast::Num(x),
Token::Bool(x) => Ast::Bool(x),
};
literal.or(ast
.repeated()
.delimited_by(just(Token::LParen), just(Token::RParen))
.map(Ast::List))
});
use Token::*;
assert_eq!(
ast.parse(vec![LParen, Num(5), LParen, Bool(false), Num(42), RParen, RParen]),
Ok(Ast::List(vec![
Ast::Num(5),
Ast::List(vec![
Ast::Bool(false),
Ast::Num(42),
]),
])),
);