diff --git a/crates/oxide_emit/Cargo.toml b/crates/oxide_emit/Cargo.toml index 30b938e..31112c1 100644 --- a/crates/oxide_emit/Cargo.toml +++ b/crates/oxide_emit/Cargo.toml @@ -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" } diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index 1076e7b..e3e99af 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -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); diff --git a/crates/oxide_emit/src/emit.rs b/crates/oxide_emit/src/emit.rs index 3a067c3..2b023ca 100644 --- a/crates/oxide_emit/src/emit.rs +++ b/crates/oxide_emit/src/emit.rs @@ -198,6 +198,14 @@ pub struct CompileCtx { /// let/const 循环变量每迭代 fresh cell,update 写寄存器(不污染本迭代闭包 /// 捕获的 cell),下一迭代 fresh 从寄存器拷入新 cell。 pub(crate) register_update_names: Vec, + /// 模块编译上下文:当前模块命名空间对象寄存器(`__moduleObject` 返回值)。 + pub(crate) module_ns_reg: Option, + /// 已求值依赖模块的命名空间对象寄存器(按 import/export source 字符串索引)。 + pub(crate) module_dep_ns_regs: HashMap, + /// 自导入(import from 自身)的 source 字符串集合:绑定走别名语义,不能链接期快照。 + pub(crate) module_self_import_specs: HashSet, + /// 自导入别名:导出名 → 本地绑定槽寄存器(export 语句执行时回写绑定值)。 + pub(crate) module_self_aliases: HashMap, } /// 函数体编译上下文:决定 `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), } } diff --git a/crates/oxide_emit/src/expr/function/mod.rs b/crates/oxide_emit/src/expr/function/mod.rs index a0ef550..761ae97 100644 --- a/crates/oxide_emit/src/expr/function/mod.rs +++ b/crates/oxide_emit/src/expr/function/mod.rs @@ -55,7 +55,7 @@ impl Emitter { Ok(r) } - fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result { + pub(crate) fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result { // 函数表达式:编译函数体为子模块,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 { + pub(crate) fn emit_class_expression(&self, class: &Class, ctx: &mut CompileCtx) -> Result { self.emit_class(class, ctx) } diff --git a/crates/oxide_emit/src/lib.rs b/crates/oxide_emit/src/lib.rs index 3df1f33..30e16d6 100644 --- a/crates/oxide_emit/src/lib.rs +++ b/crates/oxide_emit/src/lib.rs @@ -7,6 +7,7 @@ pub mod class; pub mod closure; +pub mod module; pub mod emit; mod emit_log; pub mod emit_ctx; diff --git a/crates/oxide_emit/src/module.rs b/crates/oxide_emit/src/module.rs new file mode 100644 index 0000000..efd9c99 --- /dev/null +++ b/crates/oxide_emit/src/module.rs @@ -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; +} + +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>>) -> Vec<(String, String)> { + let mut out = Vec::new(); + if let Some(wc) = with_clause { + for attr in &wc.with_entries { + let key = match &attr.key { + ImportAttributeKey::Identifier(id) => id.name.to_string(), + ImportAttributeKey::StringLiteral(s) => s.value.to_string(), + }; + out.push((key, attr.value.value.to_string())); + } + } + out +} + +/// 收集模块自身直接导出的名称集合(含字符串导出名与 default): +/// 供 self-import 链接期校验(自引用导入不存在的导出 → 编译期错误)。 +fn module_own_export_names(body: &[Statement]) -> HashSet { + let mut names = HashSet::new(); + for stmt in body { + match stmt { + Statement::ExportNamedDeclaration(exp) => { + if let Some(decl) = &exp.declaration { + match decl { + Declaration::VariableDeclaration(vd) => { + for d in &vd.declarations { + if let BindingPattern::BindingIdentifier(bi) = &d.id { + names.insert(bi.name.to_string()); + } + } + } + Declaration::FunctionDeclaration(fd) => { + if let Some(id) = &fd.id { + names.insert(id.name.to_string()); + } + } + Declaration::ClassDeclaration(cl) => { + if let Some(id) = &cl.id { + names.insert(id.name.to_string()); + } + } + _ => {} + } + } else { + for spec in &exp.specifiers { + names.insert(module_export_name_str(&spec.exported)); + } + } + } + Statement::ExportDefaultDeclaration(_) => { + names.insert("default".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 { + 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, 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, + ) -> Result { + 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 { + 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 { + 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 { + 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, 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) + } +} diff --git a/crates/oxide_emit/src/prepass.rs b/crates/oxide_emit/src/prepass.rs index 6d1c696..2b11e8c 100644 --- a/crates/oxide_emit/src/prepass.rs +++ b/crates/oxide_emit/src/prepass.rs @@ -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, + ); + } + } + _ => {} + } + } _ => {} } } diff --git a/crates/oxide_emit/src/shared/binding.rs b/crates/oxide_emit/src/shared/binding.rs index 7249618..4f1188c 100644 --- a/crates/oxide_emit/src/shared/binding.rs +++ b/crates/oxide_emit/src/shared/binding.rs @@ -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> { diff --git a/crates/oxide_emit/src/stmt/declaration/class_decl.rs b/crates/oxide_emit/src/stmt/declaration/class_decl.rs index 421bfed..b40d367 100644 --- a/crates/oxide_emit/src/stmt/declaration/class_decl.rs +++ b/crates/oxide_emit/src/stmt/declaration/class_decl.rs @@ -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, String> { let name = class .id .as_ref() diff --git a/crates/oxide_emit/src/stmt/declaration/function_decl.rs b/crates/oxide_emit/src/stmt/declaration/function_decl.rs index 052ab24..39a0f33 100644 --- a/crates/oxide_emit/src/stmt/declaration/function_decl.rs +++ b/crates/oxide_emit/src/stmt/declaration/function_decl.rs @@ -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, String> { let name = if let Some(id) = &fd.id { id.name.to_string() } else { diff --git a/crates/oxide_emit/src/stmt/declaration/var.rs b/crates/oxide_emit/src/stmt/declaration/var.rs index af8f92c..eb05533 100644 --- a/crates/oxide_emit/src/stmt/declaration/var.rs +++ b/crates/oxide_emit/src/stmt/declaration/var.rs @@ -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, String> { let mut r = None; for d in &decl.declarations { let is_const = matches!(decl.kind, VariableDeclarationKind::Const);