diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index d8e3fc0..77c197a 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -260,7 +260,7 @@ impl Parser<'_> { | TokenKind::Or => self.parse_infix_operation(start_token, left)?, TokenKind::LSquare => self.parse_index(left)?, TokenKind::Dot => self.parse_dot_index(left)?, - TokenKind::LBracket => todo!("parse function call"), + TokenKind::LBracket => self.parse_fn_call(left)?, TokenKind::Assign => self.parse_assign(left)?, _ => return Ok(left), @@ -580,6 +580,27 @@ impl Parser<'_> { )) } + fn parse_fn_call(&mut self, left: ast::Node) -> Result<(ast::NodeValue, Position)> { + // Read arguments + let (args, end) = + self.parse_multiple(TokenKind::RBracket, TokenKind::Comma, |parser, token| { + parser.parse_node(token, Precedence::Lowest) + })?; + + // Check all nodes are expression + for arg in &args { + validate_node_kind(arg, NodeKind::Expression)?; + } + + Ok(( + ast::NodeValue::FunctionCall { + function: Box::new(left), + arguments: args, + }, + end, + )) + } + // Helper function that reads block { ... }. // It returns vector of nodes and end position, which is the end // position of `}` diff --git a/parser/src/parser/test.rs b/parser/src/parser/test.rs index 94a1170..398a044 100644 --- a/parser/src/parser/test.rs +++ b/parser/src/parser/test.rs @@ -1132,6 +1132,74 @@ fn fn_literal_named() -> Result<()> { Ok(()) } +#[test] +fn fn_call() -> Result<()> { + let tests = [ + ( + "foo()", + ast::Node { + value: ast::NodeValue::FunctionCall { + function: Box::new(ast::Node { + value: ast::NodeValue::Identifier("foo".to_string()), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 3), + }, + }), + arguments: vec![], + }, + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 5), + }, + }, + ), + ( + "foo(\n1,\n2,\n)", + ast::Node { + value: ast::NodeValue::FunctionCall { + function: Box::new(ast::Node { + value: ast::NodeValue::Identifier("foo".to_string()), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 3), + }, + }), + arguments: vec![ + ast::Node { + value: ast::NodeValue::IntegerLiteral(1), + range: Range { + start: Position::new(1, 0), + end: Position::new(1, 1), + }, + }, + ast::Node { + value: ast::NodeValue::IntegerLiteral(2), + range: Range { + start: Position::new(2, 0), + end: Position::new(2, 1), + }, + }, + ], + }, + range: Range { + start: Position::new(0, 0), + end: Position::new(3, 1), + }, + }, + ), + ]; + + for (input, expected) in tests { + let program = parse(input)?; + + assert_eq!(program.statements.len(), 1); + assert_eq!(program.statements[0], expected); + } + + Ok(()) +} + #[test] fn return_statement() -> Result<()> { let program = parse("return 1 + 2")?; @@ -1273,6 +1341,10 @@ fn precedence() -> Result<()> { ("//", ""), ("return 1 + 1 * 2", "return (1 + (1 * 2))"), ("return fn(){}", "return fn() {}"), + ("fn(){}()", "(fn() {}())"), + ("foo()[0]", "((foo())[0])"), + ("foo[0]()", "((foo[0])())"), + ("foo[0].bar(1, 1 + 2)", "(((foo[0])[\"bar\"])(1, (1 + 2)))"), ]; for (input, expected) in tests {