parser: add support for multidimensional arrays

This commit is contained in:
yor1xd
2026-05-29 00:57:01 +02:00
committed by Guillem L. Jara
parent 19d1b46ca2
commit ad6ba45c7c
5 changed files with 77 additions and 17 deletions
+2
View File
@@ -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!(),
}
}
+4
View File
@@ -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."),
}
}
+18
View File
@@ -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);
+39 -17
View File
@@ -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<Vec<'a, Expr<'a>>> {
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 {
+14
View File
@@ -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, ")")
}
}
}
}