docs: 补充注释与格式化

This commit is contained in:
爱特每羊队
2026-08-06 23:10:27 +08:00
parent 4e0fd762c2
commit 328b8a3ddc
156 changed files with 2393 additions and 1687 deletions
-1
View File
@@ -1,2 +1 @@
//! 类编译核心预留模块(当前为空,为后续类相关公共状态预留位置)。
+17 -4
View File
@@ -3,9 +3,9 @@
//! 函数:`emit_class`。
use crate::{CompileCtx, Emitter, FunctionBodyContext};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{Class, ClassElement, MethodDefinitionKind, PropertyKey};
impl Emitter {
@@ -66,9 +66,20 @@ impl Emitter {
let emit_instance_fields = |compiler: &Emitter, field_ctx: &mut CompileCtx| -> Result<(), String> {
for field in &instance_fields {
if let PropertyKey::PrivateIdentifier(private) = &field.key {
compiler.emit_private_field_init(Operand::This, private.name.as_str(), field.value.as_ref(), field_ctx)?;
compiler.emit_private_field_init(
Operand::This,
private.name.as_str(),
field.value.as_ref(),
field_ctx,
)?;
} else {
compiler.emit_public_field_init(Operand::This, &field.key, field.computed, field.value.as_ref(), field_ctx)?;
compiler.emit_public_field_init(
Operand::This,
&field.key,
field.computed,
field.value.as_ref(),
field_ctx,
)?;
}
}
Ok(())
@@ -108,7 +119,9 @@ impl Emitter {
module.insts.extend(field_ctx.insts);
module.constants = field_ctx.constants;
module.n_registers = field_ctx.max_regs.max(1);
module.insts.push(Inst::new(OpCode::RETURN, Operand::None, Operand::None, Operand::None));
module
.insts
.push(Inst::new(OpCode::RETURN, Operand::None, Operand::None, Operand::None));
}
module
};
+17 -6
View File
@@ -5,10 +5,10 @@ use oxide_ir::operand::Operand;
use oxide_parser::{ClassElement, PropertyKey};
impl Emitter {
/// Emit static field initializers and static blocks in source order.
/// JS class semantics interleave them (e.g. `static x = 1; static {
/// this.y = 1 } static z = this.y + 1` must run in that order). Emitting
/// all fields before all blocks would make `z` read `y` before it is set.
/// 按源码顺序发静态字段初始化与静态块。
/// JS 类语义要求两者交织执行(如 `static x = 1; static { this.y = 1 }
/// static z = this.y + 1` 必须按此顺序),若全部字段先于静态块发出,
/// `z` 会在 `y` 赋值前读到它。
pub(crate) fn emit_class_static_elements(
&self, elements: &[ClassElement], ctor_reg: u32, ctx: &mut CompileCtx,
) -> Result<(), String> {
@@ -23,9 +23,20 @@ impl Emitter {
let prop = prop.as_ref();
if prop.r#static {
if let PropertyKey::PrivateIdentifier(private) = &prop.key {
self.emit_private_field_init(Operand::Reg(ctor_reg), private.name.as_str(), prop.value.as_ref(), ctx)?;
self.emit_private_field_init(
Operand::Reg(ctor_reg),
private.name.as_str(),
prop.value.as_ref(),
ctx,
)?;
} else {
self.emit_public_field_init(Operand::Reg(ctor_reg), &prop.key, prop.computed, prop.value.as_ref(), ctx)?;
self.emit_public_field_init(
Operand::Reg(ctor_reg),
&prop.key,
prop.computed,
prop.value.as_ref(),
ctx,
)?;
}
}
}
+14 -4
View File
@@ -2,10 +2,10 @@
//! 负责单个方法函数体(含 `super` 与 home object)。
use crate::{CompileCtx, Emitter, FunctionBodyContext};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{ClassElement, MethodDefinitionKind, PropertyKey};
impl Emitter {
@@ -36,9 +36,19 @@ impl Emitter {
match method.kind {
MethodDefinitionKind::Method => {
if method.computed {
ctx.inst(Inst::new(OpCode::SET_PROP_DYNAMIC, Operand::Reg(home_reg), Operand::Reg(key_reg), Operand::Reg(accessor_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP_DYNAMIC,
Operand::Reg(home_reg),
Operand::Reg(key_reg),
Operand::Reg(accessor_reg),
));
} else {
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(home_reg), Operand::Reg(accessor_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(home_reg),
Operand::Reg(accessor_reg),
Operand::Reg(key_reg),
));
}
}
MethodDefinitionKind::Get | MethodDefinitionKind::Set => {
+32 -7
View File
@@ -1,10 +1,10 @@
//! 类原型对象构造:`emit_class_prototype` 建立 `Class.prototype` 与属性初始化。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
impl Emitter {
pub(crate) fn emit_class_prototype(
@@ -17,21 +17,46 @@ impl Emitter {
let parent_proto_key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(parent_proto_key_reg), proto_key_idx));
let parent_proto_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PROP, Operand::Reg(super_reg), Operand::Reg(parent_proto_reg), Operand::Reg(parent_proto_key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PROP,
Operand::Reg(super_reg),
Operand::Reg(parent_proto_reg),
Operand::Reg(parent_proto_key_reg),
));
let proto_link_idx = ctx.add_constant(Constant::String("__proto__".to_string()));
let proto_link_key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(proto_link_key_reg), proto_link_idx));
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(proto_reg), Operand::Reg(parent_proto_reg), Operand::Reg(proto_link_key_reg)));
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(ctor_reg), Operand::Reg(super_reg), Operand::Reg(proto_link_key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(proto_reg),
Operand::Reg(parent_proto_reg),
Operand::Reg(proto_link_key_reg),
));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(ctor_reg),
Operand::Reg(super_reg),
Operand::Reg(proto_link_key_reg),
));
}
let ctor_key_idx = ctx.add_constant(Constant::String("constructor".to_string()));
let ctor_key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(ctor_key_reg), ctor_key_idx));
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(proto_reg), Operand::Reg(ctor_reg), Operand::Reg(ctor_key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(proto_reg),
Operand::Reg(ctor_reg),
Operand::Reg(ctor_key_reg),
));
let proto_key_idx = ctx.add_constant(Constant::String("prototype".to_string()));
let proto_key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(proto_key_reg), proto_key_idx));
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(ctor_reg), Operand::Reg(proto_reg), Operand::Reg(proto_key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(ctor_reg),
Operand::Reg(proto_reg),
Operand::Reg(proto_key_reg),
));
Ok(())
}
}
+6 -11
View File
@@ -12,7 +12,6 @@ use oxide_parser::{Expression, Statement};
use crate::Emitter;
impl Emitter {
fn collect_fn_param_names(&self, params: &oxide_parser::FormalParameters) -> HashSet<String> {
let mut names = HashSet::new();
for p in &params.items {
@@ -288,7 +287,9 @@ impl Emitter {
}
Expression::StaticMemberExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
Expression::PrivateFieldExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
Expression::ParenthesizedExpression(p) => self.collect_capture_names_expr(&p.expression, ref_set, shadow, out),
Expression::ParenthesizedExpression(p) => {
self.collect_capture_names_expr(&p.expression, ref_set, shadow, out)
}
Expression::TemplateLiteral(tl) => {
for e in &tl.expressions {
self.collect_capture_names_expr(e, ref_set, shadow, out);
@@ -348,11 +349,7 @@ impl Emitter {
// 名字排序分配 cell_idx(稳定跨 run,父 MAKE_CELL 与子 upvalue 统一引用)
let mut sorted: Vec<String> = names.into_iter().collect();
sorted.sort();
sorted
.into_iter()
.enumerate()
.map(|(i, n)| (n, i as u8))
.collect()
sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect()
}
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
@@ -498,7 +495,6 @@ impl Emitter {
}
}
/// 分析子函数 body:引用父级绑定的名字 → upvalue_captures(enclosing_reg 由父 emit 完成后填充)。
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
/// cell_idx 直接取父 captured_bindings 映射(父 emit 前已确定,索引一致);
/// enclosing_reg 由父 emit 完成后填充(assemble_ir)。
@@ -509,9 +505,8 @@ impl Emitter {
let mut names = HashSet::new();
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
// HashSet 迭代序带随机种子(进程级非确定),必须排序使 upvalue_captures 的顺序与
// 父 captured_bindings 的 cell_idx(BTreeMap 名字序)对齐——否则 uv_idx(identifier.rs
// LOAD_UPVALUE 的 a 槽编码)与 cell_idx 错位,读错 upvalue(hoisted_function_reads_outer_var_and_function
// 抖动根因)。
// 父 captured_bindings 的 cell_idx(BTreeMap 名字序)对齐——否则 LOAD_UPVALUE 的
// a 槽 uv_idx 编码与 cell_idx 错位,读错 upvalue。
let mut names: Vec<String> = names.into_iter().collect();
names.sort();
names
+49 -57
View File
@@ -124,9 +124,8 @@ pub(crate) struct FieldBuffer {
pub(crate) labels: Vec<(LabelId, usize)>,
}
/// A labeled-statement scope active during emission. `break label` targets
/// `break_label`; `continue label` targets `continue_label` (only set when the
/// labeled statement directly wraps an iteration statement).
/// 标签语句作用域:编译期内登记 `break label` / `continue label` 的跳转目标。
/// `continue_label` 仅在标签直接包裹迭代语句时存在。
#[derive(Debug, Clone)]
pub struct LabelScope {
pub(crate) name: String,
@@ -146,9 +145,8 @@ pub struct CompileCtx {
pub(crate) labels: LabelCtx,
pub(crate) scopes: ScopeCtx,
pub(crate) nested: Vec<IRFunction>,
/// Register holding `this` in the enclosing function context.
/// Used by arrow functions to capture lexical `this`.
/// Initialized to 254 (conventional this register) at the top level.
/// 外层函数上下文中持有 `this` 的寄存器。
/// 箭头函数用它捕获词法 `this`;顶层初始化为 254(约定 this 寄存器)。
pub(crate) enclosing_this_reg: u8,
pub(crate) in_derived_constructor: bool,
pub(crate) in_instance_method: bool,
@@ -247,7 +245,7 @@ impl CompileCtx {
pub(crate) fn alloc_reg(&mut self) -> u32 {
let r = self.next_reg;
// vreg 化(D-02):寄存器号无上限,RegAlloc 阶段负责压缩到物理域(≤253)。
// vreg 化:寄存器号无上限,RegAlloc 阶段负责压缩到物理域(≤253)。
// 254/255 是 VM 保留的 this/new.target,vreg 世界允许虚拟号越过它们,
// 只有 RegAlloc 完成映射后 lower 的物理域检查才相关。
self.next_reg += 1;
@@ -406,9 +404,8 @@ impl CompileCtx {
self.labels.label_scopes.iter().rev().find(|s| s.name == name)
}
/// Queue a label name to be bound to the continue target of the next loop
/// emitted as the labeled statement's body. Rejects duplicates in the active
/// or pending sets.
/// 登记一个待绑定标签名:该标签将作为下一个 emit 的循环(标签语句体)的
/// continue 目标。活动集合与待绑定集合中出现重名报错。
pub(crate) fn queue_loop_label(&mut self, name: &str) -> Result<(), String> {
if self.labels.label_scopes.iter().any(|s| s.name == name)
|| self.labels.pending_loop_labels.iter().any(|n| n == name)
@@ -419,8 +416,8 @@ impl CompileCtx {
Ok(())
}
/// Drain queued loop labels into active scopes bound to this loop's break and
/// continue targets. Returns how many scopes were pushed (to pop after).
/// 把待绑定标签名落地为活动标签作用域,绑定到本次循环的 break/continue 目标。
/// 返回压入的作用域个数(供事后对称弹出)。
pub(crate) fn take_pending_loop_labels(&mut self, break_label: LabelId, continue_label: LabelId) -> usize {
let names = std::mem::take(&mut self.labels.pending_loop_labels);
let count = names.len();
@@ -458,9 +455,8 @@ impl CompileCtx {
}
pub(crate) fn pre_register_builtins(&mut self) {
// Builtin globals are resolved lazily by lookup_or_builtin(). Keeping this
// hook preserves the compile pipeline without reserving ~60 registers in
// every module.
// builtin 全局由 lookup_or_builtin() 惰性解析。保留此钩子维持编译管线形态,
// 避免在每个模块预留约 60 个寄存器槽。
}
/// 组装 IRFunction(两出口共用),take 走编译产物状态。
@@ -546,13 +542,11 @@ impl Emitter {
Ok((param_specs, body_stmts))
}
/// Compile a function body (used for FD, FE, and arrow functions).
/// This performs both counting and emitting in one pass.
/// When `is_expression_body` is true (arrow function with expression body),
/// the last expression's value is returned instead of undefined.
/// `is_arrow` controls whether super flags are inherited from the parent scope
/// (true for arrow functions, which have lexical super) or reset to false
/// (false for regular functions, which create a new super scope).
/// 编译函数体(函数声明/函数表达式/箭头函数共用),单 pass 完成发码。
///
/// `is_expression_body` 为 true(箭头表达式体)时返回最后一个表达式的值,
/// 否则返回 undefined。`is_arrow` 控制 super 相关标志的继承:箭头函数词法
/// 继承外层 super,普通函数重置 super 作用域。
pub(crate) fn compile_function_body<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, is_arrow: bool,
@@ -588,13 +582,13 @@ impl Emitter {
)
}
/// Pre-register all builtin identifiers referenced anywhere in this body
/// (expressions, member objects, call args, class fields, etc.) so their
/// register slots are reserved *before* any temporary register is emitted.
/// 预注册 builtin 引用并编译函数体(普通/箭头/类元素方法共用入口)。
///
/// vreg 化(D-01)后临时值不复用(独立 vreg),但 builtin 槽预注册仍
/// 保证分配序稳定:builtin 槽先于临时值池,nested 继承边界(B012)不受扰。
/// 本函数体内任意位置(表达式、成员对象、调用实参、类字段等)引用的内置全局
/// 标识符,其寄存器槽都先于任何临时寄存器登记。
///
/// vreg 化后临时值不复用(独立 vreg),但 builtin 槽预注册仍保证分配序稳定:
/// builtin 槽先于临时值池,嵌套函数继承边界不受扰。
#[allow(clippy::too_many_arguments)]
pub(crate) fn compile_function_body_with_field_hooks<'a, E>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
@@ -606,16 +600,16 @@ impl Emitter {
{
let mut ctx = CompileCtx::new();
// Inherit parent's builtin_reg_map so builtin identifiers (Math, Object, etc.)
// resolve to the correct pre-allocated registers in the sub-module's register file.
// 继承父内置寄存器映射:子模块寄存器文件中,内置标识符(Math、Object 等)
// 解析到父预先分配的槽位。
ctx.scopes.builtin_reg_map = parent_ctx.scopes.builtin_reg_map.clone();
ctx.scopes.private_name_map = parent_ctx.scopes.private_name_map.clone();
ctx.scopes.next_private_name_id = parent_ctx.scopes.next_private_name_id;
// Propagate enclosing_this_reg so nested arrow functions capture the correct `this`.
// 传递 enclosing_this_reg:嵌套箭头函数捕获正确的 `this`。
ctx.enclosing_this_reg = parent_ctx.enclosing_this_reg;
// Arrow functions inherit lexical super. Class method bodies also need the
// class-provided super context for their top-level body compilation.
// 箭头函数词法继承 super;类方法体顶层编译也需要类提供的 super 上下文。
if matches!(body_context, FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement) {
ctx.in_derived_constructor = parent_ctx.in_derived_constructor;
ctx.in_instance_method = parent_ctx.in_instance_method;
@@ -626,8 +620,7 @@ impl Emitter {
ctx.in_static_method = false;
}
// Inherit parent's global scope entries so previously-declared function names
// are visible from within the body.
// 继承父全局作用域条目:先前声明的函数名在函数体内可见。
let mut inherited_reg_start = 1u32.max(ctx.builtin_reg_floor());
for (name, binding) in &parent_ctx.scopes.symbols.scopes[0].bindings {
ctx.scopes.symbols.scopes[0].bindings.insert(
@@ -653,20 +646,17 @@ impl Emitter {
}
ctx.reserved_reg_start = inherited_reg_start.max(1);
// Align next_reg with builtin count so both count and emit passes start at the
// same register offset (params go after builtin slots).
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
ctx.reset_regs();
let param_base = self.emit_params_prologue(param_specs, body_stmts, parent_ctx, &mut ctx, body_context)?;
self.predeclare_function_declarations(body_stmts, &mut ctx);
// Pre-register builtin identifier references before emitting any temporary
// register, so builtin slots never collide with reused temporaries.
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。
self.pre_register_builtin_references(body_stmts, &mut ctx);
// Pre-declare `var` names so hoisted function declarations (emitted in the
// first sub-pass below) can resolve the outer vars they close over.
// 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。
self.predeclare_var_declarations(body_stmts, &mut ctx);
if let Some(emit) = emit_fields.as_mut() {
@@ -692,11 +682,10 @@ impl Emitter {
}
}
// Emit body statements(先函数声明 hoisting,再其余)。
// 发 body 语句(先函数声明 hoisting,再其余)。
let last_result_reg = self.emit_body_stmts(body_stmts, &mut ctx)?;
// Emit implicit RETURN: expression body returns the last expression,
// statement body returns undefined.
// 隐式 RETURN:表达式体返回最后表达式,语句体返回 undefined。
if is_expression_body {
if let Some(reg) = last_result_reg {
ctx.inst(Inst::new(OpCode::RETURN, Operand::Reg(reg), Operand::None, Operand::None));
@@ -731,7 +720,7 @@ impl Emitter {
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
let param_base = ctx.next_reg;
// Emit parameters and destructuring prologue.
// 发参数与解构 prologue。
for spec in param_specs {
let name = spec.register_name();
let reg = ctx.alloc_reg();
@@ -757,11 +746,16 @@ impl Emitter {
let name = spec.register_name();
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
let reg = ctx.lookup(name)?;
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(reg), Operand::Imm(cell_idx as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
}
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
// 自由变量分析(仅普通/箭头函数):收集 upvalue 捕获。
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
ctx.current_upvalue_captures =
self.collect_upvalue_names(body_stmts, &parent_ctx.captured_bindings, &ctx.own_bindings);
@@ -850,35 +844,33 @@ impl Emitter {
}
}
/// Emit a full program into an IRFunction (top-level module body).
/// Split from the original `Compiler::compile`: this is the emit half;
/// oxide_compiler::Compiler::compile calls this then `oxide_ir::lower::lower`.
/// 把完整程序编译为顶层模块体的 IRFunction。
///
/// 调用方为 `oxide_compiler::Compiler::compile`:本函数完成 emit 半程,
/// 随后由 `oxide_ir::lower::lower` 降为字节码。
pub fn emit_program(&self, program: &oxide_parser::Program) -> Result<IRFunction, String> {
let mut ctx = CompileCtx::new();
ctx.pre_register_builtins();
self.predeclare_function_declarations(&program.body, &mut ctx);
// Pre-register builtin identifier references before any temporary register
// is emitted, keeping builtin slots clear of the temporary register pool.
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不进入临时寄存器池。
self.pre_register_builtin_references(&program.body, &mut ctx);
// Pre-declare top-level `var` names so hoisted function declarations
// (emitted in the first sub-pass below) can resolve the outer vars.
// 预声明顶层 `var` 名,使首个 sub-pass 中提升的函数声明能解析外层 var。
self.predeclare_var_declarations(&program.body, &mut ctx);
// 闭包捕获分析(AST 级,emit 前确定)
ctx.own_bindings = self.collect_own_binding_names(&[], &program.body);
ctx.captured_bindings = self.collect_captured_bindings(&program.body, &ctx.own_bindings);
// First sub-pass: emit FunctionDeclarations (hoisting)
// This ensures function objects are available before any code runs.
// 首个 sub-pass:发函数声明(hoisting),保证任何代码运行前函数对象已就绪。
for stmt in &program.body {
if matches!(stmt, Statement::FunctionDeclaration(_)) {
self.emit_statement(stmt, &mut ctx)?;
}
}
// Second sub-pass: emit all other statements
// 第二个 sub-pass:发其余所有语句。
let mut last_result: Option<u32> = None;
for stmt in &program.body {
if matches!(stmt, Statement::FunctionDeclaration(_)) {
+10 -12
View File
@@ -1,24 +1,23 @@
//! Grouped `CompileCtx` sub-contexts.
//! `CompileCtx` 的成组子上下文。
//!
//! Splits the compiler's central `CompileCtx` so syntax-domain workers borrow
//! only the slice they need: `LabelCtx` for jump-target resolution, `ScopeCtx`
//! for identifier binding. `PatternCtx` is reserved for destructuring work.
//! Execution-stream fields (insts, registers, pc, …) stay flat on
//! `CompileCtx`.
//! 把编译器中心 `CompileCtx` 拆开,语法域 worker 只借用所需切片:
//! `LabelCtx` 负责跳转目标解析,`ScopeCtx` 负责标识符绑定。
//! `PatternCtx` 为解构工作预留。执行流字段(insts/registers/pc 等)仍
//! 平铺在 `CompileCtx` 上。
use crate::symbol_table::SymbolTable;
use crate::LabelScope;
use oxide_ir::operand::LabelId;
/// Jump-target / labeled-statement resolution state.
/// 跳转目标 / 标签语句解析状态。
pub(crate) struct LabelCtx {
/// label id → 指令下标。id 连续递增,Vec 索引即 id;写入前须扩容。
pub(crate) label_pos: Vec<Option<usize>>,
pub(crate) loop_stack: Vec<(LabelId, LabelId)>,
pub(crate) switch_stack: Vec<LabelId>,
/// Active labeled-statement scopes (resolves `break label` / `continue label`).
/// 活动标签语句作用域(解析 `break label` / `continue label`)。
pub(crate) label_scopes: Vec<LabelScope>,
/// Label names awaiting binding to the next emitted loop's continue target.
/// 等待绑定到下一个循环 continue 目标的标签名。
pub(crate) pending_loop_labels: Vec<String>,
pub(crate) label_counter: u32,
}
@@ -33,7 +32,7 @@ impl LabelCtx {
}
}
/// Identifier-binding state: symbols, builtin registers, private names.
/// 标识符绑定状态:符号表、builtin 寄存器、私有名。
pub(crate) struct ScopeCtx {
pub(crate) symbols: SymbolTable,
pub(crate) builtin_reg_map: Vec<(String, u32)>,
@@ -41,7 +40,6 @@ pub(crate) struct ScopeCtx {
pub(crate) next_private_name_id: u32,
}
/// Reserved for destructuring-pattern state (Phase 15). Intentionally empty
/// today; named so future pattern work has a home without touching `ScopeCtx`.
/// 预留的解构 pattern 状态。当前为空;为后续解构工作预留归属地,避免改动 `ScopeCtx`。
#[allow(dead_code)]
pub(crate) struct PatternCtx;
+82 -17
View File
@@ -2,10 +2,10 @@
//! 函数:`emit_assignment_expression`。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::AssignmentOperator;
impl Emitter {
@@ -22,13 +22,23 @@ impl Emitter {
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(obj_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::ic_get(Operand::Reg(result_reg), Operand::Reg(key_reg)));
self.emit_logical_assign_test(logical_op, result_reg, store_label, end_label, ctx)?;
ctx.labels.set_label_pos(store_label, ctx.insts.len());
let val_reg = self.emit_expression(&assign.right, ctx)?;
ctx.inst(Inst::ic_set(Operand::Reg(obj_reg), Operand::Reg(val_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(val_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(val_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
return Ok(result_reg);
}
@@ -63,19 +73,39 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(result_reg)));
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(result_reg),
));
self.emit_logical_assign_test(logical_op, result_reg, store_label, end_label, ctx)?;
ctx.labels.set_label_pos(store_label, ctx.insts.len());
let val_reg = self.emit_expression(&assign.right, ctx)?;
ctx.inst(Inst::new(OpCode::SET_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(val_reg)));
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(val_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::SET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(val_reg),
));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(val_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
return Ok(result_reg);
}
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let val_reg = self.emit_expression(&assign.right, ctx)?;
ctx.inst(Inst::new(OpCode::SET_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(val_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(val_reg),
));
Ok(val_reg)
} else if let oxide_parser::AssignmentTarget::PrivateFieldExpression(member) = &assign.left {
if assign.operator != AssignmentOperator::Assign {
@@ -84,7 +114,12 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let val_reg = self.emit_expression(&assign.right, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
ctx.inst(Inst::new(OpCode::SET_PRIVATE, Operand::Reg(obj_reg), Operand::Reg(val_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PRIVATE,
Operand::Reg(obj_reg),
Operand::Reg(val_reg),
Operand::Reg(key_reg),
));
Ok(val_reg)
} else if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(id_ref) = &assign.left {
if assign.operator != AssignmentOperator::Assign {
@@ -94,14 +129,29 @@ impl Emitter {
let name = id_ref.name.as_str();
let var_reg = ctx.lookup_or_global(name);
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(var_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(var_reg),
Operand::None,
));
self.emit_logical_assign_test(logical_op, result_reg, store_label, end_label, ctx)?;
ctx.labels.set_label_pos(store_label, ctx.insts.len());
let val_reg = self.emit_expression(&assign.right, ctx)?;
let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 };
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg), Operand::Reg(val_reg), Operand::Imm(const_flag)));
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(val_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(var_reg),
Operand::Reg(val_reg),
Operand::Imm(const_flag),
));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(val_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(result_reg)
} else if assign.operator == AssignmentOperator::Addition
@@ -143,20 +193,35 @@ impl Emitter {
} else {
let val_reg = self.emit_expression(&assign.right, ctx)?;
let name = id_ref.name.as_str();
// Check if target is an upvalue reference
// 目标若是 upvalue 引用,走 STORE_UPVALUE
if let Some(uv_idx) = ctx.current_upvalue_captures.iter().position(|u| u.name == name) {
ctx.inst(Inst::new(OpCode::STORE_UPVALUE, Operand::None, Operand::Reg(val_reg), Operand::Imm(uv_idx as u16)));
ctx.inst(Inst::new(
OpCode::STORE_UPVALUE,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(uv_idx as u16),
));
return Ok(val_reg);
}
// Check if target is a captured cell
// 目标若是被捕获 cell,走 CELL_SET
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
ctx.inst(Inst::new(OpCode::CELL_SET, Operand::None, Operand::Reg(val_reg), Operand::Imm(cell_idx as u16)));
ctx.inst(Inst::new(
OpCode::CELL_SET,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(cell_idx as u16),
));
return Ok(val_reg);
}
let var_reg = ctx.lookup_or_global(name);
let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 };
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg), Operand::Reg(val_reg), Operand::Imm(const_flag)));
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(var_reg),
Operand::Reg(val_reg),
Operand::Imm(const_flag),
));
Ok(val_reg)
}
} else if matches!(
+17 -7
View File
@@ -2,10 +2,10 @@
//! 函数:`emit_call_expression`、`emit_call_domain`。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::Expression;
impl Emitter {
@@ -41,7 +41,12 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let callee_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PRIVATE, Operand::Reg(callee_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
Operand::Reg(callee_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
(callee_reg, obj_reg)
}
Expression::StaticMemberExpression(member) => {
@@ -69,7 +74,12 @@ impl Emitter {
};
ctx.inst(Inst::new(op, Operand::Reg(callee_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
} else {
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(callee_reg), Operand::Reg(obj_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(callee_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::ic_get(Operand::Reg(callee_reg), Operand::Reg(key_reg)));
}
(callee_reg, obj_reg)
@@ -125,9 +135,9 @@ impl Emitter {
}
}
/// 把调用参数打包到连续寄存器块(VM 按 `regs[first_arg + i]` 连续读参数,D-17/调用契约)。
/// vreg 化(05-02)后各参数由独立 vreg 承载,复杂表达式(对象/数组字面量、嵌套调用)
/// 的临时寄存器会使参数 vreg 不连续——这里检测到不连续时用 MOV 打包到新连续块。
/// 把调用参数打包到连续寄存器块(VM 按 `regs[first_arg + i]` 连续读参数)。
/// 各参数由独立 vreg 承载,复杂表达式(对象/数组字面量、嵌套调用)的临时寄存器
/// 会使参数 vreg 不连续——检测到不连续时用 MOV 打包到新连续块。
/// 返回首参寄存器;参数为空时返回 0。
fn pack_arg_regs(arg_regs: &mut [u32], ctx: &mut CompileCtx) -> u32 {
let consecutive = arg_regs.windows(2).all(|w| w[1] == w[0] + 1);
+6 -7
View File
@@ -11,12 +11,12 @@ impl Emitter {
fn emit_arrow_function_expression(
&self, arrow: &oxide_parser::ArrowFunctionExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
// Rest params not yet supported
// 未支持:箭头函数 rest 参数
if let Some(_rest) = &arrow.params.rest {
return Err("rest params in arrow functions not yet supported".into());
}
// Extract param names (same pattern as FunctionExpression)
// 提取形参名(与函数表达式相同的形态)
let mut param_names = Vec::new();
for (idx, param) in arrow.params.items.iter().enumerate() {
match &param.pattern {
@@ -32,8 +32,7 @@ impl Emitter {
}
}
// Expression body: pass body statements directly with is_expression_body=true.
// Statement body: pass body statements with is_expression_body=false.
// 表达式体:以 is_expression_body=true 编译;语句体:以 false 编译。
let body_stmts = &arrow.body.statements;
let is_expr_body = arrow.expression;
@@ -41,7 +40,7 @@ impl Emitter {
sub_module.is_arrow = true;
ctx.nested.push(sub_module);
// 1-indexed: 0 = no sub_module (sentinel)
// 子模块下标 1 起始:0 保留为无子模块哨兵
let sub_idx = ctx.nested.len() as u16;
let r = ctx.alloc_reg();
@@ -50,7 +49,7 @@ impl Emitter {
}
fn emit_function_expression(&self, fe: &oxide_parser::Function, ctx: &mut CompileCtx) -> Result<u32, String> {
// FunctionExpression: compile body, emit LOAD_CONST(BytecodeFunc)
// 函数表达式:编译函数体为子模块,create_closure 实例化闭包
let mut param_names = Vec::new();
for (idx, param) in fe.params.items.iter().enumerate() {
match &param.pattern {
@@ -73,7 +72,7 @@ impl Emitter {
sub_module.function_name = Some(id.name.to_string());
}
ctx.nested.push(sub_module);
// 1-indexed: 0 = no sub_module (sentinel)
// 子模块下标 1 起始:0 保留为无子模块哨兵
let sub_idx = ctx.nested.len() as u16;
let r = ctx.alloc_reg();
+7 -2
View File
@@ -1,9 +1,9 @@
//! 标识符表达式 emit:`emit_identifier_expression` 按绑定/builtin/全局解析寄存器。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
impl Emitter {
pub(crate) fn emit_identifier_expression(
@@ -23,7 +23,12 @@ impl Emitter {
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
let r = ctx.alloc_reg();
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r), Operand::Reg(binding.reg), Operand::Imm(cell_idx as u16)));
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(r),
Operand::Reg(binding.reg),
Operand::Imm(cell_idx as u16),
));
} else {
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(r), Operand::None, Operand::Imm(cell_idx as u16)));
}
+8 -3
View File
@@ -2,10 +2,10 @@
//! 整数走立即数编码(`is_int_literal`),其余入常量池。
use crate::{is_int_literal, CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::Expression;
impl Emitter {
@@ -74,7 +74,12 @@ impl Emitter {
let flags_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(flags_reg), flags_ci));
let r = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::CREATE_REGEXP, Operand::Reg(r), Operand::Reg(pat_reg), Operand::Reg(flags_reg)));
ctx.inst(Inst::new(
OpCode::CREATE_REGEXP,
Operand::Reg(r),
Operand::Reg(pat_reg),
Operand::Reg(flags_reg),
));
Ok(r)
} else {
Err(format!("unsupported regexp literal: {:?}", lit))
+23 -6
View File
@@ -3,10 +3,10 @@
//! `emit_private_field_expression`、`emit_chain_expression`、`emit_member_domain`。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::Expression;
impl Emitter {
@@ -47,7 +47,12 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
let r = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(r)));
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(r),
));
Ok(r)
}
@@ -57,16 +62,28 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let r = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PRIVATE, Operand::Reg(r), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
Operand::Reg(r),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(r)
}
fn emit_chain_expression(&self, chain: &oxide_parser::ChainExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
fn emit_chain_expression(
&self, chain: &oxide_parser::ChainExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let short_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let value_reg = self.emit_chain_element(&chain.expression, Some(short_label), ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(value_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(value_reg),
Operand::None,
));
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(short_label, ctx.insts.len());
let undefined_idx = ctx.add_constant(Constant::Undefined);
+8 -3
View File
@@ -1,10 +1,10 @@
//! 数组字面量 emit:`emit_array_expression` 逐元素求值并建数组(含 holes)。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
impl Emitter {
pub(crate) fn emit_array_expression(
&self, arr: &oxide_parser::ArrayExpression, ctx: &mut CompileCtx,
@@ -20,7 +20,12 @@ impl Emitter {
let idx_reg = ctx.alloc_reg();
let idx = ctx.add_constant(Constant::Int(i as i32));
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx));
ctx.inst(Inst::new(OpCode::SET_ELEM, Operand::Reg(arr_reg), Operand::Reg(idx_reg), Operand::Reg(val_reg)));
ctx.inst(Inst::new(
OpCode::SET_ELEM,
Operand::Reg(arr_reg),
Operand::Reg(idx_reg),
Operand::Reg(val_reg),
));
}
Ok(arr_reg)
}
@@ -1,10 +1,10 @@
//! 对象字面量 emit:`emit_object_expression` 逐属性定义(含 getter/setter/展开)。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{Expression, ObjectPropertyKind, PropertyKey, PropertyKind};
impl Emitter {
@@ -52,7 +52,12 @@ impl Emitter {
sub_mod.function_name = Some(prop_name.to_string());
}
}
ctx.inst(Inst::new(OpCode::SET_PROP, Operand::Reg(obj_reg), Operand::Reg(val_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP,
Operand::Reg(obj_reg),
Operand::Reg(val_reg),
Operand::Reg(key_reg),
));
}
}
}
+80 -18
View File
@@ -3,10 +3,10 @@
//! 函数:`emit_operator` 及各类 `emit_*_expression`。
use crate::{is_side_effect_free, BinaryOperator, CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{ChainElement, Expression, LogicalOperator, SimpleAssignmentTarget, UnaryOperator, UpdateOperator};
impl Emitter {
@@ -16,11 +16,18 @@ impl Emitter {
let obj_reg = self.emit_expression(&pin.right, ctx)?;
let key_reg = self.emit_private_id_reg(pin.left.name.as_str(), ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::PRIVATE_BRAND_IN, Operand::Reg(result_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::PRIVATE_BRAND_IN,
Operand::Reg(result_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(result_reg)
}
fn emit_binary_expression(&self, bin: &oxide_parser::BinaryExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
fn emit_binary_expression(
&self, bin: &oxide_parser::BinaryExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let left = self.emit_expression(&bin.left, ctx)?;
let right = self.emit_expression(&bin.right, ctx)?;
let op = match bin.operator {
@@ -67,7 +74,12 @@ impl Emitter {
Expression::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
ctx.inst(Inst::new(OpCode::DELETE_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::DELETE_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(obj_reg)
}
Expression::ChainExpression(chain) => {
@@ -77,7 +89,12 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
if member.optional {
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(obj_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(dup_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::jmp_if_nullish(dup_reg, short_label));
}
let prop_name = member.property.name.as_str();
@@ -89,11 +106,21 @@ impl Emitter {
let obj_reg = self.emit_expression(&member.object, ctx)?;
if member.optional {
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(obj_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(dup_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::jmp_if_nullish(dup_reg, short_label));
}
let key_reg = self.emit_expression(&member.expression, ctx)?;
ctx.inst(Inst::new(OpCode::DELETE_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::DELETE_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
obj_reg
}
_ => return Err("invalid delete target".into()),
@@ -150,13 +177,23 @@ impl Emitter {
let cons_reg = self.emit_expression(&cond.consequent, ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(cons_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(cons_reg),
Operand::None,
));
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(else_label, ctx.insts.len());
let alt_reg = self.emit_expression(&cond.alternate, ctx)?;
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(alt_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(alt_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(result_reg)
@@ -220,13 +257,18 @@ impl Emitter {
match &update.argument {
SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => {
let name = id.name.as_str();
// Check if this is an upvalue or captured cell reference
// 判断目标是 upvalue 还是被捕获 cell
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
let captured_cell = ctx.captured_bindings.get(name).copied();
if let Some(uv) = uv_idx {
// Upvalue: LOAD_UPVALUE + CONST(1) + ADD/SUB + STORE_UPVALUE
// upvalue:LOAD_UPVALUE + 常量 1 + ADD/SUB + STORE_UPVALUE
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_UPVALUE, Operand::Reg(val_reg), Operand::Imm(uv as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_UPVALUE,
Operand::Reg(val_reg),
Operand::Imm(uv as u16),
Operand::None,
));
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
@@ -236,15 +278,30 @@ impl Emitter {
OpCode::SUB
};
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(val_reg), Operand::Reg(one_reg)));
ctx.inst(Inst::new(OpCode::STORE_UPVALUE, Operand::None, Operand::Reg(val_reg), Operand::Imm(uv as u16)));
ctx.inst(Inst::new(
OpCode::STORE_UPVALUE,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(uv as u16),
));
Ok(val_reg)
} else if let Some(cell_idx) = captured_cell {
// Captured cell: CELL_GET + CONST(1) + ADD/SUB + CELL_SET
// 被捕获 cell:CELL_GET + 常量 1 + ADD/SUB + CELL_SET
let val_reg = ctx.alloc_reg();
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(val_reg), Operand::Reg(binding.reg), Operand::Imm(cell_idx as u16)));
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(val_reg),
Operand::Reg(binding.reg),
Operand::Imm(cell_idx as u16),
));
} else {
ctx.inst(Inst::new(OpCode::CELL_GET, Operand::Reg(val_reg), Operand::None, Operand::Imm(cell_idx as u16)));
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(val_reg),
Operand::None,
Operand::Imm(cell_idx as u16),
));
}
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
@@ -255,7 +312,12 @@ impl Emitter {
OpCode::SUB
};
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(val_reg), Operand::Reg(one_reg)));
ctx.inst(Inst::new(OpCode::CELL_SET, Operand::None, Operand::Reg(val_reg), Operand::Imm(cell_idx as u16)));
ctx.inst(Inst::new(
OpCode::CELL_SET,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(cell_idx as u16),
));
Ok(val_reg)
} else {
let var_reg = ctx.lookup_or_global(name);
+32 -7
View File
@@ -1,10 +1,10 @@
//! 标签模板表达式 emit:`emit_tagged_template_expression` 构造 template object 并调用标签函数。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
impl Emitter {
pub(crate) fn emit_tagged_template_expression(
&self, tt: &oxide_parser::TaggedTemplateExpression, ctx: &mut CompileCtx,
@@ -15,7 +15,12 @@ impl Emitter {
let tag_reg = self.emit_expression(&tt.tag, ctx)?;
let cooked_temp = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::NEW_ARRAY, Operand::Reg(cooked_temp), Operand::Imm(quasis.len() as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::NEW_ARRAY,
Operand::Reg(cooked_temp),
Operand::Imm(quasis.len() as u16),
Operand::None,
));
for (i, quasi) in quasis.iter().enumerate() {
let s = quasi.value.cooked.as_ref().map(|c| c.to_string()).unwrap_or_default();
let const_idx = ctx.add_constant(Constant::String(s));
@@ -24,11 +29,21 @@ impl Emitter {
let idx_const = ctx.add_constant(Constant::Int(i as i32));
let idx_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx_const));
ctx.inst(Inst::new(OpCode::SET_ELEM, Operand::Reg(cooked_temp), Operand::Reg(idx_reg), Operand::Reg(str_reg)));
ctx.inst(Inst::new(
OpCode::SET_ELEM,
Operand::Reg(cooked_temp),
Operand::Reg(idx_reg),
Operand::Reg(str_reg),
));
}
let raw_temp = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::NEW_ARRAY, Operand::Reg(raw_temp), Operand::Imm(quasis.len() as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::NEW_ARRAY,
Operand::Reg(raw_temp),
Operand::Imm(quasis.len() as u16),
Operand::None,
));
for (i, quasi) in quasis.iter().enumerate() {
let raw = quasi.value.raw.to_string();
let const_idx = ctx.add_constant(Constant::String(raw));
@@ -37,7 +52,12 @@ impl Emitter {
let idx_const = ctx.add_constant(Constant::Int(i as i32));
let idx_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx_const));
ctx.inst(Inst::new(OpCode::SET_ELEM, Operand::Reg(raw_temp), Operand::Reg(idx_reg), Operand::Reg(str_reg)));
ctx.inst(Inst::new(
OpCode::SET_ELEM,
Operand::Reg(raw_temp),
Operand::Reg(idx_reg),
Operand::Reg(str_reg),
));
}
let mut expr_temps = Vec::new();
@@ -52,7 +72,12 @@ impl Emitter {
expr_slots.push(ctx.alloc_reg());
}
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(cooked_slot), Operand::Reg(cooked_temp), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(cooked_slot),
Operand::Reg(cooked_temp),
Operand::None,
));
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(raw_slot), Operand::Reg(raw_temp), Operand::None));
for (slot, temp) in expr_slots.iter().zip(expr_temps.iter()) {
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(*slot), Operand::Reg(*temp), Operand::None));
@@ -2,9 +2,9 @@
//! 拼接字面量段与内插表达式。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
impl Emitter {
pub(crate) fn emit_template_literal_expression(
@@ -42,12 +42,7 @@ impl Emitter {
}
}
ctx.inst(Inst::template_str(
Operand::Reg(r),
segment_count as u32,
total_len_hint as u16,
&parts,
));
ctx.inst(Inst::template_str(Operand::Reg(r), segment_count as u32, total_len_hint as u16, &parts));
Ok(r)
}
+1 -1
View File
@@ -1,9 +1,9 @@
//! `this` 表达式 emit:`emit_this_expression` 解析当前函数的 this 寄存器。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
impl Emitter {
pub(crate) fn emit_this_expression(&self, ctx: &mut CompileCtx) -> Result<u32, String> {
+1 -1
View File
@@ -15,7 +15,7 @@ pub mod shared;
pub mod stmt;
pub mod symbol_table;
pub use emit::{CompileCtx, Emitter, FunctionBodyContext, LabelScope, ParamSpec};
pub use emit::{is_int_literal, is_side_effect_free};
pub use emit::{CompileCtx, Emitter, FunctionBodyContext, LabelScope, ParamSpec};
pub use oxide_bytecode::module::Constant;
pub use oxide_parser::{AssignmentOperator, BinaryOperator, UnaryOperator};
+9 -10
View File
@@ -8,8 +8,7 @@ use crate::{CompileCtx, Emitter};
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
impl Emitter {
/// builtin slot allocation ahead of the temporary register pool.
/// 在临时寄存器池之前分配 builtin 槽位。
pub(crate) fn pre_register_builtin_references(&self, stmts: &[Statement], ctx: &mut CompileCtx) {
for stmt in stmts {
self.pre_scan_builtin_stmt(stmt, ctx);
@@ -264,7 +263,6 @@ impl Emitter {
}
}
pub(crate) fn predeclare_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
for statement in statements {
let Statement::FunctionDeclaration(function) = statement else {
@@ -278,10 +276,8 @@ impl Emitter {
}
}
/// Pre-declare all `var` bindings in this statement list so hoisted function
/// declarations emitted earlier can resolve them. Mirrors the removed count
/// pass behavior (see fe8bd86): top-level `var` names must be visible while
/// compiling function bodies that close over them.
/// 预声明语句列表中的全部 `var` 绑定,使先发的提升函数声明能解析它们。
/// 顶层 `var` 名在编译闭包捕获它的函数体时必须可见。
pub(crate) fn predeclare_var_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
for statement in statements {
match statement {
@@ -315,8 +311,12 @@ impl Emitter {
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);
let _ = ctx.declare_initialized(
bi.name.as_str(),
reg,
VariableDeclarationKind::Var,
false,
);
}
}
}
@@ -344,5 +344,4 @@ impl Emitter {
}
}
}
}
+40 -11
View File
@@ -3,10 +3,10 @@
//! `emit_object_binding`、`emit_assign_target` 等。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{
ArrayAssignmentTarget, ArrayPattern, AssignmentTarget, AssignmentTargetMaybeDefault, AssignmentTargetProperty,
BindingPattern, Expression, ObjectAssignmentTarget, ObjectPattern, VariableDeclarationKind,
@@ -18,12 +18,22 @@ impl Emitter {
) -> Result<u32, String> {
let undef_reg = self.emit_undefined(ctx);
let eq_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::STRICT_EQ, Operand::Reg(eq_reg), Operand::Reg(val_reg), Operand::Reg(undef_reg)));
ctx.inst(Inst::new(
OpCode::STRICT_EQ,
Operand::Reg(eq_reg),
Operand::Reg(val_reg),
Operand::Reg(undef_reg),
));
// val != undefined(eq 为 false)→ 跳过默认值
let end_label = ctx.next_label_id();
ctx.inst(Inst::jmp_if_false(eq_reg, end_label));
let default_reg = self.emit_expression(default_expr, ctx)?;
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(val_reg), Operand::Reg(default_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(val_reg),
Operand::Reg(default_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(val_reg)
}
@@ -32,8 +42,7 @@ impl Emitter {
&self, name: &str, src_reg: u32, kind: VariableDeclarationKind, is_const: bool, ctx: &mut CompileCtx,
) -> Result<(), String> {
let target_reg = if matches!(kind, VariableDeclarationKind::Var) {
// `var` names are pre-declared (hoisting); reuse the pre-registered slot
// instead of allocating a new one so n_registers matches let/const.
// `var` 名已预声明(hoisting),复用预登记槽位而非新分配,使 n_registers 与 let/const 一致。
if let Some(reg) = ctx.scopes.symbols.lookup_any(name) {
reg
} else {
@@ -47,13 +56,23 @@ impl Emitter {
var_reg
};
if let Some(&cell_idx) = ctx.captured_bindings.get(name) {
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(src_reg), Operand::Imm(cell_idx as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(src_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
} else {
// B011: const 声明路径 STORE_VAR 恒 b=0,不查运行时 guard。
// const 声明路径 STORE_VAR 恒 b=0,不查运行时 guard。
// guard 读 regs[rd] 判断槽是否已初始化,依赖槽初始为 undefined;
// 声明冗余检查由编译期 declare() 完成(重复声明编译报错),
// 运行时 guard 只服务"对 const 再赋值"(赋值路径,见 emit_assign_target)。
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg), Operand::Reg(src_reg), Operand::Imm(0)));
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(target_reg),
Operand::Reg(src_reg),
Operand::Imm(0),
));
}
ctx.init_var(name);
Ok(())
@@ -132,9 +151,19 @@ impl Emitter {
ctx.inst(Inst::jmp_if_false(has_reg, loop_end));
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::FOR_OF_NEXT, Operand::Reg(val_reg), Operand::None, Operand::None));
ctx.inst(Inst::new(OpCode::SET_ELEM, Operand::Reg(rest_reg), Operand::Reg(idx_reg), Operand::Reg(val_reg)));
ctx.inst(Inst::new(
OpCode::SET_ELEM,
Operand::Reg(rest_reg),
Operand::Reg(idx_reg),
Operand::Reg(val_reg),
));
let tmp_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::INC_PRE, Operand::Reg(idx_reg), Operand::Reg(tmp_reg), Operand::Reg(tmp_reg)));
ctx.inst(Inst::new(
OpCode::INC_PRE,
Operand::Reg(idx_reg),
Operand::Reg(tmp_reg),
Operand::Reg(tmp_reg),
));
ctx.inst(Inst::jmp(loop_start));
ctx.labels.set_label_pos(loop_end, ctx.insts.len());
Ok(rest_reg)
+33 -8
View File
@@ -2,10 +2,10 @@
//! 函数:`emit_chainable_expression`、`emit_optional_guard`、`emit_chain_call` 等。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::{LabelId, Operand};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::{LabelId, Operand};
use oxide_parser::{ChainElement, Expression, LogicalOperator, PropertyKey};
impl Emitter {
@@ -45,7 +45,12 @@ impl Emitter {
}
let key_reg = self.emit_expression(&member.expression, ctx)?;
let value_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PROP_DYNAMIC, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(value_reg)));
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(value_reg),
));
Ok((value_reg, obj_reg))
}
@@ -68,7 +73,12 @@ impl Emitter {
}
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let callee_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PRIVATE, Operand::Reg(callee_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
Operand::Reg(callee_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
(callee_reg, obj_reg)
}
_ => {
@@ -152,7 +162,12 @@ impl Emitter {
}
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let value_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PRIVATE, Operand::Reg(value_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
Operand::Reg(value_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(value_reg)
}
Expression::CallExpression(call) => self.emit_chain_call(call, short_label, ctx),
@@ -182,7 +197,12 @@ impl Emitter {
}
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let value_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PRIVATE, Operand::Reg(value_reg), Operand::Reg(obj_reg), Operand::Reg(key_reg)));
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
Operand::Reg(value_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(value_reg)
}
ChainElement::CallExpression(call) => self.emit_chain_call(call, short_label, ctx),
@@ -204,7 +224,7 @@ impl Emitter {
Ok(())
}
pub(crate) fn emit_object_property_read( &self, src_reg: u32, key: &str, ctx: &mut CompileCtx) -> u32 {
pub(crate) fn emit_object_property_read(&self, src_reg: u32, key: &str, ctx: &mut CompileCtx) -> u32 {
let prop_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(prop_reg), Operand::Reg(src_reg), Operand::None));
let key_idx = ctx.add_constant(Constant::String(key.to_string()));
@@ -257,7 +277,12 @@ impl Emitter {
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(prop_reg), Operand::Reg(src_reg), Operand::None));
let key_reg = self.emit_property_key_expression(key, ctx)?;
let val_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::GET_PROP_DYNAMIC, Operand::Reg(prop_reg), Operand::Reg(key_reg), Operand::Reg(val_reg)));
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(prop_reg),
Operand::Reg(key_reg),
Operand::Reg(val_reg),
));
Ok((val_reg, None))
}
}
+7 -2
View File
@@ -1,9 +1,9 @@
//! 类字段初始化 emit:公有/私有实例字段与私有方法的实例化初始化。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{Expression, PropertyKey};
impl Emitter {
@@ -17,7 +17,12 @@ impl Emitter {
self.emit_undefined(ctx)
};
if computed {
ctx.inst(Inst::new(OpCode::SET_PROP_DYNAMIC, target, Operand::Reg(key_reg), Operand::Reg(value_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP_DYNAMIC,
target,
Operand::Reg(key_reg),
Operand::Reg(value_reg),
));
} else {
ctx.inst(Inst::new(OpCode::SET_PROP, target, Operand::Reg(value_reg), Operand::Reg(key_reg)));
}
+1 -1
View File
@@ -2,9 +2,9 @@
//! 函数:`private_name_id`、`emit_private_id_reg`、`emit_class_key_reg` 等。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_parser::PropertyKey;
impl Emitter {
@@ -1,9 +1,9 @@
//! return 语句 emit:`emit_return_statement` 求值返回值并生成返回指令。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::Statement;
impl Emitter {
+2 -2
View File
@@ -1,10 +1,10 @@
//! 控制流语句 emit:`if` 条件分支(含 else)与域分发 `emit_control_domain`。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::Statement;
impl Emitter {
@@ -1,9 +1,9 @@
//! 类声明语句 emit:`emit_class_declaration_statement` 声明类名并初始化类对象。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{Statement, VariableDeclarationKind};
impl Emitter {
@@ -23,7 +23,12 @@ impl Emitter {
ctx.init_var(&name);
let ctor_reg = self.emit_class(class, ctx)?;
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(var_reg), Operand::Imm(cell_idx as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(var_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
} else {
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg), Operand::Reg(ctor_reg), Operand::None));
}
@@ -1,9 +1,9 @@
//! 函数声明语句 emit:`emit_function_declaration_statement` 创建闭包并绑定函数名。
use crate::{CompileCtx, Emitter, ParamSpec};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::Statement;
impl Emitter {
@@ -38,7 +38,12 @@ impl Emitter {
ctx.reserve_reg(var_reg);
ctx.inst(Inst::create_closure(Operand::Reg(var_reg), ctx.nested.len() as u16));
if let Some(&cell_idx) = ctx.captured_bindings.get(&name) {
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(var_reg), Operand::Imm(cell_idx as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(var_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
} else {
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(var_reg), Operand::Reg(var_reg), Operand::None));
}
@@ -8,7 +8,9 @@ mod function_decl;
mod var;
impl Emitter {
pub(crate) fn emit_declaration_domain(&self, stmt: &Statement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
pub(crate) fn emit_declaration_domain(
&self, stmt: &Statement, ctx: &mut CompileCtx,
) -> Result<Option<u32>, String> {
match stmt {
Statement::VariableDeclaration(_) => self.emit_variable_declaration_statement(stmt, ctx),
Statement::FunctionDeclaration(_) => self.emit_function_declaration_statement(stmt, ctx),
@@ -1,10 +1,10 @@
//! var/let/const 声明语句 emit:声明 + 初始化表达式,处理提升与解构 pattern。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{BindingPattern, Expression, Statement, VariableDeclarationKind};
impl Emitter {
@@ -49,7 +49,12 @@ impl Emitter {
var_reg
};
if let Some(&cell_idx) = ctx.captured_bindings.get(bi.name.as_str()) {
ctx.inst(Inst::new(OpCode::MAKE_CELL, Operand::Reg(tmp), Operand::Imm(cell_idx as u16), Operand::None));
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(tmp),
Operand::Imm(cell_idx as u16),
Operand::None,
));
} else {
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg), Operand::Reg(tmp), Operand::None));
}
@@ -1,9 +1,9 @@
//! throw 语句 emit:`emit_throw_statement` 求值异常值并生成 THROW。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::Statement;
impl Emitter {
@@ -1,9 +1,9 @@
//! try/catch/finally 语句 emit:`emit_try_statement` 生成 TRY_BEGIN 与处理入口。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{Statement, VariableDeclarationKind};
impl Emitter {
@@ -29,7 +29,12 @@ impl Emitter {
last_try_result = Some(r);
}
}
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(last_try_result.unwrap_or(result_reg)), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(last_try_result.unwrap_or(result_reg)),
Operand::None,
));
if has_catch {
ctx.inst(Inst::new(OpCode::TRY_END, Operand::None, Operand::None, Operand::None));
}
@@ -54,7 +59,12 @@ impl Emitter {
last_catch_result = Some(r);
}
}
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(last_catch_result.unwrap_or(result_reg)), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(last_catch_result.unwrap_or(result_reg)),
Operand::None,
));
ctx.pop_scope();
}
if has_finally {
@@ -65,7 +75,12 @@ impl Emitter {
last_finally_result = Some(r);
}
}
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(last_finally_result.unwrap_or(result_reg)), Operand::None));
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(last_finally_result.unwrap_or(result_reg)),
Operand::None,
));
ctx.inst(Inst::new(OpCode::TRY_FINALLY_END, Operand::None, Operand::None, Operand::None));
}
ctx.labels.set_label_pos(try_end_label, ctx.insts.len());
@@ -5,7 +5,9 @@ use oxide_ir::inst::Inst;
use oxide_parser::Statement;
impl Emitter {
pub(crate) fn emit_do_while_statement(&self, stmt: &Statement, ctx: &mut CompileCtx) -> Result<Option<u32>, String> {
pub(crate) fn emit_do_while_statement(
&self, stmt: &Statement, ctx: &mut CompileCtx,
) -> Result<Option<u32>, String> {
let Statement::DoWhileStatement(dw) = stmt else {
return Ok(None);
};
+8 -3
View File
@@ -1,10 +1,10 @@
//! for 语句 emit:`emit_for_statement` 含 init/test/update 三段与循环跳转。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{BindingPattern, ForStatementInit, Statement, VariableDeclarationKind};
impl Emitter {
@@ -40,7 +40,12 @@ impl Emitter {
ctx.declare(bi.name.as_str(), var_reg, decl.kind, is_const)?;
var_reg
};
ctx.inst(Inst::new(OpCode::STORE_VAR, Operand::Reg(target_reg), Operand::Reg(tmp), Operand::None));
ctx.inst(Inst::new(
OpCode::STORE_VAR,
Operand::Reg(target_reg),
Operand::Reg(tmp),
Operand::None,
));
ctx.init_var(bi.name.as_str());
}
}
@@ -1,9 +1,9 @@
//! for-in 语句 emit:`emit_for_in_statement` 遍历可枚举属性名。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{ForStatementLeft, Statement, VariableDeclarationKind};
impl Emitter {
@@ -1,9 +1,9 @@
//! for-of 语句 emit:`emit_for_of_statement` 迭代器协议遍历。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::{ForStatementLeft, Statement};
impl Emitter {
+7 -2
View File
@@ -1,9 +1,9 @@
//! switch 语句 emit:case 匹配链 + 穿落(fallthrough)与 default,见 `emit_switch_statement`。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_bytecode::opcode::OpCode;
use oxide_parser::Statement;
impl Emitter {
@@ -22,7 +22,12 @@ impl Emitter {
if let Some(test) = &case.test {
let test_reg = self.emit_expression(test, ctx)?;
let eq_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::EQ, Operand::Reg(eq_reg), Operand::Reg(disc_reg), Operand::Reg(test_reg)));
ctx.inst(Inst::new(
OpCode::EQ,
Operand::Reg(eq_reg),
Operand::Reg(disc_reg),
Operand::Reg(test_reg),
));
ctx.inst(Inst::jmp_if_true(eq_reg, case_label));
}
}
+5 -5
View File
@@ -284,16 +284,16 @@ mod tests {
#[test]
fn var_hoists_to_function_scope() {
let mut st = SymbolTable::new();
// Global scope is FunctionScope
// 全局作用域是函数作用域
st.declare("x", 0, l(), false).unwrap();
st.init_var("x");
// Push a block scope
// 压入块作用域
st.push_scope();
// var declaration inside block should go to function scope
// 块内的 var 声明应落到函数作用域
st.declare("y", 1, v(), false).unwrap();
st.init_var("y");
st.pop_scope();
// y should be accessible (it was declared in function scope, not block scope)
// y 可见(声明在函数作用域而非块作用域)
assert_eq!(st.lookup("y").unwrap(), 1);
}
@@ -326,7 +326,7 @@ mod tests {
st.declare("y", 1, v(), false).unwrap();
st.pop_scope();
st.push_scope();
// Same function scope, so this should be a duplicate
// 同一函数作用域,故应为重复声明
assert!(st.declare("y", 2, v(), false).is_err());
st.pop_scope();
}