diff --git a/examples/indent.rs b/examples/indent.rs index 8db42225..7b33c7b1 100644 --- a/examples/indent.rs +++ b/examples/indent.rs @@ -1,25 +1,61 @@ use chumsky::prelude::*; +use chumsky::pratt::*; + +#[derive(Clone, Debug)] +pub enum Expr { + Add(Box, Box), + Sub(Box, Box), + Mul(Box, Box), + Div(Box, Box), + Pow(Box, Box), + Neg(Box), + Factorial(Box), + Deref(Box), + Literal(i32), +} #[derive(Clone, Debug)] pub enum Stmt { - Expr, + Expr(Expr), Loop(Vec), } -fn parser<'a>() -> impl Parser<'a, &'a str, Vec> { - let expr = just("expr"); // TODO +fn parser() -> impl Parser<'static, &'static str, Vec> { + let atom = text::int(10) + .from_str() + .unwrapped() + .map(Expr::Literal) + .padded(); + + let op = |c| just(c).padded(); + + let expr = atom.pratt(( + postfix(5, op('!'), |lhs, _, _| Expr::Factorial(Box::new(lhs))), + infix(right(4), op('^'), |l, _, r, _| Expr::Pow(Box::new(l), Box::new(r))), + prefix(3, op('-'), |_, rhs, _| Expr::Neg(Box::new(rhs))), + prefix(3, op('*'), |_, rhs, _| Expr::Deref(Box::new(rhs))), + infix(left(1), op('+'), |l, _, r, _| Expr::Add(Box::new(l), Box::new(r))), + infix(left(1), op('-'), |l, _, r, _| Expr::Sub(Box::new(l), Box::new(r))), + infix(left(2), op('*'), |l, _, r, _| Expr::Mul(Box::new(l), Box::new(r))), + infix(left(2), op('/'), |l, _, r, _| Expr::Div(Box::new(l), Box::new(r))), + )); let block = recursive(|block| { let indent = just(' ') .repeated() .configure(|cfg, parent_indent| cfg.exactly(*parent_indent)); - let expr_stmt = expr.then_ignore(text::newline()).to(Stmt::Expr); + + let expr_stmt = expr + .then_ignore(text::newline().or_not()) + .map(Stmt::Expr); + let control_flow = just("loop:") .then(text::newline()) .ignore_then(block) .map(Stmt::Loop); - let stmt = expr_stmt.or(control_flow); + + let stmt = control_flow.or(expr_stmt); text::whitespace() .count() @@ -32,17 +68,14 @@ fn parser<'a>() -> impl Parser<'a, &'a str, Vec> { fn main() { let stmts = parser().padded().parse( r#" -expr -expr + loop: - expr - loop: - expr - expr - expr -expr + *1 + -2 * 3! + loop: + 10 + "#, ); - println!("{:#?}", stmts.output()); - println!("{:?}", stmts.errors().collect::>()); + println!("Parsed statements:\n{:?}", stmts.output().unwrap()); + println!("Errors:\n{:?}", stmts.errors().collect::>()); }