parser: handle chained array indexing in parse_place and add tests

This commit is contained in:
yor1xd
2026-05-28 16:08:17 -03:00
committed by Guillem L. Jara
parent ad6ba45c7c
commit 1df4886ac5
2 changed files with 61 additions and 6 deletions
+21 -6
View File
@@ -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
}
+40
View File
@@ -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 = "