Files
OxideJS-New/crates/oxide_emit/src/function_body.rs
T

1197 lines
58 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.
//! 函数体编译域:`FunctionBodyContext` / `ParamSpec` 类型与函数体编译链
//! (参数 prologue、参数默认值与闭包捕获分析、双 sub-pass 语句发射)。
//!
//! 两类型经 lib.rs 重导出供各语法域构造实参;编译链为 `Emitter` 方法,
//! 捕获分析经自由函数调用 capture 族,与所在文件无关。
use std::collections::{BTreeMap, HashSet};
use oxide_bytecode::module::{Constant, UpvalueCapture};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::{LabelId, Operand};
use oxide_ir::IRFunction;
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
use crate::capture::{
collect_binding_pattern_names, collect_captured_bindings, collect_fn_scope_names, collect_upvalue_names,
has_nested_function, FnScopeNames,
};
use crate::compile_ctx::{CompileCtx, FieldBuffer};
use crate::symbol_table::{Binding, ScopeKind};
use crate::Emitter;
/// 函数体编译上下文:决定 `this`/`super` 绑定与参数前导(prologue)形态。
#[derive(Clone, Copy)]
pub enum FunctionBodyContext {
/// 普通函数:自身 `this`、独立作用域。
Ordinary,
/// 箭头函数:词法捕获外层 `this`,不生成参数前导。
Arrow,
/// 类元素方法:按类语义处理 `super` 与 home object。
ClassElement,
}
/// 参数规格:普通形参为标识符(可带默认值 initializer),解构形参用合成名 + 原始 pattern,
/// rest 形参为数组(无默认值,只能是最末形参)。
pub enum ParamSpec<'a> {
Identifier {
name: String,
initializer: Option<&'a Expression<'a>>,
},
Pattern {
synthetic_name: String,
pattern: &'a oxide_parser::BindingPattern<'a>,
initializer: Option<&'a Expression<'a>>,
},
Rest {
name: String,
},
}
impl ParamSpec<'_> {
pub(crate) fn register_name(&self) -> &str {
match self {
Self::Identifier { name, .. } => name,
Self::Pattern { synthetic_name, .. } => synthetic_name,
Self::Rest { name } => name,
}
}
}
impl Emitter {
/// 遍历解构 pattern 收集内嵌默认值表达式(AssignmentPattern.right)与
/// 计算键表达式(`{[k]: a}` 的键,运行时求值)——二者都会在参数绑定期被
/// 内部闭包引用,须一并纳入捕获分析。
fn collect_pattern_default_exprs<'a>(
&self, pattern: &'a oxide_parser::BindingPattern<'a>, out: &mut Vec<&'a oxide_parser::Expression<'a>>,
) {
use oxide_parser::BindingPattern;
match pattern {
BindingPattern::AssignmentPattern(ap) => {
out.push(&ap.right);
self.collect_pattern_default_exprs(&ap.left, out);
}
BindingPattern::ArrayPattern(ap) => {
for p in ap.elements.iter().flatten() {
self.collect_pattern_default_exprs(p, out);
}
if let Some(rest) = &ap.rest {
self.collect_pattern_default_exprs(&rest.argument, out);
}
}
BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
if prop.computed {
out.push(prop.key.to_expression());
}
self.collect_pattern_default_exprs(&prop.value, out);
}
if let Some(rest) = &op.rest {
self.collect_pattern_default_exprs(&rest.argument, out);
}
}
_ => {}
}
}
/// 把 rest 形参的绑定模式追加为 `ParamSpec::Rest`:仅支持标识符形态(解构 rest 未支持)。
pub(crate) fn push_rest_param<'a>(
&self, argument: &'a oxide_parser::BindingPattern<'a>, out: &mut Vec<ParamSpec<'a>>,
) -> Result<(), String> {
match argument {
oxide_parser::BindingPattern::BindingIdentifier(bi) => {
out.push(ParamSpec::Rest { name: bi.name.to_string() });
}
_ => return Err("rest parameters with destructuring patterns not yet supported".into()),
}
Ok(())
}
/// 收集函数参数的绑定名(BindingIdentifier 形态)。
pub(crate) fn extract_function_parts<'a>(
&self, function: &'a oxide_parser::Function<'a>,
) -> Result<(Vec<ParamSpec<'a>>, &'a [Statement<'a>]), String> {
let mut param_specs = Vec::new();
for (idx, param) in function.params.items.iter().enumerate() {
match &param.pattern {
oxide_parser::BindingPattern::BindingIdentifier(bi) => {
param_specs.push(ParamSpec::Identifier {
name: bi.name.to_string(),
initializer: param.initializer.as_deref(),
});
}
pattern => {
param_specs.push(ParamSpec::Pattern {
synthetic_name: format!("@@param_{idx}"),
pattern,
initializer: param.initializer.as_deref(),
});
}
}
}
if let Some(rest) = &function.params.rest {
self.push_rest_param(&rest.rest.argument, &mut param_specs)?;
}
let body_stmts: &[Statement] = if let Some(body) = &function.body { &body.statements } else { &[] };
Ok((param_specs, body_stmts))
}
/// 编译函数体(函数声明/函数表达式/箭头函数共用),单 pass 完成发码。
///
/// `is_expression_body` 为 true(箭头表达式体)时返回最后一个表达式的值,
/// 否则返回 undefined。`is_arrow` 控制 super 相关标志的继承:箭头函数词法
/// 继承外层 super,普通函数重置 super 作用域。`name` 为函数名(具名函数
/// 声明/表达式传名,箭头与匿名传 `None`),用于函数名不可写绑定登记。
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, is_arrow: bool, own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
is_arrow,
false,
false,
own_strict,
name,
)
}
/// 编译函数体并显式指定生成器标志(`function*` 走此入口)。
pub(crate) fn compile_generator_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs,
body_stmts,
parent_ctx,
false,
false,
true,
false,
own_strict,
name,
)
}
/// 编译异步生成器函数体(`async function*` / async 生成器表达式走此入口):
/// 同时标记 `is_generator` 与 `is_async`,VM 调用时按异步生成器协议执行
/// (next 返回 Promise,yield 挂起与 await 挂起共存)。
pub(crate) fn compile_async_generator_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx, own_strict: bool,
name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs,
body_stmts,
parent_ctx,
false,
false,
true,
true,
own_strict,
name,
)
}
/// 编译异步函数体(`async function` / async 箭头走此入口):`is_async` 使
/// `assemble_ir` 标记模块,VM 调用时按异步函数协议执行。
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_async_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, is_arrow: bool, own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_flags(
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
is_arrow,
false,
true,
own_strict,
name,
)
}
#[allow(clippy::too_many_arguments)]
fn compile_function_body_with_flags<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, is_arrow: bool, is_generator: bool, is_async: bool, own_strict: bool,
name: Option<&str>,
) -> Result<IRFunction, String> {
let body_context = if is_arrow {
FunctionBodyContext::Arrow
} else {
FunctionBodyContext::Ordinary
};
self.compile_function_body_with_bindings_gen(
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
&[],
body_context,
is_generator,
is_async,
own_strict,
name,
)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body_with_bindings_gen<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
is_generator: bool, is_async: bool, own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String> {
self.compile_function_body_with_field_hooks_gen(
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
extra_bindings,
body_context,
None::<fn(&Emitter, &mut CompileCtx) -> Result<(), String>>,
false,
&[],
&[],
is_generator,
is_async,
own_strict,
name,
)
}
/// 预注册 builtin 引用并编译函数体(普通/箭头/类元素方法共用入口)。
///
/// 本函数体内任意位置(表达式、成员对象、调用实参、类字段等)引用的内置全局
/// 标识符,其寄存器槽都先于任何临时寄存器登记。
///
/// vreg 化后临时值不复用(独立 vreg),但 builtin 槽预注册仍保证分配序稳定:
/// builtin 槽先于临时值池,嵌套函数继承边界不受扰。
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body_with_field_hooks<'a, E>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
extra_upvalue_names: &[(String, u8)], own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String>
where
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
{
self.compile_function_body_with_field_hooks_gen(
param_specs,
body_stmts,
parent_ctx,
is_expression_body,
extra_bindings,
body_context,
emit_fields,
fields_after_super,
extra_capture_exprs,
extra_upvalue_names,
false,
false,
own_strict,
name,
)
}
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body_with_field_hooks_gen<'a, E>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
mut emit_fields: Option<E>, fields_after_super: bool, extra_capture_exprs: &[&'a Expression<'a>],
extra_upvalue_names: &[(String, u8)], is_generator: bool, is_async: bool, own_strict: bool, name: Option<&str>,
) -> Result<IRFunction, String>
where
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
{
let mut ctx = CompileCtx::new();
ctx.is_generator = is_generator;
ctx.is_async = is_async;
// 函数 strict = 自身 directive ‖ 外层严格(规范不可解除);
// 类元素方法/构造器恒 strict(ClassBody 是严格模式代码)。
ctx.is_strict = own_strict || matches!(body_context, FunctionBodyContext::ClassElement) || parent_ctx.is_strict;
// 形参名集(含解构叶子与 rest):块级函数名同名的 web-compat 守卫查此集。
let mut param_names = HashSet::new();
for spec in param_specs {
param_names.insert(spec.register_name().to_string());
if let ParamSpec::Pattern { pattern, .. } = spec {
collect_binding_pattern_names(pattern, &mut param_names);
}
}
ctx.param_names = param_names;
// length = 第一个带默认值形参之前的形参数(解构默认与标识符默认同规则);
// rest 参数不计入 length(以 0 结尾即止)。
ctx.function_length = param_specs
.iter()
.take_while(|spec| match spec {
ParamSpec::Identifier { initializer, .. } => initializer.is_none(),
ParamSpec::Pattern { initializer, .. } => initializer.is_none(),
ParamSpec::Rest { .. } => false,
})
.count() as u32;
// simple 参数列表:全部形参为无初始值标识符且无 rest(规范
// simpleParameterList)。arguments 对象 callee 形态(数据属性 vs
// 受限访问器)按 strict ‖ !simple 分流,length 口径不可代用
// (f({x}) 的 length 与 n_args 相等但非 simple)。
ctx.has_simple_params = param_specs
.iter()
.all(|spec| matches!(spec, ParamSpec::Identifier { initializer: None, .. }));
// 继承父内置寄存器映射:子模块寄存器文件中,内置标识符(Math、Object 等)
// 解析到父预先分配的槽位。
ctx.scopes.builtin_reg_map = parent_ctx.scopes.builtin_reg_map.clone();
ctx.scopes.private_name_map = parent_ctx.scopes.private_name_map.clone();
ctx.scopes.private_element_kinds = parent_ctx.scopes.private_element_kinds.clone();
ctx.scopes.private_brand_id = parent_ctx.scopes.private_brand_id;
ctx.scopes.next_private_name_id = parent_ctx.scopes.next_private_name_id;
// 标签模板 site 序号继承:整棵编译树全局唯一(跨嵌套函数递增),
// 运行时以 (flat_id, site_no) 缓存模板对象,跨函数不冲突。
ctx.next_template_site = parent_ctx.next_template_site;
// 传递 enclosing_this_reg:嵌套箭头函数捕获正确的 `this`。
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
// 编码源口径是整棵编译树属性(嵌套函数仍在同一编码源内)。
ctx.source_encoded = parent_ctx.source_encoded;
// 箭头函数词法继承 super;类方法体顶层编译也需要类提供的 super 上下文。
// 对象方法体(Ordinary 上下文)在父带任一 super 上下文时同样继承:对象方法
// 发射期已置父 ctx 的 in_instance_method,其内嵌套箭头/普通函数经此继承。
// 非法 super 位置(嵌套普通函数内等)由解析器前置拒绝,emit 侧只收到合法程序。
if matches!(body_context, FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement)
|| parent_ctx.in_derived_constructor
|| parent_ctx.in_instance_method
|| parent_ctx.in_static_method
{
ctx.in_derived_constructor = parent_ctx.in_derived_constructor;
ctx.in_instance_method = parent_ctx.in_instance_method;
ctx.in_static_method = parent_ctx.in_static_method;
} else {
ctx.in_derived_constructor = false;
ctx.in_instance_method = false;
ctx.in_static_method = false;
}
// 继承父全局作用域条目:先前声明的函数名在函数体内可见。
let mut inherited_reg_start = 1u32.max(ctx.builtin_reg_floor());
for (name, binding) in &parent_ctx.scopes.symbols.scopes[0].bindings {
ctx.scopes.symbols.scopes[0].bindings.insert(
name.clone(),
Binding {
reg: binding.reg,
initialized: binding.initialized,
is_const: binding.is_const,
lexical: binding.lexical,
predeclared: false,
// 父层 cell 索引在子帧无效:子帧经 upvalue 路径访问父捕获
// 绑定,不复制索引(复制会让解析点误发子帧 cell 表读)。
cell_idx: None,
non_writable: binding.non_writable,
},
);
inherited_reg_start = inherited_reg_start.max(binding.reg.saturating_add(1));
}
// 隐式全局登记集合随继承绑定传入:父层未声明名已登记全局作用域,子层解析
// 命中继承绑定时须同样补全局对象属性写(或严格模式抛错)。读写两侧登记
// 一并继承——读侧登记的全局槽与写侧同属一个槽,写判定跨嵌套函数一致。
ctx.implicit_global_writes = parent_ctx.implicit_global_writes.clone();
ctx.implicit_global_reads = parent_ctx.implicit_global_reads.clone();
// 顶层已声明 var 名集随作用域继承:嵌套函数裸读/写顶层 var 直连全局对象
// (经继承的 scope-0 绑定 + 作用域索引判定,不被局部同名遮蔽误判)。
ctx.global_tier_names = parent_ctx.global_tier_names.clone();
// eval 起源随作用域继承:eval 顶层 var/函数名在嵌套函数内同样可删(物化
// c:true 全局属性),delete 分类判定读此标志。
ctx.is_eval_origin = parent_ctx.is_eval_origin;
for (name, reg) in extra_bindings {
ctx.scopes.symbols.scopes[0].bindings.insert(
(*name).to_string(),
Binding {
reg: *reg,
initialized: true,
is_const: true,
// 类 this 自绑定非用户词法声明,不置位。
lexical: false,
predeclared: false,
cell_idx: None,
non_writable: false,
},
);
inherited_reg_start = inherited_reg_start.max(reg.saturating_add(1));
}
ctx.reserved_reg_start = inherited_reg_start.max(1);
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
ctx.reset_regs();
// 函数作用域六个名字面单趟收集(形参名先注入 own 面):本函数体编译链
// 各调用点(参数 prologue / builtin 排除 / 入口实例化)共用此结果。
let param_name_refs: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
let scope_names = collect_fn_scope_names(&param_name_refs, body_stmts);
let param_base = self.emit_params_prologue(
param_specs,
body_stmts,
parent_ctx,
&mut ctx,
body_context,
extra_capture_exprs,
extra_upvalue_names,
name,
&scope_names,
)?;
// 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。
ctx.field_keys_uv = ctx
.current_upvalue_captures
.iter()
.position(|u| u.name == "@@field_keys")
.map(|i| i as u8);
self.predeclare_function_declarations(body_stmts, &mut ctx);
self.predeclare_labeled_function_declarations(body_stmts, &mut ctx);
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。
// 函数体直接子级词法声明名排除登记(顶层词法遮蔽同口径,见 program.rs)。
let lexical_excluded = scope_names.direct_lexical_names.clone();
self.pre_register_builtin_references(body_stmts, &lexical_excluded, &mut ctx);
// 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。
self.predeclare_var_declarations(body_stmts, &mut ctx);
// 预声明 body 级 `let`/`const`/`class`(未初始化 TDZ 占位),
// 使声明点前读取可编译为运行时 ReferenceError。函数体 lexical 声明是
// 局部绑定,不做受限全局名检查;重复声明错在 emit 期报。
let _ = self.predeclare_lexical_declarations(body_stmts, &mut ctx);
// 块级函数名 web-compat 外层 var 绑定(sloppy):块内函数声明名在实例化
// 期于函数作用域建外层 var 绑定——无同名绑定则新建 var 槽;名在抑制集
// (形参/词法声明同名,该形退化为纯块作用域)则不建。求值期声明点把
// 函数对象写回此绑定(见函数声明 emit)。
if !ctx.is_strict {
ctx.block_fn_suppressed = self.collect_block_fn_suppressed_names(body_stmts, &ctx.param_names);
for name in self.collect_block_function_names(body_stmts) {
if !ctx.block_fn_suppressed.contains(&name) {
self.predeclare_var_name(&name, &mut ctx);
}
}
}
// 函数级绑定 cell 索引回填:预声明完成后函数级绑定已齐,捕获集的名字
// 排序索引写入各绑定实例,解析点据此按绑定身份取索引。
ctx.backfill_captured_cell_idxs();
// `var` 与块级函数外层 var 绑定入口实例化(非捕获名):预声明只登记槽位、
// 不发射定义指令,声明点对已绑定名又跳过 undefined 写,缺失入口写会让首次
// 写入前的读取取到调用方遗留的寄存器值。捕获名已由参数 prologue 的
// MAKE_CELL(undefined) 实例化,此处只补未捕获名。
self.instantiate_var_bindings(body_stmts, &mut ctx, &scope_names);
// 被捕获的函数名绑定同样建 cell(MAKE_CELL):值源是帧槽写入已置位的
// 名槽寄存器(函数对象),非 undefined。名槽寄存器此时已知(非抑制面
// 在名登记时分配、抑制面在 instantiate_var_bindings 回填)。
if let Some(fn_name) = ctx.function_name.as_deref() {
if let Some(&cell_idx) = ctx.captured_bindings.get(fn_name) {
if let Some(name_reg) = ctx.function_name_reg {
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(name_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
}
}
// 函数体是释放作用域:仅当体含 using 声明时发 mark/pop(无 using 的体
// 不发,防早退 return 跳过 POP 留未配对水位错乱外层对齐)。
let has_using = Self::scope_contains_using(body_stmts);
// 生成器:body 起点标记——调用时参数初始化(emit_params_prologue)结束后挂起于此,
// 参数副作用/异常在 `g()` 调用时刻生效,首次 next() 从这继续执行 body。
if is_generator {
ctx.inst(Inst::suspend_body());
// 生成器体环境在 `g()` 调用时建立、首次 next() 从挂起点后继续:水位登记
// 在挂起点之后,体声明的资源只在体尾(生成器完成)释放。
if has_using {
ctx.emit_dispose_mark();
}
} else if has_using {
// 普通函数体环境在参数 prologue 后建立:body 语句发射前登记水位。
ctx.emit_dispose_mark();
}
if let Some(emit) = emit_fields.as_mut() {
if fields_after_super {
let mut parent_insts = Vec::new();
let mut parent_label_pos = Vec::new();
std::mem::swap(&mut ctx.insts, &mut parent_insts);
std::mem::swap(&mut ctx.labels.label_pos, &mut parent_label_pos);
emit(self, &mut ctx)?;
let field_buffer = FieldBuffer {
insts: std::mem::take(&mut ctx.insts),
labels: std::mem::take(&mut ctx.labels.label_pos)
.into_iter()
.enumerate()
.filter_map(|(id, pos)| pos.map(|p| (id as LabelId, p)))
.collect(),
};
ctx.insts = parent_insts;
ctx.labels.label_pos = parent_label_pos;
ctx.field_buffer = Some(field_buffer);
} else {
emit(self, &mut ctx)?;
}
}
// 发 body 语句(先函数声明 hoisting,再其余)。
let last_result_reg = self.emit_body_stmts(body_stmts, &mut ctx)?;
// 隐式 RETURN:表达式体返回最后表达式,语句体返回 undefined。
// 函数尾词法上不在任何循环内,迭代器逃出计数恒 0。
// 函数尾正常完成:逆序释放体声明的资源(早 return 跳过本点,归穿越面)。
if has_using {
ctx.emit_dispose_pop();
}
if is_expression_body {
if let Some(reg) = last_result_reg {
ctx.inst(Inst::ret(Operand::Reg(reg), 0, 0, 0));
} else {
let undef_idx = ctx.add_constant(Constant::Undefined);
let undef_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0, 0));
}
} else {
let undef_idx = ctx.add_constant(Constant::Undefined);
let undef_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(undef_reg), undef_idx));
ctx.inst(Inst::ret(Operand::Reg(undef_reg), 0, 0, 0));
}
// 调用契约参数段只含固定形参:rest 是函数体内普通变量,不在 VM 实参传递区。
let fixed_count = param_specs
.iter()
.filter(|spec| !matches!(spec, ParamSpec::Rest { .. }))
.count() as u32;
let ir = ctx.assemble_ir(
oxide_ir::ParamLayout {
base: param_base,
count: fixed_count,
},
Some(parent_ctx),
);
Ok(ir)
}
/// 规范 `argumentsObjNeeded` 的引擎判据:函数作用域是否声明 `arguments`
/// 从而抑制自动 arguments 对象。
///
/// 规范 FunctionDeclarationInstantiation 仅在箭头函数、形参名含
/// `arguments`、或(无参数表达式时)函数体**顶层**函数/词法声明含
/// `arguments` 时不建对象;嵌套块、循环、`switch`/`try` 内的同名声明属块
/// 作用域,不构成抑制。
///
/// # 边界与前提
/// - `param_names` 须含解构形参叶名(规范 `paramNames`)。
/// - `has_param_exprs` 为形参默认值存在性(规范 `ContainsExpression`):
/// 为 true 时顶层函数声明不抑制,对象须在参数求值期已可读。
/// - 函数体顶层词法声明同名无条件抑制:引擎同一作用域无法同时承载自动
/// 绑定与顶层词法绑定。
/// - `var arguments` 不在规范 `funcNames` 内,不抑制。
fn arguments_obj_needed(
&self, body_stmts: &[Statement], param_names: &HashSet<String>, has_param_exprs: bool,
) -> bool {
if param_names.contains("arguments") {
return false;
}
for stmt in body_stmts {
match stmt {
// 顶层 let/const/class 与自动绑定同作用域冲突,无条件抑制。
Statement::VariableDeclaration(vd) if !matches!(vd.kind, VariableDeclarationKind::Var) => {
let mut names = HashSet::new();
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, &mut names);
}
if names.contains("arguments") {
return false;
}
}
Statement::ClassDeclaration(cd) => {
if cd.id.as_ref().is_some_and(|id| id.name == "arguments") {
return false;
}
}
// 顶层函数声明仅无参数默认值时抑制。
Statement::FunctionDeclaration(fd) => {
if !has_param_exprs && fd.id.as_ref().is_some_and(|id| id.name == "arguments") {
return false;
}
}
// Annex B.3.2 标签链直接包裹的函数声明与直接子函数声明同面。
_ => {
if !has_param_exprs
&& Self::labeled_function_decl(stmt)
.is_some_and(|fd| fd.id.as_ref().is_some_and(|id| id.name == "arguments"))
{
return false;
}
}
}
}
true
}
/// 参数 prologue:函数作用域 + 参数声明/解构 + 函数名不可写绑定登记 +
/// 闭包捕获与 upvalue 分析。返回 param_base。
///
/// `name` 为函数名(具名函数声明/表达式传名,箭头与匿名传 `None`):
/// 非抑制面在函数作用域登记不可写绑定并分配名槽寄存器(帧槽写入目标);
/// 抑制面(形参/var 同名、arguments 特例)不建名绑定,var 同名时名槽
/// 回填到 var 槽寄存器(`instantiate_var_bindings` 处)。
#[allow(clippy::too_many_arguments)]
fn emit_params_prologue<'a>(
&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,
) -> Result<u32, String> {
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
let param_base = ctx.next_reg;
// 发参数声明(分配寄存器;分析用 register_name 引用)。
for spec in param_specs {
let name = spec.register_name();
let reg = ctx.alloc_reg();
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
}
// 闭包捕获分析(AST 级,emit 前确定):须在参数默认值 emit 之前,
// 否则默认值内嵌套函数(IIFE)编译时父分析为空 → upvalue 捕获丢失。
let param_names: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
let mut param_defaults: Vec<&oxide_parser::Expression> = Vec::new();
for spec in param_specs {
match spec {
ParamSpec::Identifier { initializer, .. } => {
if let Some(init) = initializer {
param_defaults.push(init);
}
}
ParamSpec::Pattern { pattern, initializer, .. } => {
if let Some(init) = initializer {
param_defaults.push(init);
}
// 模式内嵌默认值(`[x = expr]` 的 AssignmentPattern.right)也会被
// 内部闭包引用,需纳入捕获分析。
self.collect_pattern_default_exprs(pattern, &mut param_defaults);
}
ParamSpec::Rest { .. } => {}
}
}
// 早退守卫:体与附加表达式无嵌套函数/类节点时,捕获集
// (collect_captured_bindings,仅从嵌套函数/类节点产出名字)必为空,跳过该
// 趟;own_bindings 是 upvalue 分析的遮蔽集、upvalue 捕获是本体对父的捕获,
// 二者独立于嵌套函数,不得跳过。
let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone();
capture_exprs.extend_from_slice(extra_capture_exprs);
let has_nested = has_nested_function(body_stmts, &capture_exprs);
ctx.own_bindings = scope_names.own_binding_names.clone();
for spec in param_specs {
if let ParamSpec::Pattern { pattern, .. } = spec {
collect_binding_pattern_names(pattern, &mut ctx.own_bindings);
}
}
// 自动声明 arguments 绑定(非箭头函数,且函数作用域未声明同名标识符)。
// 先登记符号并纳入 own_bindings,使嵌套箭头引用 arguments 被识别为本函数
// 绑定(否则被当自由变量 → 子模块 upvalue 解析错位)。
let mut arguments_reg = None;
if !matches!(body_context, FunctionBodyContext::Arrow)
&& self.arguments_obj_needed(body_stmts, &ctx.param_names, !param_defaults.is_empty())
{
let reg = ctx.alloc_reg();
ctx.declare_initialized("arguments", reg, VariableDeclarationKind::Var, false)?;
ctx.own_bindings.insert("arguments".to_string());
arguments_reg = Some(reg);
}
// 函数名不可写绑定(15.2.10.1 步 m):函数名在函数作用域登记为不可写
// 绑定,帧槽写入把它初始化为函数对象。抑制面(形参同名 / 体内容器 var
// 同名 / arguments 对象占位)不建名绑定:前两者名解析到参数/var 绑定,
// 后者 arguments 绑定占位(var 同名时由帧槽写入初始化为函数对象)。
// 名登记须先于 set_captured_bindings:嵌套函数捕获名分析依赖 own_bindings
// 完整(名被捕获时须识别为本函数绑定并建 cell)。
if let Some(fn_name) = name {
let var_names = &scope_names.var_binding_names;
let suppressed = ctx.param_names.contains(fn_name)
|| var_names.contains(fn_name)
|| (fn_name == "arguments" && arguments_reg.is_some());
if !suppressed {
let reg = ctx.alloc_reg();
ctx.scopes.symbols.scopes.last_mut().expect("函数作用域已压入").bindings.insert(
fn_name.to_string(),
Binding {
reg,
initialized: true,
is_const: false,
lexical: false,
predeclared: false,
cell_idx: None,
non_writable: true,
},
);
ctx.own_bindings.insert(fn_name.to_string());
ctx.function_name = Some(fn_name.to_string());
ctx.function_name_reg = Some(reg);
} else if var_names.contains(fn_name) {
// 抑制面:var 绑定持名槽,帧槽写入把函数对象写入该 var 槽。
// var 绑定此时未声明(predeclare_var_declarations 在后),名槽
// 寄存器在 instantiate_var_bindings 回填。
ctx.function_name = Some(fn_name.to_string());
}
}
if has_nested {
ctx.set_captured_bindings(collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings));
}
// 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。
if matches!(
body_context,
FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement
) {
// 只有创建点父作用域链内可解析的父捕获名才可能成为子函数 upvalue:
// 捕获集是函数级名字并集,块级 let/const 在块退出后 cell 仍存留但名字
// 已不可解析,块外嵌套函数按名命中会错误读取已失效的 cell。父自身
// upvalue 代表的祖父绑定在父函数体内恒可见,不参与过滤。
// C 风格 for 头 let/const 名在 init 内尚未 declare,但同头声明会为其
// 建 cell,前向捕获须按父捕获集保留(见 `pending_for_head_names`)。
// 索引按父可见绑定实例取(块级遮蔽绑定持追加索引);词法循环头名
// (for-in/for-of 头绑定在右值区编译时未进符号表,按名回查会误命中
// 外层同名绑定)与 for 头前向名无条件取捕获映射值(ForHeadEnv 覆盖
// 索引或名字排序索引);绑定未分配索引的其余名(命名空间导入等)
// 回退映射值。顶层 tier 名(顶层 var/函数)已在捕获集剔除阶段出集,
// 不在此列。
let visible_parent_captured: BTreeMap<String, u8> = parent_ctx
.captured_bindings
.iter()
.filter(|(n, _)| {
// for 头前向名(C 风格 for 头 pending / for-in/for-of env):
// 头绑定未 declare,按名回查命中外层同名 tier 绑定,映射值是
// ForHeadEnv 的 TDZ 索引,须保留为 upvalue。
let for_head = parent_ctx.pending_for_head_names.contains(n.as_str())
|| parent_ctx.for_head_env_names.contains(n.as_str());
// tier 绑定(scope 0 顶层 var/函数):全局对象属性是唯一存储,
// 不建 cell;嵌套函数直读全局,不入 upvalue。映射中为同名块级
// 绑定保留的 entry 不属该 tier 绑定,不得按名捕获。
let tier =
!for_head
&& parent_ctx.scopes.symbols.lookup_any_binding(n.as_str()).is_some_and(
|(_, scope_idx)| scope_idx == 0 && parent_ctx.global_tier_names.contains(n.as_str()),
);
if tier {
return false;
}
parent_ctx.visible_binding_reg(n.as_str()).is_some()
|| parent_ctx.pending_for_head_names.contains(n.as_str())
})
.map(|(n, &i)| {
let idx = if parent_ctx.for_head_env_names.contains(n.as_str())
|| parent_ctx.pending_for_head_names.contains(n.as_str())
{
// 词法循环头名:头绑定在右值区编译时未进符号表(按名回查
// 会误命中外层同名绑定),索引由 ForHeadEnv 覆盖映射分配,
// 无条件取映射值。
i
} else {
// 其余名按绑定实例取索引(块级遮蔽绑定持追加索引);
// 绑定未分配索引(命名空间导入等绑定点走映射值不写绑定
// 字段)回退映射值,与基线按名取索引同口径。
parent_ctx
.scopes
.symbols
.lookup_any_binding(n.as_str())
.and_then(|(b, _)| b.cell_idx)
.unwrap_or(i)
};
(n.clone(), idx)
})
.collect();
ctx.current_upvalue_captures = collect_upvalue_names(
body_stmts,
&capture_exprs,
&visible_parent_captured,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
);
// 捕获 const 信息快照:父作用域符号表此时完整(预声明已完成),
// 直接查绑定 is_const(不依赖初始化状态,TDZ 中 const 也须拦截)。
ctx.upvalue_const_flags = ctx
.current_upvalue_captures
.iter()
.filter(|u| u.parent_uv_idx.is_none())
.filter(|u| {
parent_ctx
.scopes
.symbols
.lookup_any_binding(u.name.as_str())
.map(|(b, _)| b.is_const)
.unwrap_or(false)
})
.map(|u| u.name.clone())
.collect();
// 捕获函数名不可写信息快照:与 const 快照同口径,供子函数写路径
// non_writable 守卫(sloppy 静默 no-op / strict 抛 TypeError)使用。
ctx.upvalue_non_writable_flags = ctx
.current_upvalue_captures
.iter()
.filter(|u| u.parent_uv_idx.is_none())
.filter(|u| {
parent_ctx
.scopes
.symbols
.lookup_any_binding(u.name.as_str())
.map(|(b, _)| b.non_writable)
.unwrap_or(false)
})
.map(|u| u.name.clone())
.collect();
// 类字段 computed key 数组等合成捕获:直接追加 upvalue(cell_idx 由父分配)。
for (name, cell_idx) in extra_upvalue_names {
if !ctx.own_bindings.contains(name) && !ctx.current_upvalue_captures.iter().any(|u| u.name == *name) {
ctx.current_upvalue_captures.push(UpvalueCapture {
name: name.clone(),
enclosing_reg: 0,
cell_idx: *cell_idx,
parent_uv_idx: None,
});
}
}
// 私有 brand 链随函数体继承:父帧每条 brand 链条目按同形态追加为
// upvalue 捕获(父条目描述父帧如何到达 brand cell,子帧 upvalue 以
// 同一方式指向父帧)。子帧 brand 链记录各条目在子捕获列表中的位置,
// 嵌套类逐层继承,跨类 brand 检查据此定位声明类的 brand 对象。
for (brand_id, cell_idx, parent_uv_idx) in &parent_ctx.brand_chain {
let name = format!("@@class_brand_{brand_id}");
if !ctx.own_bindings.contains(&name) && !ctx.current_upvalue_captures.iter().any(|u| u.name == name) {
ctx.current_upvalue_captures.push(UpvalueCapture {
name,
enclosing_reg: 0,
cell_idx: *cell_idx,
parent_uv_idx: *parent_uv_idx,
});
}
}
ctx.brand_chain = parent_ctx
.brand_chain
.iter()
.map(|(brand_id, _, _)| {
let name = format!("@@class_brand_{brand_id}");
let pos = ctx
.current_upvalue_captures
.iter()
.position(|u| u.name == name)
.expect("brand 链条目已追加或已存在捕获列表");
(*brand_id, 0, Some(pos as u8))
})
.collect();
}
// 创建 arguments 对象:指令须在默认参数求值前发出(默认参数可引用 arguments)。
if let Some(reg) = arguments_reg {
ctx.inst(Inst::create_arguments(Operand::Reg(reg)));
}
// 形参名 TDZ 集:按形参序收集每形参绑定名(含解构叶),重名面不建集
// (规范变量环境面无 TDZ)。默认值发射期读路径命中此集抛 ReferenceError。
let param_bound_names: Vec<Vec<String>> = param_specs
.iter()
.map(|spec| match spec {
ParamSpec::Identifier { name, .. } | ParamSpec::Rest { name } => vec![name.clone()],
ParamSpec::Pattern { pattern, .. } => {
let mut names = HashSet::new();
collect_binding_pattern_names(pattern, &mut names);
names.into_iter().collect()
}
})
.collect();
let has_param_duplicates = {
let total: usize = param_bound_names.iter().map(|v| v.len()).sum();
let mut seen = HashSet::new();
for names in &param_bound_names {
for n in names {
seen.insert(n.clone());
}
}
seen.len() < total
};
for (idx, spec) in param_specs.iter().enumerate() {
// 循环首置 TDZ 集:当前形参自身名(含解构叶)加其后全部形参名;
// 重名面保持空集。
if !has_param_duplicates {
ctx.param_tdz_names.clear();
ctx.param_tdz_names.extend(param_bound_names[idx].iter().cloned());
for subsequent in &param_bound_names[idx + 1..] {
ctx.param_tdz_names.extend(subsequent.iter().cloned());
}
}
match spec {
ParamSpec::Pattern {
synthetic_name,
pattern,
initializer,
} => {
let src_reg = ctx.lookup(synthetic_name)?;
let src_reg = if let Some(init) = initializer {
self.emit_default_if_undefined(src_reg, init, Some(synthetic_name), ctx)?
} else {
src_reg
};
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, false, ctx)?;
}
ParamSpec::Identifier { name, initializer } => {
if let Some(init) = initializer {
// 默认参数:实参为 undefined 时用默认值。
let reg = ctx.lookup(name)?;
self.emit_default_if_undefined(reg, init, Some(name), ctx)?;
}
}
ParamSpec::Rest { name } => {
// rest 数组:从实参区收集固定形参之后的实参,绑定为普通变量。
let reg = ctx.lookup(name)?;
let fixed_count =
param_specs.iter().filter(|s| !matches!(s, ParamSpec::Rest { .. })).count() as u32;
ctx.inst(Inst::create_rest_array(Operand::Reg(reg), fixed_count));
}
}
// 每形参处理完即清空,防 TDZ 集泄漏到 body 读取。
ctx.param_tdz_names.clear();
}
// 被捕获的参数也必须建 cell(MAKE_CELL):否则子函数经 lazy upvalue 路径读
// 自身寄存器(依赖调用者寄存器残留),vreg 化/RegAlloc 移动寄存器后读到垃圾。
// 与 var/let/const 的 MAKE_CELL 语义一致(binding.rs:50)。须在默认值之后
// (默认值 emit 会读参数寄存器)。
for spec in param_specs {
let name = spec.register_name();
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
let reg = ctx.lookup(name)?;
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
}
// 被捕获的 arguments 绑定同样建 cell(与参数一致,须在默认值之后)。
if let (Some(reg), Some(&cell_idx)) = (arguments_reg, ctx.captured_bindings.get("arguments")) {
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
// var 与块级函数外层 var 绑定函数入口实例化:被捕获名统一
// MAKE_CELL(undefined)。规范上 var 在函数入口即初始化为 undefined
// (HoistDeclaration),sloppy 下块级函数名同建外层 var 绑定;声明语句只是
// 赋值。缺此实例化时,声明点前创建的闭包读取占位 cell → TDZ 误报,非捕获面
// 则取调用方寄存器残留。参数与 arguments 已在上方初始化(跳过以免覆盖参数
// 值);let/const/class 保持 TDZ 语义不动。声明语句的 MAKE_CELL 按占位更新
// 语义覆盖此初值。
let mut captured_entry_names = scope_names.var_binding_names.clone();
// 块级函数外层 var 名与 instantiate_var_bindings 同源并入;抑制名(形参/
// 词法声明同名)无外层绑定,不并入。抑制集在此独立计算:本循环早于函数体
// 的 block_fn_suppressed 构建。
if !ctx.is_strict {
let suppressed = self.collect_block_fn_suppressed_names(body_stmts, &ctx.param_names);
for name in self.collect_block_function_names(body_stmts) {
if !suppressed.contains(&name) {
captured_entry_names.insert(name);
}
}
}
let mut var_names: Vec<String> = captured_entry_names
.into_iter()
.filter(|n| !param_names.contains(&n.as_str()) && n != "arguments")
.filter(|n| ctx.captured_bindings.contains_key(n))
// 函数名(抑制面 var 同名)由专属 MAKE_CELL 处理(值源是帧槽写入的
// 名槽寄存器,非 undefined),此处排除以免误发 undefined 源。
.filter(|n| Some(n.as_str()) != ctx.function_name.as_deref())
.collect();
// HashSet 迭代序带随机种子,排序后入口 MAKE_CELL 发射序跨进程稳定。
var_names.sort();
if !var_names.is_empty() {
let undef_reg = self.emit_undefined(ctx);
for name in var_names {
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(undef_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
}
}
// 被捕获函数作用域词法(let/const/class)入口 TDZ 占位 cell:函数声明
// hoisting 先于声明语句执行时,闭包指向此未初始化 cell,声明前读写经
// 运行时抛真 TDZ;声明语句的 MAKE_CELL 按占位更新语义原位翻转。名集只取
// 直接子级(块级名不提升到函数作用域,与块内重执行 cell 族零交集),
// 排序保证发射序跨进程稳定。
let mut lex_names: Vec<String> = scope_names
.direct_lexical_names
.iter()
.filter(|n| !param_names.contains(&n.as_str()) && n != &"arguments")
.filter(|n| ctx.captured_bindings.contains_key(n.as_str()))
.cloned()
.collect();
lex_names.sort();
if !lex_names.is_empty() {
let undef_reg = self.emit_undefined(ctx);
for name in lex_names {
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
// 未初始化标志折入 16 位立即数高字节(0x0100),dispatch 侧
// 按字节拆回两字段。
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(undef_reg),
Operand::Imm(cell_idx as u16 | 0x0100),
Operand::None,
));
}
}
}
Ok(param_base)
}
/// 非捕获 `var` 名与块级函数外层 var 名的函数入口实例化:把每个未捕获槽在入口
/// 写为 undefined。
///
/// # 边界与前提
/// - 须在 `var` 预声明与块级函数外层 var 预声明之后、body 语句发射之前调用:
/// 预声明只登记槽位不发定义指令,声明语句对已绑定名又跳过 undefined 写,缺失
/// 入口写会让首次写入前的读取取到调用方遗留的寄存器值。
/// - 形参与 `arguments` 由参数 prologue 写入实参,跳过以免覆盖。
/// - 捕获名由参数 prologue 的 MAKE_CELL(undefined) 实例化;STORE_VAR 不更新
/// cell,跳过以免冗余。
/// - 块级函数名仅在 sloppy 模式并入:strict 下块函数是块级词法绑定,不建外层
/// var;被形参/词法同名抑制的名字无外层绑定,不并入。直接子标签函数声明由
/// 函数入口单独物化闭包,不并入。
/// - 符号表查不到的名字(如解构 pattern 叶名未被预声明)跳过,不报错。
fn instantiate_var_bindings(&self, body_stmts: &[Statement], ctx: &mut CompileCtx, scope_names: &FnScopeNames) {
let mut name_set = scope_names.var_binding_names.clone();
// 块级函数外层 var 绑定同样只预声明不发射定义指令,缺失入口写会让块前读取
// 取到调用方残留;入口写须并入(strict 与抑制名除外)。
if !ctx.is_strict {
// 直接子标签函数声明在函数入口首 sub-pass 物化闭包,声明点前读即为函数;
// 此处按名排除只省一次冗余的非捕获 undefined 写,非正确性必需。
let labeled_hoisted: HashSet<&str> = body_stmts
.iter()
.filter_map(|stmt| Self::labeled_function_decl(stmt))
.filter_map(|fd| fd.id.as_ref())
.map(|id| id.name.as_str())
.collect();
for name in self.collect_block_function_names(body_stmts) {
if !ctx.block_fn_suppressed.contains(&name) && !labeled_hoisted.contains(name.as_str()) {
name_set.insert(name);
}
}
}
// 抑制面:函数名是 var 绑定,帧槽写入把它初始化为函数对象,入口 undefined
// 写须排除该名(否则覆盖帧槽写入的函数对象),并回填名槽寄存器供帧槽写入。
// 非抑制面名绑定不是 var(不在 name_set 内),remove 返回 false 不回填。
if let Some(fn_name) = ctx.function_name.as_deref() {
if name_set.remove(fn_name) {
if let Some(reg) = ctx.scopes.symbols.lookup_any(fn_name) {
ctx.function_name_reg = Some(reg);
}
}
}
let mut names: Vec<String> = name_set
.into_iter()
.filter(|n| !ctx.param_names.contains(n) && n != "arguments")
.filter(|n| !ctx.captured_bindings.contains_key(n))
.collect();
if names.is_empty() {
return;
}
// 按名排序发射:哈希集迭代序随进程变化,排序使字节码确定。
names.sort();
let undef_reg = self.emit_undefined(ctx);
for name in names {
if let Some(reg) = ctx.scopes.symbols.lookup_any(&name) {
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(reg), Operand::Reg(undef_reg), Operand::Imm(0)));
}
}
}
/// 标签链直接包裹的函数声明(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 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 Self::is_body_hoisted_function_decl(stmt) {
continue;
}
if let Some(reg) = self.emit_statement(stmt, ctx)? {
last_result_reg = Some(reg);
}
}
Ok(last_result_reg)
}
}