Use pratt parser for prefix logic

This commit is contained in:
Joscha 2022-11-01 15:14:30 +01:00
parent 11d9a2f1c7
commit 23b0a5e5fc
2 changed files with 62 additions and 69 deletions

View file

@ -59,34 +59,33 @@ variable = {
| "e" | "e"
} }
unop_neg = { "-" } prefix_neg = { "-" }
unop_not = { "!" } prefix_not = { "!" }
unop = _{ unop_neg | unop_not } prefix = _{ prefix_neg | prefix_not }
op_add = { "+" } infix_add = { "+" }
op_sub = { "-" } infix_sub = { "-" }
op_mul = { "*" } infix_mul = { "*" }
op_div = { "/" } infix_div = { "/" }
op_mod = { "%" } infix_mod = { "%" }
op_eq = { "=" } infix_eq = { "=" }
op_neq = { "!=" } infix_neq = { "!=" }
op_lt = { "<" } infix_lt = { "<" }
op_lte = { "<=" } infix_lte = { "<=" }
op_gt = { ">" } infix_gt = { ">" }
op_gte = { ">=" } infix_gte = { ">=" }
op_and = { "&" } infix_and = { "&" }
op_or = { "|" } infix_or = { "|" }
op_xor = { "^" } infix_xor = { "^" }
op = _{ infix = _{
op_add | op_sub | op_mul | op_div | op_mod infix_add | infix_sub | infix_mul | infix_div | infix_mod
| op_eq | op_neq | op_lt | op_lte | op_gt | op_gte | infix_eq | infix_neq | infix_lt | infix_lte | infix_gt | infix_gte
| op_and | op_or | op_xor | infix_and | infix_or | infix_xor
} }
paren_expr = { "(" ~ expr ~ ")" } paren_expr = { "(" ~ expr ~ ")" }
unop_expr = { unop ~ expr } term = { number | boolean | variable | paren_expr }
term = { number | boolean | variable | paren_expr | unop_expr } expr = { prefix* ~ term ~ (infix ~ prefix* ~ term)* }
expr = { term ~ (op ~ term)* }
date_fixed_start = { datum ~ delta? ~ time? } date_fixed_start = { datum ~ delta? ~ time? }
date_fixed_end = { datum ~ delta? ~ time? | delta ~ time? | time } date_fixed_end = { datum ~ delta? ~ time? | delta ~ time? | time }

View file

@ -359,24 +359,6 @@ fn parse_variable(p: Pair<'_, Rule>) -> Var {
} }
} }
fn parse_unop_expr(p: Pair<'_, Rule>) -> Spanned<Expr> {
assert_eq!(p.as_rule(), Rule::unop_expr);
let span = (&p.as_span()).into();
let mut p = p.into_inner();
let p_op = p.next().unwrap();
let p_expr = p.next().unwrap();
assert_eq!(p.next(), None);
let inner = parse_expr(p_expr);
let expr = match p_op.as_rule() {
Rule::unop_neg => Expr::Neg(Box::new(inner)),
Rule::unop_not => Expr::Not(Box::new(inner)),
_ => unreachable!(),
};
Spanned::new(span, expr)
}
fn parse_paren_expr(p: Pair<'_, Rule>) -> Spanned<Expr> { fn parse_paren_expr(p: Pair<'_, Rule>) -> Spanned<Expr> {
assert_eq!(p.as_rule(), Rule::paren_expr); assert_eq!(p.as_rule(), Rule::paren_expr);
let span = (&p.as_span()).into(); let span = (&p.as_span()).into();
@ -392,34 +374,43 @@ fn parse_term(p: Pair<'_, Rule>) -> Spanned<Expr> {
Rule::number => Spanned::new(span, Expr::Lit(parse_number(p).into())), Rule::number => Spanned::new(span, Expr::Lit(parse_number(p).into())),
Rule::boolean => Spanned::new(span, Expr::Var(parse_boolean(p))), Rule::boolean => Spanned::new(span, Expr::Var(parse_boolean(p))),
Rule::variable => Spanned::new(span, Expr::Var(parse_variable(p))), Rule::variable => Spanned::new(span, Expr::Var(parse_variable(p))),
Rule::unop_expr => parse_unop_expr(p),
Rule::paren_expr => parse_paren_expr(p), Rule::paren_expr => parse_paren_expr(p),
_ => unreachable!(), _ => unreachable!(),
} }
} }
fn parse_op(l: Spanned<Expr>, p: Pair<'_, Rule>, r: Spanned<Expr>) -> Spanned<Expr> { fn parse_prefix(p: Pair<'_, Rule>, s: Spanned<Expr>) -> Spanned<Expr> {
let span = s.span.join((&p.as_span()).into());
let expr = match p.as_rule() {
Rule::prefix_neg => Expr::Neg(Box::new(s)),
Rule::prefix_not => Expr::Not(Box::new(s)),
_ => unreachable!(),
};
Spanned::new(span, expr)
}
fn parse_infix(l: Spanned<Expr>, p: Pair<'_, Rule>, r: Spanned<Expr>) -> Spanned<Expr> {
let span = l.span.join(r.span); let span = l.span.join(r.span);
let expr = match p.as_rule() { let expr = match p.as_rule() {
// Integer-y operations // Integer-y operations
Rule::op_add => Expr::Add(Box::new(l), Box::new(r)), Rule::infix_add => Expr::Add(Box::new(l), Box::new(r)),
Rule::op_sub => Expr::Sub(Box::new(l), Box::new(r)), Rule::infix_sub => Expr::Sub(Box::new(l), Box::new(r)),
Rule::op_mul => Expr::Mul(Box::new(l), Box::new(r)), Rule::infix_mul => Expr::Mul(Box::new(l), Box::new(r)),
Rule::op_div => Expr::Div(Box::new(l), Box::new(r)), Rule::infix_div => Expr::Div(Box::new(l), Box::new(r)),
Rule::op_mod => Expr::Mod(Box::new(l), Box::new(r)), Rule::infix_mod => Expr::Mod(Box::new(l), Box::new(r)),
// Comparisons // Comparisons
Rule::op_eq => Expr::Eq(Box::new(l), Box::new(r)), Rule::infix_eq => Expr::Eq(Box::new(l), Box::new(r)),
Rule::op_neq => Expr::Neq(Box::new(l), Box::new(r)), Rule::infix_neq => Expr::Neq(Box::new(l), Box::new(r)),
Rule::op_lt => Expr::Lt(Box::new(l), Box::new(r)), Rule::infix_lt => Expr::Lt(Box::new(l), Box::new(r)),
Rule::op_lte => Expr::Lte(Box::new(l), Box::new(r)), Rule::infix_lte => Expr::Lte(Box::new(l), Box::new(r)),
Rule::op_gt => Expr::Gt(Box::new(l), Box::new(r)), Rule::infix_gt => Expr::Gt(Box::new(l), Box::new(r)),
Rule::op_gte => Expr::Gte(Box::new(l), Box::new(r)), Rule::infix_gte => Expr::Gte(Box::new(l), Box::new(r)),
// Boolean-y operations // Boolean-y operations
Rule::op_and => Expr::And(Box::new(l), Box::new(r)), Rule::infix_and => Expr::And(Box::new(l), Box::new(r)),
Rule::op_or => Expr::Or(Box::new(l), Box::new(r)), Rule::infix_or => Expr::Or(Box::new(l), Box::new(r)),
Rule::op_xor => Expr::Xor(Box::new(l), Box::new(r)), Rule::infix_xor => Expr::Xor(Box::new(l), Box::new(r)),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -429,19 +420,22 @@ fn parse_op(l: Spanned<Expr>, p: Pair<'_, Rule>, r: Spanned<Expr>) -> Spanned<Ex
fn parse_expr(p: Pair<'_, Rule>) -> Spanned<Expr> { fn parse_expr(p: Pair<'_, Rule>) -> Spanned<Expr> {
assert_eq!(p.as_rule(), Rule::expr); assert_eq!(p.as_rule(), Rule::expr);
fn infl(rule: Rule) -> Op<Rule> {
Op::infix(rule, Assoc::Left)
}
PrattParser::new() PrattParser::new()
.op(infl(Rule::op_or) | infl(Rule::op_xor)) .op(Op::infix(Rule::infix_or, Assoc::Left) | Op::infix(Rule::infix_xor, Assoc::Left))
.op(infl(Rule::op_and)) .op(Op::infix(Rule::infix_and, Assoc::Left))
.op(infl(Rule::op_eq) | infl(Rule::op_neq)) .op(Op::infix(Rule::infix_eq, Assoc::Left) | Op::infix(Rule::infix_neq, Assoc::Left))
.op(infl(Rule::op_lt) | infl(Rule::op_lte) | infl(Rule::op_gt) | infl(Rule::op_gte)) .op(Op::infix(Rule::infix_lt, Assoc::Left)
.op(infl(Rule::op_mul) | infl(Rule::op_div) | infl(Rule::op_mod)) | Op::infix(Rule::infix_lte, Assoc::Left)
.op(infl(Rule::op_add) | infl(Rule::op_sub)) | Op::infix(Rule::infix_gt, Assoc::Left)
| Op::infix(Rule::infix_gte, Assoc::Left))
.op(Op::infix(Rule::infix_mul, Assoc::Left)
| Op::infix(Rule::infix_div, Assoc::Left)
| Op::infix(Rule::infix_mod, Assoc::Left))
.op(Op::infix(Rule::infix_add, Assoc::Left) | Op::infix(Rule::infix_sub, Assoc::Left))
.op(Op::prefix(Rule::prefix_neg) | Op::prefix(Rule::prefix_not))
.map_primary(parse_term) .map_primary(parse_term)
.map_infix(parse_op) .map_prefix(parse_prefix)
.map_infix(parse_infix)
.parse(p.into_inner()) .parse(p.into_inner())
} }