mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: emit 模块编译(快照式链接:依赖子模块闭包 + import/export 域)
- emit_program_module:模块顶层编译(is_global_scope=false,顶层 this undefined 由 VM 按标志绑定) - emit_module_into_ctx:预声明/闭包分析识别 export 包裹声明与 import 绑定 - 依赖收集:import/re-export/star 的 source 去重、循环检测、json/text 数据模块 - 导入绑定初始化:__moduleLinkGet 链接期检查;self-import 别名语义(export 处回写) - export 域:声明/重导出/export */export default 就地注册命名空间 - re-export 链接检查移至 prelude(先于 body 求值) - emit_module_call 参数打包连续寄存器(CALL_NATIVE 契约) - CompileCtx 增 module_ns_reg/module_dep_ns_regs/self-import 映射 - 拆分 declaration helper(export 声明复用);function/class 表达式 emitter 提升可见性
This commit is contained in:
@@ -8,6 +8,7 @@ description = "OxideJS - AST to IR emit pass"
|
||||
|
||||
[dependencies]
|
||||
oxide_parser = { path = "../oxide_parser" }
|
||||
oxc_allocator.workspace = true
|
||||
oxide_bytecode = { path = "../oxide_bytecode" }
|
||||
oxide_ir = { path = "../oxide_ir" }
|
||||
oxide_log = { path = "../oxide_log" }
|
||||
|
||||
@@ -86,6 +86,60 @@ impl Emitter {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
// import 绑定是模块作用域 const 绑定,须计入 own_bindings 供
|
||||
// 嵌套函数 cell 捕获。
|
||||
Statement::ImportDeclaration(imp) => {
|
||||
if let Some(specifiers) = &imp.specifiers {
|
||||
for sp in specifiers {
|
||||
match sp {
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportSpecifier(s) => {
|
||||
out.insert(s.local.name.to_string());
|
||||
}
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
|
||||
out.insert(s.local.name.to_string());
|
||||
}
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
|
||||
out.insert(s.local.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(decl) = &exp.declaration {
|
||||
match decl {
|
||||
oxide_parser::Declaration::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
self.collect_binding_pattern_names(&d.id, out);
|
||||
}
|
||||
}
|
||||
oxide_parser::Declaration::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::Declaration::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
|
||||
oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
Statement::BlockStatement(b) => self.collect_decl_names_stmt(&b.body, out),
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(&is.consequent), out);
|
||||
@@ -259,6 +313,58 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(decl) = &exp.declaration {
|
||||
match decl {
|
||||
oxide_parser::Declaration::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.collect_capture_names_expr(init, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
oxide_parser::Declaration::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] =
|
||||
fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fd.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_fn_default_names(&fd.params, ref_set, shadow, out);
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
oxide_parser::Declaration::ClassDeclaration(cd) => {
|
||||
let mut class_shadow = shadow.clone();
|
||||
if let Some(id) = &cd.id {
|
||||
class_shadow.insert(id.name.as_str().to_string());
|
||||
}
|
||||
self.collect_class_capture_names(&cd.body, ref_set, &class_shadow, out);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
|
||||
oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fd.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_fn_default_names(&fd.params, ref_set, shadow, out);
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
|
||||
let mut class_shadow = shadow.clone();
|
||||
if let Some(id) = &cd.id {
|
||||
class_shadow.insert(id.name.as_str().to_string());
|
||||
}
|
||||
self.collect_class_capture_names(&cd.body, ref_set, &class_shadow, out);
|
||||
}
|
||||
other => {
|
||||
if let Some(e) = other.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
},
|
||||
Statement::ThrowStatement(ts) => self.collect_capture_names_expr(&ts.argument, ref_set, shadow, out),
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.collect_capture_names_expr(&sw.discriminant, ref_set, shadow, out);
|
||||
|
||||
@@ -198,6 +198,14 @@ pub struct CompileCtx {
|
||||
/// let/const 循环变量每迭代 fresh cell,update 写寄存器(不污染本迭代闭包
|
||||
/// 捕获的 cell),下一迭代 fresh 从寄存器拷入新 cell。
|
||||
pub(crate) register_update_names: Vec<String>,
|
||||
/// 模块编译上下文:当前模块命名空间对象寄存器(`__moduleObject` 返回值)。
|
||||
pub(crate) module_ns_reg: Option<u32>,
|
||||
/// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。
|
||||
pub(crate) module_dep_ns_regs: HashMap<String, u32>,
|
||||
/// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。
|
||||
pub(crate) module_self_import_specs: HashSet<String>,
|
||||
/// 自导入别名:导出名 → 本地绑定槽寄存器(export 语句执行时回写绑定值)。
|
||||
pub(crate) module_self_aliases: HashMap<String, u32>,
|
||||
}
|
||||
|
||||
/// 函数体编译上下文:决定 `this`/`super` 绑定与参数前导(prologue)形态。
|
||||
@@ -295,6 +303,10 @@ impl CompileCtx {
|
||||
with_stack: Vec::new(),
|
||||
open_try_handlers: Vec::new(),
|
||||
register_update_names: Vec::new(),
|
||||
module_ns_reg: None,
|
||||
module_dep_ns_regs: HashMap::new(),
|
||||
module_self_import_specs: HashSet::new(),
|
||||
module_self_aliases: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +608,7 @@ impl CompileCtx {
|
||||
|
||||
/// 组装 IRFunction(两出口共用),take 走编译产物状态。
|
||||
/// `parent_ctx` 用于补全 upvalue_captures 的 enclosing_reg(父符号表在父 emit 完成后完整)。
|
||||
fn assemble_ir(&mut self, param_layout: oxide_ir::ParamLayout, parent_ctx: Option<&CompileCtx>) -> IRFunction {
|
||||
pub(crate) fn assemble_ir(&mut self, param_layout: oxide_ir::ParamLayout, parent_ctx: Option<&CompileCtx>) -> IRFunction {
|
||||
let upvalue_captures = self
|
||||
.current_upvalue_captures
|
||||
.iter()
|
||||
@@ -1250,6 +1262,9 @@ impl Emitter {
|
||||
Statement::ContinueStatement(c) => self.emit_continue_statement(c, ctx),
|
||||
Statement::LabeledStatement(ls) => self.emit_labeled_statement(ls, ctx),
|
||||
Statement::WithStatement(_) => self.emit_with_domain(stmt, ctx),
|
||||
Statement::ExportNamedDeclaration(_)
|
||||
| Statement::ExportDefaultDeclaration(_)
|
||||
| Statement::ExportAllDeclaration(_) => self.emit_module_export_domain(stmt, ctx),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ impl Emitter {
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
pub(crate) fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
// 函数表达式:编译函数体为子模块,create_closure 实例化闭包
|
||||
let mut param_names = Vec::new();
|
||||
for (idx, param) in fe.params.items.iter().enumerate() {
|
||||
@@ -102,7 +102,7 @@ impl Emitter {
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn emit_class_expression(&self, class: &Class, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
pub(crate) fn emit_class_expression(&self, class: &Class, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
self.emit_class(class, ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
pub mod class;
|
||||
pub mod closure;
|
||||
pub mod module;
|
||||
pub mod emit;
|
||||
mod emit_log;
|
||||
pub mod emit_ctx;
|
||||
|
||||
@@ -0,0 +1,561 @@
|
||||
//! 模块编译:import/export 解析、依赖加载(递归)、快照式链接与命名空间。
|
||||
//!
|
||||
//! 快照式链接:依赖模块先整体求值(`__moduleEval`)并返回命名空间对象,
|
||||
//! 导入绑定在 prelude 一次性初始化;`export` 语句就地注册导出值。
|
||||
//! live binding / defer / source-phase 语义留待后续轮次(循环导入在编译期跳过)。
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::path::Path;
|
||||
|
||||
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, ImportAttributeKey, ImportDeclarationSpecifier,
|
||||
ModuleExportName, Statement, VariableDeclarationKind, WithClause,
|
||||
};
|
||||
|
||||
/// 数据模块种类(非 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,
|
||||
}
|
||||
|
||||
/// 模块加载器:由调用方(test262 runner / CLI)提供文件解析。
|
||||
pub trait ModuleSourceLoader {
|
||||
fn resolve(
|
||||
&mut self, base_dir: &str, specifier: &str, attributes: &[(&str, &str)],
|
||||
) -> Result<ResolvedModule, String>;
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
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".to_string());
|
||||
}
|
||||
Statement::ExportAllDeclaration(exp) => {
|
||||
if let Some(exported) = &exp.exported {
|
||||
names.insert(module_export_name_str(exported));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
names
|
||||
}
|
||||
|
||||
fn is_hoisted_function_decl(stmt: &Statement) -> bool {
|
||||
match stmt {
|
||||
Statement::FunctionDeclaration(_) => true,
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
matches!(&exp.declaration, Some(Declaration::FunctionDeclaration(_)))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl Emitter {
|
||||
/// 编译 ES module:顶层 body + 递归依赖。
|
||||
/// `module_path` 为模块文件的规范路径(依赖解析基准 = 其父目录)。
|
||||
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());
|
||||
let mut ctx = CompileCtx::new();
|
||||
// 模块顶层 var/function 不写全局对象(模块作用域绑定)。
|
||||
ctx.is_global_scope = false;
|
||||
let mut path_stack = vec![module_path.to_string()];
|
||||
self.emit_module_into_ctx(program, module_path, loader, &mut path_stack, &mut ctx)?;
|
||||
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
||||
}
|
||||
|
||||
/// 模块体 emit(顶层与依赖模块共用入口)。
|
||||
#[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,
|
||||
) -> Result<(), String> {
|
||||
let body = &program.body;
|
||||
|
||||
// —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)——
|
||||
self.predeclare_function_declarations(body, ctx);
|
||||
self.pre_register_builtin_references(body, ctx);
|
||||
self.predeclare_var_declarations(body, ctx);
|
||||
self.predeclare_lexical_declarations(body, ctx);
|
||||
|
||||
// 闭包捕获分析(import 绑定名纳入 own_bindings,供嵌套函数 cell 捕获)。
|
||||
ctx.own_bindings = self.collect_own_binding_names(&[], body);
|
||||
ctx.captured_bindings = self.collect_captured_bindings(body, &[], &ctx.own_bindings);
|
||||
|
||||
// —— 模块命名空间对象 ——
|
||||
let ns_reg = self.emit_module_call(ctx, "__moduleObject", &[])?;
|
||||
ctx.module_ns_reg = Some(ns_reg);
|
||||
|
||||
// —— 依赖收集(import + re-export/star 的 source,按首次出现去重)——
|
||||
let base_dir = Path::new(module_path)
|
||||
.parent()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.unwrap_or_default();
|
||||
let mut deps: Vec<(String, Vec<(String, String)>)> = Vec::new();
|
||||
for stmt in body {
|
||||
let (spec, attrs) = match stmt {
|
||||
Statement::ImportDeclaration(imp) => {
|
||||
(imp.source.value.to_string(), module_attributes(&imp.with_clause))
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(src) = &exp.source {
|
||||
(src.value.to_string(), module_attributes(&exp.with_clause))
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Statement::ExportAllDeclaration(exp) => {
|
||||
(exp.source.value.to_string(), module_attributes(&exp.with_clause))
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
if !deps.iter().any(|(s, _)| *s == spec) {
|
||||
deps.push((spec, attrs));
|
||||
}
|
||||
}
|
||||
|
||||
// —— 编译并求值依赖 ——
|
||||
for (spec, attrs) in deps {
|
||||
let attr_refs: Vec<(&str, &str)> = attrs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
|
||||
let resolved = loader.resolve(&base_dir, &spec, &attr_refs)?;
|
||||
let dep_ns_reg = if resolved.path == module_path {
|
||||
// 自导入:读自身命名空间(依赖即本模块,勿递归)。
|
||||
ns_reg
|
||||
} else {
|
||||
if path_stack.iter().any(|p| *p == resolved.path) {
|
||||
return Err(format!("circular module import not supported: {}", resolved.path));
|
||||
}
|
||||
path_stack.push(resolved.path.clone());
|
||||
let dep_ir = 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::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));
|
||||
self.emit_module_call(ctx, "__moduleEval", &[fn_reg])?
|
||||
};
|
||||
ctx.module_dep_ns_regs.insert(spec.clone(), dep_ns_reg);
|
||||
if resolved.path == module_path {
|
||||
// 自导入:绑定走别名语义(源导出在 body 执行中才就绪),
|
||||
// 不能像普通依赖那样链接期快照。
|
||||
ctx.module_self_import_specs.insert(spec.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// —— 导入绑定初始化(const 语义;命名空间绑定直接引用 ns 对象)——
|
||||
let own_export_names = module_own_export_names(body);
|
||||
// export * from 'x'(无命名再导出)会把依赖的全部导出转发给自身:
|
||||
// self-import 的名称可能来自 star,编译期无法静态判定,校验放宽。
|
||||
let has_unnamed_star = body
|
||||
.iter()
|
||||
.any(|s| matches!(s, Statement::ExportAllDeclaration(e) if e.exported.is_none()));
|
||||
// 自导入(import from 自身)的绑定在 body 执行中由 export 语句回写:
|
||||
// prelude 先初始化为 undefined(规范:实例化后未求值前 var 源绑定为
|
||||
// undefined),并登记 导出名 → 本地绑定槽 供回写。
|
||||
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);
|
||||
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 {
|
||||
if !own_export_names.contains(&imported) && !has_unnamed_star {
|
||||
return Err(format!(
|
||||
"requested module export is not exported: {imported}"
|
||||
));
|
||||
}
|
||||
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(
|
||||
s.local.name.as_str(), undef_reg, VariableDeclarationKind::Const, true,
|
||||
false, ctx,
|
||||
)?;
|
||||
if let Ok(reg) = ctx.lookup(s.local.name.as_str()) {
|
||||
ctx.module_self_aliases.insert(imported, 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,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
|
||||
if is_self {
|
||||
if !own_export_names.contains("default") {
|
||||
return Err("requested module export is not exported: default".into());
|
||||
}
|
||||
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(
|
||||
s.local.name.as_str(), undef_reg, VariableDeclarationKind::Const, true,
|
||||
false, ctx,
|
||||
)?;
|
||||
if let Ok(reg) = ctx.lookup(s.local.name.as_str()) {
|
||||
ctx.module_self_aliases.insert("default".to_string(), reg);
|
||||
}
|
||||
} else {
|
||||
let name_reg = self.load_string_const("default", 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,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
|
||||
// 命名空间绑定引用 ns 对象本身:自导入时同一对象,
|
||||
// body 执行后导出自然可见。
|
||||
self.emit_bind_target(
|
||||
s.local.name.as_str(), dep_ns_reg, VariableDeclarationKind::Const, true, false,
|
||||
ctx,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// —— re-export(export { x } from 'mod')链接检查:实例化期解析,须先于
|
||||
// body 求值($DONOTEVALUATE 等断言依赖链接错误先抛)——
|
||||
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 处理)——
|
||||
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)?;
|
||||
}
|
||||
|
||||
// —— 收尾:封冻命名空间并返回(顶层 RETURN 亦终止 run)——
|
||||
self.emit_module_call(ctx, "__moduleSeal", &[ns_reg])?;
|
||||
ctx.inst(Inst::new(OpCode::RETURN, Operand::Reg(ns_reg), Operand::None, Operand::None));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 编译 JS 依赖模块(递归)。
|
||||
fn compile_js_dep(
|
||||
&self, resolved: &ResolvedModule, loader: &mut dyn ModuleSourceLoader,
|
||||
path_stack: &mut Vec<String>,
|
||||
) -> Result<IRFunction, 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;
|
||||
self.emit_module_into_ctx(&program, &resolved.path, loader, path_stack, &mut ctx)?;
|
||||
Ok(ctx.assemble_ir(ParamLayout { base: 0, count: 0 }, None))
|
||||
}
|
||||
|
||||
/// 编译数据模块(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::new(OpCode::RETURN, Operand::Reg(val_reg), Operand::None, Operand::None));
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/// 自导入别名回写:导出名若被本模块 self-import 绑定别名引用,
|
||||
/// export 语句执行时同步把值写回本地绑定槽。
|
||||
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) {
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::STORE_VAR,
|
||||
Operand::Reg(alias_reg),
|
||||
Operand::Reg(value_reg),
|
||||
Operand::None,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
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();
|
||||
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_module_set(ctx, ns_reg, 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_module_set(ctx, ns_reg, 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_module_set(ctx, ns_reg, name, val_reg)?;
|
||||
self.emit_self_alias_write(ctx, name, val_reg);
|
||||
}
|
||||
}
|
||||
_ => return Err("unsupported export declaration".into()),
|
||||
}
|
||||
} else {
|
||||
let dep_ns_opt = exp.source.as_ref().map(|src| {
|
||||
ctx.module_dep_ns_regs.get(src.value.as_str()).copied()
|
||||
});
|
||||
for spec in &exp.specifiers {
|
||||
let local_name = module_export_name_str(&spec.local);
|
||||
let exported_name = module_export_name_str(&spec.exported);
|
||||
let val_reg = match dep_ns_opt {
|
||||
Some(Some(dep_ns_reg)) => {
|
||||
let name_reg = self.load_string_const(&local_name, ctx);
|
||||
self.emit_module_call(ctx, "__moduleLinkGet", &[dep_ns_reg, name_reg])?
|
||||
}
|
||||
Some(None) => {
|
||||
return Err(format!(
|
||||
"export from unknown module: {}",
|
||||
exp.source.as_ref().unwrap().value
|
||||
))
|
||||
}
|
||||
None => self.load_var_reg(&local_name, ctx)?,
|
||||
};
|
||||
self.emit_module_set(ctx, ns_reg, &exported_name, val_reg)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => {
|
||||
let val_reg = match &exp.declaration {
|
||||
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
let reg = self.emit_function_expression(fd, ctx)?;
|
||||
if let Some(id) = &fd.id {
|
||||
self.emit_bind_target(
|
||||
id.name.as_str(), reg, VariableDeclarationKind::Const, true, false, ctx,
|
||||
)?;
|
||||
}
|
||||
reg
|
||||
}
|
||||
ExportDefaultDeclarationKind::ClassDeclaration(cl) => {
|
||||
let reg = self.emit_class_expression(cl, ctx)?;
|
||||
if let Some(id) = &cl.id {
|
||||
self.emit_bind_target(
|
||||
id.name.as_str(), reg, VariableDeclarationKind::Const, true, false, ctx,
|
||||
)?;
|
||||
}
|
||||
reg
|
||||
}
|
||||
other => {
|
||||
let expr = other
|
||||
.as_expression()
|
||||
.ok_or_else(|| "unsupported export default declaration".to_string())?;
|
||||
self.emit_expression(expr, ctx)?
|
||||
}
|
||||
};
|
||||
self.emit_module_set(ctx, ns_reg, "default", val_reg)?;
|
||||
self.emit_self_alias_write(ctx, "default", 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}"))?;
|
||||
if let Some(exported) = &exp.exported {
|
||||
// export * as ns from '...':命名空间再导出。
|
||||
let exported_name = module_export_name_str(exported);
|
||||
self.emit_module_set(ctx, ns_reg, &exported_name, dep_ns_reg)?;
|
||||
} else {
|
||||
self.emit_module_call(ctx, "__moduleStar", &[ns_reg, dep_ns_reg])?;
|
||||
}
|
||||
}
|
||||
_ => return Err("unsupported module export statement".into()),
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
//! 支持提升语义。
|
||||
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_parser::{BindingPattern, Expression, Statement, VariableDeclarationKind};
|
||||
use oxide_parser::{BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, Statement, VariableDeclarationKind};
|
||||
|
||||
impl Emitter {
|
||||
/// 在临时寄存器池之前分配 builtin 槽位。
|
||||
@@ -117,6 +117,20 @@ impl Emitter {
|
||||
self.pre_scan_builtin_expr(super_class, ctx);
|
||||
}
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.pre_scan_builtin_expr(init, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => {
|
||||
if let Some(e) = exp.declaration.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(_) | Statement::BreakStatement(_) | Statement::ContinueStatement(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
@@ -283,8 +297,15 @@ impl Emitter {
|
||||
|
||||
pub(crate) fn predeclare_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
let Statement::FunctionDeclaration(function) = statement else {
|
||||
continue;
|
||||
let function = match statement {
|
||||
Statement::FunctionDeclaration(f) => f,
|
||||
Statement::ExportNamedDeclaration(exp) => match &exp.declaration {
|
||||
Some(Declaration::FunctionDeclaration(f)) => f,
|
||||
_ => continue,
|
||||
},
|
||||
// export default function foo(){}:foo 绑定由 lexical predeclare 以
|
||||
// Const 预声明(emit 侧 emit_bind_target(Const) 消费预登记槽)。
|
||||
_ => continue,
|
||||
};
|
||||
let Some(identifier) = &function.id else {
|
||||
continue;
|
||||
@@ -361,6 +382,24 @@ impl Emitter {
|
||||
Statement::WithStatement(ws) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&ws.body), ctx);
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(Declaration::VariableDeclaration(decl)) = &exp.declaration {
|
||||
if !matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
continue;
|
||||
}
|
||||
for d in &decl.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(
|
||||
bi.name.as_str(),
|
||||
reg,
|
||||
VariableDeclarationKind::Var,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -400,6 +439,60 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(decl) = &exp.declaration {
|
||||
match decl {
|
||||
Declaration::VariableDeclaration(vd) => {
|
||||
if matches!(vd.kind, VariableDeclarationKind::Var) {
|
||||
continue;
|
||||
}
|
||||
let is_const = matches!(vd.kind, VariableDeclarationKind::Const);
|
||||
for d in &vd.declarations {
|
||||
self.predeclare_lexical_pattern(&d.id, is_const, ctx);
|
||||
}
|
||||
}
|
||||
Declaration::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_predeclared(
|
||||
id.name.as_str(),
|
||||
reg,
|
||||
VariableDeclarationKind::Const,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => {
|
||||
match &exp.declaration {
|
||||
ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_predeclared(
|
||||
id.name.as_str(),
|
||||
reg,
|
||||
VariableDeclarationKind::Const,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_predeclared(
|
||||
id.name.as_str(),
|
||||
reg,
|
||||
VariableDeclarationKind::Const,
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ impl Emitter {
|
||||
|
||||
/// 绑定单个标识符到槽位。`fresh_cell` 为 true 时对被捕获绑定用 MAKE_CELL_FRESH
|
||||
/// (循环每迭代绑定:无条件新建 cell,本迭代闭包捕获新 cell)。
|
||||
fn emit_bind_target(
|
||||
pub(crate) fn emit_bind_target(
|
||||
&self, name: &str, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, fresh_cell: bool,
|
||||
ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
|
||||
@@ -10,6 +10,13 @@ impl Emitter {
|
||||
let Statement::ClassDeclaration(class) = stmt else {
|
||||
return Err("ClassDeclaration without name".into());
|
||||
};
|
||||
self.emit_class_declaration(class, ctx)
|
||||
}
|
||||
|
||||
/// 类声明本体:供 export 声明复用(导出声明先按普通声明 emit,再就地注册导出值)。
|
||||
pub(crate) fn emit_class_declaration(
|
||||
&self, class: &oxide_parser::Class, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let name = class
|
||||
.id
|
||||
.as_ref()
|
||||
|
||||
@@ -13,6 +13,13 @@ impl Emitter {
|
||||
let Statement::FunctionDeclaration(fd) = stmt else {
|
||||
return Err("FunctionDeclaration without name".into());
|
||||
};
|
||||
self.emit_function_declaration(fd, ctx)
|
||||
}
|
||||
|
||||
/// 函数声明本体:供 export 声明复用(导出声明先按普通声明 emit,再就地注册导出值)。
|
||||
pub(crate) fn emit_function_declaration(
|
||||
&self, fd: &oxide_parser::Function, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let name = if let Some(id) = &fd.id {
|
||||
id.name.to_string()
|
||||
} else {
|
||||
|
||||
@@ -5,7 +5,7 @@ use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::{BindingPattern, Statement, VariableDeclarationKind};
|
||||
use oxide_parser::{BindingPattern, Statement, VariableDeclaration, VariableDeclarationKind};
|
||||
|
||||
impl Emitter {
|
||||
pub(crate) fn emit_variable_declaration_statement(
|
||||
@@ -14,6 +14,13 @@ impl Emitter {
|
||||
let Statement::VariableDeclaration(decl) = stmt else {
|
||||
return Ok(None);
|
||||
};
|
||||
self.emit_variable_declaration(decl, ctx)
|
||||
}
|
||||
|
||||
/// 变量声明本体:供 export 声明复用(导出声明需先按普通声明 emit,再就地注册导出值)。
|
||||
pub(crate) fn emit_variable_declaration(
|
||||
&self, decl: &VariableDeclaration, ctx: &mut CompileCtx,
|
||||
) -> Result<Option<u32>, String> {
|
||||
let mut r = None;
|
||||
for d in &decl.declarations {
|
||||
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
|
||||
|
||||
Reference in New Issue
Block a user