diff --git a/parser/src/parser/mod.rs b/parser/src/parser/mod.rs index bbeb4df..ec16838 100644 --- a/parser/src/parser/mod.rs +++ b/parser/src/parser/mod.rs @@ -148,7 +148,7 @@ impl Parser<'_> { range, })?, TokenKind::LBracket => self.parse_grouped(range)?, - TokenKind::LSquare => todo!("parse array literal"), + TokenKind::LSquare => self.parse_array_literal(range)?, TokenKind::LCurly => todo!("parse hash map literal"), TokenKind::If => todo!("parse if statement"), TokenKind::While => todo!("parse while loop"), @@ -322,6 +322,64 @@ impl Parser<'_> { Ok((node.value, closing_token.range.end)) } + + fn parse_array_literal(&mut self, start_range: Range) -> Result<(ast::NodeValue, Position)> { + let mut res = vec![]; + let mut end = start_range.end; + + let mut can_parse = true; + loop { + self.skip_eol()?; + + let Some(token) = self.lexer.next() else { + return Err(Error { + kind: ErrorKind::UnexpectedEof, + range: Range { + start: start_range.start, + end, + }, + }); + }; + let token = token?; + + if token.kind == TokenKind::RSquare { + return Ok((ast::NodeValue::ArrayLiteral(res), token.range.end)); + } + + if !can_parse { + return Err(Error { + kind: ErrorKind::InvalidTokenKind { + expected: TokenKind::RSquare, + got: token.kind, + }, + range: token.range, + }); + } + + let item = self.parse_node(token, Precedence::Lowest)?; + end = item.range.end; + res.push(item); + + peek_token!( + self, + token_peek, + return Err(Error { + kind: ErrorKind::UnexpectedEof, + range: Range { + start: start_range.start, + end, + } + }) + ); + + if token_peek.kind == TokenKind::Comma { + self.lexer.next(); + can_parse = true; + } else { + can_parse = false; + } + } + } } fn token_to_infix_operator(token: &TokenKind) -> InfixOperatorKind { diff --git a/parser/src/parser/test.rs b/parser/src/parser/test.rs index 5e288d3..5b40b71 100644 --- a/parser/src/parser/test.rs +++ b/parser/src/parser/test.rs @@ -404,6 +404,125 @@ fn grouped() -> Result<()> { Ok(()) } +#[test] +fn array_literal() -> Result<()> { + let tests = [ + ( + "[]", + ast::Node { + value: ast::NodeValue::ArrayLiteral(vec![]), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 2), + }, + }, + ), + ( + "[1]", + ast::Node { + value: ast::NodeValue::ArrayLiteral(vec![ast::Node { + value: ast::NodeValue::IntegerLiteral(1), + range: Range { + start: Position::new(0, 1), + end: Position::new(0, 2), + }, + }]), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 3), + }, + }, + ), + ( + "[1, 2]", + ast::Node { + value: ast::NodeValue::ArrayLiteral(vec![ + ast::Node { + value: ast::NodeValue::IntegerLiteral(1), + range: Range { + start: Position::new(0, 1), + end: Position::new(0, 2), + }, + }, + ast::Node { + value: ast::NodeValue::IntegerLiteral(2), + range: Range { + start: Position::new(0, 4), + end: Position::new(0, 5), + }, + }, + ]), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 6), + }, + }, + ), + ( + "[1, 2,]", + ast::Node { + value: ast::NodeValue::ArrayLiteral(vec![ + ast::Node { + value: ast::NodeValue::IntegerLiteral(1), + range: Range { + start: Position::new(0, 1), + end: Position::new(0, 2), + }, + }, + ast::Node { + value: ast::NodeValue::IntegerLiteral(2), + range: Range { + start: Position::new(0, 4), + end: Position::new(0, 5), + }, + }, + ]), + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 7), + }, + }, + ), + ( + r#"[ + 1, + 2, + ]"#, + ast::Node { + value: ast::NodeValue::ArrayLiteral(vec![ + ast::Node { + value: ast::NodeValue::IntegerLiteral(1), + range: Range { + start: Position::new(1, 20), + end: Position::new(1, 21), + }, + }, + ast::Node { + value: ast::NodeValue::IntegerLiteral(2), + range: Range { + start: Position::new(2, 20), + end: Position::new(2, 21), + }, + }, + ]), + range: Range { + start: Position::new(0, 0), + end: Position::new(3, 17), + }, + }, + ), + ]; + + for (input, expected) in tests { + let program = parse(input)?; + + assert_eq!(program.statements.len(), 1); + assert_eq!(program.statements[0], expected); + } + + Ok(()) +} + #[test] fn precedence() -> Result<()> { let tests = [ @@ -417,6 +536,7 @@ fn precedence() -> Result<()> { ("-1 + 1 * 2 % 3 / 4", "((-1) + (((1 * 2) % 3) / 4))"), ("1 + -2", "(1 + (-2))"), ("1 * (2 + 3)", "(1 * (2 + 3))"), + ("[1 + 2, 3 + 4 * 5]", "[(1 + 2), (3 + (4 * 5))]"), ]; for (input, expected) in tests {