feat: 添加内置函数支持(len, typeof, push, pop),更新相关错误处理和测试用例

This commit is contained in:
0264408
2026-06-16 19:03:47 +08:00
parent 18fa53cf4a
commit 75c1d230ad
7 changed files with 314 additions and 9 deletions
+192 -1
View File
@@ -397,7 +397,7 @@ impl Interpreter {
fn call_function(&mut self, func_val: Value, args: Vec<Value>) -> Result<Value, RuntimeError> {
match func_val {
Value::NativeFunction(native_fn) => {
Ok(native_fn(args))
native_fn(args)
}
Value::Function(f) => {
let env = Rc::new(RefCell::new(Env::new(Some(Rc::clone(&f.env)))));
@@ -1421,5 +1421,196 @@ mod tests {
});
assert!(result.is_err(), "Expected error for index on non-array");
}
// =========================================================================
// Builtins: len
// =========================================================================
#[test]
fn eval_len_string() {
assert_num(&eval_expr("len(\"hello\")"), 5.0);
}
#[test]
fn eval_len_empty_string() {
assert_num(&eval_expr("len(\"\")"), 0.0);
}
#[test]
fn eval_len_array() {
assert_num(&eval_expr("len([1, 2, 3])"), 3.0);
}
#[test]
fn eval_len_empty_array() {
assert_num(&eval_expr("len([])"), 0.0);
}
#[test]
fn eval_len_object() {
assert_num(&eval_expr("len({a: 1, b: 2})"), 2.0);
}
#[test]
fn eval_len_empty_object() {
assert_num(&eval_expr("len({})"), 0.0);
}
#[test]
fn error_len_no_args() {
let result = std::panic::catch_unwind(|| {
eval_expr("len()");
});
assert!(result.is_err(), "Expected error for len() with no args");
}
#[test]
fn error_len_number() {
let result = std::panic::catch_unwind(|| {
eval_expr("len(42)");
});
assert!(result.is_err(), "Expected error for len(42)");
}
// =========================================================================
// Builtins: typeof
// =========================================================================
#[test]
fn eval_typeof_number() {
match eval_expr("typeof(42)") {
Value::String(s) => assert_eq!(s, "number"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_string() {
match eval_expr("typeof(\"hello\")") {
Value::String(s) => assert_eq!(s, "string"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_bool() {
match eval_expr("typeof(true)") {
Value::String(s) => assert_eq!(s, "bool"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_nil() {
match eval_expr("typeof(nil)") {
Value::String(s) => assert_eq!(s, "nil"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_object() {
match eval_expr("typeof({a: 1})") {
Value::String(s) => assert_eq!(s, "object"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_array() {
match eval_expr("typeof([1, 2])") {
Value::String(s) => assert_eq!(s, "array"),
v => panic!("Expected String, got {:?}", v),
}
}
#[test]
fn eval_typeof_function() {
let interp = run("fn f() {}");
// f is a variable, not an expression — use get_var
match get_var(&interp, "f") {
Value::Function(_) => {} // just verify it's a function
v => panic!("Expected Function, got {:?}", v),
}
}
// =========================================================================
// Builtins: push / pop
// =========================================================================
#[test]
fn eval_push_returns_value() {
assert_num(&eval_expr("push([1, 2], 3)"), 3.0);
}
#[test]
fn eval_push_modifies_array() {
let interp = run("let arr = [1, 2]; push(arr, 3);");
match get_var(&interp, "arr") {
Value::Array(arr) => {
let arr = arr.borrow();
assert_eq!(arr.len(), 3);
assert_num(&arr[0], 1.0);
assert_num(&arr[1], 2.0);
assert_num(&arr[2], 3.0);
}
v => panic!("Expected Array, got {:?}", v),
}
}
#[test]
fn eval_push_string_to_array() {
let interp = run("let arr = [\"a\"]; push(arr, \"b\");");
match get_var(&interp, "arr") {
Value::Array(arr) => {
let arr = arr.borrow();
assert_eq!(arr.len(), 2);
}
v => panic!("Expected Array, got {:?}", v),
}
}
#[test]
fn eval_pop_returns_last() {
assert_num(&eval_expr("pop([1, 2, 3])"), 3.0);
}
#[test]
fn eval_pop_modifies_array() {
let interp = run("let arr = [1, 2, 3]; pop(arr);");
match get_var(&interp, "arr") {
Value::Array(arr) => {
let arr = arr.borrow();
assert_eq!(arr.len(), 2);
assert_num(&arr[0], 1.0);
assert_num(&arr[1], 2.0);
}
v => panic!("Expected Array, got {:?}", v),
}
}
#[test]
fn error_pop_empty_array() {
let result = std::panic::catch_unwind(|| {
eval_expr("pop([])");
});
assert!(result.is_err(), "Expected error for pop([])");
}
#[test]
fn error_push_non_array() {
let result = std::panic::catch_unwind(|| {
eval_expr("push(42, 1)");
});
assert!(result.is_err(), "Expected error for push on non-array");
}
#[test]
fn error_pop_non_array() {
let result = std::panic::catch_unwind(|| {
eval_expr("pop(42)");
});
assert!(result.is_err(), "Expected error for pop on non-array");
}
}