mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 19:21:11 +08:00
feat: 跨模块可重赋导出活读
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
use oxide_parser::{Expression, Statement};
|
||||
use oxide_parser::{Declaration, ExportDefaultDeclarationKind, Expression, Statement};
|
||||
|
||||
use super::collect_fn_param_names;
|
||||
use super::names::collect_own_binding_names;
|
||||
@@ -103,6 +103,60 @@ pub(crate) fn collect_captured_stmt(stmt: &Statement, own: &HashSet<String>, out
|
||||
}
|
||||
collect_class_capture_names(&cd.body, own, &class_shadow, out);
|
||||
}
|
||||
// export 包裹的变量/函数/类声明:捕获分析须下探声明体,否则被导出函数体内
|
||||
// 引用模块绑定(含自引用)不会被识别为捕获,闭包内读写退化为隐式全局。
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(decl) = &exp.declaration {
|
||||
match decl {
|
||||
Declaration::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
collect_captured_binding_keys(&d.id, own, out);
|
||||
if let Some(init) = &d.init {
|
||||
collect_captured_expr(init, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Declaration::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
collect_fn_default_captured(&fd.params, own, out);
|
||||
let mut fn_shadow = HashSet::new();
|
||||
fn_shadow.extend(collect_fn_param_names(&fd.params));
|
||||
fn_shadow.extend(collect_own_binding_names(&[], body));
|
||||
collect_capture_names_shadowed(body, own, &fn_shadow, out);
|
||||
}
|
||||
Declaration::ClassDeclaration(cd) => {
|
||||
let mut class_shadow = HashSet::new();
|
||||
if let Some(id) = &cd.id {
|
||||
class_shadow.insert(id.name.as_str().to_string());
|
||||
}
|
||||
collect_class_capture_names(&cd.body, own, &class_shadow, out);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
|
||||
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
collect_fn_default_captured(&fd.params, own, out);
|
||||
let mut fn_shadow = HashSet::new();
|
||||
fn_shadow.extend(collect_fn_param_names(&fd.params));
|
||||
fn_shadow.extend(collect_own_binding_names(&[], body));
|
||||
collect_capture_names_shadowed(body, own, &fn_shadow, out);
|
||||
}
|
||||
ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
|
||||
let mut class_shadow = HashSet::new();
|
||||
if let Some(id) = &cd.id {
|
||||
class_shadow.insert(id.name.as_str().to_string());
|
||||
}
|
||||
collect_class_capture_names(&cd.body, own, &class_shadow, out);
|
||||
}
|
||||
other => {
|
||||
if let Some(e) = other.as_expression() {
|
||||
collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
},
|
||||
Statement::ExpressionStatement(es) => collect_captured_expr(&es.expression, own, out),
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
|
||||
@@ -149,6 +149,19 @@ pub struct CompileCtx {
|
||||
/// 非自导入的导入局部名 → (依赖模块规范路径, 导入名)。命名空间导入的导入名为
|
||||
/// `oxide_kernel::MODULE_NAMESPACE_BINDING`;再导出据此重分类为间接导出。
|
||||
pub(crate) module_import_origins: HashMap<String, (String, String)>,
|
||||
/// 依赖 source 字符串 → 依赖模块是否含可重赋导出(`compile_js_dep` 回传;
|
||||
/// Json/Text 数据模块恒 false)。导入方据此把命名/默认导入登记为活读。
|
||||
pub(crate) module_dep_reassignable: HashMap<String, bool>,
|
||||
/// 导入本地名 → (依赖命名空间对象寄存器, 导出名):可重赋依赖的命名/默认导入
|
||||
/// 活读映射。顶层读点据此改发 `__moduleGet` 活读;仅模块顶层 ctx 填充,嵌套
|
||||
/// 函数 ctx 不继承,闭包内读退化为链接期快照。
|
||||
pub(crate) module_live_imports: HashMap<String, (u32, String)>,
|
||||
/// 本模块是否含可重赋导出。仅在依赖模块(`top_level == false`)且捕获/写穿
|
||||
/// 消费者需要时置真;入口模块恒假,保证纯导出入口 IR 零变化。
|
||||
pub(crate) module_live_dep: bool,
|
||||
/// live 命名空间激活:自导入 ns 或本模块含可重赋导出时为真。写穿反演与
|
||||
/// 导出预注册据此发射;非 live 模块编译产物逐字节不变。
|
||||
pub(crate) module_live_ns_active: bool,
|
||||
/// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。
|
||||
pub(crate) module_self_import_specs: HashSet<String>,
|
||||
/// 自导入别名:导出名 → 本地绑定槽寄存器(export 语句执行时回写绑定值)。
|
||||
@@ -240,6 +253,10 @@ impl CompileCtx {
|
||||
module_dep_ns_regs: HashMap::new(),
|
||||
module_dep_paths: HashMap::new(),
|
||||
module_import_origins: HashMap::new(),
|
||||
module_dep_reassignable: HashMap::new(),
|
||||
module_live_imports: HashMap::new(),
|
||||
module_live_dep: false,
|
||||
module_live_ns_active: false,
|
||||
module_self_import_specs: HashSet::new(),
|
||||
module_self_aliases: HashMap::new(),
|
||||
module_alias_pairs: Vec::new(),
|
||||
|
||||
@@ -10,8 +10,18 @@ use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
|
||||
impl Emitter {
|
||||
/// 静态标识符读取:upvalue / 被捕获 cell / 全局槽。
|
||||
/// 静态标识符读取:可重赋依赖导入活读 / upvalue / 被捕获 cell / 全局槽。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 活读映射仅模块顶层 ctx 填充:嵌套函数内读 import 名仍走链接期快照
|
||||
/// (`current_upvalue_captures` 不在此列,闭包内不继承映射)。
|
||||
fn emit_static_identifier_read(&self, name: &str, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
// 可重赋依赖的命名/默认导入:读点直接查依赖命名空间当前值,跟随源模块重赋。
|
||||
if let Some((dep_ns, exported)) = ctx.module_live_imports.get(name).cloned() {
|
||||
let name_reg = self.load_string_const(&exported, ctx);
|
||||
return self.emit_module_call(ctx, "__moduleGet", &[dep_ns, name_reg]);
|
||||
}
|
||||
|
||||
for (uv_idx, up) in ctx.current_upvalue_captures.iter().enumerate() {
|
||||
if up.name == name {
|
||||
let r = ctx.alloc_reg();
|
||||
|
||||
+175
-37
@@ -1,10 +1,11 @@
|
||||
//! 模块编译:import/export 解析、依赖加载(递归)、快照式链接与命名空间。
|
||||
//!
|
||||
//! 普通依赖的导入绑定在 prelude 一次性链接为快照;自导入(`import ... from
|
||||
//! 自身`)的局部名解析为本模块源绑定的活别名,TDZ/提升/活值/不可变四语义全部
|
||||
//! 委托源绑定。`export` 语句就地注册导出值。
|
||||
//! 未支持:跨模块 live binding(导入绑定不跟随依赖模块值变化)、defer(延迟
|
||||
//! 求值)、source-phase;star 转发的自导入名退化为链接期快照;循环导入在编译期跳过。
|
||||
//! 普通依赖的导入绑定在 prelude 链接:依赖含可重赋导出时顶层读点经
|
||||
//! `__moduleGet` 活读,其余退化为快照;被闭包捕获的导出挂共享 cell,闭包内写
|
||||
//! 随活读可见。自导入(`import ... from 自身`)的局部名解析为本模块源绑定的活
|
||||
//! 别名,TDZ/提升/活值/不可变四语义全部委托源绑定。`export` 语句就地注册导出值。
|
||||
//! 未支持:嵌套闭包内读 import 名(仍为链接期快照)、defer(延迟求值)、
|
||||
//! source-phase;star 转发与经再导出链的活值仍为快照;循环导入在编译期跳过。
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::Path;
|
||||
@@ -248,6 +249,62 @@ fn module_var_scoped_export_names(body: &[Statement]) -> HashSet<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 {
|
||||
@@ -436,14 +493,15 @@ impl Emitter {
|
||||
return Err(format!("circular module import not supported: {}", resolved.path));
|
||||
}
|
||||
path_stack.push(resolved.path.clone());
|
||||
let dep_ir = match resolved.kind {
|
||||
let (dep_ir, dep_reassignable) = match resolved.kind {
|
||||
ModuleKind::Js => self.compile_js_dep(&resolved, loader, path_stack)?,
|
||||
ModuleKind::Json => self.compile_data_dep("json", &resolved.source)?,
|
||||
ModuleKind::Text => self.compile_data_dep("text", &resolved.source)?,
|
||||
ModuleKind::Json => (self.compile_data_dep("json", &resolved.source)?, false),
|
||||
ModuleKind::Text => (self.compile_data_dep("text", &resolved.source)?, false),
|
||||
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));
|
||||
self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?
|
||||
@@ -468,6 +526,9 @@ impl Emitter {
|
||||
// 导出名 → 本模块源绑定名: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;
|
||||
@@ -517,6 +578,12 @@ impl Emitter {
|
||||
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) => {
|
||||
@@ -563,6 +630,13 @@ impl Emitter {
|
||||
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) => {
|
||||
@@ -591,11 +665,16 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
// —— 写穿反演:源绑定槽寄存器 → 导出名集合。仅 live 模块(自导入 ns)填充:
|
||||
// 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 has_self_ns_import {
|
||||
if live_active {
|
||||
let mut pairs: Vec<(&String, &String)> =
|
||||
export_name_map.iter().map(|(exported, source)| (source, exported)).collect();
|
||||
pairs.sort();
|
||||
@@ -611,7 +690,7 @@ impl Emitter {
|
||||
// 按名序预注册全部本地导出名,使自导入 ns 在读点先观察到未初始化状态。
|
||||
// var/函数类导出(VarScopedDeclarations)在实例化期即初始化为 undefined,
|
||||
// lexical/class 保持未初始化(TDZ)。 ——
|
||||
if has_self_ns_import {
|
||||
if live_active {
|
||||
let var_scoped = module_var_scoped_export_names(body);
|
||||
let mut export_names: Vec<String> = own_export_names.into_iter().collect();
|
||||
export_names.sort();
|
||||
@@ -709,10 +788,17 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 编译 JS 依赖模块(递归)。
|
||||
/// 编译 JS 依赖模块(递归),回传 IR 与「是否含可重赋导出」标志。
|
||||
///
|
||||
/// # 边界与前提
|
||||
/// - 标志取自依赖 ctx 的 `module_live_dep`;入口模块不参与,依赖模块恒按
|
||||
/// `!top_level` 判定,故 const-only 依赖回传 false。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 导入方据标志决定是否登记活读映射;标志不改变本模块 IR。
|
||||
fn compile_js_dep(
|
||||
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader, path_stack: &mut Vec<String>,
|
||||
) -> Result<IRFunction, String> {
|
||||
) -> Result<(IRFunction, bool), String> {
|
||||
let alloc = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse_module(&alloc, &resolved.source).map_err(|errs| {
|
||||
format!(
|
||||
@@ -725,7 +811,8 @@ impl Emitter {
|
||||
// 依赖模块经 parse_module 解析,顶层恒严格模式。
|
||||
ctx.is_strict = true;
|
||||
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx, false)?;
|
||||
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
||||
let reassignable = ctx.module_live_dep;
|
||||
Ok((ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None), reassignable))
|
||||
}
|
||||
|
||||
/// 编译数据模块(json/text):body 仅为 __moduleData 调用 + RETURN。
|
||||
@@ -759,7 +846,7 @@ impl Emitter {
|
||||
Ok(result_reg)
|
||||
}
|
||||
|
||||
fn load_string_const(&self, s: &str, ctx: &mut CompileCtx) -> u32 {
|
||||
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));
|
||||
@@ -803,6 +890,53 @@ impl Emitter {
|
||||
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,
|
||||
@@ -919,7 +1053,7 @@ impl Emitter {
|
||||
if let BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let name = bi.name.as_str();
|
||||
let val_reg = self.load_var_reg(name, ctx)?;
|
||||
self.emit_module_set(ctx, ns_reg, name, val_reg)?;
|
||||
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
|
||||
self.emit_self_alias_write(ctx, name, val_reg);
|
||||
}
|
||||
}
|
||||
@@ -929,7 +1063,7 @@ impl Emitter {
|
||||
if let Some(id) = &fd.id {
|
||||
let name = id.name.as_str();
|
||||
let val_reg = self.load_var_reg(name, ctx)?;
|
||||
self.emit_module_set(ctx, ns_reg, name, val_reg)?;
|
||||
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
|
||||
self.emit_self_alias_write(ctx, name, val_reg);
|
||||
}
|
||||
}
|
||||
@@ -938,7 +1072,7 @@ impl Emitter {
|
||||
if let Some(id) = &cl.id {
|
||||
let name = id.name.as_str();
|
||||
let val_reg = self.load_var_reg(name, ctx)?;
|
||||
self.emit_module_set(ctx, ns_reg, name, val_reg)?;
|
||||
self.emit_export_registration(ctx, ns_reg, name, name, val_reg)?;
|
||||
self.emit_self_alias_write(ctx, name, val_reg);
|
||||
}
|
||||
}
|
||||
@@ -982,12 +1116,12 @@ impl Emitter {
|
||||
}
|
||||
// 本地导出:来源恒为 Local。
|
||||
let val_reg = self.load_var_reg(&local_name, ctx)?;
|
||||
self.emit_module_set(ctx, ns_reg, &exported_name, val_reg)?;
|
||||
self.emit_export_registration(ctx, ns_reg, &exported_name, &local_name, val_reg)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => {
|
||||
let val_reg = match &exp.declaration {
|
||||
let (val_reg, source_name) = match &exp.declaration {
|
||||
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
let reg = self.emit_function_expression(fd, ctx)?;
|
||||
// 具名 default 函数绑定自身 id 名;匿名 default 函数绑定合成
|
||||
@@ -1000,13 +1134,14 @@ impl Emitter {
|
||||
.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 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);
|
||||
}
|
||||
reg
|
||||
// 具名 default 的注册源是该 id 绑定(可重赋),匿名退化为合成名。
|
||||
(reg, binding.unwrap_or_else(|| SYNTHETIC_DEFAULT_BINDING.to_string()))
|
||||
}
|
||||
ExportDefaultDeclarationKind::ClassDeclaration(cl) => {
|
||||
let reg = self.emit_class_with_binding(
|
||||
@@ -1024,19 +1159,22 @@ impl Emitter {
|
||||
false,
|
||||
ctx,
|
||||
)?;
|
||||
} 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, 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())
|
||||
}
|
||||
reg
|
||||
}
|
||||
other => {
|
||||
let expr = other
|
||||
@@ -1072,10 +1210,10 @@ impl Emitter {
|
||||
ctx,
|
||||
)?;
|
||||
}
|
||||
reg
|
||||
(reg, SYNTHETIC_DEFAULT_BINDING.to_string())
|
||||
}
|
||||
};
|
||||
self.emit_module_set(ctx, ns_reg, DEFAULT_EXPORT_NAME, val_reg)?;
|
||||
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) => {
|
||||
|
||||
Reference in New Issue
Block a user