diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 6158083..7b602c9 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -141,8 +141,4 @@ impl Parser { let new_lines = "\n".repeat(3); format!("{new_lines}Hint: {}\n", msg) } - - pub(super) fn prev(&mut self) -> Option { - self.prev.clone() - } } diff --git a/src/parser/rules.rs b/src/parser/rules.rs index 3c4256c..43b2329 100644 --- a/src/parser/rules.rs +++ b/src/parser/rules.rs @@ -254,10 +254,15 @@ impl Parser { Expression::Variable(ident.clone()) }; - // TODO: Use match statement if self.peek_token(TokenKind::BraceOpen).is_ok() { - let state = self.parse_function_call(Some(ident))?; - Ok(Statement::Exp(state)) + let fn_call = self.parse_function_call(Some(ident))?; + let next = self.peek()?; + if BinOp::try_from(next.kind.clone()).is_ok() { + let bin_op = self.parse_bin_op(Some(fn_call))?; + Ok(Statement::Exp(bin_op)) + } else { + Ok(Statement::Exp(fn_call)) + } } else if self.peek_token(TokenKind::Assign).is_ok() { let state = self.parse_assignent(Some(expr))?; Ok(state) @@ -270,8 +275,6 @@ impl Parser { _ => Ok(Statement::Exp(expr)), } } else if BinOp::try_from(self.peek()?.kind).is_ok() { - // Parse Binary operation - let expr = Expression::Variable(ident); let state = Statement::Exp(self.parse_bin_op(Some(expr))?); Ok(state) } else if self.peek_token(TokenKind::Dot).is_ok() { @@ -333,6 +336,7 @@ impl Parser { let expr = Expression::FunctionCall { fn_name, args }; match self.peek()?.kind { TokenKind::Dot => self.parse_field_access(expr), + _ if BinOp::try_from(self.peek()?.kind).is_ok() => self.parse_bin_op(Some(expr)), _ => Ok(expr), } } @@ -406,7 +410,6 @@ impl Parser { other => return Err(format!("Expected Expression, found {:?}", other)), }; - // Only try to peek if we have more tokens if !self.has_more() { return Ok(expr); } @@ -454,7 +457,6 @@ impl Parser { } } - /// TODO: Cleanup fn parse_struct_initialization(&mut self) -> Result { let name = self.match_identifier()?; self.match_token(TokenKind::CurlyBracesOpen)?; @@ -670,25 +672,10 @@ impl Parser { } } - /// In some occurences a complex expression has been evaluated before a binary operation is encountered. - /// The following expression is one such example: - /// ``` - /// foo(1) * 2 - /// ``` - /// In this case, the function call has already been evaluated, and needs to be passed to this function. fn parse_bin_op(&mut self, lhs: Option) -> Result { let left = match lhs { Some(lhs) => lhs, - None => { - let prev = self.prev().ok_or("Expected token")?; - match &prev.kind { - TokenKind::Identifier(_) | TokenKind::Literal(_) | TokenKind::Keyword(_) => { - Ok(Expression::try_from(prev)?) - } - _ => Err(self - .make_error_msg(prev.pos, "Failed to parse binary operation".to_string())), - }? - } + None => self.parse_expression()?, }; let op = self.match_operator()?; diff --git a/src/parser/tests.rs b/src/parser/tests.rs index 3eb3000..56ee764 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -259,6 +259,170 @@ fn test_parse_compound_ops_with_function_call() { assert!(tree.is_ok()) } +#[test] +fn test_parse_function_call_binary_op() { + let raw = " + fn main() { + foo(1) * 2 + } + + fn foo(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse 'foo(1) * 2': {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_complex_function_call_binary_op() { + let raw = " + fn main() { + let x = foo(bar(1, 2)) * 3 + 4 + } + + fn foo(x: int) { + return x + } + + fn bar(x: int, y: int) { + return x + y + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse nested function calls with binary ops: {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_function_call_binary_op_in_return() { + let raw = " + fn main() { + return foo(1) * bar(2) + } + + fn foo(x: int) { + return x + } + + fn bar(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse binary op in return statement: {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_function_call_binary_op_nested() { + let raw = " + fn main() { + let x = (foo(1) * 2) + (bar(3) * 4) + } + + fn foo(x: int) { + return x + } + + fn bar(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse nested binary operations: {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_function_call_binary_op_with_variables() { + let raw = " + fn main() { + let a = 5 + let result = foo(a) * 2 + } + + fn foo(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse binary op with variables: {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_function_call_comparison_op() { + let raw = " + fn main() { + if foo(1) > bar(2) { + return true + } + return false + } + + fn foo(x: int) { + return x + } + + fn bar(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse comparison with function calls: {:?}", + tree.err() + ); +} + +#[test] +fn test_parse_function_call_binary_op_precedence() { + let raw = " + fn main() { + let result = foo(1) * 2 + bar(3) * 4 + } + + fn foo(x: int) { + return x + } + + fn bar(x: int) { + return x + } + "; + let tokens = tokenize(raw).unwrap(); + let tree = parse(tokens, Some(raw.to_string())); + assert!( + tree.is_ok(), + "Failed to parse operator precedence with function calls: {:?}", + tree.err() + ); +} + #[test] fn test_parse_compound_ops_with_strings() { let raw = "