Precedence

This commit is contained in:
Greg Shuflin 2021-11-03 23:57:22 -07:00
parent 54eb8252a9
commit 8e19b7c39d
3 changed files with 58 additions and 9 deletions

View File

@ -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> {

View File

@ -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 =

View File

@ -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]