feat: 添加数组字面量和索引访问功能,更新解析器和解释器以支持数组操作

This commit is contained in:
0264408
2026-04-28 10:14:13 +08:00
parent 5dc55c3476
commit dd3f18da6f
7 changed files with 177 additions and 0 deletions
+78
View File
@@ -159,6 +159,54 @@ impl Interpreter {
}),
}
}
Expr::IndexGet { array, index } => {
let arr = self.evaluate(*array)?;
let idx = self.evaluate(*index)?;
let i = self.as_array_index(&idx)?;
match arr {
Value::Array(vec) => {
let vec = vec.borrow();
vec.get(i).cloned().ok_or_else(|| RuntimeError::RuntimeError {
message: format!("Index {} out of bounds (len {})", i, vec.len()),
token: None,
})
}
Value::String(s) => {
let chars: Vec<char> = s.chars().collect();
chars.get(i).map(|&c| Value::String(c.to_string())).ok_or_else(|| RuntimeError::RuntimeError {
message: format!("Index {} out of bounds (len {})", i, chars.len()),
token: None,
})
}
_ => Err(RuntimeError::RuntimeError {
message: "Index access on non-array, non-string value".to_string(),
token: None,
}),
}
}
Expr::IndexSet { array, index, value } => {
let arr = self.evaluate(*array)?;
let idx = self.evaluate(*index)?;
let val = self.evaluate(*value)?;
let i = self.as_array_index(&idx)?;
match arr {
Value::Array(vec) => {
let mut vec = vec.borrow_mut();
if i >= vec.len() {
return Err(RuntimeError::RuntimeError {
message: format!("Index {} out of bounds (len {})", i, vec.len()),
token: None,
});
}
vec[i] = val.clone();
Ok(val)
}
_ => Err(RuntimeError::RuntimeError {
message: "Index assignment on non-array value".to_string(),
token: None,
}),
}
}
Expr::ObjectLiteral { properties } => {
let mut map = HashMap::new();
for (key, value_expr) in properties {
@@ -167,6 +215,13 @@ impl Interpreter {
}
Ok(Value::Object(Rc::new(RefCell::new(map))))
}
Expr::ArrayLiteral { elements } => {
let mut arr = Vec::new();
for e in elements {
arr.push(self.evaluate(e)?);
}
Ok(Value::Array(Rc::new(RefCell::new(arr))))
}
Expr::Unary { op, right } => {
let val = self.evaluate(*right)?;
match op {
@@ -303,6 +358,12 @@ impl Interpreter {
(Value::Bool(x), Value::Bool(y)) => x==y,
(Value::Number(x), Value::Number(y)) => x==y,
(Value::String(x), Value::String(y)) => x==y,
(Value::Array(x), Value::Array(y)) => {
let x = x.borrow();
let y = y.borrow();
if x.len() != y.len() { return false; }
x.iter().zip(y.iter()).all(|(a,b)| self.is_equal(a,b))
}
_ => false,
}
}
@@ -317,5 +378,22 @@ impl Interpreter {
})
}
}
fn as_array_index(&self, val: &Value) -> Result<usize, RuntimeError> {
if let Value::Number(n) = val {
if *n < 0.0 || n.fract() != 0.0 {
return Err(RuntimeError::RuntimeError {
message: format!("Index must be a non-negative integer, got {}", n),
token: None,
});
}
Ok(*n as usize)
} else {
Err(RuntimeError::RuntimeError {
message: "Index must be a number".to_string(),
token: None,
})
}
}
}