diff --git a/schala-lang/language/src/ast/operators.rs b/schala-lang/language/src/ast/operators.rs index c7cbf9d..1bdc015 100644 --- a/schala-lang/language/src/ast/operators.rs +++ b/schala-lang/language/src/ast/operators.rs @@ -47,6 +47,10 @@ impl BinOp { let s = token_kind_to_sigil(op_tok)?; Some(binop_precedences(s)) } + + pub fn get_precedence(&self) -> i32 { + binop_precedences(self.sigil.as_ref()) + } } fn token_kind_to_sigil(tok: &TokenKind) -> Option<&str> { diff --git a/schala-lang/language/src/parsing/new.rs b/schala-lang/language/src/parsing/new.rs index 181d1a3..a2b7c38 100644 --- a/schala-lang/language/src/parsing/new.rs +++ b/schala-lang/language/src/parsing/new.rs @@ -1,9 +1,45 @@ use crate::ast::*; use std::rc::Rc; +#[derive(Debug)] +struct BinopSequence { + first: ExpressionKind, + next: Vec<(BinOp, ExpressionKind)>, +} + +impl BinopSequence { + fn do_precedence(self) -> ExpressionKind { + fn helper(precedence: i32, lhs: ExpressionKind, rest: &mut Vec<(BinOp, ExpressionKind)>) -> Expression { + let mut lhs = Expression::new(Default::default(), lhs); + loop { + let (next_op, next_rhs) = match rest.pop() { + Some((a, b)) => (a, b), + None => break, + }; + let new_precedence = next_op.get_precedence(); + if precedence >= new_precedence { + rest.push((next_op, next_rhs)); + break; + } + let rhs = helper(new_precedence, next_rhs, rest); + lhs = Expression::new(Default::default(), + ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)) + ); + } + lhs + } + let mut as_stack = self.next.into_iter().rev().collect(); + helper(BinOp::min_precedence(), self.first, &mut as_stack).kind + } +} + peg::parser! { pub grammar schala_parser() for str { + rule whitespace() = [' ' | '\t']* + + rule _ = quiet!{ whitespace() } + pub rule program() -> AST = n:(statement() ** delimiter() ) { AST { id: Default::default(), statements: n.into() } } @@ -18,7 +54,16 @@ peg::parser! { kind:expression_kind() { Expression { id: Default::default(), type_anno: None, kind: kind } } rule expression_kind() -> ExpressionKind = - primary() + precedence_expr() + + rule precedence_expr() -> ExpressionKind = + first:primary() _ next:(precedence_continuation())* { + let next = next.into_iter().map(|(sigil, expr)| (BinOp::from_sigil(sigil), expr)).collect(); + BinopSequence { first, next }.do_precedence() + } + + rule precedence_continuation() -> (&'input str, ExpressionKind) = + op:operator() _ expr:primary() _ { (op, expr) } //TODO maybe make this more complex rule operator() -> &'input str = diff --git a/schala-lang/language/src/parsing/test.rs b/schala-lang/language/src/parsing/test.rs index f0f2bc3..6d569c9 100644 --- a/schala-lang/language/src/parsing/test.rs +++ b/schala-lang/language/src/parsing/test.rs @@ -172,7 +172,7 @@ fn binexps() { use ExpressionKind::*; use StatementKind::Expression; - assert_expr!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); + assert_expr2!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); assert_eq!( parse("3; 4; 4.3").unwrap(), AST { @@ -186,16 +186,16 @@ fn binexps() { } ); - assert_expr!( + assert_expr2!( "1 + 2 * 3", binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3)))) ); - assert_expr!( + assert_expr2!( "1 * 2 + 3", binop("+", binop("*", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3))) ); - assert_expr!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2)))); - assert_expr!( + assert_expr2!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2)))); + assert_expr2!( "1 + 2 * 3 + 4", binop( "+", @@ -203,12 +203,12 @@ fn binexps() { expr(NatLiteral(4)) ) ); - assert_expr!( + assert_expr2!( "(1 + 2) * 3", binop("*", binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), expr(NatLiteral(3))) ); - assert_expr!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2)))); - assert_expr!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.)))); + assert_expr2!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2)))); + assert_expr2!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.)))); } #[test]