diff --git a/interpreter/src/ir/lower.rs b/interpreter/src/ir/lower.rs index a4a36a3..eedf85c 100644 --- a/interpreter/src/ir/lower.rs +++ b/interpreter/src/ir/lower.rs @@ -286,6 +286,7 @@ impl<'a> Code<'a> { self.bc .emit(Instruction::LoadBuiltinArray((dest, dest, var_index(var)))); } + Place::ChainedIndex(_, _) => todo!(), } } @@ -317,6 +318,7 @@ impl<'a> Code<'a> { .emit(Instruction::StoreBuiltinArray((src, *rhs, var_index(var)))); self.free_reg(rhs); } + Place::ChainedIndex(_, _) => todo!(), } } diff --git a/parser/src/ast.rs b/parser/src/ast.rs index f435db7..af3e864 100644 --- a/parser/src/ast.rs +++ b/parser/src/ast.rs @@ -100,6 +100,7 @@ pub enum ExprNode<'a> { UnaryPlaceOperation(UnaryPlaceOperator, Place<'a>), BinaryPlaceOperation(BinaryPlaceOperator, Place<'a>, Expr<'a>), ArrayOperation(ArrayOperator, Variable<'a>, Vec<'a, Expr<'a>>), + NestedArray(Expr<'a>, Vec<'a, Expr<'a>>), Ternary(Expr<'a>, Expr<'a>, Expr<'a>), Getline(Getline<'a>), } @@ -163,6 +164,7 @@ pub enum Place<'a> { Record(Expr<'a>), Variable(Variable<'a>), Index(Variable<'a>, Vec<'a, Expr<'a>>), + ChainedIndex(Expr<'a>, Vec<'a, Expr<'a>>), } /// GNU docs: https://www.gnu.org/software/gawk/manual/html_node/Redirection.html @@ -430,11 +432,13 @@ impl<'a> Place<'a> { &*node, &ExprNode::UnaryOperation(UnaryOperator::Record, _) | &ExprNode::ArrayOperation(ArrayOperator::Index, _, _) + | &ExprNode::NestedArray(_, _) ) => { match Box::into_inner(node) { ExprNode::UnaryOperation(_, index) => Ok(Self::Record(index)), ExprNode::ArrayOperation(_, var, index) => Ok(Self::Index(var, index)), + ExprNode::NestedArray(arr, indices) => Ok(Self::ChainedIndex(arr, indices)), _ => unreachable!("Box is magic; handled awkwardly in the match guard."), } } diff --git a/parser/src/idempotency.rs b/parser/src/idempotency.rs index 160165f..72be174 100644 --- a/parser/src/idempotency.rs +++ b/parser/src/idempotency.rs @@ -240,6 +240,11 @@ impl Display for Place<'_> { write_args(f, args, 0)?; write!(f, "]") } + Self::ChainedIndex(arr, args) => { + write!(f, "{arr}[")?; + write_args(f, args, 0)?; + write!(f, "]") + } } } } @@ -319,6 +324,19 @@ impl Display for ExprNode<'_> { } Ok(()) } + Self::NestedArray(arr, args) => { + let left_bp = ArrayOperator::Index.binding_power().0; + if left_bp < parent_bp { + write!(f, "(")?; + } + write!(f, "{arr}[")?; + write_args(f, args, indent)?; + write!(f, "]")?; + if left_bp < parent_bp { + write!(f, ")")?; + } + Ok(()) + } Self::Ternary(cond, then_expr, else_expr) => { let ternary_bp = Ternary.binding_power().0; let inner_w = encode(indent, 0); diff --git a/parser/src/pratt.rs b/parser/src/pratt.rs index 0fdb176..6e03420 100644 --- a/parser/src/pratt.rs +++ b/parser/src/pratt.rs @@ -54,6 +54,18 @@ impl<'a, 'b> Pratt<'a, 'b> { self.fold_rhs(lex, lhs, min_bp, |_| false) } + fn parse_index_exprs( + &mut self, + lex: &mut Lexer<'a>, + op: ArrayOperator, + ) -> Result>> { + lex.next(); + let expr = self.parse_expression(lex, op.binding_power().1)?; + let indices = self.parse_comma_expr(lex, expr)?; + lex.expect(&Token::ClosedBracket, ParsingError::UnclosedArrayAccess)?; + Ok(indices) + } + fn fold_rhs( &mut self, lex: &mut Lexer<'a>, @@ -101,24 +113,34 @@ impl<'a, 'b> Pratt<'a, 'b> { self.parse_place_op(lex, op, place)? } else if let Ok(op) = ArrayOperator::parse(next, &span) { match op { - ArrayOperator::Index => { - let place = match Place::lower_from(lhs.take(), lex.span()) { - Ok(Place::Variable(var)) => var, - Ok(_) => return Err(ParsingError::OperatorExpectsVariable(lex.span())), - Err((expr, _)) => { - lhs = expr; - if op.binding_power().0 < min_bp { - break; - } - return Err(ParsingError::OperatorExpectsVariable(lex.span())); + ArrayOperator::Index => match Place::lower_from(lhs.take(), lex.span()) { + Ok(Place::Variable(var)) => { + let index = self.parse_index_exprs(lex, op)?; + Expr::node(op.expr(var, index), self.parser.arena) + } + Ok(Place::Index(var, index)) => { + let new_indices = self.parse_index_exprs(lex, op)?; + let inner = Expr::node( + ExprNode::ArrayOperation(ArrayOperator::Index, var, index), + self.parser.arena, + ); + Expr::node(ExprNode::NestedArray(inner, new_indices), self.parser.arena) + } + Ok(Place::ChainedIndex(arr, indices)) => { + let new_indices = self.parse_index_exprs(lex, op)?; + let inner = + Expr::node(ExprNode::NestedArray(arr, indices), self.parser.arena); + Expr::node(ExprNode::NestedArray(inner, new_indices), self.parser.arena) + } + Ok(_) => return Err(ParsingError::OperatorExpectsVariable(lex.span())), + Err((expr, _)) => { + lhs = expr; + if op.binding_power().0 < min_bp { + break; } - }; - lex.next(); - let expr = self.parse_expression(lex, op.binding_power().1)?; - let comma_expr = self.parse_comma_expr(lex, expr)?; - lex.expect(&Token::ClosedBracket, ParsingError::UnclosedArrayAccess)?; - Expr::node(op.expr(place, comma_expr), self.parser.arena) - } + return Err(ParsingError::OperatorExpectsVariable(lex.span())); + } + }, ArrayOperator::In => { lex.next(); let Place::Variable(var) = self.parse_place(lex)? else { diff --git a/parser/src/sexpr.rs b/parser/src/sexpr.rs index 837ed51..89d0777 100644 --- a/parser/src/sexpr.rs +++ b/parser/src/sexpr.rs @@ -200,6 +200,13 @@ impl Debug for Expr<'_> { } write!(f, ")") } + ExprNode::NestedArray(inner, args) => { + write!(f, "(Index {inner:?}")?; + for arg in args { + write!(f, " {arg:?}")?; + } + write!(f, ")") + } ExprNode::UnaryPlaceOperation(op, a) => write!(f, "({op:?} {a:?})"), ExprNode::Ternary(a, b, c) => write!(f, "(?: {a:?} {b:?} {c:?})"), ExprNode::Getline(getline) => match getline { @@ -304,6 +311,13 @@ impl Debug for Place<'_> { } write!(f, ")") } + Self::ChainedIndex(expr, index) => { + write!(f, "(Index {expr:?}")?; + for i in index { + write!(f, " {i:?}")?; + } + write!(f, ")") + } } } }