mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
fix: 函数体内标签包裹的函数声明参与入口提升
This commit is contained in:
@@ -402,6 +402,7 @@ impl Emitter {
|
||||
.map(|i| i as u8);
|
||||
|
||||
self.predeclare_function_declarations(body_stmts, &mut ctx);
|
||||
self.predeclare_labeled_function_declarations(body_stmts, &mut ctx);
|
||||
|
||||
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。
|
||||
self.pre_register_builtin_references(body_stmts, &mut ctx);
|
||||
@@ -720,18 +721,48 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 标签链直接包裹的函数声明(Annex B.3.2 Labelled Function Declarations):
|
||||
/// 展开任意层 `LabeledStatement` 后取内层函数声明。至少经过一层标签才返回
|
||||
/// `Some`;直接子函数声明由调用方单独匹配。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 标签体为块/分支等其它语句时返回 `None`(归块面或普通标签发射处理)。
|
||||
/// - 不递归进函数体:嵌套函数是独立编译单元。
|
||||
pub(crate) fn labeled_function_decl<'a, 'b>(stmt: &'b Statement<'a>) -> Option<&'b oxide_parser::Function<'a>> {
|
||||
let mut cur: &'b Statement<'a> = match stmt {
|
||||
Statement::LabeledStatement(labeled) => &labeled.body,
|
||||
_ => return None,
|
||||
};
|
||||
loop {
|
||||
match cur {
|
||||
Statement::LabeledStatement(labeled) => cur = &labeled.body,
|
||||
Statement::FunctionDeclaration(fd) => return Some(fd),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 函数体内参与入口提升的函数声明语句:直接子函数声明,或标签链直接包裹的
|
||||
/// 函数声明(sloppy 下标签不改变执行流,二者同等在函数入口物化闭包)。
|
||||
fn is_body_hoisted_function_decl(stmt: &Statement) -> bool {
|
||||
matches!(stmt, Statement::FunctionDeclaration(_)) || Self::labeled_function_decl(stmt).is_some()
|
||||
}
|
||||
|
||||
/// 双 sub-pass emit body:先函数声明(hoisting),再其余语句。返回最后结果寄存器。
|
||||
///
|
||||
/// 首 sub-pass 覆盖直接子函数声明与标签链直接包裹的函数声明:二者均在函数
|
||||
/// 入口物化闭包,次 sub-pass 跳过声明语句本身,声明点不重编以保函数对象同一性。
|
||||
fn emit_body_stmts(&self, body_stmts: &[Statement], ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
|
||||
let mut last_result_reg = None;
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
if Self::is_body_hoisted_function_decl(stmt) {
|
||||
if let Some(reg) = self.emit_statement(stmt, ctx)? {
|
||||
last_result_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
if Self::is_body_hoisted_function_decl(stmt) {
|
||||
continue;
|
||||
}
|
||||
if let Some(reg) = self.emit_statement(stmt, ctx)? {
|
||||
|
||||
@@ -27,6 +27,28 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 预声明函数体直接子级中标签链直接包裹的函数声明名(Annex B.3.2 Labelled
|
||||
/// Function Declarations):sloppy 下标签不改变执行流,该声明的名与直接子
|
||||
/// 函数声明一样是函数作用域 `var` 绑定,须在入口物化闭包前完成预登记。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 仅扫描直接子语句(标签链展开后须是函数声明);标签包块等其它形归块面
|
||||
/// 块级函数预声明路径。
|
||||
/// - 与块级函数名收集路径可能对同名重复建绑定:`declare_initialized` 命中
|
||||
/// 已存在绑定时只补初始化标志,不改变既有寄存器分配,语义幂等。
|
||||
pub(crate) fn predeclare_labeled_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
let Some(function) = Self::labeled_function_decl(statement) else {
|
||||
continue;
|
||||
};
|
||||
let Some(identifier) = &function.id else {
|
||||
continue;
|
||||
};
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// 预声明单个 `var` 名:仅顶层(全局作用域)的内置名落内置镜像槽(预载全局
|
||||
/// 属性值的固定寄存器槽,本轮求值开始时预载),使 GlobalDeclarationInstantiation
|
||||
/// (脚本顶层声明实例化)序言与声明点同步都用入口原值,而非程序求值前
|
||||
|
||||
Reference in New Issue
Block a user