//! 模块编译:import/export 解析、依赖加载(递归)、快照式链接与命名空间。 //! //! 普通依赖的导入绑定在 prelude 链接:依赖含可重赋导出时顶层读点经 //! `__moduleGet` 活读,其余退化为快照;被闭包捕获的导出挂共享 cell,闭包内写 //! 随活读可见。自导入(`import ... from 自身`)的局部名解析为本模块源绑定的活 //! 别名,TDZ/提升/活值/不可变四语义全部委托源绑定。`export` 语句就地注册导出值。 //! defer 导入(`import defer * as ns`)的依赖不求值:编译入子模块树并发 //! `__moduleDeferObject` 构造 deferred namespace 对象(逐名预注册静态导出名), //! 绑定该对象;自导入/祖先 defer 回边发哨兵形态(不递归、不编译)。 //! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、source-phase; //! star 转发与经再导出链的活值仍为快照;eager 环导入在编译期跳过。 use std::collections::{HashMap, HashSet}; use std::path::Path; use crate::capture::{collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names}; use crate::expr::call::pack_arg_regs; use crate::{CompileCtx, Emitter}; use oxc_allocator::Box; use oxide_bytecode::module::Constant; use oxide_bytecode::opcode::OpCode; use oxide_ir::inst::Inst; use oxide_ir::operand::Operand; use oxide_ir::{IRFunction, ParamLayout}; use oxide_parser::{ BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, ImportAttributeKey, ImportDeclarationSpecifier, ImportPhase, ModuleExportName, Statement, VariableDeclarationKind, WithClause, }; use oxide_types::MODULE_NAMESPACE_BINDING; /// 数据模块种类(非 JS 源码模块)。 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ModuleKind { Js, Json, Text, Bytes, } /// 已解析的依赖模块。 pub struct ResolvedModule { /// 模块源码(JS / 数据内容)。 pub source: String, /// 模块规范路径(用于自身导入识别与循环检测)。 pub path: String, /// 模块种类。 pub kind: ModuleKind, } /// 单个依赖 spec 的 phase 跟踪:eager/defer 双标志与首次出现的导入属性。 /// /// `eager` 为真表示该 spec 被任一非 defer 语句(导入或再导出)引用; /// `defer` 为真表示被任一 `import defer * as` 引用。两标志可并存(mixed 依赖)。 struct DepPhase { eager: bool, defer: bool, attrs: Vec<(String, String)>, } /// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。 pub trait ModuleSourceLoader { /// 解析依赖模块:按 `base_dir` 与 `specifier` 定位模块源码,`attributes` 为 /// with 子句的导入属性键值对。 fn resolve( &mut self, base_dir: &str, specifier: &str, attributes: &[(&str, &str)], ) -> Result; } /// `export default` 的默认导出名,也是匿名默认导出函数/类的隐式 `name`。 const DEFAULT_EXPORT_NAME: &str = "default"; /// 剥离可能的多层括号表达式,供隐式名分派判定内层函数/类形态。 fn strip_parens<'a, 'b>(expr: &'b Expression<'a>) -> &'b Expression<'a> { let mut cur = expr; while let Expression::ParenthesizedExpression(p) = cur { cur = &p.expression; } cur } /// 把隐式名写到刚发射的匿名函数子模块。 /// /// # 副作用 /// - 修改 `ctx.nested` 末项的 `function_name`;已有名(具名函数)不覆盖。 /// /// # 注意事项 /// - 仅用于函数/箭头/生成器:它们在发射期只 push 一个子模块,末项即目标。 /// 类在构造器之后还会 push 方法子模块,末项不是构造器,类名必须经 /// `emit_class_with_binding` 的 `implicit_name` 参数落名。 fn set_implicit_name_of_last_nested(ctx: &mut CompileCtx, name: &str) { if let Some(m) = ctx.nested.last_mut() { if m.function_name.is_none() { m.function_name = Some(name.to_string()); } } } /// 把 `ModuleExportName`(标识符名 / 标识符引用 / 字符串字面量)统一转为字符串导出名。 fn module_export_name_str(m: &ModuleExportName) -> String { match m { ModuleExportName::IdentifierName(i) => i.name.to_string(), ModuleExportName::IdentifierReference(i) => i.name.to_string(), ModuleExportName::StringLiteral(s) => s.value.to_string(), } } /// 从 with 子句提取导入属性键值对(键取标识符或字符串字面量,值取字符串字面量)。 fn module_attributes(with_clause: &Option>>) -> Vec<(String, String)> { let mut out = Vec::new(); if let Some(wc) = with_clause { for attr in &wc.with_entries { let key = match &attr.key { ImportAttributeKey::Identifier(id) => id.name.to_string(), ImportAttributeKey::StringLiteral(s) => s.value.to_string(), }; out.push((key, attr.value.value.to_string())); } } out } /// 收集模块自身直接导出的名称集合(含字符串导出名与 default): /// 供 self-import 链接期校验(自引用导入不存在的导出 → 编译期错误)。 fn module_own_export_names(body: &[Statement]) -> HashSet { let mut names = HashSet::new(); for stmt in body { match stmt { Statement::ExportNamedDeclaration(exp) => { if let Some(decl) = &exp.declaration { match decl { Declaration::VariableDeclaration(vd) => { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { names.insert(bi.name.to_string()); } } } Declaration::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { names.insert(id.name.to_string()); } } Declaration::ClassDeclaration(cl) => { if let Some(id) = &cl.id { names.insert(id.name.to_string()); } } _ => {} } } else { for spec in &exp.specifiers { names.insert(module_export_name_str(&spec.exported)); } } } Statement::ExportDefaultDeclaration(_) => { names.insert(DEFAULT_EXPORT_NAME.to_string()); } Statement::ExportAllDeclaration(exp) => { if let Some(exported) = &exp.exported { names.insert(module_export_name_str(exported)); } } _ => {} } } names } /// 收集模块实例化期即初始化为 undefined 的导出名(VarScopedDeclarations): /// `export var`、`export function`、`export default function`(具名与匿名)以及 /// 经 `export { x }` 本地再导出、底层绑定为 var/function 的导出名。 /// /// # 边界与前提 /// - lexical(let/const/class)与跨模块再导出(`export { x } from`)不在集合内, /// 其命名空间条目保持未初始化(TDZ)。 /// - `export { x as y }` 只认本模块顶层直接声明的 var/function;自导入别名等 /// 间接名不判真(按 TDZ 处理)。 /// - 匿名 `export default function` 的导出名是 `default`,按 HoistableDeclaration /// 预初始化。 fn module_var_scoped_export_names(body: &[Statement]) -> HashSet { let mut var_locals: HashSet = HashSet::new(); for stmt in body { match stmt { Statement::VariableDeclaration(vd) => { if matches!(vd.kind, VariableDeclarationKind::Var) { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { var_locals.insert(bi.name.to_string()); } } } } Statement::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { var_locals.insert(id.name.to_string()); } } Statement::ExportNamedDeclaration(exp) => { if let Some(decl) = &exp.declaration { match decl { Declaration::VariableDeclaration(vd) => { if matches!(vd.kind, VariableDeclarationKind::Var) { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { var_locals.insert(bi.name.to_string()); } } } } Declaration::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { var_locals.insert(id.name.to_string()); } } _ => {} } } } _ => {} } } let mut names = HashSet::new(); for stmt in body { match stmt { Statement::ExportNamedDeclaration(exp) => { if let Some(decl) = &exp.declaration { match decl { Declaration::VariableDeclaration(vd) => { if matches!(vd.kind, VariableDeclarationKind::Var) { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { names.insert(bi.name.to_string()); } } } } Declaration::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { names.insert(id.name.to_string()); } } _ => {} } } else if exp.source.is_none() { for spec in &exp.specifiers { if var_locals.contains(module_export_name_str(&spec.local).as_str()) { names.insert(module_export_name_str(&spec.exported)); } } } } Statement::ExportDefaultDeclaration(exp) => { if matches!(&exp.declaration, ExportDefaultDeclarationKind::FunctionDeclaration(_)) { names.insert(DEFAULT_EXPORT_NAME.to_string()); } } _ => {} } } names } /// 判断模块是否含可重赋导出:导出源绑定既非顶层 const 也非导入本地名时为真。 /// /// # 边界与前提 /// - 依据 `module_export_name_map`(导出名 → 源绑定名)与顶层 const 绑定名集合: /// var/let/function/class 与 default(含合成 `*default*`)均判真,const-only 判假。 /// - 经导入本地名再导出(`export { x }` 底层为 import 绑定)不判真:源绑定不可重赋, /// 其可变性归来源模块。star 转发名不在映射表内,天然不参与判定。 /// /// # 注意事项 /// - 保守超集:`export default 42` 之类不可重赋值也判真,仅使该依赖多一次预注册, /// 导入方读值等价。 fn module_has_reassignable_export(body: &[Statement], export_name_map: &HashMap) -> bool { let mut const_names = HashSet::new(); let mut import_names = HashSet::new(); for stmt in body { match stmt { Statement::VariableDeclaration(vd) => { if matches!(vd.kind, VariableDeclarationKind::Const) { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { const_names.insert(bi.name.to_string()); } } } } Statement::ExportNamedDeclaration(exp) => { if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration { if matches!(vd.kind, VariableDeclarationKind::Const) { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { const_names.insert(bi.name.to_string()); } } } } } Statement::ImportDeclaration(imp) => { if let Some(specifiers) = &imp.specifiers { for sp in specifiers { let local = match sp { ImportDeclarationSpecifier::ImportSpecifier(s) => &s.local.name, ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => &s.local.name, ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => &s.local.name, }; import_names.insert(local.to_string()); } } } _ => {} } } export_name_map .values() .any(|source| !const_names.contains(source) && !import_names.contains(source)) } /// 判断语句是否为提升的函数声明(含 export 包装的函数声明)。 fn is_hoisted_function_decl(stmt: &Statement) -> bool { match stmt { Statement::FunctionDeclaration(_) => true, Statement::ExportNamedDeclaration(exp) => { matches!(&exp.declaration, Some(Declaration::FunctionDeclaration(_))) } // export default function 声明形态在实例化期绑定并预初始化(提升至模块求值前), // 与普通函数声明同一发射次序。 Statement::ExportDefaultDeclaration(exp) => { matches!(&exp.declaration, ExportDefaultDeclarationKind::FunctionDeclaration(_)) } _ => false, } } /// 合成默认导出的源绑定名(匿名 default 函数/类与 default 表达式共用)。 /// 含 `*`,与任何用户标识符都不可能重名。 pub(crate) const SYNTHETIC_DEFAULT_BINDING: &str = "*default*"; /// 收集模块自身导出名 → 源绑定名映射:把 self-import 的局部名别名到该映射给出的 /// 源绑定,使别名读/写/TDZ/const 全部经源绑定通道自然成立。 /// /// # 边界与前提 /// - 带声明的导出:var/fn/class 的每个绑定名 → 自身名。 /// - 无 source 再导出 `export { x as y }`:`y → x`。 /// - self source 再导出 `export { local as indirect } from './self'`:`indirect → local`。 /// - 非 self source 再导出与 star 转发不入表(跨模块面由运行期刷新承载), /// 映射缺失时调用方回退非别名路径。 /// - `export default`:具名 fn/class → 具名 id;匿名 fn/class 与表达式 → 合成 `*default*`。 /// /// # 注意事项 /// - 须在依赖收集循环之后构建(self 再导出判定读 `module_self_import_specs`)。 fn module_export_name_map(body: &[Statement], self_specs: &HashSet) -> HashMap { let mut map = HashMap::new(); for stmt in body { match stmt { Statement::ExportNamedDeclaration(exp) => { if let Some(decl) = &exp.declaration { match decl { Declaration::VariableDeclaration(vd) => { for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { let name = bi.name.to_string(); map.insert(name.clone(), name); } } } Declaration::FunctionDeclaration(fd) => { if let Some(id) = &fd.id { let name = id.name.to_string(); map.insert(name.clone(), name); } } Declaration::ClassDeclaration(cl) => { if let Some(id) = &cl.id { let name = id.name.to_string(); map.insert(name.clone(), name); } } _ => {} } } else if let Some(src) = &exp.source { // self 再导出:导出名解析到本模块的本地名,本模块体执行中 // 该本地名(可能是 import 名或本地声明)对别名可见。 if self_specs.contains(src.value.as_str()) { for spec in &exp.specifiers { map.insert(module_export_name_str(&spec.exported), module_export_name_str(&spec.local)); } } } else { // 无 source 再导出:导出名直接映射到本地声明名。 for spec in &exp.specifiers { map.insert(module_export_name_str(&spec.exported), module_export_name_str(&spec.local)); } } } Statement::ExportDefaultDeclaration(exp) => { let source = match &exp.declaration { ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { fd.id.as_ref().map(|id| id.name.to_string()) } ExportDefaultDeclarationKind::ClassDeclaration(cl) => cl.id.as_ref().map(|id| id.name.to_string()), _ => None, }; map.insert( DEFAULT_EXPORT_NAME.to_string(), source.unwrap_or_else(|| SYNTHETIC_DEFAULT_BINDING.to_string()), ); } _ => {} } } map } impl Emitter { /// 编译 ES module:顶层 body + 递归依赖。 /// `module_path` 为模块文件路径;入口即归一为规范绝对路径(依赖解析基准 = /// 其父目录),与加载器 resolve 的绝对规范口径对齐,使自导入身份比较稳定。 pub fn emit_program_module( &self, program: &oxide_parser::Program, module_path: &str, loader: &mut dyn ModuleSourceLoader, ) -> Result { crate::emit_debug!("emit_program_module: {} stmts", program.body.len()); // 顶层模块路径归一为规范绝对路径:自导入身份比较(resolved.path == // module_path)与 base_dir 需与加载器 resolve 的 canonicalize 绝对口径 // 一致——若保留相对发现路径,自导入比较恒 false、自导入被当外部依赖 // 重编译。文件不存在(虚拟/内存模块)时 canonicalize 失败,保留原路径。 let canonical = std::fs::canonicalize(module_path) .map(|p| p.to_string_lossy().into_owned()) .unwrap_or_else(|_| module_path.to_string()); let module_path = canonical.as_str(); let mut ctx = CompileCtx::new(); // 模块顶层 var/function 不写全局对象(模块作用域绑定)。 ctx.is_global_scope = false; // ES module 顶层恒严格模式(模块代码是严格模式代码,嵌套函数经父 ctx 继承)。 ctx.is_strict = true; let mut path_stack = vec![module_path.to_string()]; self.emit_module_into_ctx(program, module_path, loader, &mut path_stack, &mut ctx, true)?; Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None)) } /// 模块体 emit(顶层与依赖模块共用入口)。 /// /// `top_level` 区分收尾返回口径:顶层模块求值完成值按规范为空记录 /// (对外 undefined),依赖模块经 `__moduleEval` 以返回值作命名空间对象。 #[allow(clippy::too_many_arguments)] fn emit_module_into_ctx( &self, program: &oxide_parser::Program, module_path: &str, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec, ctx: &mut CompileCtx, top_level: bool, ) -> Result<(), String> { let body = &program.body; // —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)—— self.predeclare_function_declarations(body, ctx); // 模块顶层词法声明名排除镜像登记(词法绑定遮蔽同名全局属性,同 program.rs)。 let lexical_excluded = collect_direct_lexical_names(body); self.pre_register_builtin_references(body, &lexical_excluded, ctx); self.predeclare_var_declarations(body, ctx); // 模块 lexical 声明入模块环境(非全局对象),不做受限全局名检查。 let _ = self.predeclare_lexical_declarations(body, ctx); // 闭包捕获分析(import 绑定名纳入 own_bindings,供嵌套函数 cell 捕获)。 ctx.own_bindings = collect_own_binding_names(&[], body); ctx.set_captured_bindings(collect_captured_bindings(body, &[], &ctx.own_bindings)); // 模块顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。 ctx.backfill_captured_cell_idxs(); // —— 模块命名空间对象 —— let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?; ctx.module_ns_reg = Some(ns_reg); // —— 依赖收集(import + re-export/star 的 source,按首次出现去重,记 phase)—— // eager_order 为各 spec 首个 eager 语句的出现序(求值序);defer_order 为各 spec // 首次出现序(defer-only 组发射序)。无 defer 的模块两序与首次出现序恒等, // 发射产物与现态逐字节一致。 let base_dir = Path::new(module_path) .parent() .map(|p| p.to_string_lossy().to_string()) .unwrap_or_default(); let mut phase_map: HashMap = HashMap::new(); let mut eager_order: Vec = Vec::new(); let mut defer_order: Vec = Vec::new(); for stmt in body { let (spec, attrs, is_defer) = match stmt { Statement::ImportDeclaration(imp) => { let is_defer = imp.phase == Some(ImportPhase::Defer); (imp.source.value.to_string(), module_attributes(&imp.with_clause), is_defer) } Statement::ExportNamedDeclaration(exp) => { if let Some(src) = &exp.source { (src.value.to_string(), module_attributes(&exp.with_clause), false) } else { continue; } } Statement::ExportAllDeclaration(exp) => { (exp.source.value.to_string(), module_attributes(&exp.with_clause), false) } _ => continue, }; let is_new = !phase_map.contains_key(&spec); let entry = phase_map .entry(spec.clone()) .or_insert_with(|| DepPhase { eager: false, defer: false, attrs }); if is_new { defer_order.push(spec.clone()); } if !is_defer && !entry.eager { entry.eager = true; eager_order.push(spec.clone()); } if is_defer { entry.defer = true; } } // 本模块自身导出名与 var 作用域导出名:自导入 mixed 的 defer 预注册复用, // 亦供下方绑定循环与 live 预注册消费。 let own_export_names = module_own_export_names(body); let var_scoped_export_names = module_var_scoped_export_names(body); // —— 编译并求值依赖:eager 组先行(按 eager 语句序),defer-only 组随后 —— for spec in eager_order { let phase = &phase_map[&spec]; let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(); let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?; let is_self = resolved.path == module_path; let (dep_ns_reg, fn_reg, dep_own_names, dep_var_scoped) = if is_self { // 自导入:读自身命名空间(依赖即本模块,勿递归)。 (ns_reg, None, own_export_names.clone(), var_scoped_export_names.clone()) } else { if path_stack.contains(&resolved.path) { return Err(format!("circular module import not supported: {}", resolved.path)); } path_stack.push(resolved.path.clone()); let (dep_ir, dep_reassignable, dep_own_names, dep_var_scoped) = match resolved.kind { ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?, ModuleKind::Json => ( self.compile_data_dep("json", &resolved.source)?, false, HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), ), ModuleKind::Text => ( self.compile_data_dep("text", &resolved.source)?, false, HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), ), ModuleKind::Bytes => return Err("bytes module not supported".into()), }; path_stack.pop(); ctx.nested.push(dep_ir); ctx.module_dep_reassignable.insert(spec.clone(), dep_reassignable); let fn_reg = ctx.alloc_reg(); ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16)); let real_ns = self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?; (real_ns, Some(fn_reg), dep_own_names, dep_var_scoped) }; ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg); ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone()); if is_self { // 自导入:绑定走别名语义(源导出在 body 执行中才就绪), // 不能像普通依赖那样链接期快照。 ctx.module_self_import_specs.insert(spec.clone()); } if phase.defer { // mixed 依赖:模块已急切求值,deferred 对象承载已求值态 // ([[Evaluated]]=true、[[Namespace]]=真实 ns)。 let fn_or_sentinel = if is_self { // 自导入 mixed:模块函数在导入方 prelude 期不可得,发哨兵形态。 self.emit_undefined(ctx) } else { fn_reg.expect("非自导入 eager 依赖必有闭包寄存器") }; let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[fn_or_sentinel, dep_ns_reg])?; ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns); self.emit_defer_pre_register(ctx, defer_ns, &dep_own_names, &dep_var_scoped)?; } } // defer-only 组(eager == false 的 spec,按 defer_order):不求值、不发 // __moduleEval。祖先判定(自导入或父链回边)命中时发哨兵形态 // __moduleDeferObject(undefined, undefined)——不递归、不压 path_stack、不编译; // 否则正常编译并发 __moduleDeferObject(fn, undefined) + 逐名预注册。 for spec in defer_order { let phase = &phase_map[&spec]; if phase.eager { continue; } let attr_refs: Vec<(&str, &str)> = phase.attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect(); let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?; let is_ancestor = resolved.path == module_path || path_stack.contains(&resolved.path); if is_ancestor { // 哨兵:模块函数在导入方 prelude 期不可得(自导入是自身、祖先是 // 父链),defer 回边在导入图上成环,编译期不得报循环。 let undef = self.emit_undefined(ctx); let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[undef, undef])?; ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns); ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns); ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone()); } else { path_stack.push(resolved.path.clone()); let (dep_ir, _dep_reassignable, dep_own_names, dep_var_scoped) = match resolved.kind { ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?, ModuleKind::Json => ( self.compile_data_dep("json", &resolved.source)?, false, HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), ), ModuleKind::Text => ( self.compile_data_dep("text", &resolved.source)?, false, HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), HashSet::from([DEFAULT_EXPORT_NAME.to_string()]), ), ModuleKind::Bytes => return Err("bytes module not supported".into()), }; path_stack.pop(); ctx.nested.push(dep_ir); let fn_reg = ctx.alloc_reg(); ctx.inst(Inst::create_closure(Operand::Reg(fn_reg), ctx.nested.len() as u16)); let undef = self.emit_undefined(ctx); let defer_ns = self.emit_module_call(ctx, "__moduleDeferObject", &[fn_reg, undef])?; ctx.module_dep_ns_regs.insert(spec.clone(), defer_ns); ctx.module_defer_ns_regs.insert(spec.clone(), defer_ns); ctx.module_dep_paths.insert(spec.clone(), resolved.path.clone()); self.emit_defer_pre_register(ctx, defer_ns, &dep_own_names, &dep_var_scoped)?; } } // —— 导入绑定初始化(普通依赖为链接期快照;命名空间绑定直接引用 ns 对象; // defer 命名空间绑定引用 deferred 对象;自导入绑定解析为本模块源绑定的活别名)—— // 无命名 `export * from 'x'` 会把依赖的全部导出转发给自身;自导入名可能来自 // star 再导出,编译期无法静态判定该名是否存在于自身导出,故链接校验放宽。 let has_unnamed_star = body .iter() .any(|s| matches!(s, Statement::ExportAllDeclaration(e) if e.exported.is_none())); // 导出名 → 本模块源绑定名:self-import 的局部名别名到该源绑定。star 转发的 // 自导入名不在表内(退化为下方非别名占位路径)。 let export_name_map = module_export_name_map(body, &ctx.module_self_import_specs); // 依赖模块的可重赋导出标志:仅依赖模块(非入口)参与判定,入口模块恒假, // 使纯导出入口(含 `export let x`)的 IR 逐字节不变。 ctx.module_live_dep = !top_level && module_has_reassignable_export(body, &export_name_map); // live 命名空间门控:仅自导入 `import * as ns from './self'` 的模块需要预注册 // 真实导出槽,其余模块(含普通外部命名空间导入)编译产物逐字节不变。 let mut has_self_ns_import = false; for stmt in body { if let Statement::ImportDeclaration(imp) = stmt { let dep_spec = imp.source.value.to_string(); let dep_ns_reg = *ctx .module_dep_ns_regs .get(&dep_spec) .ok_or_else(|| format!("module dependency missing: {dep_spec}"))?; let is_self = ctx.module_self_import_specs.contains(&dep_spec); // 再导出重分类依据:非自导入局部名 → (依赖路径, 导入名)。 let dep_path = ctx.module_dep_paths.get(&dep_spec).cloned().unwrap_or_default(); if let Some(specifiers) = &imp.specifiers { for sp in specifiers { match sp { ImportDeclarationSpecifier::ImportSpecifier(s) => { let imported = module_export_name_str(&s.imported); if !is_self { ctx.module_import_origins .insert(s.local.name.to_string(), (dep_path.clone(), imported.clone())); } let alias_source = is_self.then(|| export_name_map.get(&imported)).flatten(); if is_self && !own_export_names.contains(&imported) && !has_unnamed_star { return Err(format!("requested module export is not exported: {imported}")); } if let Some(source) = alias_source { // 导出名可静态解析到本模块源绑定:局部名注册为 // 源绑定的活别名(源不存在时回退占位路径)。 if ctx.add_alias(s.local.name.as_str(), source).is_ok() { ctx.module_alias_pairs.push((s.local.name.to_string(), source.to_string())); continue; } } if is_self { let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?; ctx.module_self_aliases.entry(imported).or_default().push(alias_reg); } else { let name_reg = self.load_string_const(&imported, ctx); let val_reg = self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?; self.emit_bind_target( s.local.name.as_str(), val_reg, VariableDeclarationKind::Const, true, false, ctx, )?; // 依赖含可重赋导出:登记活读映射,顶层读点改走 // `__moduleGet`,快照绑定仅服务嵌套闭包读。 if ctx.module_dep_reassignable.get(&dep_spec).copied().unwrap_or(false) { ctx.module_live_imports .insert(s.local.name.to_string(), (dep_ns_reg, imported.clone())); } } } ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => { if !is_self { ctx.module_import_origins.insert( s.local.name.to_string(), (dep_path.clone(), DEFAULT_EXPORT_NAME.to_string()), ); } let alias_source = is_self.then(|| export_name_map.get(DEFAULT_EXPORT_NAME)).flatten().cloned(); if is_self && !own_export_names.contains(DEFAULT_EXPORT_NAME) { return Err("requested module export is not exported: default".into()); } if let Some(source) = alias_source { // 匿名 default 函数/类与 default 表达式无本地声明名, // 源绑定须惰性建:只在此处存在 self-import default 时 // 建立,保证无 self-import 的模块零 IR 变化。 if source == SYNTHETIC_DEFAULT_BINDING && ctx.scopes.symbols.lookup_any(&source).is_none() { let reg = ctx.alloc_reg(); ctx.declare_predeclared(&source, reg, VariableDeclarationKind::Let, false)?; // 表达式形态 TDZ 保持;函数声明形态由提升臂在求值 // 前初始化,此处不做初始化。 } if ctx.add_alias(s.local.name.as_str(), &source).is_ok() { ctx.module_alias_pairs.push((s.local.name.to_string(), source.clone())); continue; } } if is_self { let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?; ctx.module_self_aliases .entry(DEFAULT_EXPORT_NAME.to_string()) .or_default() .push(alias_reg); } else { let name_reg = self.load_string_const(DEFAULT_EXPORT_NAME, ctx); let val_reg = self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?; self.emit_bind_target( s.local.name.as_str(), val_reg, VariableDeclarationKind::Const, true, false, ctx, )?; // 默认导入同命名导入:可重赋依赖的 default 导出活读。 if ctx.module_dep_reassignable.get(&dep_spec).copied().unwrap_or(false) { ctx.module_live_imports.insert( s.local.name.to_string(), (dep_ns_reg, DEFAULT_EXPORT_NAME.to_string()), ); } } } ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => { let is_defer = imp.phase == Some(ImportPhase::Defer); // 命名空间绑定引用 ns 对象本身:自导入时同一对象, // body 执行后导出自然可见;defer 绑定 deferred 对象。 // defer 自导入不得激活 live ns(不置 has_self_ns_import)。 if is_self && !is_defer { has_self_ns_import = true; } else if !is_self { ctx.module_import_origins.insert( s.local.name.to_string(), (dep_path.clone(), MODULE_NAMESPACE_BINDING.to_string()), ); } let bind_reg = if is_defer { *ctx .module_defer_ns_regs .get(&dep_spec) .ok_or_else(|| format!("module dependency missing: {dep_spec}"))? } else { dep_ns_reg }; self.emit_bind_target( s.local.name.as_str(), bind_reg, VariableDeclarationKind::Const, true, false, ctx, )?; } } } } } } // live 命名空间激活:自导入 ns(本模块自身观测 ns)或本模块含可重赋导出 // (外部导入方需活读)。非 live 模块写穿与预注册均不发射,IR 逐字节不变。 let live_active = has_self_ns_import || ctx.module_live_dep; ctx.module_live_ns_active = live_active; // —— 写穿反演:源绑定槽寄存器 → 导出名集合。仅 live 模块填充: // 非 live 模块不激活写穿,编译产物逐字节零 IR 变化。以槽位为键使块级/catch // 同名遮蔽解析到内层槽时不命中;按名排序保证多导出名映射到同一源绑定的 // 发射顺序确定。—— if live_active { let mut pairs: Vec<(&String, &String)> = export_name_map.iter().map(|(exported, source)| (source, exported)).collect(); pairs.sort(); for (source, exported) in pairs { let Some(reg) = ctx.scopes.symbols.lookup_any(source) else { continue; }; ctx.module_local_export_regs.entry(reg).or_default().push(exported.clone()); } } // —— live 命名空间预注册:早于 hoisted 函数声明的 __moduleSet 与 body 求值, // 按名序预注册全部本地导出名,使自导入 ns 在读点先观察到未初始化状态。 // var/函数类导出(VarScopedDeclarations)在实例化期即初始化为 undefined, // lexical/class 保持未初始化(TDZ)。 —— if live_active { let mut export_names: Vec = own_export_names.into_iter().collect(); export_names.sort(); for name in export_names { let name_reg = self.load_string_const(&name, ctx); let var_like_reg = self.load_bool_const(var_scoped_export_names.contains(&name), ctx); self.emit_module_call(ctx, "__modulePreRegister", &[ns_reg, name_reg, var_like_reg])?; } } // —— 别名捕获后处理:源绑定被嵌套函数捕获时,别名必须落到同一 cell, // 否则两处各持一份值。无捕获时别名读经源寄存器天然活。此后源被捕获的 // var 名在模块入口统一 MAKE_CELL(undefined),与脚本顶层实例化同语义。—— self.reconcile_alias_captures(ctx); { let mut var_names: Vec = crate::capture::collect_var_binding_names(body) .into_iter() .filter(|n| !ctx.param_names.contains(n.as_str())) .filter(|n| ctx.captured_bindings.contains_key(n)) .collect(); 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:模块词法导出 // 既有预注册保持未初始化 TDZ(命名空间对象面,按导出名),入口 cell // 只覆盖被嵌套函数捕获的名(按捕获名),两面名集独立。声明语句的 // MAKE_CELL 按占位更新语义原位翻转;直接子级 only,块级名不提升。 let mut lex_names: Vec = crate::capture::collect_direct_lexical_names(body) .into_iter() .filter(|n| !ctx.param_names.contains(n.as_str())) .filter(|n| ctx.captured_bindings.contains_key(n)) .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, )); } } } } // —— re-export(export { x } from 'mod')链接检查:实例化期解析,须先于 // body 求值。$DONOTEVALUATE 是 test262 测试框架的断言工具,断言链接错误先于 // body 求值抛出,故链接检查必须先于 body 发射。—— for stmt in body { if let Statement::ExportNamedDeclaration(exp) = stmt { if exp.declaration.is_some() { continue; } if let Some(src) = &exp.source { let dep_spec = src.value.to_string(); if ctx.module_self_import_specs.contains(&dep_spec) { continue; // 自身导出未就绪,body 执行中再解析 } if let Some(&dep_ns_reg) = ctx.module_dep_ns_regs.get(&dep_spec) { for spec in &exp.specifiers { let local_name = module_export_name_str(&spec.local); let name_reg = self.load_string_const(&local_name, ctx); self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?; } } } } } // —— body(函数声明 hoisting 先发,随后其余;import 已由 prelude 处理)—— // directive 序言是 AST 独立字段(顶格字符串字面量,不在 body):纯字符串 // 无副作用,按源序先于 body 发射,与脚本 emit_program 的发射口径一致。 for dir in &program.directives { self.emit_string_literal_expression(&dir.expression, ctx)?; } for stmt in body { if is_hoisted_function_decl(stmt) { self.emit_statement(stmt, ctx)?; } } for stmt in body { if is_hoisted_function_decl(stmt) { continue; } if matches!(stmt, Statement::ImportDeclaration(_)) { continue; } self.emit_statement(stmt, ctx)?; } // —— 自别名收尾刷新:star 复制等跨模块注册路径后占位槽可能仍为旧值, // 封冻命名空间前统一从命名空间非抛出回读兜底。 —— self.emit_self_alias_refresh(ctx, ns_reg)?; // —— 收尾:封冻命名空间并返回(顶层 RETURN 亦终止 run)—— self.emit_module_call(ctx, "__moduleSeal", &[ns_reg])?; if top_level { // 顶层模块求值完成值为空记录(对外表现 undefined);依赖模块求值必须返回 // 命名空间对象(`__moduleEval` 以依赖返回值作命名空间)——两条路径的返回 // 值契约不同,顶层路径不得复用依赖路径的返回值。 let undef_idx = ctx.add_constant(Constant::Undefined); let r = ctx.alloc_reg(); ctx.inst(Inst::load_const(Operand::Reg(r), undef_idx)); ctx.inst(Inst::ret(Operand::Reg(r), 0, 0)); } else { ctx.inst(Inst::ret(Operand::Reg(ns_reg), 0, 0)); } Ok(()) } /// 编译 JS 依赖模块(递归),回传 IR、「是否含可重赋导出」标志、 /// 自身静态导出名集与 var 作用域导出名集。 /// /// # 边界与前提 /// - 可重赋标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按 /// `!top_level` 判定,故 const-only 依赖回传 false。 /// - 导出名集在函数内对解析产物就地计算,供导入方 defer 预注册消费。 /// /// # 注意事项 /// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。 fn compile_js_dep( &self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec, ) -> Result<(IRFunction, bool, HashSet, HashSet), String> { let alloc = oxide_parser::Allocator::default(); let program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| { format!( "module parse error: {}", errs.first().map(|e| e.message.as_str()).unwrap_or("parse failed") ) })?; let mut ctx = CompileCtx::new(); ctx.is_global_scope = false; // 依赖模块经 parse_module 解析,顶层恒严格模式。 ctx.is_strict = true; self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?; let reassignable = ctx.module_live_dep; let own_export_names = module_own_export_names(&program.body); let var_scoped = module_var_scoped_export_names(&program.body); Ok(( ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None), reassignable, own_export_names, var_scoped, )) } /// 发 defer 预注册:对 deferred namespace 对象逐名 `__modulePreRegister`, /// 名字按字典序排序保证发射序确定。var 作用域导出名(var/function) /// 预注册为已初始化(undefined),lexical/class 保持未初始化(TDZ)。 fn emit_defer_pre_register( &self, ctx: &mut CompileCtx, defer_ns_reg: u32, export_names: &HashSet, var_scoped: &HashSet, ) -> Result<(), String> { let mut names: Vec<&String> = export_names.iter().collect(); names.sort(); for name in names { let name_reg = self.load_string_const(name, ctx); let var_like_reg = self.load_bool_const(var_scoped.contains(name), ctx); self.emit_module_call(ctx, "__modulePreRegister", &[defer_ns_reg, name_reg, var_like_reg])?; } Ok(()) } /// 编译数据模块(json/text):body 仅为 __moduleData 调用 + RETURN。 fn compile_data_dep(&self, kind: &str, content: &str) -> Result { let mut ctx = CompileCtx::new(); let kind_reg = self.load_string_const(kind, &mut ctx); let content_reg = self.load_string_const(content, &mut ctx); let val_reg = self.emit_module_call(&mut ctx, "__moduleData", &[kind_reg, content_reg])?; ctx.inst(Inst::ret(Operand::Reg(val_reg), 0, 0)); Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None)) } /// 内部辅助调用:CALL_NATIVE 到全局 native(__module*),返回结果寄存器。 pub(crate) fn emit_module_call(&self, ctx: &mut CompileCtx, name: &str, arg_regs: &[u32]) -> Result { let callee_reg = ctx.lookup_or_builtin(name)?; let this_reg = ctx.alloc_reg(); let undef_idx = ctx.add_constant(Constant::Undefined); ctx.inst(Inst::load_const(Operand::Reg(this_reg), undef_idx)); // CALL_NATIVE 按 regs[first_arg + i] 连续读参数:把非连续虚拟寄存器(vreg,经寄存器 // 分配后映射为物理号)打包为连续寄存器块。 let mut packed = arg_regs.to_vec(); let first_arg_reg = if packed.is_empty() { this_reg } else { pack_arg_regs(&mut packed, ctx) }; ctx.inst(Inst::call_native( Operand::Reg(callee_reg), Operand::Reg(this_reg), Operand::Reg(first_arg_reg), packed.len() as u8, )); let result_reg = ctx.alloc_reg(); ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None)); Ok(result_reg) } pub(crate) fn load_string_const(&self, s: &str, ctx: &mut CompileCtx) -> u32 { let idx = ctx.add_constant(Constant::String(s.to_string())); let reg = ctx.alloc_reg(); ctx.inst(Inst::load_const(Operand::Reg(reg), idx)); reg } fn load_bool_const(&self, b: bool, ctx: &mut CompileCtx) -> u32 { let idx = ctx.add_constant(Constant::Boolean(b)); let reg = ctx.alloc_reg(); ctx.inst(Inst::load_const(Operand::Reg(reg), idx)); reg } /// 自导入别名回写:导出名若被本模块 self-import 绑定别名引用, /// export 语句执行时同步把值写回本地绑定槽。同名多槽(default 双绑定) /// 逐槽并列回写。 fn emit_self_alias_write(&self, ctx: &mut CompileCtx, export_name: &str, value_reg: u32) { let regs = ctx.module_self_aliases.get(export_name).cloned().unwrap_or_default(); for &alias_reg in ®s { ctx.inst(Inst::new( OpCode::STORE_VAR, Operand::Reg(alias_reg), Operand::Reg(value_reg), Operand::None, )); } } /// 自导入别名统一刷新:对每个登记的自导入占位名,从命名空间非抛出读回写 /// 占位槽(命名空间无该名时保留占位值,不抛错)。star 转发的自导入名在 /// 导出语句处静态不可知,故每次 star 复制后与 body 收尾各刷新一次; /// 名集按字典序排序后发射,保证发射序确定性。 fn emit_self_alias_refresh(&self, ctx: &mut CompileCtx, ns_reg: u32) -> Result<(), String> { if ctx.module_self_aliases.is_empty() { return Ok(()); } let mut names: Vec = ctx.module_self_aliases.keys().cloned().collect(); names.sort(); for name in names { let regs = ctx.module_self_aliases.get(&name).cloned().unwrap_or_default(); for &alias_reg in ®s { let name_reg = self.load_string_const(&name, ctx); let cur_reg = ctx.alloc_reg(); ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(cur_reg), Operand::Reg(alias_reg), Operand::None)); let r = self.emit_module_call(ctx, "__moduleAlias", &[ns_reg, name_reg, cur_reg])?; ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(alias_reg), Operand::Reg(r), Operand::None)); } } Ok(()) } /// 自导入绑定的非别名占位:源绑定无法静态解析(star 转发的自导入名)时, /// prelude 把局部名绑成已初始化的 undefined 常量槽并登记回写,由 export /// 语句执行时就地刷新,body 收尾再统一从命名空间回读兜底。 /// 返回该本地绑定槽寄存器。 fn emit_self_alias_placeholder(&self, local: &str, ctx: &mut CompileCtx) -> Result { 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)); self.emit_bind_target(local, undef_reg, VariableDeclarationKind::Const, true, false, ctx)?; ctx.lookup(local) } fn emit_module_set(&self, ctx: &mut CompileCtx, ns_reg: u32, name: &str, value_reg: u32) -> Result<(), String> { let name_reg = self.load_string_const(name, ctx); self.emit_module_call(ctx, "__moduleSet", &[ns_reg, name_reg, value_reg])?; Ok(()) } /// 发 `__moduleSetCell`:把导出条目挂到源绑定的共享 cell(cell_idx 常量传参)。 /// /// # 边界与前提 /// - `cell_idx` 来自 `ctx.captured_bindings`,在同一模块顶层帧的 `cell_stack` /// 内由声明点的 MAKE_CELL 建好;导出注册点晚于声明点,故 cell 必已存在。 /// /// # 副作用 /// - 依赖运行期 `module_frame_cell(cell_idx)` 取当前字节码帧 cell,改命名空间 /// 条目状态为共享 cell。 fn emit_module_set_cell( &self, ctx: &mut CompileCtx, ns_reg: u32, export_name: &str, cell_idx: u8, ) -> Result<(), String> { let name_reg = self.load_string_const(export_name, ctx); let idx = ctx.add_constant(Constant::Int(cell_idx as i32)); let cell_reg = ctx.alloc_reg(); ctx.inst(Inst::load_const(Operand::Reg(cell_reg), idx)); self.emit_module_call(ctx, "__moduleSetCell", &[ns_reg, name_reg, cell_reg])?; Ok(()) } /// 导出注册:被捕获的源绑定在 live 模块挂共享 cell(闭包写随活读可见), /// 其余回退 `__moduleSet` 快照/写穿路径。 /// /// # 边界与前提 /// - 仅 `module_live_ns_active` 模块激活;非 live 模块恒回退 `__moduleSet`, /// 编译产物与引入 Cell 前逐字节一致。 /// - `source_name` 命中 `module_live_imports`(导入快照)时回退:不得把导入 /// 本地槽误注册为活条目。 /// - 源绑定须在 `captured_bindings` 内且当前作用域可解析(`visible_binding_reg` /// 有值)——块退出后残留的同名 cell 不可见,此时回退快照注册。 /// /// # 副作用 /// - 命中时发 `__moduleSetCell`(条目状态改 Cell);否则发 `__moduleSet`。 fn emit_export_registration( &self, ctx: &mut CompileCtx, ns_reg: u32, exported_name: &str, source_name: &str, value_reg: u32, ) -> Result<(), String> { if ctx.module_live_ns_active && !ctx.module_live_imports.contains_key(source_name) && ctx.visible_binding_reg(source_name).is_some() { if let Some(&cell_idx) = ctx.captured_bindings.get(source_name) { return self.emit_module_set_cell(ctx, ns_reg, exported_name, cell_idx); } } self.emit_module_set(ctx, ns_reg, exported_name, value_reg) } /// 发 `__moduleSetReexport`:注册带 `(dep_path, imported)` 来源身份的再导出。 fn emit_module_set_reexport( &self, ctx: &mut CompileCtx, ns_reg: u32, export_name: &str, value_reg: u32, dep_path: &str, imported: &str, ) -> Result<(), String> { let name_reg = self.load_string_const(export_name, ctx); let path_reg = self.load_string_const(dep_path, ctx); let imported_reg = self.load_string_const(imported, ctx); self.emit_module_call(ctx, "__moduleSetReexport", &[ns_reg, name_reg, value_reg, path_reg, imported_reg])?; Ok(()) } /// 顶层对导出源绑定的写入同步到命名空间:按反演表把新值写入每个导出名。 /// /// # 边界与前提 /// - 仅在模块顶层 live 模块激活:`module_local_export_regs` 只由自导入 ns 模块 /// 填充,嵌套函数 ctx 不继承该表,行为自然为零。 /// - `name` 按当前作用域解析到绑定槽,槽不在表内(未声明名、块级/catch 同名 /// 遮蔽等)时直接返回,不误写同名导出。 /// - 调用方保证 `value_reg` 是写入后的当前值;const 抛错分支不得调用本函数。 /// /// # 副作用 /// - 每个命中导出名发射一次 `__moduleSet` 调用,更新命名空间条目与真实槽值。 pub(crate) fn emit_module_write_through( &self, name: &str, value_reg: u32, ctx: &mut CompileCtx, ) -> Result<(), String> { let Some(ns_reg) = ctx.module_ns_reg else { return Ok(()); }; let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) else { return Ok(()); }; let Some(export_names) = ctx.module_local_export_regs.get(&binding.reg).cloned() else { return Ok(()); }; for export_name in export_names { self.emit_module_set(ctx, ns_reg, &export_name, value_reg)?; } Ok(()) } /// 别名捕获后处理:把源/别名对合并到同一 cell。 /// /// # 边界与前提 /// - `captured_bindings` 是名字级索引;源与别名共用寄存器槽,但捕获分析按 /// 名字给出各自(或仅一方)的 entry。同一源的多个别名须并入同一 cell: /// 声明点的 MAKE_CELL 只按源名发射,未被覆盖的别名 cell 会停留未初始化。 /// - 权威 cell 优先取源名自身的 entry(源被捕获时声明点的 MAKE_CELL 写它); /// 源未被捕获而别名被捕获时取组内别名已分配的 entry,再把源名补进映射。 /// - 两者都未被捕获时读路径直接读源寄存器,天然活值,无需处理。 /// /// # 副作用 /// - 修改 `captured_bindings` 映射;每个名字仍占一个 entry,容量口径不变 /// (`cells_needed` 按名字集大小取,cell 下标可重复,见 `assemble_ir`)。 fn reconcile_alias_captures(&self, ctx: &mut CompileCtx) { let pairs = std::mem::take(&mut ctx.module_alias_pairs); // 以最终基源名为组键统一组内全部名字。逐个 pair 直接覆盖会让同源的多个 // 别名中后处理者把源改指向新 cell,先处理的别名与源分裂成两个 cell。 let mut authority: HashMap = HashMap::new(); for (local, source) in pairs { let source = ctx.scopes.symbols.resolve_alias_base(&source).to_string(); let cell = authority.get(&source).copied().or_else(|| { ctx.captured_bindings .get(source.as_str()) .or_else(|| ctx.captured_bindings.get(local.as_str())) .copied() }); let Some(cell) = cell else { continue }; authority.insert(source.clone(), cell); ctx.captured_bindings.insert(source, cell); ctx.captured_bindings.insert(local, cell); } // cell 下标由名字排序分配,可重复使用;容量按名字集大小取,故每个下标 // 必须落在名字集范围内,否则子函数 upvalue 会索引到未分配的 cell。 debug_assert!( ctx.captured_bindings .values() .all(|&i| (i as usize) < ctx.captured_bindings.len()), "cell 下标须落在 captured_bindings 名字集范围内" ); } fn load_var_reg(&self, name: &str, ctx: &mut CompileCtx) -> Result { let var_reg = ctx.lookup(name)?; let val_reg = ctx.alloc_reg(); // 被捕获绑定只更新 cell,寄存器停留在捕获前的旧值;导出注册须经 cell // 读取当前值,否则命名空间属性固化声明时的快照。 if let Some(&cell_idx) = ctx.captured_bindings.get(name) { if ctx.visible_binding_reg(name).is_some() { ctx.inst(Inst::new( OpCode::CELL_GET, Operand::Reg(val_reg), Operand::Reg(var_reg), Operand::Imm(cell_idx as u16), )); return Ok(val_reg); } } ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(val_reg), Operand::Reg(var_reg), Operand::None)); Ok(val_reg) } /// export 语句 emit:声明照常 + 导出值就地注册到命名空间。 pub(crate) fn emit_module_export_domain( &self, stmt: &Statement, ctx: &mut CompileCtx, ) -> Result, String> { let ns_reg = ctx.module_ns_reg.ok_or_else(|| "export outside module context".to_string())?; match stmt { Statement::ExportNamedDeclaration(exp) => { if let Some(decl) = &exp.declaration { match decl { Declaration::VariableDeclaration(vd) => { self.emit_variable_declaration(vd, ctx)?; for d in &vd.declarations { if let BindingPattern::BindingIdentifier(bi) = &d.id { let name = bi.name.as_str(); let val_reg = self.load_var_reg(name, ctx)?; self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?; self.emit_self_alias_write(ctx, name, val_reg); } } } Declaration::FunctionDeclaration(fd) => { self.emit_function_declaration(fd, ctx)?; if let Some(id) = &fd.id { let name = id.name.as_str(); let val_reg = self.load_var_reg(name, ctx)?; self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?; self.emit_self_alias_write(ctx, name, val_reg); } } Declaration::ClassDeclaration(cl) => { self.emit_class_declaration(cl, ctx)?; if let Some(id) = &cl.id { let name = id.name.as_str(); let val_reg = self.load_var_reg(name, ctx)?; self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?; self.emit_self_alias_write(ctx, name, val_reg); } } _ => return Err("unsupported export declaration".into()), } } else { let dep_source = exp.source.as_ref().map(|src| src.value.to_string()); for spec in &exp.specifiers { let local_name = module_export_name_str(&spec.local); let exported_name = module_export_name_str(&spec.exported); // 有 source:来源身份为 (依赖模块路径, 导入名)。 if let Some(source) = &dep_source { let dep_ns_reg = ctx .module_dep_ns_regs .get(source.as_str()) .copied() .ok_or_else(|| format!("export from unknown module: {source}"))?; let dep_path = ctx .module_dep_paths .get(source.as_str()) .cloned() .ok_or_else(|| format!("export from unknown module: {source}"))?; let name_reg = self.load_string_const(&local_name, ctx); let val_reg = self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?; self.emit_module_set_reexport( ctx, ns_reg, &exported_name, val_reg, &dep_path, &local_name, )?; // 自导入名可能来自 star 转发(占位路径):导出语句执行时 // 就地刷新本地槽,覆盖同模块 body 内导出后读取的形态。 self.emit_self_alias_write(ctx, &exported_name, val_reg); continue; } // 无 source 但局部名是导入绑定:按规范重分类为间接导出,来源为 // (依赖模块路径, 导入名);命名空间导入的导入名为共享哨兵。 if let Some((dep_path, imported)) = ctx.module_import_origins.get(&local_name).cloned() { let val_reg = self.load_var_reg(&local_name, ctx)?; self.emit_module_set_reexport(ctx, ns_reg, &exported_name, val_reg, &dep_path, &imported)?; // 自导入名重分类为间接导出时同样就地刷新占位槽。 self.emit_self_alias_write(ctx, &exported_name, val_reg); continue; } // 本地导出:来源恒为 Local。 let val_reg = self.load_var_reg(&local_name, ctx)?; self.emit_export_registration(ctx, ns_reg, &exported_name, &local_name, val_reg)?; } } } Statement::ExportDefaultDeclaration(exp) => { let (val_reg, source_name) = match &exp.declaration { ExportDefaultDeclarationKind::FunctionDeclaration(fd) => { let reg = self.emit_function_expression(fd, ctx)?; // 具名 default 函数绑定自身 id 名;匿名 default 函数绑定合成 // `*default*` 源名(仅在该绑定已由 self-import 惰性建立时)。 // 声明形态的函数绑定可变(CreateMutableBinding),提升臂已在 // 预声明期预初始化,此处是声明点的赋值。 let binding = fd.id.as_ref().map(|id| id.name.to_string()).or_else(|| { ctx.scopes .symbols .lookup_any(SYNTHETIC_DEFAULT_BINDING) .map(|_| SYNTHETIC_DEFAULT_BINDING.to_string()) }); if let Some(name) = &binding { self.emit_bind_target(name, reg, VariableDeclarationKind::Var, false, false, ctx)?; } if fd.id.is_none() { set_implicit_name_of_last_nested(ctx, DEFAULT_EXPORT_NAME); } // 具名 default 的注册源是该 id 绑定(可重赋),匿名退化为合成名。 (reg, binding.unwrap_or_else(|| SYNTHETIC_DEFAULT_BINDING.to_string())) } ExportDefaultDeclarationKind::ClassDeclaration(cl) => { let reg = self.emit_class_with_binding( cl, ctx, None, cl.id.is_none().then_some(DEFAULT_EXPORT_NAME), )?; if let Some(id) = &cl.id { self.emit_bind_target( id.name.as_str(), reg, VariableDeclarationKind::Const, true, false, ctx, )?; (reg, id.name.to_string()) } else { if ctx.scopes.symbols.lookup_any(SYNTHETIC_DEFAULT_BINDING).is_some() { // 匿名 default 类按规范在求值点初始化合成 `*default*` // 绑定(仅在存在 self-import default 时惰性建立)。 self.emit_bind_target( SYNTHETIC_DEFAULT_BINDING, reg, VariableDeclarationKind::Let, false, false, ctx, )?; } (reg, SYNTHETIC_DEFAULT_BINDING.to_string()) } } other => { let expr = other .as_expression() .ok_or_else(|| "unsupported export default declaration".to_string())?; let reg = if crate::is_anonymous_function_definition(expr) { match strip_parens(expr) { // 匿名类:构造器落名后还会 push 方法子模块,必须经 // implicit_name 写构造器;具名类由 ctor_name 优先。 Expression::ClassExpression(cl) => { self.emit_class_with_binding(cl, ctx, None, Some(DEFAULT_EXPORT_NAME))? } // 函数/生成器/箭头:发射期只 push 一个子模块,末项即目标; // 具名函数表达式已有名,守卫不覆盖。 _ => { let reg = self.emit_expression(expr, ctx)?; set_implicit_name_of_last_nested(ctx, DEFAULT_EXPORT_NAME); reg } } } else { self.emit_expression(expr, ctx)? }; // default 表达式/匿名类的合成源绑定只在存在 self-import default // 时惰性建立;无 self-import 时保持零 IR 变化(不建绑定、不赋值)。 if ctx.scopes.symbols.lookup_any(SYNTHETIC_DEFAULT_BINDING).is_some() { self.emit_bind_target( SYNTHETIC_DEFAULT_BINDING, reg, VariableDeclarationKind::Let, false, false, ctx, )?; } (reg, SYNTHETIC_DEFAULT_BINDING.to_string()) } }; self.emit_export_registration(ctx, ns_reg, DEFAULT_EXPORT_NAME, &source_name, val_reg)?; self.emit_self_alias_write(ctx, DEFAULT_EXPORT_NAME, val_reg); } Statement::ExportAllDeclaration(exp) => { let source = exp.source.value.as_str(); let dep_ns_reg = *ctx .module_dep_ns_regs .get(source) .ok_or_else(|| format!("export * from unknown module: {source}"))?; let dep_path = ctx .module_dep_paths .get(source) .cloned() .ok_or_else(|| format!("export * from unknown module: {source}"))?; if let Some(exported) = &exp.exported { // export * as ns from '...':命名空间再导出,绑定身份用共享哨兵。 let exported_name = module_export_name_str(exported); self.emit_module_set_reexport( ctx, ns_reg, &exported_name, dep_ns_reg, &dep_path, MODULE_NAMESPACE_BINDING, )?; // 自导入的 star-as 名走占位路径:就地刷新为命名空间对象。 self.emit_self_alias_write(ctx, &exported_name, dep_ns_reg); } else { // 来源传播:star 复制按 (dep_path, 绑定) 判同名冲突。 let path_reg = self.load_string_const(&dep_path, ctx); self.emit_module_call(ctx, "__moduleStar", &[ns_reg, dep_ns_reg, path_reg])?; // star 复制后 star 转发的自导入名已就位:就地刷新占位槽, // 覆盖 body 内 star 语句之后立即读取的形态。 self.emit_self_alias_refresh(ctx, ns_reg)?; } } _ => return Err("unsupported module export statement".into()), } Ok(None) } }