99 lines
3.4 KiB
Rust
99 lines
3.4 KiB
Rust
use crate::interp::*;
|
|
|
|
#[allow(unused_imports)]
|
|
use super::helpers::*;
|
|
|
|
#[test]
|
|
fn extern_handle_round_trips() {
|
|
let mut i = Interpreter::new();
|
|
let h = Value::Extern(ExternHandle { kind: "toroid".into(), id: 42 });
|
|
i.set_var("t", h);
|
|
let back = i.eval("t").unwrap();
|
|
match back {
|
|
Value::Extern(h) => {
|
|
assert_eq!(h.kind, "toroid");
|
|
assert_eq!(h.id, 42);
|
|
}
|
|
_ => panic!("expected Extern"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn custom_builtin_invoked_from_cordial() {
|
|
use std::cell::Cell;
|
|
use std::rc::Rc;
|
|
let calls = Rc::new(Cell::new(0));
|
|
let calls_h = Rc::clone(&calls);
|
|
let mut i = Interpreter::new();
|
|
i.register_builtin("scene_update", move |_interp, args| {
|
|
calls_h.set(calls_h.get() + 1);
|
|
match args {
|
|
[Value::Extern(h)] => Ok(Value::Str(format!("updated {}#{}", h.kind, h.id))),
|
|
_ => Err("scene_update(extern)".into()),
|
|
}
|
|
});
|
|
i.set_var("t1", Value::Extern(ExternHandle { kind: "node".into(), id: 7 }));
|
|
let r = i.eval("scene_update(t1)").unwrap();
|
|
assert_eq!(r.display(), "updated node#7");
|
|
assert_eq!(calls.get(), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn custom_builtin_overrides_hardcoded() {
|
|
let mut i = Interpreter::new();
|
|
i.register_builtin("sin", |_interp, _args| Ok(Value::Number(42.0)));
|
|
assert_eq!(i.eval("sin(0)").unwrap().display(), "42");
|
|
}
|
|
|
|
#[test]
|
|
fn unregister_restores_hardcoded() {
|
|
let mut i = Interpreter::new();
|
|
i.register_builtin("sin", |_interp, _args| Ok(Value::Number(42.0)));
|
|
i.unregister_builtin("sin");
|
|
let r = i.eval("sin(0)").unwrap();
|
|
assert!(matches!(r, Value::Number(n) if n.abs() < 1e-9));
|
|
}
|
|
|
|
#[test]
|
|
fn call_invokes_user_fn_by_name_with_values() {
|
|
let mut i = Interpreter::new();
|
|
i.exec("fn add(a, b) {\n return a + b\n}").unwrap();
|
|
let r = i.call("add", &[Value::Number(3.0), Value::Number(4.0)]).unwrap();
|
|
assert_eq!(r.display(), "7");
|
|
}
|
|
|
|
#[test]
|
|
fn call_passes_extern_through_user_fn() {
|
|
let mut i = Interpreter::new();
|
|
i.exec("fn pass(x) {\n return x\n}").unwrap();
|
|
let h = Value::Extern(ExternHandle { kind: "anchor".into(), id: 9 });
|
|
let r = i.call("pass", &[h]).unwrap();
|
|
match r {
|
|
Value::Extern(h) => { assert_eq!(h.kind, "anchor"); assert_eq!(h.id, 9); }
|
|
_ => panic!("expected Extern back"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn host_driven_loop_round_trip() {
|
|
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
let scene_log: Rc<RefCell<Vec<u64>>> = Rc::new(RefCell::new(Vec::new()));
|
|
let log_h = Rc::clone(&scene_log);
|
|
let mut i = Interpreter::new();
|
|
i.register_builtin("emit", move |_interp, args| {
|
|
if let [Value::Extern(h)] = args {
|
|
log_h.borrow_mut().push(h.id);
|
|
Ok(Value::Void)
|
|
} else {
|
|
Err("emit(extern)".into())
|
|
}
|
|
});
|
|
i.exec("fn step(handle) {\n emit(handle)\n return handle\n}").unwrap();
|
|
for id in 0..3u64 {
|
|
let h = Value::Extern(ExternHandle { kind: "node".into(), id });
|
|
i.call("step", &[h]).unwrap();
|
|
}
|
|
assert_eq!(*scene_log.borrow(), vec![0, 1, 2]);
|
|
}
|