Files
OxideJS-New/crates/oxide_vm/tests/array_literal_elision_tests.rs
T

104 lines
3.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 数组字面量 elision(hole 元素)引擎钉:静态字面量 elision 由 emit 侧删除置洞,
//! spread 字面量 elision 由 SET_ELEM 扩长 + DELETE_PROP_DYNAMIC 置洞,
//! 行为对齐 `in`、`length`、`Object.keys`、`join`、for-in 键集与原型链读取。
use std::sync::Arc;
use oxide_compiler::compiler::Compiler;
use oxide_types::value::JsValue;
use oxide_vm::vm::Vm;
fn eval(source: &str) -> Result<(Vm, JsValue), String> {
let allocator = oxide_parser::Allocator::default();
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
let mut vm = Vm::new();
let result = vm.run(&Arc::new(module))?;
Ok((vm, result))
}
fn eval_str(source: &str) -> Result<String, String> {
let (vm, v) = eval(source)?;
// 字符串结果须在同一 VM 上读:perm 串指向 VM 私有内核,VM drop 后指针悬垂。
if v.is_string() {
Ok(vm.lookup_str(v).unwrap_or_default())
} else {
Ok(format!("{v}"))
}
}
// 钉 1:静态 elision 是真洞(`in` 为 false、`Object.keys` 不含洞下标)。
#[test]
fn static_elision_is_hole() {
assert_eq!(eval_str("''+(0 in [,,])+':'+Object.keys([,,]).length").unwrap(), "false:0");
}
// 钉 2:界内静态 elision 读回为洞(length 含洞、`in` 为 false)。
#[test]
fn static_inner_elision_is_hole() {
assert_eq!(eval_str("''+[1,,3].length+':'+(1 in [1,,3])").unwrap(), "3:false");
}
// 钉 3:首元素 elision(length 含洞、0 下标为洞)。
#[test]
fn static_leading_elision_is_hole() {
assert_eq!(eval_str("''+[,1].length+':'+(0 in [,1])").unwrap(), "2:false");
}
// 钉 4:显式 undefined 元素是 present 属性(与 elision 区分)。
#[test]
fn explicit_undefined_is_present() {
assert_eq!(eval_str("''+(0 in [undefined])").unwrap(), "true");
}
// 钉 5:静态 elision 落原型链(原型有 0 下标时 `in` 为 true、读回原型上的值)。
#[test]
fn static_elision_falls_to_proto_chain() {
assert_eq!(eval_str("Array.prototype[0]='g'; ''+(0 in [,,])+':'+[,,][0]").unwrap(), "true:g",);
}
// 钉 6:join 跳洞(两个洞产生一个分隔符)。
#[test]
fn static_elision_join_skips_holes() {
assert_eq!(eval_str("[,,].join(\",\")").unwrap(), ",");
}
// 钉 7:for-in 键集不含洞下标。
#[test]
fn static_elision_for_in_no_keys() {
assert_eq!(eval_str("var c=0; for (var k in [,,]) c++; ''+c").unwrap(), "0");
}
// 钉 8:连续尾部 elision 计入 length。
#[test]
fn static_trailing_elisions_count_in_length() {
assert_eq!(eval_str("''+[4,5,,,,].length").unwrap(), "5");
}
// 钉 9:spread 后尾逗号不产生 elision 元素(length 不变)。
#[test]
fn spread_trailing_comma_not_elision() {
assert_eq!(eval_str("''+[...[1],].length").unwrap(), "1");
}
// 钉 10:spread 后尾逗号不产生 elision 元素(length = spread 长度)。
#[test]
fn spread_trailing_comma_not_elision_dense() {
assert_eq!(eval_str("''+[...[1,2,3],].length").unwrap(), "3");
}
// 钉 11:spread 中间 elision 置洞并计入 length(界内形)。
#[test]
fn spread_inner_elision_is_hole() {
assert_eq!(eval_str("const a=[0,...[1],,2]; ''+a.length+':'+(2 in a)").unwrap(), "4:false",);
}
// 钉 12:spread 空展开后界外 elision 扩长并置洞。
#[test]
fn spread_out_of_bounds_elision_extends_and_holes() {
assert_eq!(
eval_str("const b=[...[],,,]; ''+b.length+':'+(0 in b)+':'+(1 in b)").unwrap(),
"2:false:false",
);
}