Parse binary operators
For now, they're all left associative.
This commit is contained in:
parent
63f8026007
commit
408219073a
10 changed files with 99 additions and 39 deletions
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use chumsky::prelude::*;
|
||||
|
||||
use crate::ast::Expr;
|
||||
use crate::ast::{BinOp, Expr};
|
||||
use crate::span::HasSpan;
|
||||
|
||||
use super::basic::{space, Error};
|
||||
use super::lit::lit;
|
||||
|
|
@ -14,7 +15,7 @@ use super::var::var;
|
|||
|
||||
fn atom_paren(
|
||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Error> {
|
||||
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
||||
just('(')
|
||||
.ignore_then(space())
|
||||
.then(expr)
|
||||
|
|
@ -30,7 +31,7 @@ fn atom_paren(
|
|||
|
||||
fn atom(
|
||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Error> {
|
||||
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
||||
let lit = lit(expr.clone()).map(Expr::Lit);
|
||||
let var = var(expr.clone()).map(Expr::Var);
|
||||
let table_constr = table_constr(expr.clone()).map(Expr::TableConstr);
|
||||
|
|
@ -41,8 +42,57 @@ fn atom(
|
|||
prefixed(suffixed(base, expr))
|
||||
}
|
||||
|
||||
fn left_assoc(
|
||||
op: impl Parser<char, BinOp, Error = Error> + Clone,
|
||||
over: impl Parser<char, Expr, Error = Error> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Error> + Clone {
|
||||
let op_over = space()
|
||||
.then(op)
|
||||
.then(space())
|
||||
.then(over.clone())
|
||||
.map(|(((s0, op), s1), right)| (s0, op, s1, right));
|
||||
|
||||
over.then(op_over.repeated())
|
||||
.foldl(|left, (s0, op, s1, right)| Expr::BinOp {
|
||||
span: left.span().join(right.span()),
|
||||
left: Box::new(left),
|
||||
s0,
|
||||
op,
|
||||
s1,
|
||||
right: Box::new(right),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn expr(
|
||||
expr: impl Parser<char, Expr, Error = Error> + Clone,
|
||||
) -> impl Parser<char, Expr, Error = Error> {
|
||||
atom(expr)
|
||||
// * / %
|
||||
let prec0 = (just('*').to(BinOp::Mul))
|
||||
.or(just('/').to(BinOp::Div))
|
||||
.or(just('%').to(BinOp::Mod));
|
||||
|
||||
// + -
|
||||
let prec1 = (just('+').to(BinOp::Add)).or(just('-').to(BinOp::Sub));
|
||||
|
||||
// == != > >= < <=
|
||||
let prec2 = (just("==").to(BinOp::Eq))
|
||||
.or(just("!=").to(BinOp::Neq))
|
||||
.or(just('>').to(BinOp::Gt))
|
||||
.or(just(">=").to(BinOp::Ge))
|
||||
.or(just('<').to(BinOp::Lt))
|
||||
.or(just("<=").to(BinOp::Le));
|
||||
|
||||
// and
|
||||
let prec3 = text::keyword("and").to(BinOp::And);
|
||||
|
||||
// or
|
||||
let prec4 = text::keyword("or").to(BinOp::Or);
|
||||
|
||||
left_assoc(
|
||||
prec4,
|
||||
left_assoc(
|
||||
prec3,
|
||||
left_assoc(prec2, left_assoc(prec1, left_assoc(prec0, atom(expr)))),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue