feat: 添加数组字面量和索引访问功能,更新解析器和解释器以支持数组操作
This commit is contained in:
@@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user