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

1470 lines
77 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.
//! 模块编译: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<ResolvedModule, String>;
}
/// `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<Box<'_, WithClause<'_>>>) -> 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<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) => {
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<String> {
let mut var_locals: HashSet<String> = 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<String, String>) -> 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<String>) -> HashMap<String, String> {
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<IRFunction, String> {
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<String>, 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<String, DepPhase> = HashMap::new();
let mut eager_order: Vec<String> = Vec::new();
let mut defer_order: Vec<String> = 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<String> = 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<String> = 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<String> = 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, 0));
} else {
ctx.inst(Inst::ret(Operand::Reg(ns_reg), 0, 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<String>,
) -> Result<(IRFunction, bool, HashSet<String>, HashSet<String>), 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<String>, var_scoped: &HashSet<String>,
) -> 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<IRFunction, String> {
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, 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<u32, String> {
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 &regs {
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<String> = 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 &regs {
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<u32, String> {
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<String, u8> = 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<u32, String> {
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<Option<u32>, 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)
}
}