parser_parse_tree

Macro parser_parse_tree 

Source
macro_rules! parser_parse_tree {
    (@rule $input:ident $state:ident $commit:ident $token:ident [$(,)?] @expr $rhs:expr) => { ... };
    (@rule $input:ident $state:ident $commit:ident $token:ident [$(,)?] @expr_res $rhs:expr) => { ... };
    (@rule $input:ident $state:ident $commit:ident $token:ident [$(,)?] @subtree $($rhs:tt)+) => { ... };
    (@rule $input:ident $state:ident $commit:ident $token:ident
        [$n:ident @ $lhs:expr $(,$($tail:tt)*)?] $($rhs:tt)+
    ) => { ... };
    (@rule $input:ident $state:ident $commit:ident $token:ident
        [$lhs:expr $(,$($tail:tt)*)?] $($rhs:tt)+
    ) => { ... };
    (@toplevel $input:ident $state:ident $commit:ident $token:ident
        ($($lhs:tt)+) => $rhs:expr $(, $($tail:tt)*)?
    ) => { ... };
    (@toplevel $input:ident $state:ident $commit:ident $token:ident
        ($($lhs:tt)+) =?> $rhs:expr $(, $($tail:tt)*)?
    ) => { ... };
    (@toplevel $input:ident $state:ident $commit:ident $token:ident
        ($($lhs:tt)+) =>> {$($rhs:tt)+} $(, $($tail:tt)*)?
    ) => { ... };
    (@toplevel $input:ident $state:ident $commit:ident $token:ident $(,)?) => { ... };
    (($($first:tt)+) $($tail:tt)+) => { ... };
}
Expand description

Helper 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 to Ok, the value contained inside is returned. Otherwise, the string contained inside the Err is handled as a custom ParseError, and parsing will continue with the following rule.
  • Subtree (=>>): The right-hand side is a nested set of rules enclosed in braces.

Both the top-level and each =>> subtree create their own commit scopes. If a parser commits, no more branches within the current scope are tried.

ยง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")));