mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
fix: 逻辑赋值标识符目标接入不可写全局内置拦截,目标位置内置预登记稳定槽解析
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
//! 不可写全局内置(undefined/NaN/Infinity)写路径拦截测试:写命中全局不可写
|
||||
//! 内置绑定时编译期拦截——sloppy 静默 no-op(后续读回原值,全局对象不变),
|
||||
//! strict 抛 TypeError。覆盖简单/复合/更新赋值、声明(var 无初始化与带初始化)、
|
||||
//! 解构赋值、for-in/for-of 标识符目标与嵌套函数形态;局部遮蔽绑定(var/let/
|
||||
//! 参数)与其他可写内置(Math)不受影响。
|
||||
//! strict 抛 TypeError。覆盖简单/复合/更新/逻辑赋值、声明(var 无初始化与
|
||||
//! 带初始化)、解构赋值、for-in/for-of 标识符目标与嵌套函数形态;局部遮蔽
|
||||
//! 绑定(var/let/参数)与其他可写内置(Math)不受影响。逻辑赋值额外钉住
|
||||
//! 短路时序:短路未通过不发生 put(strict 不抛),通过才在写点拦截。
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_types::value::JsValue;
|
||||
@@ -160,6 +161,68 @@ fn postfix_update_returns_old_value() {
|
||||
assert!(r.is_bool() && !r.as_bool(), "Infinity-- 后缀形式应返回旧值 Infinity,实际 {:?}", r);
|
||||
}
|
||||
|
||||
// ── 逻辑赋值(||=/&&=/??=)标识符目标:短路时序与 PutValue 对齐——短路未通过
|
||||
// 不发生 put(strict 不抛、表达式值 = LHS 旧值),通过才在写点拦截 ──
|
||||
#[test]
|
||||
fn logical_assign_sloppy_matrix_keeps_value() {
|
||||
// 三常量 × 三逻辑符:短路通过者静默 no-op 读回原值,短路未通过者不写。
|
||||
let cases: &[(&str, &str)] = &[
|
||||
("undefined ||= 5; '' + undefined", "undefined"),
|
||||
("undefined &&= 5; '' + undefined", "undefined"),
|
||||
("undefined ??= 5; '' + undefined", "undefined"),
|
||||
("NaN ||= 1; '' + NaN", "NaN"),
|
||||
("NaN &&= 1; '' + NaN", "NaN"),
|
||||
("NaN ??= 1; '' + NaN", "NaN"),
|
||||
("Infinity ||= 2; '' + Infinity", "Infinity"),
|
||||
("Infinity &&= 2; '' + Infinity", "Infinity"),
|
||||
("Infinity ??= 2; '' + Infinity", "Infinity"),
|
||||
];
|
||||
for &(source, expected) in cases {
|
||||
let s = eval_str(source);
|
||||
assert_eq!(s, expected, "sloppy 逻辑赋值命中不可写内置应静默 no-op,读回原值,源码: {source}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_assign_strict_write_path_throws() {
|
||||
// 短路通过(||=/??= 遇 falsy/nullish、&&= 遇 truthy)到达写点:put 失败抛 TypeError。
|
||||
let sources = [
|
||||
"'use strict'; undefined ||= 5",
|
||||
"'use strict'; undefined ??= 5",
|
||||
"'use strict'; NaN ||= 1",
|
||||
"'use strict'; Infinity &&= 2",
|
||||
];
|
||||
for source in sources {
|
||||
let result = eval(source);
|
||||
assert_err_contains(result, "read-only");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_assign_strict_short_circuit_no_throw() {
|
||||
// 短路未通过不发生 put:strict 不抛错,表达式值 = LHS 旧值。
|
||||
let cases: &[(&str, &str)] = &[
|
||||
("'use strict'; '' + (undefined &&= 5)", "undefined"),
|
||||
("'use strict'; '' + (NaN &&= 1)", "NaN"),
|
||||
("'use strict'; '' + (NaN ??= 1)", "NaN"),
|
||||
("'use strict'; '' + (Infinity ||= 2)", "Infinity"),
|
||||
("'use strict'; '' + (Infinity ??= 2)", "Infinity"),
|
||||
];
|
||||
for &(source, expected) in cases {
|
||||
let s = eval_str(source);
|
||||
assert_eq!(
|
||||
s, expected,
|
||||
"逻辑赋值短路未通过不 put,strict 不应抛错且表达式值 = LHS 旧值,源码: {source}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_or_assign_expression_value_is_rhs() {
|
||||
let s = eval_str("(undefined ||= 5) + ':' + undefined");
|
||||
assert_eq!(s, "5:undefined", "逻辑赋值写点表达式值应为 RHS,槽值保持原值");
|
||||
}
|
||||
|
||||
// ── 解构赋值目标:命中项静默跳过,strict 抛错 ──
|
||||
#[test]
|
||||
fn destructure_assign_keeps_value() {
|
||||
@@ -192,6 +255,25 @@ fn for_of_target_strict_empty_no_throw() {
|
||||
assert!(r.is_bool() && r.as_bool(), "空集合 for-of 不发生 put,strict 不应抛错,实际 {:?}", r);
|
||||
}
|
||||
|
||||
// ── for-in 标识符目标:键写不污染槽值,写仅在 NEXT 产生键后发生 ──
|
||||
#[test]
|
||||
fn for_in_target_keeps_value() {
|
||||
let s = eval_str("for (undefined in {a: 1}) {} '' + undefined");
|
||||
assert_eq!(s, "undefined", "sloppy for-in 目标 undefined 应静默 no-op,读回原值");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_in_target_strict_throws_type_error() {
|
||||
let result = eval("'use strict'; for (undefined in {a: 1}) {}");
|
||||
assert_err_contains(result, "read-only");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_in_target_strict_empty_no_throw() {
|
||||
let r = eval("'use strict'; for (undefined in {}) {} true").unwrap();
|
||||
assert!(r.is_bool() && r.as_bool(), "空对象 for-in 不发生 put,strict 不应抛错,实际 {:?}", r);
|
||||
}
|
||||
|
||||
// ── for 头 var 无初始化:不抹预载槽值(NaN 保留) ──
|
||||
#[test]
|
||||
fn for_header_var_no_init_keeps_slot_value() {
|
||||
|
||||
Reference in New Issue
Block a user