mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-26 03:31:12 +08:00
emit/kernel: 可写 builtin 全局标识符写双写全局属性,三常量描述符对齐规范 c:false,受限词法名集补 eval
- 谓词注册表化:targets_readonly_builtin 解析条件抽公共助手,新增 targets_writable_builtin / is_writable_builtin_global(BUILTIN_GLOBALS 减只读三常量派生,不复制名单)+ 只读/可写划分漂移守卫单测 - 12 个赋值族写点(简单/复合/更新/逻辑赋值、解构两臂、for-in/for-of 标识符目标)补双写臂:STORE_VAR 后 0x98 同步全局对象属性(既有可写 属性原地更值、保 e/c 位),裸读镜像与 globalThis 反射不失步 - for-in 头 tier 写点移除 builtin 名例外:可写 builtin 名迭代键照规范 覆写全局属性(三常量仍由拦截臂跳过) - 三常量(undefined/NaN/Infinity)全局描述符 configurable 翻正为 false:delete 拒绝、属性保留,描述符读同步 - 脚本顶层受限词法名集 3→4(补 eval,静态受限臂):let/const/class eval 顶层声明编译期 SyntaxError - 配套钉:7 处既有钉随 c 位翻正 + 2 枚 for-in/eval 形态钉反转,新增 global_builtin_writable_tests(16 钉:双写六形态 + 遮蔽/strict/eval/ 宿主名面) test262 子集:built-ins/global 29/29、三常量族 20/20、11.13.1-4 7/7、 assignmenttargettype plain 8/8 全绿;language/global-code 17 失败文件 双树单跑一致(pre-existing);annexB assignmenttargettype 7 个 parse error 为既有解析器缺口
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
//! 脚本顶层 lexical 声明撞受限全局名的编译期拒绝:let/const/class 声明名撞
|
||||
//! 全局对象不可配置自有属性(undefined/NaN/Infinity)→ SyntaxError(整程序
|
||||
//! 编译失败)。局部作用域(函数体/块/try)与 eval 代码为合法遮蔽不拒;三常量
|
||||
//! 值使用不受影响。
|
||||
//! 受限集(undefined/eval/NaN/Infinity——三常量不可配置自有属性 + eval 静态
|
||||
//! 受限臂)→ SyntaxError(整程序编译失败)。局部作用域(函数体/块/try)与
|
||||
//! eval 代码为合法遮蔽不拒;三常数值使用不受影响。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -108,10 +108,22 @@ fn top_level_let_uses_nan_value_allowed() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn top_level_let_eval_name_allowed() {
|
||||
// eval 是全局对象可配置自有属性:合法遮蔽,不在受限集。
|
||||
let r = assert_ok("let eval; 1");
|
||||
assert_eq!(r.as_int(), 1);
|
||||
fn top_level_let_eval_name_rejected() {
|
||||
// eval 属静态受限臂:顶层 lexical 声明不得遮蔽(var/function 路径不受
|
||||
// 本集约束)。
|
||||
assert_compile_err("let eval;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn top_level_const_eval_name_rejected() {
|
||||
assert_compile_err("const eval = 1;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn top_level_class_eval_name_rejected() {
|
||||
// 若解析器更早拒绝(early error 族),亦接受该拒绝相位(整程序拒绝可观察
|
||||
// 行为同形)。
|
||||
assert!(eval("class eval {}").is_err(), "class eval 类名应被拒绝");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! 全局三常量(undefined/NaN/Infinity)描述符与 var 声明交互的回归测试。
|
||||
//!
|
||||
//! 覆盖规范全局对象属性描述符 { writable:false, enumerable:false, configurable:true }:
|
||||
//! 描述符读、delete 真删、delete 后镜像裸读、var 无初始化声明的描述符不漂移与值
|
||||
//! 覆盖规范全局对象属性描述符 { writable:false, enumerable:false, configurable:false }:
|
||||
//! 描述符读、delete 拒绝且属性保留、delete 后镜像裸读、var 无初始化声明的描述符不漂移与值
|
||||
//! 保持(writable 不翻位、NaN/Infinity 不被抹成 undefined)、var 初始化声明的值
|
||||
//! 落槽、枚举面不泄漏、任务只读拦截与 strict TypeError、eval 路径、for-in 枚举面。
|
||||
|
||||
@@ -45,31 +45,31 @@ const CONSTANTS: [&str; 3] = ["undefined", "NaN", "Infinity"];
|
||||
|
||||
#[test]
|
||||
fn three_constants_descriptor_matches_spec() {
|
||||
// #1:描述符 { writable:false, enumerable:false, configurable:true } ×3 常量。
|
||||
// #1:描述符 { writable:false, enumerable:false, configurable:false } ×3 常量。
|
||||
for name in CONSTANTS {
|
||||
let src = format!(
|
||||
"var d = Object.getOwnPropertyDescriptor(globalThis, '{name}'); \
|
||||
d.writable === false && d.enumerable === false && d.configurable === true"
|
||||
d.writable === false && d.enumerable === false && d.configurable === false"
|
||||
);
|
||||
run_truthy(&src);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_three_constants_removes_property() {
|
||||
// #2:configurable → delete 返 true 且属性真删(描述符读为 undefined)×3 常量。
|
||||
fn delete_three_constants_refused_property_kept() {
|
||||
// #2:configurable:false → delete 返 false 且属性保留(描述符仍在、值不变)×3 常量。
|
||||
for name in CONSTANTS {
|
||||
let src = format!(
|
||||
"delete globalThis.{name} === true \
|
||||
&& Object.getOwnPropertyDescriptor(globalThis, '{name}') === undefined"
|
||||
"delete globalThis.{name} === false \
|
||||
&& Object.getOwnPropertyDescriptor(globalThis, '{name}') !== undefined"
|
||||
);
|
||||
run_truthy(&src);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delete_then_bare_read_via_mirror() {
|
||||
// #3:删后裸读走镜像预载(入口值),无 ReferenceError。
|
||||
fn refused_delete_then_bare_read_via_mirror() {
|
||||
// #3:delete 拒绝后裸读走镜像预载(入口值),无 ReferenceError。
|
||||
assert_eq!(run_string("delete globalThis.undefined; typeof undefined"), "undefined");
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ fn var_no_init_descriptor_unchanged() {
|
||||
let src = format!(
|
||||
"var {name}; var d = Object.getOwnPropertyDescriptor(globalThis, '{name}'); \
|
||||
{value_check} && d.writable === false && d.enumerable === false \
|
||||
&& d.configurable === true",
|
||||
&& d.configurable === false",
|
||||
);
|
||||
run_truthy(&src);
|
||||
}
|
||||
@@ -157,7 +157,7 @@ fn eval_var_readonly_builtin() {
|
||||
run_truthy(
|
||||
"eval('var undefined = 3'); \
|
||||
var d = Object.getOwnPropertyDescriptor(globalThis, 'undefined'); \
|
||||
d.writable === false && d.configurable === true",
|
||||
d.writable === false && d.configurable === false",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -199,10 +199,10 @@ fn function_declaration_builtin_name() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_in_var_head_builtin_name_compiles_and_keeps_property() {
|
||||
// 顶层 for-in var 头撞 builtin 名:序言预登记槽复用后可编译,
|
||||
// 迭代键不触及全局属性(Math 对象保)。
|
||||
run_truthy("var m = Math; for (var Math in {a:1,b:2}) {} globalThis.Math === m");
|
||||
fn for_in_var_head_writable_builtin_name_clobbers_property() {
|
||||
// 顶层 for-in var 头撞可写 builtin 名:序言预登记槽复用后可编译,
|
||||
// 迭代键照规范覆写既有全局属性(末键 'b' 落 Math 属性)。
|
||||
run_truthy("var m = Math; for (var Math in {a:1,b:2}) {} globalThis.Math === 'b'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
//! 可写 builtin 全局双写(镜像槽 + 全局对象属性)回归测试。
|
||||
//!
|
||||
//! 规范可写全局(11 个 w:true 函数 + 48 个构造器/命名空间 + globalThis + 宿主名,
|
||||
//! 描述符 {writable:true, enumerable:false, configurable:true})的标识符写须同步
|
||||
//! 全局对象属性,裸读(镜像)与 globalThis 反射(属性)不失步。覆盖:简单/复合/
|
||||
//! 更新/逻辑赋值、for-in/for-of 标识符目标、解构两臂、局部遮蔽不误伤、strict 可写
|
||||
//! put 成功、eval 路径与 TypedArray 宿主名抽样。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_parser::Allocator;
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
fn eval_truthy(source: &str) {
|
||||
let allocator = Allocator::default();
|
||||
let program = oxide_parser::parse(&allocator, source).expect("parse");
|
||||
let module = Compiler::new().compile(&program).expect("compile");
|
||||
let mut vm = Vm::new();
|
||||
let result = vm.run(&Arc::new(module)).expect("run");
|
||||
assert!(result.is_bool() && result.as_bool(), "expected true, got: {result:?}\nsource: {source}");
|
||||
}
|
||||
|
||||
// ── 简单赋值:镜像与属性同步落值 ──
|
||||
#[test]
|
||||
fn simple_assign_math_dual_writes() {
|
||||
eval_truthy("var m = Math; Math = 5; Math === 5 && globalThis.Math === 5 && m !== 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_assign_writable_names_dual_write() {
|
||||
for name in ["Object", "JSON", "Symbol", "Promise"] {
|
||||
let src = format!("var m = {name}; {name} = 5; {name} === 5 && globalThis.{name} === 5");
|
||||
eval_truthy(&src);
|
||||
}
|
||||
}
|
||||
|
||||
// ── w:true 函数族:strict 下可写 put 成功(无 TypeError) ──
|
||||
#[test]
|
||||
fn strict_writable_function_put_succeeds() {
|
||||
eval_truthy("'use strict'; parseInt = 42; parseInt === 42 && globalThis.parseInt === 42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sloppy_writable_function_put_succeeds() {
|
||||
eval_truthy("parseInt = 42; parseInt === 42 && globalThis.parseInt === 42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uri_family_dual_write() {
|
||||
eval_truthy("var m = encodeURI; encodeURI = 1; encodeURI === 1 && globalThis.encodeURI === 1");
|
||||
}
|
||||
|
||||
// ── 复合/更新/逻辑赋值:RMW 新值两侧同步 ──
|
||||
#[test]
|
||||
fn compound_assign_dual_writes() {
|
||||
eval_truthy("var m = Math; Math = 5; Math += 1; Math === 6 && globalThis.Math === 6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_assign_dual_writes() {
|
||||
eval_truthy("var m = Math; Math = 5; var r = (Math++); r === 5 && Math === 6 && globalThis.Math === 6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_assign_dual_writes() {
|
||||
// ||=:LHS falsy 触发 put;??=:LHS nullish 触发 put。
|
||||
eval_truthy("var m = Math; Math = 0; Math ||= 9; Math === 9 && globalThis.Math === 9");
|
||||
eval_truthy("var m = Math; Math = null; Math ??= 2; Math === 2 && globalThis.Math === 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_assign_short_circuit_no_put() {
|
||||
// 短路未通过不发生 put(&&= 遇 falsy、??= 遇非 nullish):值与属性均保持。
|
||||
eval_truthy("var m = Math; Math = 0; Math &&= 1; Math === 0 && globalThis.Math === 0");
|
||||
eval_truthy("var m = Math; Math = 5; Math ??= 2; Math === 5 && globalThis.Math === 5");
|
||||
}
|
||||
|
||||
// ── for-in/for-of 标识符目标:迭代值两侧同步 ──
|
||||
#[test]
|
||||
fn for_in_target_dual_writes() {
|
||||
eval_truthy("var m = Math; Math = 5; for (Math in {a:1,b:2}) {} Math === 'b' && globalThis.Math === 'b'");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_of_target_dual_writes() {
|
||||
eval_truthy("var m = Math; for (Math of [1,2]) {} Math === 2 && globalThis.Math === 2");
|
||||
}
|
||||
|
||||
// ── 解构赋值两臂:值两侧同步 ──
|
||||
#[test]
|
||||
fn destructure_assign_dual_writes() {
|
||||
eval_truthy("var m = Math; ({Math} = {Math: 1}); Math === 1 && globalThis.Math === 1");
|
||||
eval_truthy("var m = Math; ([Math = 1] = [2]); Math === 2 && globalThis.Math === 2");
|
||||
}
|
||||
|
||||
// ── 局部遮蔽不误伤:函数内 var 同名写不触全局 ──
|
||||
#[test]
|
||||
fn local_shadow_not_dual_written() {
|
||||
eval_truthy(
|
||||
"var m = Math; function g(){ var Math = 7; return Math; } \
|
||||
g() === 7 && Math === m && globalThis.Math === m",
|
||||
);
|
||||
}
|
||||
|
||||
// ── globalThis 自身可写:镜像与属性同步 ──
|
||||
#[test]
|
||||
fn global_this_self_dual_writes() {
|
||||
eval_truthy(
|
||||
"var m = globalThis; globalThis = 1; \
|
||||
globalThis === 1 && Object.getOwnPropertyDescriptor(m, 'globalThis').value === 1",
|
||||
);
|
||||
}
|
||||
|
||||
// ── 宿主名(TypedArray 抽象运算对象)同双写面 ──
|
||||
#[test]
|
||||
fn typed_array_host_name_dual_writes() {
|
||||
eval_truthy("var m = TypedArray; TypedArray = 1; TypedArray === 1 && globalThis.TypedArray === 1");
|
||||
}
|
||||
|
||||
// ── eval 路径:同一 emit 管线双写同效(外层镜像预载不重载,只钉属性面) ──
|
||||
#[test]
|
||||
fn eval_code_dual_writes_property() {
|
||||
eval_truthy("eval('Math = 5'); globalThis.Math === 5");
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//! 内置全局属性描述符测试:规范要求全局构造器/命名空间对象属性
|
||||
//! enumerable=false(不泄漏进 Object.keys(globalThis) / for-in),
|
||||
//! 全局 NaN/undefined/Infinity 三常量不可写不可枚举可配置。
|
||||
//! enumerable=false(不泄漏进 Object.keys(globalThis) / for-in)且可写可配置,
|
||||
//! 全局 NaN/undefined/Infinity 三常量不可写不可枚举不可配置。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -63,11 +63,11 @@ fn for_in_global_this_excludes_builtins() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nan_undefined_infinity_are_non_writable_configurable() {
|
||||
fn nan_undefined_infinity_are_non_writable_non_configurable() {
|
||||
for name in ["NaN", "undefined", "Infinity"] {
|
||||
let src = format!(
|
||||
"var d = Object.getOwnPropertyDescriptor(globalThis, '{name}'); \
|
||||
d.writable === false && d.enumerable === false && d.configurable === true"
|
||||
d.writable === false && d.enumerable === false && d.configurable === false"
|
||||
);
|
||||
eval_truthy(&src);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user