Skip to content

Commit 30ba2de

Browse files
committed
Parse array assign with multiple levels of indexing
1 parent bdb7221 commit 30ba2de

File tree

3 files changed

+50
-42
lines changed

3 files changed

+50
-42
lines changed

src/ast.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,7 @@ pub enum StmtEnum<T> {
273273
/// Mutable let expression, bind a single variable to an expr.
274274
LetMut(String, Option<Type>, Expr<T>),
275275
/// Assignment of a (previously as mutable declared) variable.
276-
VarAssign(String, Expr<T>),
277-
/// Assignment of an index in a (mutable) array.
278-
ArrayAssign(String, Expr<T>, Expr<T>),
276+
VarAssign(String, Vec<Accessor<T>>, Expr<T>),
279277
/// Binds an identifier to each value of an array expr, evaluating the body.
280278
ForEachLoop(Pattern<T>, Expr<T>, Vec<Stmt<T>>),
281279
/// Binds an identifier to each joined row of two tables, evaluating the body.
@@ -284,6 +282,19 @@ pub enum StmtEnum<T> {
284282
Expr(Expr<T>),
285283
}
286284

285+
/// The different ways a mutable variable can be accessed before assignment.
286+
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
287+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
288+
pub enum Accessor<T> {
289+
/// Accessing an array by index to assing to it, e.g. `array[0] = x;`.
290+
ArrayAccess {
291+
/// The type of the array being accessed by the index.
292+
array_ty: T,
293+
/// The expression that indexes the array.
294+
index: Expr<T>,
295+
},
296+
}
297+
287298
/// An expression and its location in the source code.
288299
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
289300
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

src/check.rs

+23-34
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::collections::{HashMap, HashSet};
55

66
use crate::{
77
ast::{
8-
self, ConstDef, ConstExpr, ConstExprEnum, EnumDef, Expr, ExprEnum, Mutability, Op,
9-
ParamDef, Pattern, PatternEnum, Stmt, StmtEnum, StructDef, Type, UnaryOp, Variant,
8+
self, Accessor, ConstDef, ConstExpr, ConstExprEnum, EnumDef, Expr, ExprEnum, Mutability,
9+
Op, ParamDef, Pattern, PatternEnum, Stmt, StmtEnum, StructDef, Type, UnaryOp, Variant,
1010
VariantExprEnum,
1111
},
1212
env::Env,
@@ -682,43 +682,32 @@ impl UntypedStmt {
682682
let expr = expr.type_check(top_level_defs, env, fns, defs)?;
683683
Ok(Stmt::new(StmtEnum::Expr(expr), meta))
684684
}
685-
ast::StmtEnum::VarAssign(identifier, value) => {
685+
ast::StmtEnum::VarAssign(identifier, accessors, value) => {
686686
match env.get(identifier) {
687-
Some((Some(ty), Mutability::Mutable)) => {
688-
let mut value = value.type_check(top_level_defs, env, fns, defs)?;
689-
check_type(&mut value, &ty)?;
690-
Ok(Stmt::new(
691-
StmtEnum::VarAssign(identifier.clone(), value),
692-
meta,
693-
))
694-
}
695-
Some((None, Mutability::Mutable)) => {
696-
// binding does not have a type, must have been caused by a previous error, so
697-
// just ignore the statement here
698-
Err(vec![None])
699-
}
700-
Some((_, Mutability::Immutable)) => Err(vec![Some(TypeError(
701-
TypeErrorEnum::IdentifierNotDeclaredAsMutable(identifier.clone()),
702-
meta,
703-
))]),
704-
None => Err(vec![Some(TypeError(
705-
TypeErrorEnum::UnknownIdentifier(identifier.clone()),
706-
meta,
707-
))]),
708-
}
709-
}
710-
ast::StmtEnum::ArrayAssign(identifier, index, value) => {
711-
match env.get(identifier) {
712-
Some((Some(array_ty), Mutability::Mutable)) => {
713-
let elem_ty = expect_array_type(&array_ty, meta)?;
714-
715-
let mut index = index.type_check(top_level_defs, env, fns, defs)?;
716-
check_or_constrain_unsigned(&mut index, UnsignedNumType::Usize)?;
687+
Some((Some(mut elem_ty), Mutability::Mutable)) => {
688+
let mut typed_accessors = vec![];
689+
for access in accessors {
690+
let typed = match access {
691+
Accessor::ArrayAccess { index, .. } => {
692+
let array_ty = elem_ty.clone();
693+
elem_ty = expect_array_type(&elem_ty, meta)?;
717694

695+
let mut index =
696+
index.type_check(top_level_defs, env, fns, defs)?;
697+
check_or_constrain_unsigned(
698+
&mut index,
699+
UnsignedNumType::Usize,
700+
)?;
701+
println!("Accessor for {array_ty} with {index:?}");
702+
Accessor::ArrayAccess { array_ty, index }
703+
}
704+
};
705+
typed_accessors.push(typed);
706+
}
718707
let mut value = value.type_check(top_level_defs, env, fns, defs)?;
719708
check_type(&mut value, &elem_ty)?;
720709
Ok(Stmt::new(
721-
StmtEnum::ArrayAssign(identifier.clone(), index, value),
710+
StmtEnum::VarAssign(identifier.clone(), typed_accessors, value),
722711
meta,
723712
))
724713
}

src/parse.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use std::{collections::HashMap, iter::Peekable, vec::IntoIter};
44

55
use crate::{
66
ast::{
7-
ConstDef, ConstExpr, ConstExprEnum, EnumDef, Expr, ExprEnum, FnDef, Op, ParamDef, Pattern,
8-
PatternEnum, Program, Stmt, StmtEnum, StructDef, Type, UnaryOp, Variant, VariantExprEnum,
7+
Accessor, ConstDef, ConstExpr, ConstExprEnum, EnumDef, Expr, ExprEnum, FnDef, Op, ParamDef,
8+
Pattern, PatternEnum, Program, Stmt, StmtEnum, StructDef, Type, UnaryOp, Variant,
9+
VariantExprEnum,
910
},
1011
scan::Tokens,
1112
token::{MetaInfo, SignedNumType, Token, TokenEnum, UnsignedNumType},
@@ -455,7 +456,7 @@ impl Parser {
455456
if !self.peek(&TokenEnum::RightBrace) && !self.peek(&TokenEnum::Comma) {
456457
self.expect(&TokenEnum::Semicolon)?;
457458
}
458-
Stmt::new(StmtEnum::VarAssign(identifier, value), meta)
459+
Stmt::new(StmtEnum::VarAssign(identifier, vec![], value), meta)
459460
} else if let Some(Token(next, _)) = self.tokens.peek() {
460461
let op = match next {
461462
TokenEnum::AddAssign => Some(Op::Add),
@@ -489,7 +490,7 @@ impl Parser {
489490
),
490491
meta,
491492
);
492-
Stmt::new(StmtEnum::VarAssign(identifier, binary_op), meta)
493+
Stmt::new(StmtEnum::VarAssign(identifier, vec![], binary_op), meta)
493494
} else {
494495
let expr = Expr::untyped(ExprEnum::Identifier(identifier), meta);
495496
if !self.peek(&TokenEnum::RightBrace) && !self.peek(&TokenEnum::Comma) {
@@ -514,7 +515,14 @@ impl Parser {
514515
self.expect(&TokenEnum::Semicolon)?;
515516
}
516517
Stmt::new(
517-
StmtEnum::ArrayAssign(identifier.clone(), *index, value),
518+
StmtEnum::VarAssign(
519+
identifier.clone(),
520+
vec![Accessor::ArrayAccess {
521+
array_ty: (),
522+
index: *index,
523+
}],
524+
value,
525+
),
518526
meta,
519527
)
520528
} else {

0 commit comments

Comments
 (0)