diff --git a/parser/src/pratt.rs b/parser/src/pratt.rs index 6e03420..2ca4d95 100644 --- a/parser/src/pratt.rs +++ b/parser/src/pratt.rs @@ -382,15 +382,30 @@ impl<'a, 'b> Pratt<'a, 'b> { } tok if tok.is_place() => { let expr = self.parse_lhs(lex, 0)?; - if lex.consume(&Token::OpenBracket) { + if lex.peek_is(&Token::OpenBracket) { let Expr::Leaf(Atom::Variable(var)) = expr else { return Err(ParsingError::OperatorExpectsVariable(start..lex.span().end)); }; - let expr = - self.parse_expression(lex, ArrayOperator::Index.binding_power().1)?; - let index = self.parse_comma_expr(lex, expr)?; - lex.expect(&Token::ClosedBracket, ParsingError::UnclosedArrayAccess)?; - return Ok(Place::Index(var, index)); + + let index = self.parse_index_exprs(lex, ArrayOperator::Index)?; + + if !lex.peek_is(&Token::OpenBracket) { + return Ok(Place::Index(var, index)); + } + + let mut lhs = Expr::node( + ExprNode::ArrayOperation(ArrayOperator::Index, var, index), + self.parser.arena, + ); + + while lex.peek_is(&Token::OpenBracket) { + let index = self.parse_index_exprs(lex, ArrayOperator::Index)?; + if lex.peek_is(&Token::OpenBracket) { + lhs = Expr::node(ExprNode::NestedArray(lhs, index), self.parser.arena); + } else { + return Ok(Place::ChainedIndex(lhs, index)); + } + } } expr } diff --git a/parser/src/tests.rs b/parser/src/tests.rs index f8045a3..833849d 100644 --- a/parser/src/tests.rs +++ b/parser/src/tests.rs @@ -282,6 +282,46 @@ fn test_parser_arrays() { )); } +#[test] +fn test_parser_nested_arrays() { + let source = " + { a[1][2] } + { a[1][2][3] } + { a[1][2] = 2 } + { a[1][2][3] = 2 } + { a[1][2][3][4][5] = 2 } + { ++a[1][2] } + { a[1][2]-- } + { a[1][2] += 1 } + { b = a[1][2] } + { b = a[1][2][3] } + { a[1, 2][3] } + { a[1][2, 3] } + "; + test_parser!(source => { + rules: [ + (None, Some("(body (Index (Index awk::a 1) 2))")), + (None, Some("(body (Index (Index (Index awk::a 1) 2) 3))")), + (None, Some("(body (Assignment (Index (Index awk::a 1) 2) 2))")), + (None, Some("(body (Assignment (Index (Index (Index awk::a 1) 2) 3) 2))")), + (None, Some("(body (Assignment (Index (Index (Index (Index (Index awk::a 1) 2) 3) 4) 5) 2))")), + (None, Some("(body (IncrementL (Index (Index awk::a 1) 2)))")), + (None, Some("(body (DecrementR (Index (Index awk::a 1) 2)))")), + (None, Some("(body (AddAssign (Index (Index awk::a 1) 2) 1))")), + (None, Some("(body (Assignment awk::b (Index (Index awk::a 1) 2)))")), + (None, Some("(body (Assignment awk::b (Index (Index (Index awk::a 1) 2) 3)))")), + (None, Some("(body (Index (Index awk::a 1 2) 3))")), + (None, Some("(body (Index (Index awk::a 1) 2 3))")), + ], + }); + + test_parser!(is_err!( + "{ 2[1][2] }", + "{ \"a\"[1][2] }", + "{ (a + b)[1][2] }" + )); +} + #[test] fn test_parser_for_loop() { let source = "