mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 块函数名绑定可写化并收窄 catch 参数抑制面
This commit is contained in:
Generated
+21
-21
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1258,7 +1258,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1272,7 +1272,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1288,7 +1288,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1300,7 +1300,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_fold"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_bytecode",
|
||||
@@ -1312,7 +1312,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1335,7 +1335,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1347,7 +1347,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1356,11 +1356,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1375,7 +1375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1391,7 +1391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1404,7 +1404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1424,7 +1424,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.19.36"
|
||||
version = "0.19.37"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -44,8 +44,8 @@ pub(crate) struct FnScopeNames {
|
||||
/// 块级普通函数声明名(源序去重;直接子级是提升 var 声明不纳,async/生成器
|
||||
/// 是块级词法绑定不纳,不递归嵌套函数体)。
|
||||
pub(crate) block_function_names: Vec<String>,
|
||||
/// 块级函数名的外层 var 绑定抑制集(形参名 ∪ 树内词法声明名;命中抑制的名字
|
||||
/// 不建外层 var 绑定、不求值写回)。
|
||||
/// 块级函数名的外层 var 绑定抑制集(形参名 ∪ 树内词法声明名,绑定标识符 catch
|
||||
/// 参数除外;命中抑制的名字不建外层 var 绑定、不求值写回)。
|
||||
pub(crate) block_fn_suppressed: HashSet<String>,
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
}
|
||||
}
|
||||
// 抑制面:词法名与块函数名同名时退化为纯块作用域(各层均收集)。
|
||||
// 规范口径:var 声明与函数体任一层词法声明同名即产生早期错误
|
||||
// (LexicallyDeclaredNames 递归收集嵌套块),故嵌套 let/const 亦入集。
|
||||
if !is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_fn_suppressed);
|
||||
@@ -141,7 +143,7 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
let name = id.name.to_string();
|
||||
// own 面:类名是本作用域 const 绑定。
|
||||
out.own_binding_names.insert(name.clone());
|
||||
// 抑制面:类名是词法声明,与块函数名同名时退化纯块作用域。
|
||||
// 抑制面:类名是词法声明,与块函数名同名时退化纯块作用域(各层均收集)。
|
||||
out.block_fn_suppressed.insert(name.clone());
|
||||
if top {
|
||||
// 直接子词法面:顶层类是顶层词法绑定。
|
||||
@@ -269,7 +271,7 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域。
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域(各层均收集)。
|
||||
if !is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_fn_suppressed);
|
||||
@@ -288,7 +290,7 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
collect_for_left_decl_names(&fi.left, &mut out.own_binding_names);
|
||||
if !is_var {
|
||||
collect_for_left_decl_names(&fi.left, &mut out.block_level_decl_names);
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域。
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域(各层均收集)。
|
||||
collect_for_left_decl_names(&fi.left, &mut out.block_fn_suppressed);
|
||||
}
|
||||
}
|
||||
@@ -303,7 +305,7 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
collect_for_left_decl_names(&fo.left, &mut out.own_binding_names);
|
||||
if !is_var {
|
||||
collect_for_left_decl_names(&fo.left, &mut out.block_level_decl_names);
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域。
|
||||
// 抑制面:for 头词法名与块函数名同名时退化纯块作用域(各层均收集)。
|
||||
collect_for_left_decl_names(&fo.left, &mut out.block_fn_suppressed);
|
||||
}
|
||||
}
|
||||
@@ -319,11 +321,16 @@ fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top:
|
||||
// 与旧收集器逐位一致(各集合面不受访问序影响)。
|
||||
collect_fn_scope_names_impl(&ts.block.body, out, false);
|
||||
if let Some(h) = &ts.handler {
|
||||
// catch 参数是本作用域的词法绑定:own、块级与抑制三面均计入。
|
||||
// catch 参数是本作用域的词法绑定:own 与块级两面的计入。
|
||||
// 抑制面:仅解构 catch 参数(BindingPattern)计入。绑定标识符
|
||||
// catch 参数(CatchParameter:BindingIdentifier)按 B.3.5 例外条款
|
||||
// 豁免 var 碰撞早期错误,同名块函数仍提升全局,不入抑制集。
|
||||
if let Some(param) = &h.param {
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.own_binding_names);
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.block_level_decl_names);
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.block_fn_suppressed);
|
||||
if !matches!(param.pattern, oxide_parser::BindingPattern::BindingIdentifier(_)) {
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.block_fn_suppressed);
|
||||
}
|
||||
}
|
||||
collect_fn_scope_names_impl(&h.body.body, out, false);
|
||||
}
|
||||
@@ -656,7 +663,7 @@ mod tests {
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
&["b", "e"],
|
||||
&["b"],
|
||||
);
|
||||
assert_scope_names(
|
||||
"try { var a; } catch { let b; }",
|
||||
@@ -795,7 +802,7 @@ mod tests {
|
||||
&[],
|
||||
&[],
|
||||
&["bf6", "bf7", "bf8"],
|
||||
&["e"],
|
||||
&[],
|
||||
);
|
||||
assert_scope_names(
|
||||
"L2: { function bf9() {} } with (o) { function bf10() {} }",
|
||||
@@ -891,7 +898,8 @@ mod tests {
|
||||
&["s"],
|
||||
&["s"],
|
||||
);
|
||||
// catch 参数与块函数名同名:catch 体外的 if 臂块函数被抑制。
|
||||
// catch 参数与块函数名同名:绑定标识符 catch 参数按 B.3.5 例外条款豁免 var
|
||||
// 碰撞早期错误,不入抑制集(同名块函数仍提升全局)。
|
||||
assert_scope_names(
|
||||
"try {} catch (e) {} if (x) { function e() {} }",
|
||||
&[],
|
||||
@@ -902,7 +910,7 @@ mod tests {
|
||||
&[],
|
||||
&[],
|
||||
&["e"],
|
||||
&["e"],
|
||||
&[],
|
||||
);
|
||||
// 形参名进抑制面:块函数名撞形参名退化纯块作用域(形参名同时注入 own 面)。
|
||||
assert_scope_names(
|
||||
|
||||
@@ -278,6 +278,7 @@ impl Emitter {
|
||||
is_async: false,
|
||||
own_strict: true,
|
||||
name: None,
|
||||
is_block_function: false,
|
||||
};
|
||||
let ctor_hooks = ClassElementHooks {
|
||||
extra_bindings: &self_binding,
|
||||
|
||||
@@ -140,6 +140,7 @@ impl Emitter {
|
||||
is_async: method_value.r#async,
|
||||
own_strict: true,
|
||||
name: None,
|
||||
is_block_function: false,
|
||||
},
|
||||
hooks,
|
||||
)?;
|
||||
|
||||
@@ -63,6 +63,10 @@ pub struct CompileCtx {
|
||||
/// `is_eval_script`——该标志只标识当前顶层程序,且还控制顶层全局写点与块级
|
||||
/// 函数门控,整体传播语义过宽。
|
||||
pub(crate) is_eval_origin: bool,
|
||||
/// 是否处于首个 sub-pass(提升函数声明发射期):声明点据此区分顶层函数
|
||||
/// 声明(名绑定恒不可写)与块级函数声明(Annex B.3.3 块绑定为可变 var 绑定)。
|
||||
/// 仅程序/函数体发射入口在提升 sub-pass 内置位,不跨嵌套函数继承。
|
||||
pub(crate) in_hoisting_subpass: bool,
|
||||
/// 源码是否为 `source_escape` 产物(动态编译入口):正则字面量源文本切片
|
||||
/// 的池键形态据此选择(见 [`Emitter::source_encoded`])。
|
||||
pub(crate) source_encoded: bool,
|
||||
@@ -285,6 +289,7 @@ impl CompileCtx {
|
||||
repl_persist: false,
|
||||
is_eval_script: false,
|
||||
is_eval_origin: false,
|
||||
in_hoisting_subpass: false,
|
||||
source_encoded: false,
|
||||
static_block_this_reg: None,
|
||||
field_buffer: None,
|
||||
|
||||
@@ -45,6 +45,7 @@ impl Emitter {
|
||||
is_async: arrow.r#async,
|
||||
own_strict: arrow.has_use_strict_directive(),
|
||||
name: None,
|
||||
is_block_function: false,
|
||||
};
|
||||
let mut sub_module =
|
||||
self.compile_simple_function_body(¶m_names, body_stmts, ctx, FunctionBodyContext::Arrow, flags)?;
|
||||
@@ -100,6 +101,7 @@ impl Emitter {
|
||||
is_async: fe.r#async,
|
||||
own_strict,
|
||||
name: fn_name,
|
||||
is_block_function: false,
|
||||
};
|
||||
let mut sub_module =
|
||||
self.compile_simple_function_body(¶m_names, body_stmts, ctx, FunctionBodyContext::Ordinary, flags)?;
|
||||
|
||||
@@ -73,6 +73,9 @@ pub struct FunctionFlags<'a> {
|
||||
pub own_strict: bool,
|
||||
/// 函数名(具名函数声明/表达式传名,箭头与匿名传 `None`),用于函数名不可写绑定登记。
|
||||
pub name: Option<&'a str>,
|
||||
/// 块级普通函数声明(Annex B.3.3):函数名绑定为可写 var 绑定,体内容器内
|
||||
/// `f = 123` 可覆写块绑定(非块级函数声明的函数名绑定恒不可写)。
|
||||
pub is_block_function: bool,
|
||||
}
|
||||
|
||||
/// 类元素钩子:类元素函数(构造器/方法/字段)的额外绑定、字段发射与捕获组,
|
||||
@@ -353,6 +356,7 @@ impl Emitter {
|
||||
hooks.extra_upvalue_names,
|
||||
flags.name,
|
||||
&scope_names,
|
||||
flags.is_block_function,
|
||||
)?;
|
||||
// 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。
|
||||
ctx.field_keys_uv = ctx
|
||||
@@ -574,6 +578,7 @@ impl Emitter {
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
ctx: &mut CompileCtx, body_context: FunctionBodyContext, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(String, u8)], name: Option<&str>, scope_names: &FnScopeNames,
|
||||
is_block_function: bool,
|
||||
) -> Result<u32, String> {
|
||||
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
|
||||
let param_base = ctx.next_reg;
|
||||
@@ -633,6 +638,9 @@ impl Emitter {
|
||||
// 绑定,帧槽写入把它初始化为函数对象。抑制面(形参同名 / 体内容器 var
|
||||
// 同名 / arguments 对象占位)不建名绑定:前两者名解析到参数/var 绑定,
|
||||
// 后者 arguments 绑定占位(var 同名时由帧槽写入初始化为函数对象)。
|
||||
// 块级普通函数声明(Annex B.3.3)的块绑定是可变 var 绑定:体内容器内
|
||||
// `f = 123` 可覆写块绑定(非块级函数声明的函数名绑定恒不可写);strict
|
||||
// 函数名绑定恒不可写(strict 块函数名绑定 eval 自身词法环境,同不可写)。
|
||||
// 名登记须先于 set_captured_bindings:嵌套函数捕获名分析依赖 own_bindings
|
||||
// 完整(名被捕获时须识别为本函数绑定并建 cell)。
|
||||
if let Some(fn_name) = name {
|
||||
@@ -651,7 +659,7 @@ impl Emitter {
|
||||
lexical: false,
|
||||
predeclared: false,
|
||||
cell_idx: None,
|
||||
non_writable: true,
|
||||
non_writable: ctx.is_strict || !is_block_function,
|
||||
},
|
||||
);
|
||||
ctx.own_bindings.insert(fn_name.to_string());
|
||||
@@ -1088,6 +1096,9 @@ impl Emitter {
|
||||
/// 入口物化闭包,次 sub-pass 跳过声明语句本身,声明点不重编以保函数对象同一性。
|
||||
fn emit_body_stmts(&self, body_stmts: &[Statement], ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
|
||||
let mut last_result_reg = None;
|
||||
// 提升 sub-pass 标志置位:声明点据此区分顶层函数声明(名绑定恒不可写)
|
||||
// 与块级函数声明(Annex B.3.3 块绑定为可变 var 绑定)。
|
||||
ctx.in_hoisting_subpass = true;
|
||||
for stmt in body_stmts {
|
||||
if Self::is_body_hoisted_function_decl(stmt) {
|
||||
if let Some(reg) = self.emit_statement(stmt, ctx)? {
|
||||
@@ -1095,6 +1106,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.in_hoisting_subpass = false;
|
||||
for stmt in body_stmts {
|
||||
if Self::is_body_hoisted_function_decl(stmt) {
|
||||
continue;
|
||||
|
||||
@@ -448,11 +448,15 @@ impl Emitter {
|
||||
}
|
||||
|
||||
// 首个 sub-pass:发函数声明(hoisting),保证任何代码运行前函数对象已就绪。
|
||||
// 提升 sub-pass 标志置位:声明点据此区分顶层函数声明(名绑定恒不可写)
|
||||
// 与块级函数声明(Annex B.3.3 块绑定为可变 var 绑定)。
|
||||
ctx.in_hoisting_subpass = true;
|
||||
for stmt in &program.body {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
self.emit_statement(stmt, &mut ctx)?;
|
||||
}
|
||||
}
|
||||
ctx.in_hoisting_subpass = false;
|
||||
|
||||
// 第二个 sub-pass:发其余所有语句。
|
||||
let mut last_result: Option<u32> = None;
|
||||
|
||||
@@ -77,7 +77,7 @@ impl Emitter {
|
||||
return Ok(());
|
||||
};
|
||||
let name = id.name.to_string();
|
||||
self.materialize_function_declaration(fd, &name, ctx)?;
|
||||
self.materialize_function_declaration(fd, &name, ctx, true)?;
|
||||
// 登记声明节点 arena 地址(Box 解引到 arena 本体):声明点
|
||||
// 以同一节点地址判同一,区分本声明入口物化与同名支臂。
|
||||
ctx.block_fn_entry_mats
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//! 函数声明语句 emit:`emit_function_declaration_statement` 创建闭包并绑定函数名。
|
||||
|
||||
use crate::symbol_table::ScopeKind;
|
||||
use crate::{CompileCtx, Emitter, FunctionBodyContext, FunctionFlags, ParamSpec};
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
@@ -34,20 +33,20 @@ impl Emitter {
|
||||
// 闭包落 fresh 寄存器写回外层 var;
|
||||
// - 其余(支臂首次求值):执行期自物化闭包写入块槽。
|
||||
// 非块路径(顶层/函数作用域声明点)恒自物化。
|
||||
let binding_scope_kind = ctx
|
||||
.scopes
|
||||
.symbols
|
||||
.lookup_any_binding(&name)
|
||||
.map(|(_, scope_idx)| ctx.scopes.symbols.scopes[scope_idx].kind);
|
||||
let node = fd as *const _ as *const ();
|
||||
let var_reg = if binding_scope_kind == Some(ScopeKind::BlockScope) {
|
||||
// 块级普通函数声明(Annex B.3.3):块槽 Let 绑定承载块函数,函数名绑定
|
||||
// 为可变 var 绑定(体内容器内 `f = 123` 可覆写块绑定);非块路径恒不可写。
|
||||
// 判定依据提升 sub-pass 标志:首个 sub-pass 发顶层函数声明(恒不可写),
|
||||
// 其余 sub-pass 发的函数声明皆为块级(if/while/for/switch/try 支臂与块直接子)。
|
||||
let is_block_function = !ctx.in_hoisting_subpass;
|
||||
let var_reg = if is_block_function {
|
||||
match ctx.block_fn_entry_mats.last().and_then(|m| m.get(&name)) {
|
||||
Some(&m) if m == node => ctx.lookup(&name)?,
|
||||
Some(_) => self.materialize_function_declaration_var_only(fd, &name, ctx)?,
|
||||
None => self.materialize_function_declaration(fd, &name, ctx)?,
|
||||
Some(_) => self.materialize_function_declaration_var_only(fd, &name, ctx, true)?,
|
||||
None => self.materialize_function_declaration(fd, &name, ctx, true)?,
|
||||
}
|
||||
} else {
|
||||
self.materialize_function_declaration(fd, &name, ctx)?
|
||||
self.materialize_function_declaration(fd, &name, ctx, false)?
|
||||
};
|
||||
// sloppy 模式下按 Annex B.3.3 为块级普通函数声明建外层 var 绑定并写回:
|
||||
// 预声明期为该名实例化的函数作用域 var 绑定在此写入块槽位里的函数对象,
|
||||
@@ -110,11 +109,11 @@ impl Emitter {
|
||||
/// - 闭包的 upvalue/cell 捕获在函数入口的捕获分析期固定,本调用点的时序
|
||||
/// 只决定 CREATE_CLOSURE 在指令流中的落点。
|
||||
pub(crate) fn materialize_function_declaration(
|
||||
&self, fd: &oxide_parser::Function, name: &str, ctx: &mut CompileCtx,
|
||||
&self, fd: &oxide_parser::Function, name: &str, ctx: &mut CompileCtx, is_block_function: bool,
|
||||
) -> Result<u32, String> {
|
||||
let var_reg = ctx.lookup(name)?;
|
||||
ctx.reserve_reg(var_reg);
|
||||
self.materialize_function_closure(fd, name, var_reg, ctx, true)?;
|
||||
self.materialize_function_closure(fd, name, var_reg, ctx, true, is_block_function)?;
|
||||
Ok(var_reg)
|
||||
}
|
||||
|
||||
@@ -122,15 +121,16 @@ impl Emitter {
|
||||
/// 直接子占用块槽,嵌套捕获读槽 cell 与 V8 块绑定一致)。调用点经返回
|
||||
/// 寄存器把闭包写回外层 var 绑定。
|
||||
pub(crate) fn materialize_function_declaration_var_only(
|
||||
&self, fd: &oxide_parser::Function, name: &str, ctx: &mut CompileCtx,
|
||||
&self, fd: &oxide_parser::Function, name: &str, ctx: &mut CompileCtx, is_block_function: bool,
|
||||
) -> Result<u32, String> {
|
||||
let reg = ctx.alloc_reg();
|
||||
self.materialize_function_closure(fd, name, reg, ctx, false)?;
|
||||
self.materialize_function_closure(fd, name, reg, ctx, false, is_block_function)?;
|
||||
Ok(reg)
|
||||
}
|
||||
|
||||
fn materialize_function_closure(
|
||||
&self, fd: &oxide_parser::Function, name: &str, reg: u32, ctx: &mut CompileCtx, write_slot: bool,
|
||||
is_block_function: bool,
|
||||
) -> Result<(), String> {
|
||||
let mut param_names = Vec::new();
|
||||
for (idx, param) in fd.params.items.iter().enumerate() {
|
||||
@@ -157,6 +157,7 @@ impl Emitter {
|
||||
is_async: fd.r#async,
|
||||
own_strict,
|
||||
name: Some(name),
|
||||
is_block_function,
|
||||
};
|
||||
let mut sub_module =
|
||||
self.compile_simple_function_body(¶m_names, body_stmts, ctx, FunctionBodyContext::Ordinary, flags)?;
|
||||
|
||||
@@ -132,13 +132,13 @@ fn switch_case_function_captured_by_outer() {
|
||||
|
||||
#[test]
|
||||
fn switch_case_function_binding_independent_of_outer_var() {
|
||||
// 函数名不可写绑定(15.2.10.1 步 m):体内容器对 f 重新赋值静默失败(sloppy),
|
||||
// 块内 f 仍为函数对象;外层 var 绑定独立,不被改写。
|
||||
// 块级函数(Annex B.3.3)块绑定为可变 var 绑定:体内容器 `f = 123` 覆写块绑定,
|
||||
// currentBV 取 123;外层 var 绑定(globalThis.f)独立,仍为函数对象。
|
||||
let src = "var r1, r2; (function(){ var initialBV, currentBV; \
|
||||
switch(1){case 1: function f(){ initialBV=f; f=123; currentBV=f; return 'decl'; }} \
|
||||
var varBinding=f; f(); r1 = initialBV() === 'decl'; \
|
||||
r2 = currentBV === f && varBinding() === 'decl'; }()); r1 && r2";
|
||||
assert!(eval(src).unwrap().as_bool(), "函数名不可写绑定自引用重赋静默失败,外层 var 绑定独立");
|
||||
r2 = currentBV === 123 && varBinding() === 'decl'; }()); r1 && r2";
|
||||
assert!(eval(src).unwrap().as_bool(), "块函数块绑定可变覆写,外层 var 绑定独立");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user