Skip to content

Commit fae6c72

Browse files
Refactor array handling to use Rc<RefCell<Vec<Value>>> to gain O(1) read and write (#7)
* Refactor array handling to use Rc<RefCell<Vec<Value>>> for nested arrays * Enhance nested array support by updating index type to Vec<Expression> and adjusting parser and compiler logic for multi-dimensional indexing
1 parent 77ed35d commit fae6c72

5 files changed

Lines changed: 134 additions & 39 deletions

File tree

src/ast/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::{cell::RefCell, rc::Rc};
2+
13
#[derive(Debug)]
24
pub enum Statement {
35
Expression(Expression),
@@ -39,7 +41,7 @@ pub enum Statement {
3941
},
4042
AssignmentIndex {
4143
array: String,
42-
index: Expression,
44+
index: Vec<Expression>,
4345
value: Expression,
4446
},
4547
}
@@ -87,5 +89,5 @@ pub enum Expression {
8789
pub enum Value {
8890
Number(i32),
8991
String(String),
90-
Array(Vec<Value>),
92+
Array(Rc<RefCell<Vec<Value>>>),
9193
}

src/compiler/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,14 @@ pub fn compile_statements(
262262
instructions.push(Instruction::LoadVar(array.clone()));
263263

264264
// index is expression
265-
compile_expr(instructions, &index);
266-
265+
for idx in &index {
266+
compile_expr(instructions, idx);
267+
instructions.push(Instruction::LoadIndex);
268+
}
269+
instructions.pop();
267270
// value is expression
268271
compile_expr(instructions, &value);
269-
270272
instructions.push(Instruction::StoreIndex);
271-
instructions.push(Instruction::AssignVar(array));
272273
}
273274
}
274275
}

src/parser/mod.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -369,28 +369,28 @@ impl Parser {
369369
}
370370
Statement::Expression(call_expr)
371371
} else if let Some(Token::SquareLeft) = self.peek() {
372-
let index = self.parse_index(name);
373-
match self.advance() {
374-
Some(Token::Equals) => {
375-
// It's an array assignment: arr[index] = value;
376-
let value = self.parse_first();
377-
match self.advance() {
378-
Some(Token::Semicolon) => {}
379-
_ => panic!("Expected ';' after array assignment"),
380-
}
381-
match index {
382-
Expression::Index { array, index } => Statement::AssignmentIndex {
383-
array: match *array {
384-
Expression::Identifier(name) => name,
385-
_ => panic!("Expected identifier for array name in assignment"),
386-
},
387-
index: *index,
388-
value,
389-
},
390-
_ => panic!("Expected array indexing expression for array assignment"),
391-
}
372+
let mut indices = Vec::new();
373+
while Some(&Token::SquareLeft) == self.peek() {
374+
self.advance();
375+
indices.push(self.parse_first());
376+
match self.advance() {
377+
Some(Token::SquareRight) => {}
378+
_ => panic!("Expected ']' after array index"),
392379
}
393-
_ => Statement::Expression(index), // Just an array access expression
380+
}
381+
match self.advance() {
382+
Some(Token::Equals) => {}
383+
_ => panic!("Expected '=' after array index"),
384+
}
385+
let value = self.parse_first();
386+
match self.advance() {
387+
Some(Token::Semicolon) => {}
388+
_ => panic!("Expected ';' after array assignment"),
389+
}
390+
Statement::AssignmentIndex {
391+
array: name,
392+
index: indices,
393+
value,
394394
}
395395
} else {
396396
self.parse_assignment(name)

src/vm/mod.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::HashMap, fmt};
1+
use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};
22

33
use crate::{
44
ast::{BinaryOperation, Value},
@@ -11,7 +11,8 @@ impl fmt::Display for Value {
1111
Value::Number(n) => write!(f, "{}", n),
1212
Value::String(s) => write!(f, "{}", s),
1313
Value::Array(arr) => {
14-
let elements = arr
14+
let vec = arr.borrow();
15+
let elements = vec
1516
.iter()
1617
.map(|v| format!("{}", v))
1718
.collect::<Vec<String>>()
@@ -308,25 +309,26 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
308309
continue;
309310
}
310311
Instruction::CreateArray(len) => {
311-
let mut elements = Vec::new();
312+
let elements = Rc::new(RefCell::new(Vec::new()));
312313
for _ in 0..len {
313314
if let Some(value) = runtime.stack.pop() {
314-
elements.push(value);
315+
elements.borrow_mut().push(value);
315316
} else {
316317
panic!("Not enough values on stack to create array");
317318
}
318319
}
319-
elements.reverse();
320+
elements.borrow_mut().reverse();
320321
runtime.stack.push(Value::Array(elements));
321322
}
322323
Instruction::LoadIndex => {
323324
let index = runtime.pop_or_panic_stack();
324325
let array = runtime.pop_or_panic_stack();
325326
if let (Value::Array(arr), Value::Number(idx)) = (array, index) {
326-
if idx < 0 || (idx as usize) >= arr.len() {
327+
let vec = arr.borrow();
328+
if idx < 0 || (idx as usize) >= vec.len() {
327329
panic!("Array index out of bounds");
328-
}
329-
runtime.stack.push(arr[idx as usize].clone());
330+
} // immutable borrow
331+
runtime.stack.push(vec[idx as usize].clone());
330332
} else {
331333
panic!("LoadIndex requires an array and a number index");
332334
}
@@ -336,12 +338,12 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
336338
let index = runtime.pop_or_panic_stack();
337339
let array = runtime.pop_or_panic_stack();
338340

339-
if let (Value::Array(mut arr), Value::Number(idx)) = (array, index) {
340-
if idx < 0 || (idx as usize) >= arr.len() {
341+
if let (Value::Array(arr), Value::Number(idx)) = (&array, index) {
342+
let mut vec = arr.borrow_mut();
343+
if idx < 0 || (idx as usize) >= vec.len() {
341344
panic!("Array index out of bounds");
342345
}
343-
arr[idx as usize] = value;
344-
runtime.stack.push(Value::Array(arr));
346+
vec[idx as usize] = value;
345347
} else {
346348
panic!("StoreIndex requires an array and a number index");
347349
}

tests/integration_tests.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,3 +1019,93 @@ fn test_nested_array_print_whole() {
10191019
let out = run_rts("let arr = [[1, 2], [3, 4]];\nprint arr;");
10201020
assert_eq!(out, "[[1, 2], [3, 4]]");
10211021
}
1022+
1023+
// ========== Nested Array Assignment ==========
1024+
1025+
#[test]
1026+
fn test_nested_array_write_depth_2() {
1027+
let code = r#"
1028+
let x = [[1, 2], [3, 4]];
1029+
x[0][1] = 99;
1030+
print x;
1031+
"#;
1032+
let out = run_rts(code);
1033+
assert_eq!(out, "[[1, 99], [3, 4]]");
1034+
}
1035+
1036+
#[test]
1037+
fn test_nested_array_write_depth_3() {
1038+
let code = r#"
1039+
let x = [10, [3, [6, 11]], 5];
1040+
x[1][1][0] = 99;
1041+
print x;
1042+
"#;
1043+
let out = run_rts(code);
1044+
assert_eq!(out, "[10, [3, [99, 11]], 5]");
1045+
}
1046+
1047+
#[test]
1048+
fn test_nested_array_write_preserves_siblings() {
1049+
let code = r#"
1050+
let x = [[1, 2], [3, 4]];
1051+
x[1][0] = 99;
1052+
print x[0];
1053+
print x[1];
1054+
"#;
1055+
let out = run_rts(code);
1056+
assert_eq!(out, "[1, 2]\n[99, 4]");
1057+
}
1058+
1059+
#[test]
1060+
fn test_nested_array_write_then_read() {
1061+
let code = r#"
1062+
let x = [[10, 20], [30, 40]];
1063+
x[0][0] = 5;
1064+
print x[0][0];
1065+
print x[0][1];
1066+
"#;
1067+
let out = run_rts(code);
1068+
assert_eq!(out, "5\n20");
1069+
}
1070+
1071+
#[test]
1072+
fn test_nested_array_write_with_expression_index() {
1073+
let code = r#"
1074+
let x = [[1, 2], [3, 4]];
1075+
let i = 1;
1076+
x[i][i - 1] = 50;
1077+
print x;
1078+
"#;
1079+
let out = run_rts(code);
1080+
assert_eq!(out, "[[1, 2], [50, 4]]");
1081+
}
1082+
1083+
#[test]
1084+
fn test_nested_array_write_in_loop() {
1085+
let code = r#"
1086+
let x = [[0, 0], [0, 0]];
1087+
for (let i = 0; i < 2; i++) {
1088+
for (let j = 0; j < 2; j++) {
1089+
x[i][j] = i * 2 + j;
1090+
}
1091+
}
1092+
print x;
1093+
"#;
1094+
let out = run_rts(code);
1095+
assert_eq!(out, "[[0, 1], [2, 3]]");
1096+
}
1097+
1098+
#[test]
1099+
fn test_nested_array_write_via_function() {
1100+
let code = r#"
1101+
function setCell(grid, r, c, val) {
1102+
grid[r][c] = val;
1103+
return 0;
1104+
}
1105+
let g = [[1, 2], [3, 4]];
1106+
setCell(g, 0, 1, 99);
1107+
print g;
1108+
"#;
1109+
let out = run_rts(code);
1110+
assert_eq!(out, "[[1, 99], [3, 4]]");
1111+
}

0 commit comments

Comments
 (0)