mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
docs: 补全 emit 小文件文档并改写类注释
This commit is contained in:
@@ -130,12 +130,10 @@ impl Emitter {
|
||||
|
||||
let (ctor_reg, proto_reg, super_reg) = self.emit_class_header(class, ctx)?;
|
||||
let self_binding = ctor_name.as_deref().map(|name| vec![(name, binding_reg)]).unwrap_or_default();
|
||||
// Class-name binding cell: class elements (ctor/method/field) that reference the
|
||||
// class name capture it through this dedicated cell. Reads inside the class then
|
||||
// resolve via LOAD_UPVALUE (same cell as the binding), so identity with other
|
||||
// references survives epoch promotion (which rewrites cell values) and inline
|
||||
// accessor calls (which clear the register file). The synthetic key keeps user
|
||||
// bindings with the same name (outer scopes) untouched.
|
||||
// 类名绑定 cell:引用类名的类元素(构造器/方法/字段)经此专用 cell 捕获。
|
||||
// 类体内的读取经 LOAD_UPVALUE 命中同一 cell,使类名与其它引用在 epoch 晋升
|
||||
// (会改写 cell 值)与内联 accessor 调用(会清空寄存器文件)之后仍保持 identity
|
||||
// 一致;合成键 @@class_self_N 不影响外层作用域的同名用户绑定。
|
||||
let class_self_cell: Option<u8> = ctor_name.as_deref().map(|_| {
|
||||
let cell_idx = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
|
||||
ctx.captured_bindings.insert(format!("@@class_self_{cell_idx}"), cell_idx);
|
||||
@@ -403,8 +401,7 @@ impl Emitter {
|
||||
Operand::None,
|
||||
));
|
||||
if let Some(cell_idx) = class_self_cell {
|
||||
// Initialize the class-name cell with the constructor and release TDZ
|
||||
// (the placeholder cell was created by the element closures at hoist time).
|
||||
// 以构造器初始化类名 cell 并解除 TDZ(占位 cell 已由类元素闭包在 hoist 期创建)。
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::MAKE_CELL,
|
||||
Operand::Reg(binding_reg),
|
||||
|
||||
@@ -11,8 +11,9 @@ impl Emitter {
|
||||
&self, ctor_reg: u32, proto_reg: u32, super_reg: Option<u32>, sub_idx: u16, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
ctx.inst(Inst::create_closure(Operand::Reg(ctor_reg), sub_idx));
|
||||
// 类原型 session 直分:实例 [[Prototype]] 与 Class.prototype 两侧须同一
|
||||
// 对象,epoch 分配在逃逸写晋升时克隆出第二份分裂 identity。
|
||||
// 类原型对象直接分配在 session 层:实例 [[Prototype]] 与 Class.prototype 属性
|
||||
// 两个引用须指向同一对象。若分配在 epoch 层,首次逃逸写会将其晋升克隆为
|
||||
// session 层的第二个对象,两个引用不再 identity 相同。
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::NEW_SESSION_OBJECT,
|
||||
Operand::Reg(proto_reg),
|
||||
|
||||
@@ -11,6 +11,7 @@ use oxide_ir::operand::{LabelId, Operand};
|
||||
use oxide_parser::{ChainElement, Expression, LogicalOperator, PropertyKey};
|
||||
|
||||
impl Emitter {
|
||||
/// 可选链短路守卫:`reg` 为 null 或 undefined 时跳转到短路标签 `short_label`。
|
||||
fn emit_optional_guard(&self, reg: u32, short_label: LabelId, ctx: &mut CompileCtx) -> Result<(), String> {
|
||||
let dup_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(reg), Operand::None));
|
||||
@@ -18,6 +19,7 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 静态成员读取并保留 base 寄存器,返回 `(值寄存器, base 寄存器)` 供链上后续调用取 this。
|
||||
fn emit_static_member_get_preserve_base(
|
||||
&self, member: &oxide_parser::StaticMemberExpression, short_label: Option<LabelId>, ctx: &mut CompileCtx,
|
||||
) -> Result<(u32, u32), String> {
|
||||
@@ -36,6 +38,7 @@ impl Emitter {
|
||||
Ok((value_reg, obj_reg))
|
||||
}
|
||||
|
||||
/// 计算成员读取并保留 base 寄存器;常量字符串键折叠为 IC 静态路径,其余走动态属性读,返回 `(值寄存器, base 寄存器)`。
|
||||
fn emit_computed_member_get_preserve_base(
|
||||
&self, member: &oxide_parser::ComputedMemberExpression, short_label: Option<LabelId>, ctx: &mut CompileCtx,
|
||||
) -> Result<(u32, u32), String> {
|
||||
@@ -66,6 +69,7 @@ impl Emitter {
|
||||
Ok((value_reg, obj_reg))
|
||||
}
|
||||
|
||||
/// 链上调用:成员 / 私有字段调用的 this 取链 base,其余调用为 undefined;实参打包与内置调用分派在此完成。
|
||||
fn emit_chain_call(
|
||||
&self, call: &oxide_parser::CallExpression, short_label: Option<LabelId>, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
@@ -160,6 +164,7 @@ impl Emitter {
|
||||
Ok(result_reg)
|
||||
}
|
||||
|
||||
/// 递归发射链元素并返回结果寄存器;可短路点由 `short_label` 标记。
|
||||
fn emit_chainable_expression(
|
||||
&self, expr: &Expression, short_label: Option<LabelId>, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
@@ -198,6 +203,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 发射单个 `ChainElement`,按变体分派成员读取 / 私有字段 / 调用;TS 非空断言不支持,直接报错。
|
||||
pub(crate) fn emit_chain_element(
|
||||
&self, element: &ChainElement, short_label: Option<LabelId>, ctx: &mut CompileCtx,
|
||||
) -> Result<u32, String> {
|
||||
@@ -235,6 +241,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 逻辑赋值短路测试:按 And / Or / Coalesce 选择跳转条件,未短路则落入赋值路径。
|
||||
pub(crate) fn emit_logical_assign_test(
|
||||
&self, op: LogicalOperator, test_reg: u32, store_label: LabelId, end_label: LabelId, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
@@ -249,6 +256,7 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 对象属性静态读:键已由调用方取为字符串,本函数按常量键走 IC 读并返回属性寄存器。
|
||||
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));
|
||||
@@ -259,6 +267,7 @@ impl Emitter {
|
||||
prop_reg
|
||||
}
|
||||
|
||||
/// 将属性键求值为寄存器:字面量键直接取常量,其余形态走通用表达式分发。
|
||||
fn emit_property_key_expression(&self, key: &PropertyKey, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||
match key {
|
||||
// 标识符计算键(`{[k]: a}`)走通用表达式分发:经 emit_static_identifier_read
|
||||
@@ -293,6 +302,8 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 读取对象属性并产出键信息:非计算键走字符串常量 IC 路径,计算键在字面量可折叠时走 IC,否则动态求值。
|
||||
/// 返回 `(结果寄存器, 常量键名, 动态键寄存器)`,后两者互补为 None。
|
||||
pub(crate) fn emit_object_property_read_key(
|
||||
&self, src_reg: u32, key: &PropertyKey, computed: bool, ctx: &mut CompileCtx,
|
||||
) -> Result<(u32, Option<String>, Option<u32>), String> {
|
||||
|
||||
@@ -56,6 +56,7 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
/// 私有字段初始化:以私有名 id 做 `init_private` 写实例 own 属性。
|
||||
pub(crate) fn emit_private_field_init(
|
||||
&self, target: Operand, name: &str, value: Option<&Expression>, ctx: &mut CompileCtx,
|
||||
) -> Result<(), String> {
|
||||
@@ -65,6 +66,7 @@ impl Emitter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 私有方法初始化:方法经 `init_private` 写入,getter / setter 对经 `define_accessor` 共享同一私有名 id。
|
||||
pub(crate) fn emit_private_method_init(
|
||||
&self, target: Operand, method: &oxide_parser::MethodDefinition, home_reg: Operand,
|
||||
self_binding: &[(&str, u32)], class_self_cell: Option<u8>, ctx: &mut CompileCtx,
|
||||
|
||||
@@ -59,6 +59,7 @@ impl SymbolTable {
|
||||
});
|
||||
}
|
||||
|
||||
/// 按给定类型压入新作用域(函数或块)。
|
||||
pub(crate) fn push_scope_with_kind(&mut self, kind: ScopeKind) {
|
||||
self.scopes.push(Scope { bindings: HashMap::new(), kind });
|
||||
}
|
||||
@@ -70,6 +71,7 @@ impl SymbolTable {
|
||||
}
|
||||
}
|
||||
|
||||
/// 从内向外查找最近的函数作用域下标,作为 `var` 的提升目标;全局作用域即函数作用域,故恒能命中,兜底返回 0。
|
||||
pub(crate) fn find_var_target_scope(&self) -> usize {
|
||||
for (i, scope) in self.scopes.iter().enumerate().rev() {
|
||||
if scope.kind == ScopeKind::FunctionScope {
|
||||
@@ -119,6 +121,7 @@ impl SymbolTable {
|
||||
Err(format!("Identifier '{name}' is not defined"))
|
||||
}
|
||||
|
||||
/// 从内向外查绑定并仅返回寄存器号;不检查初始化态,供无需 TDZ 判定的写路径使用。
|
||||
pub(crate) fn lookup_any(&self, name: &str) -> Option<u32> {
|
||||
self.scopes
|
||||
.iter()
|
||||
@@ -126,6 +129,7 @@ impl SymbolTable {
|
||||
.find_map(|scope| scope.bindings.get(name).map(|binding| binding.reg))
|
||||
}
|
||||
|
||||
/// 从内向外查绑定,返回绑定引用及其作用域下标(0 = 全局作用域,供顶层判定)。
|
||||
pub(crate) fn lookup_any_binding(&self, name: &str) -> Option<(&Binding, usize)> {
|
||||
for (i, scope) in self.scopes.iter().enumerate().rev() {
|
||||
if let Some(b) = scope.bindings.get(name) {
|
||||
|
||||
Reference in New Issue
Block a user