mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 补全 star 与再导出路径的自导入别名回写
This commit is contained in:
@@ -561,6 +561,40 @@ pub fn module_set_reexport<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
NativeResult::Ok(JsValue::undefined())
|
NativeResult::Ok(JsValue::undefined())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `__moduleAlias(ns, name, fallback)`:自别名收尾刷新用。命名空间存在该导出时
|
||||||
|
/// 返回其值,否则返回传入的 `fallback`(不抛错):star 未提供该名时占位值原样
|
||||||
|
/// 保留,与现行「星号未提供该名时静默 undefined」行为一致。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - 命名空间无该导出时不抛错(区别于 `__moduleGet` 的 TypeError 与
|
||||||
|
/// `__moduleLinkGet` 的 SyntaxError),缺失臂返回 `fallback` 原值。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 无:只读命名空间属性,不修改条目表。
|
||||||
|
pub fn module_alias<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
|
if args.len() < 4 {
|
||||||
|
return type_error(vm, "__moduleAlias: 3 arguments required");
|
||||||
|
}
|
||||||
|
let ns_val = vm.reg(args[1]);
|
||||||
|
let ns_ptr = match vm.checked_object_ptr(ns_val, "__moduleAlias: target is not an object") {
|
||||||
|
Ok(Some(p)) => p,
|
||||||
|
Ok(None) => return type_error(vm, "__moduleAlias: target is not an object"),
|
||||||
|
Err(e) => return NativeResult::Err(crate::error::create_error(vm, &e)),
|
||||||
|
};
|
||||||
|
let name_val = vm.reg(args[2]);
|
||||||
|
let name_si = vm.property_key_si(name_val);
|
||||||
|
let fallback = vm.reg(args[3]);
|
||||||
|
let obj = unsafe { &*ns_ptr };
|
||||||
|
if vm.get_own_property_slot(obj, name_si).is_some() {
|
||||||
|
match vm.ordinary_get(obj, name_si, ns_val) {
|
||||||
|
Ok(v) => NativeResult::Ok(v),
|
||||||
|
Err(e) => NativeResult::Err(crate::error::create_error(vm, &e)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NativeResult::Ok(fallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `__moduleGet(ns, name)`:读取命名空间导出属性。
|
/// `__moduleGet(ns, name)`:读取命名空间导出属性。
|
||||||
pub fn module_get<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn module_get<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
|
|||||||
@@ -175,8 +175,9 @@ pub struct CompileCtx {
|
|||||||
/// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。
|
/// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。
|
||||||
pub(crate) module_self_import_specs: HashSet<String>,
|
pub(crate) module_self_import_specs: HashSet<String>,
|
||||||
/// 自导入别名:导出名 → 本地绑定槽寄存器(export 语句执行时回写绑定值)。
|
/// 自导入别名:导出名 → 本地绑定槽寄存器(export 语句执行时回写绑定值)。
|
||||||
/// 仅承载无法静态解析源绑定的退化占位路径(star 转发的自导入名)。
|
/// 仅承载无法静态解析源绑定的退化占位路径(star 转发的自导入名);同名多绑定
|
||||||
pub(crate) module_self_aliases: HashMap<String, u32>,
|
/// (如 default 双绑定)经 Vec 并列回写。
|
||||||
|
pub(crate) module_self_aliases: HashMap<String, Vec<u32>>,
|
||||||
/// 自导入别名(本地名,基源绑定名):供别名捕获后处理合并源/别名 cell。
|
/// 自导入别名(本地名,基源绑定名):供别名捕获后处理合并源/别名 cell。
|
||||||
pub(crate) module_alias_pairs: Vec<(String, String)>,
|
pub(crate) module_alias_pairs: Vec<(String, String)>,
|
||||||
/// 标签模板 site 计数器:本编译树内全局唯一(子 ctx 继承父值继续递增)。
|
/// 标签模板 site 计数器:本编译树内全局唯一(子 ctx 继承父值继续递增)。
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
if is_self {
|
if is_self {
|
||||||
let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?;
|
let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?;
|
||||||
ctx.module_self_aliases.insert(imported, alias_reg);
|
ctx.module_self_aliases.entry(imported).or_default().push(alias_reg);
|
||||||
} else {
|
} else {
|
||||||
let name_reg = self.load_string_const(&imported, ctx);
|
let name_reg = self.load_string_const(&imported, ctx);
|
||||||
let val_reg =
|
let val_reg =
|
||||||
@@ -619,7 +619,10 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
if is_self {
|
if is_self {
|
||||||
let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?;
|
let alias_reg = self.emit_self_alias_placeholder(s.local.name.as_str(), ctx)?;
|
||||||
ctx.module_self_aliases.insert(DEFAULT_EXPORT_NAME.to_string(), alias_reg);
|
ctx.module_self_aliases
|
||||||
|
.entry(DEFAULT_EXPORT_NAME.to_string())
|
||||||
|
.or_default()
|
||||||
|
.push(alias_reg);
|
||||||
} else {
|
} else {
|
||||||
let name_reg = self.load_string_const(DEFAULT_EXPORT_NAME, ctx);
|
let name_reg = self.load_string_const(DEFAULT_EXPORT_NAME, ctx);
|
||||||
let val_reg =
|
let val_reg =
|
||||||
@@ -799,6 +802,10 @@ impl Emitter {
|
|||||||
self.emit_statement(stmt, ctx)?;
|
self.emit_statement(stmt, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// —— 自别名收尾刷新:star 复制等跨模块注册路径后占位槽可能仍为旧值,
|
||||||
|
// 封冻命名空间前统一从命名空间非抛出回读兜底。 ——
|
||||||
|
self.emit_self_alias_refresh(ctx, ns_reg)?;
|
||||||
|
|
||||||
// —— 收尾:封冻命名空间并返回(顶层 RETURN 亦终止 run)——
|
// —— 收尾:封冻命名空间并返回(顶层 RETURN 亦终止 run)——
|
||||||
self.emit_module_call(ctx, "__moduleSeal", &[ns_reg])?;
|
self.emit_module_call(ctx, "__moduleSeal", &[ns_reg])?;
|
||||||
if top_level {
|
if top_level {
|
||||||
@@ -888,9 +895,11 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 自导入别名回写:导出名若被本模块 self-import 绑定别名引用,
|
/// 自导入别名回写:导出名若被本模块 self-import 绑定别名引用,
|
||||||
/// export 语句执行时同步把值写回本地绑定槽。
|
/// export 语句执行时同步把值写回本地绑定槽。同名多槽(default 双绑定)
|
||||||
|
/// 逐槽并列回写。
|
||||||
fn emit_self_alias_write(&self, ctx: &mut CompileCtx, export_name: &str, value_reg: u32) {
|
fn emit_self_alias_write(&self, ctx: &mut CompileCtx, export_name: &str, value_reg: u32) {
|
||||||
if let Some(&alias_reg) = ctx.module_self_aliases.get(export_name) {
|
let regs = ctx.module_self_aliases.get(export_name).cloned().unwrap_or_default();
|
||||||
|
for &alias_reg in ®s {
|
||||||
ctx.inst(Inst::new(
|
ctx.inst(Inst::new(
|
||||||
OpCode::STORE_VAR,
|
OpCode::STORE_VAR,
|
||||||
Operand::Reg(alias_reg),
|
Operand::Reg(alias_reg),
|
||||||
@@ -900,9 +909,33 @@ impl Emitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 自导入别名统一刷新:对每个登记的自导入占位名,从命名空间非抛出读回写
|
||||||
|
/// 占位槽(命名空间无该名时保留占位值,不抛错)。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 ®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 转发的自导入名)时,
|
/// 自导入绑定的非别名占位:源绑定无法静态解析(star 转发的自导入名)时,
|
||||||
/// prelude 把局部名绑成已初始化的 undefined 常量槽并登记回写,由 export
|
/// prelude 把局部名绑成已初始化的 undefined 常量槽并登记回写,由 export
|
||||||
/// 语句执行时就地刷新。返回该本地绑定槽寄存器。
|
/// 语句执行时就地刷新,body 收尾再统一从命名空间回读兜底。
|
||||||
|
/// 返回该本地绑定槽寄存器。
|
||||||
fn emit_self_alias_placeholder(&self, local: &str, ctx: &mut CompileCtx) -> Result<u32, String> {
|
fn emit_self_alias_placeholder(&self, local: &str, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||||
let undef_idx = ctx.add_constant(Constant::Undefined);
|
let undef_idx = ctx.add_constant(Constant::Undefined);
|
||||||
let undef_reg = ctx.alloc_reg();
|
let undef_reg = ctx.alloc_reg();
|
||||||
@@ -1132,6 +1165,9 @@ impl Emitter {
|
|||||||
&dep_path,
|
&dep_path,
|
||||||
&local_name,
|
&local_name,
|
||||||
)?;
|
)?;
|
||||||
|
// 自导入名可能来自 star 转发(占位路径):导出语句执行时
|
||||||
|
// 就地刷新本地槽,覆盖同模块 body 内导出后读取的形态。
|
||||||
|
self.emit_self_alias_write(ctx, &exported_name, val_reg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 无 source 但局部名是导入绑定:按规范重分类为间接导出,来源为
|
// 无 source 但局部名是导入绑定:按规范重分类为间接导出,来源为
|
||||||
@@ -1139,6 +1175,8 @@ impl Emitter {
|
|||||||
if let Some((dep_path, imported)) = ctx.module_import_origins.get(&local_name).cloned() {
|
if let Some((dep_path, imported)) = ctx.module_import_origins.get(&local_name).cloned() {
|
||||||
let val_reg = self.load_var_reg(&local_name, ctx)?;
|
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_module_set_reexport(ctx, ns_reg, &exported_name, val_reg, &dep_path, &imported)?;
|
||||||
|
// 自导入名重分类为间接导出时同样就地刷新占位槽。
|
||||||
|
self.emit_self_alias_write(ctx, &exported_name, val_reg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 本地导出:来源恒为 Local。
|
// 本地导出:来源恒为 Local。
|
||||||
@@ -1265,10 +1303,15 @@ impl Emitter {
|
|||||||
&dep_path,
|
&dep_path,
|
||||||
MODULE_NAMESPACE_BINDING,
|
MODULE_NAMESPACE_BINDING,
|
||||||
)?;
|
)?;
|
||||||
|
// 自导入的 star-as 名走占位路径:就地刷新为命名空间对象。
|
||||||
|
self.emit_self_alias_write(ctx, &exported_name, dep_ns_reg);
|
||||||
} else {
|
} else {
|
||||||
// 来源传播:star 复制按 (dep_path, 绑定) 判同名冲突。
|
// 来源传播:star 复制按 (dep_path, 绑定) 判同名冲突。
|
||||||
let path_reg = self.load_string_const(&dep_path, ctx);
|
let path_reg = self.load_string_const(&dep_path, ctx);
|
||||||
self.emit_module_call(ctx, "__moduleStar", &[ns_reg, dep_ns_reg, path_reg])?;
|
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()),
|
_ => return Err("unsupported module export statement".into()),
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ pub fn bind_global(core: &Arc<KernelCore>, session: &KernelSession, global: &mut
|
|||||||
oxide_builtins::module::module_set_reexport::<crate::vm::Vm> as *const (),
|
oxide_builtins::module::module_set_reexport::<crate::vm::Vm> as *const (),
|
||||||
5,
|
5,
|
||||||
),
|
),
|
||||||
|
("__moduleAlias", oxide_builtins::module::module_alias::<crate::vm::Vm> as *const (), 3),
|
||||||
("__moduleGet", oxide_builtins::module::module_get::<crate::vm::Vm> as *const (), 2),
|
("__moduleGet", oxide_builtins::module::module_get::<crate::vm::Vm> as *const (), 2),
|
||||||
(
|
(
|
||||||
"__moduleLinkGet",
|
"__moduleLinkGet",
|
||||||
|
|||||||
Reference in New Issue
Block a user