I have an example Pest grammar:
WHITESPACE = _{ " " }
identifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_")* }
int_literal = { DECIMAL_NUMBER+ }
assignment_op = { ":=" }
formula = { (identifier ~ assignment_op ~ int_literal) | int_literal }
file = { formula ~ EOI }
and a pest-ast derives:
extern crate pest_derive;
extern crate from_pest;
extern crate pest_ast;
extern crate pest;
mod parser {
#[derive(Parser)]
#[grammar = "talk/formula.pest"]
pub struct Parser;
}
mod ast {
use super::parser::Rule;
use pest::Span;
fn span_into_str(span: Span) -> &str {
span.as_str()
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::int_literal))]
pub struct IntLiteral {
#[pest_ast(outer(with(span_into_str), with(str::parse::<i64>), with(Result::unwrap)))]
pub value: i64
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::identifier))]
pub struct Identifier {
#[pest_ast(inner(with(span_into_str), with(String::from)))]
pub value: String
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::assignment_op))]
pub struct AssignmentOp {
}
#[derive(Debug, FromPest)]
#[pest_ast(rule(Rule::formula))]
pub enum Formula {
Assignment {
lvalue: Identifier,
a: AssignmentOp, // can I skip this?
rvalue: IntLiteral,
},
IntLiteral {
rvalue: IntLiteral,
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::ast::*;
use pest::Parser;
use from_pest::FromPest;
#[test]
fn test_formula0() {
let source = "a := 12";
let mut parse_tree = parser::Parser::parse(parser::Rule::formula, source).unwrap();
println!("parse tree = {:#?}", parse_tree);
let syntax_tree: Formula = Formula::from_pest(&mut parse_tree).expect("infallible");
println!("syntax tree = {:#?}", syntax_tree);
}
}
Running the test, I'm getting infallible: NoMatch
panic.
- Does pest-ast even support deriving enum variants with fields?
- Can I match enum variant to a parenthesed
()
group of terminals? - Can I skip some terminals? I don't exactly need to know
:=
was used if I get anAssignmentExpression { lvalue, rvalue }
in the end.