Macro utils::parser_parse_tree
source · macro_rules! parser_parse_tree { (@rule $input:ident $furthest_err:ident $furthest_remaining:ident [$(,)?] @expr $rhs:expr) => { ... }; (@rule $input:ident $furthest_err:ident $furthest_remaining:ident [$(,)?] @expr_res $rhs:expr) => { ... }; (@rule $input:ident $furthest_err:ident $furthest_remaining:ident [$(,)?] @subtree $($rhs:tt)+) => { ... }; (@rule $input:ident $furthest_err:ident $furthest_remaining:ident [$n:ident @ $lhs:expr $(,$($tail:tt)*)?] $($rhs:tt)+ ) => { ... }; (@rule $input:ident $furthest_err:ident $furthest_remaining:ident [$lhs:expr $(,$($tail:tt)*)?] $($rhs:tt)+ ) => { ... }; (@toplevel $input:ident $furthest_err:ident $furthest_remaining:ident ($($lhs:tt)+) => $rhs:expr $(, $($tail:tt)*)? ) => { ... }; (@toplevel $input:ident $furthest_err:ident $furthest_remaining:ident ($($lhs:tt)+) =?> $rhs:expr $(, $($tail:tt)*)? ) => { ... }; (@toplevel $input:ident $furthest_err:ident $furthest_remaining:ident ($($lhs:tt)+) =>> {$($rhs:tt)+} $(, $($tail:tt)*)? ) => { ... }; (@toplevel $input:ident $furthest_err:ident $furthest_remaining:ident $(,)?) => { ... }; (($($first:tt)+) $($tail:tt)+) => { ... }; }
Expand description
Macro to define a custom parser using a match
inspired parse tree syntax.
Each rule is made up of a list of chained parsers enclosed in brackets on the left-hand side.
Parsers can be prefixed with an identifier followed by @
to store the result of that parser in
the supplied variable, similar to normal match patterns.
After the list of parsers, there is an arrow determining the functionality of the rule when the parsers match:
- Expression (
=>
): The expression on the right-hand is evaluated and returned. - Fallible (
=?>
): Similar to Expression, but the right-hand side evaluates a result. If the expression evaluates toOk
, the value contained inside is returned. Otherwise, the string contained inside theErr
is handled as a customParseError
, and parsing will continue with the following rule. - Subtree (
=>>
): The right-hand side is a nested set of rules enclosed in braces.
If none of the rules match successfully, the error from the rule which parsed furthest into the input is returned.
§Examples
#[derive(Debug, PartialEq)]
enum Register {
A, B, C
}
#[derive(Debug, PartialEq)]
enum Instruction {
Add(Register, Register),
AddConstant(Register, i32),
Copy(Register, Register),
Noop,
}
let register = parser::literal_map!(
"A" => Register::A, "B" => Register::B, "C" => Register::C,
);
let instruction = parser::parse_tree!(
("add ", r @ register, ", ") =>> {
(r2 @ register) => Instruction::Add(r, r2),
(v @ parser::i32()) => Instruction::AddConstant(r, v),
},
("copy ", r @ register, ", ", r2 @ register) =?> {
if r == r2 {
Err("cannot copy register to itself")
} else {
Ok(Instruction::Copy(r, r2))
}
},
("noop") => Instruction::Noop,
);
assert_eq!(
instruction.parse_complete("add A, B").unwrap(),
Instruction::Add(Register::A, Register::B)
);
assert_eq!(
instruction.parse_complete("add C, 100").unwrap(),
Instruction::AddConstant(Register::C, 100)
);
assert_eq!(
instruction.parse_complete("copy A, B").unwrap(),
Instruction::Copy(Register::A, Register::B)
);
assert!(instruction
.parse_complete("copy A, A")
.is_err_and(|err| err.to_string().contains("cannot copy register to itself")));