diff --git a/schala-lang/src/parsing/combinator.rs b/schala-lang/src/parsing/combinator.rs index d66a5a1..0834c36 100644 --- a/schala-lang/src/parsing/combinator.rs +++ b/schala-lang/src/parsing/combinator.rs @@ -2,7 +2,8 @@ use std::{cell::RefCell, rc::Rc}; use nom::{ branch::alt, - bytes::complete::{tag, escaped_transform, take_till}, + bytes::complete::{tag, escaped_transform, take_while, take_till}, + character::is_alphanumeric, character::complete::{ alpha1, alphanumeric0, char, line_ending, none_of, not_line_ending, one_of, space0, space1, @@ -132,14 +133,17 @@ fn type_singleton_name(input: Span) -> ParseResult { } pub fn expression_kind(input: Span) -> ParseResult { - context("expression-kind", prefix_expr)(input) + context("expression-kind", precedence_expr)(input) } fn precedence_expr(input: Span) -> ParseResult { + let handle = input.extra.clone(); map( pair(prefix_expr, many0(precedence_continuation)), - |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| unimplemented!(), - )(input) + move |(first, rest): (ExpressionKind, Vec<(BinOp, ExpressionKind)>)| { + let mut handle_ref = handle.borrow_mut(); + BinopSequence { first, rest }.do_precedence(&mut handle_ref) + })(input) } fn precedence_continuation(input: Span) -> ParseResult<(BinOp, ExpressionKind)> { @@ -178,12 +182,25 @@ fn extended_expr(input: Span) -> ParseResult { fn primary_expr(input: Span) -> ParseResult { context("primary-expr", alt(( - list_expr, + list_expr, paren_expr, string_literal, float_literal, number_literal, bool_literal, identifier_expr )) )(input) } +fn paren_expr(input: Span) -> ParseResult { + delimited( + tok(char('(')), + map(separated_list0(tok(char(',')), expression), + |mut exprs| match exprs.len() { + 1 => exprs.pop().unwrap().kind, + _ => ExpressionKind::TupleLiteral(exprs), + }), + tok(char(')')) + )(input) + +} + fn list_expr(input: Span) -> ParseResult { map( delimited( @@ -230,7 +247,7 @@ fn qualified_identifier(input: Span) -> ParseResult { } fn identifier(input: Span) -> ParseResult { - recognize(tuple((alt((tag("_"), alpha1)), alphanumeric0)))(input) + recognize(pair(alt((tag("_"), alpha1)), take_while(|ch: char| { is_alphanumeric(ch as u8) || ch == '_'})))(input) } fn bool_literal(input: Span) -> ParseResult { @@ -335,6 +352,40 @@ fn parse_hex(digits: &str) -> Result { Ok(result) } +#[derive(Debug)] +struct BinopSequence { + first: ExpressionKind, + rest: Vec<(BinOp, ExpressionKind)>, +} + +impl BinopSequence { + fn do_precedence(self, store: &mut IdStore) -> ExpressionKind { + fn helper( + precedence: i32, + lhs: ExpressionKind, + rest: &mut Vec<(BinOp, ExpressionKind)>, + store: &mut IdStore, + ) -> Expression { + let mut lhs = Expression::new(store.fresh(), lhs); + while let Some((next_op, next_rhs)) = rest.pop() { + 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, store); + lhs = Expression::new( + store.fresh(), + ExpressionKind::BinExp(next_op, Box::new(lhs), Box::new(rhs)), + ); + } + lhs + } + let mut as_stack = self.rest.into_iter().rev().collect(); + helper(BinOp::min_precedence(), self.first, &mut as_stack, store).kind + } +} + #[cfg(test)] mod test { use pretty_assertions::assert_eq; diff --git a/schala-lang/src/parsing/test.rs b/schala-lang/src/parsing/test.rs index df7dcc4..0f7fcb8 100644 --- a/schala-lang/src/parsing/test.rs +++ b/schala-lang/src/parsing/test.rs @@ -179,7 +179,7 @@ fn binexps() { use ExpressionKind::*; use StatementKind::Expression; - assert_expr!("0xf_f_+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); + assert_expr_comb!("0xf_f+1", binop("+", expr(NatLiteral(255)), expr(NatLiteral(1)))); assert_ast!( "3; 4; 4.3", vec![ @@ -189,16 +189,16 @@ fn binexps() { ] ); - assert_expr!( + assert_expr_comb!( "1 + 2 * 3", binop("+", expr(NatLiteral(1)), binop("*", expr(NatLiteral(2)), expr(NatLiteral(3)))) ); - assert_expr!( + assert_expr_comb!( "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_expr_comb!("1 && 2", binop("&&", expr(NatLiteral(1)), expr(NatLiteral(2)))); + assert_expr_comb!( "1 + 2 * 3 + 4", binop( "+", @@ -206,12 +206,12 @@ fn binexps() { expr(NatLiteral(4)) ) ); - assert_expr!( + assert_expr_comb!( "(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_expr_comb!(".1 + .2", binop("+", expr(FloatLiteral(0.1)), expr(FloatLiteral(0.2)))); + assert_expr_comb!("1 / 2.", binop("/", expr(NatLiteral(1)), expr(FloatLiteral(2.)))); } #[test] @@ -230,9 +230,9 @@ fn prefix_exps() { fn operators() { use ExpressionKind::*; - assert_expr!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1)))); - assert_expr!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr_comb!("a <- 1", binop("<-", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr_comb!("a || 1", binop("||", expr(Value(qn!(a))), expr(NatLiteral(1)))); + assert_expr_comb!("a <> 1", binop("<>", expr(Value(qn!(a))), expr(NatLiteral(1)))); } #[test] @@ -273,12 +273,12 @@ fn accessors() { fn tuples() { use ExpressionKind::*; - assert_expr!("()", expr(TupleLiteral(vec![]))); - assert_expr!( + assert_expr_comb!("()", expr(TupleLiteral(vec![]))); + assert_expr_comb!( r#"("hella", 34)"#, expr(TupleLiteral(vec![expr(StringLiteral(rc("hella"))), expr(NatLiteral(34))])) ); - assert_expr!( + assert_expr_comb!( r#"(1+2, "slough")"#, expr(TupleLiteral(vec![ binop("+", expr(NatLiteral(1)), expr(NatLiteral(2))), @@ -291,11 +291,11 @@ fn tuples() { fn identifiers() { use ExpressionKind::*; - assert_expr!("a", expr(Value(qn!(a)))); - assert_expr!("some_value", expr(Value(qn!(some_value)))); - assert_expr!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); - assert_expr!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); - assert_expr!("None", expr(Value(qn!(None)))); + assert_expr_comb!("a", expr(Value(qn!(a)))); + assert_expr_comb!("some_value", expr(Value(qn!(some_value)))); + assert_expr_comb!("alpha::beta::gamma", expr(Value(qn!(alpha, beta, gamma)))); + assert_expr_comb!("a + b", binop("+", expr(Value(qn!(a))), expr(Value(qn!(b))))); + assert_expr_comb!("None", expr(Value(qn!(None)))); assert_expr!( "thing::item::call()", expr(Call { f: bx(expr(Value(qn!(thing, item, call)))), arguments: vec![] }) @@ -1387,7 +1387,7 @@ fn comments() { use ExpressionKind::*; let source = "1 + /* hella /* bro */ */ 2"; - assert_expr!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2)))); + assert_expr_comb!(source, binop("+", expr(NatLiteral(1)), expr(NatLiteral(2)))); //TODO make sure this error message makes sense let source = "1 + /* hella /* bro */ 2";