feat: class 公有字段 define 语义 + computed key 类定义期求值一次

This commit is contained in:
爱特每羊队
2026-08-09 09:35:24 +08:00
parent d4fffcdcc6
commit 38abdfd9ab
15 changed files with 470 additions and 67 deletions
+114 -8
View File
@@ -3,19 +3,21 @@
//! 函数:`emit_class`。
use crate::{CompileCtx, Emitter, FunctionBodyContext};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{Class, ClassElement, MethodDefinitionKind, PropertyKey};
use oxide_parser::{Class, ClassElement, Expression, MethodDefinitionKind, PropertyKey};
impl Emitter {
pub(crate) fn emit_class(&self, class: &Class, ctx: &mut CompileCtx) -> Result<u32, String> {
let elements = &class.body.body;
let mut constructor_method = None;
let mut instance_fields = Vec::new();
let mut instance_field_indices = Vec::new();
let mut private_names = Vec::<(String, u32)>::new();
let is_derived = class.super_class.is_some();
for element in &class.body.body {
for (idx, element) in elements.iter().enumerate() {
match element {
ClassElement::MethodDefinition(method) => {
let method = method.as_ref();
@@ -47,7 +49,7 @@ impl Emitter {
private_names.push((name, id));
}
if !prop.r#static {
instance_fields.push(prop);
instance_field_indices.push(idx);
}
}
ClassElement::AccessorProperty(_) => return Err("class accessor properties not yet supported".into()),
@@ -55,6 +57,29 @@ impl Emitter {
}
}
// 计算键 slot 分配:全部元素源码序(方法 + 公有字段),私有元素非 computed。
let mut computed_slot = 0u8;
let key_slots: Vec<Option<u8>> = elements
.iter()
.map(|e| {
let computed = match e {
ClassElement::MethodDefinition(m) => m.computed,
ClassElement::PropertyDefinition(p) => {
p.computed && !matches!(p.key, PropertyKey::PrivateIdentifier(_))
}
_ => false,
};
if computed {
let s = computed_slot;
computed_slot += 1;
Some(s)
} else {
None
}
})
.collect();
let any_computed = computed_slot > 0;
let (ctor_reg, proto_reg, super_reg) = self.emit_class_header(class, ctx)?;
let ctor_name = class.id.as_ref().map(|id| id.name.to_string());
let self_binding = ctor_name.as_deref().map(|name| vec![(name, ctor_reg)]).unwrap_or_default();
@@ -63,8 +88,33 @@ impl Emitter {
ctx.in_derived_constructor = is_derived;
ctx.scopes.private_name_map = private_names.clone();
// 实例公有字段 computed key 求值于构造器帧外,须类定义期存入数组。构造器以
// upvalue 捕获该数组:父作用域登记 `@@field_keys`(cell_idx 取现有最大 +1)。
let has_computed_instance = instance_field_indices.iter().any(|&i| {
let ClassElement::PropertyDefinition(p) = &elements[i] else { return false };
p.computed && !matches!(p.key, PropertyKey::PrivateIdentifier(_))
});
let field_key_cell: Option<u8> = if has_computed_instance {
let cell_idx = ctx.captured_bindings.values().copied().max().map_or(0, |m| m.saturating_add(1));
ctx.captured_bindings.insert("@@field_keys".to_string(), cell_idx);
Some(cell_idx)
} else {
None
};
// 字段值表达式运行于构造器帧:其自由变量须纳入构造器 upvalue 捕获。
let field_value_exprs: Vec<&Expression> = instance_field_indices
.iter()
.filter_map(|&i| match &elements[i] {
ClassElement::PropertyDefinition(p) => p.value.as_ref(),
_ => None,
})
.collect();
let extra_upvalue_names: Vec<(&str, u8)> = field_key_cell.map(|c| ("@@field_keys", c)).into_iter().collect();
let emit_instance_fields = |compiler: &Emitter, field_ctx: &mut CompileCtx| -> Result<(), String> {
for field in &instance_fields {
for &idx in &instance_field_indices {
let ClassElement::PropertyDefinition(field) = &elements[idx] else { unreachable!() };
let field = field.as_ref();
if let PropertyKey::PrivateIdentifier(private) = &field.key {
compiler.emit_private_field_init(
Operand::This,
@@ -78,6 +128,7 @@ impl Emitter {
&field.key,
field.computed,
field.value.as_ref(),
key_slots[idx],
field_ctx,
)?;
}
@@ -96,6 +147,8 @@ impl Emitter {
FunctionBodyContext::ClassElement,
Some(&emit_instance_fields),
is_derived,
&field_value_exprs,
&extra_upvalue_names,
)?
} else {
let mut module = self.compile_function_body_with_field_hooks(
@@ -107,14 +160,24 @@ impl Emitter {
FunctionBodyContext::ClassElement,
Some(&emit_instance_fields),
is_derived,
&field_value_exprs,
&extra_upvalue_names,
)?;
if is_derived {
module.insts.clear();
module.constants.clear();
module.n_registers = 1;
module.insts.push(Inst::super_call(Operand::None, Operand::None, 0));
// 字段初始化直接重发:构造器 upvalue/内置槽引用须与首轮编译产物对齐。
let mut field_ctx = CompileCtx::new();
field_ctx.scopes.private_name_map = private_names.clone();
field_ctx.scopes.builtin_reg_map = module.builtin_reg_map.clone();
field_ctx.current_upvalue_captures = module.upvalue_captures.clone();
field_ctx.field_keys_uv = module
.upvalue_captures
.iter()
.position(|u| u.name == "@@field_keys")
.map(|i| i as u8);
emit_instance_fields(self, &mut field_ctx)?;
module.insts.extend(field_ctx.insts);
module.constants = field_ctx.constants;
@@ -130,10 +193,53 @@ impl Emitter {
ctor_module.is_derived_constructor = is_derived;
ctor_module.function_name = ctor_name.clone();
ctx.nested.push(ctor_module);
// 键数组构建会在 keys 表达式中压入嵌套模块(箭头/函数/类键),
// 必须在压入后用固定下标引用构造器模块,避免嵌套长度偏移。
let ctor_sub_idx = ctx.nested.len() as u16;
self.emit_class_prototype(ctor_reg, proto_reg, super_reg, ctx.nested.len() as u16, ctx)?;
self.emit_class_methods(&class.body.body, ctor_reg, proto_reg, &self_binding, ctx)?;
self.emit_class_static_elements(&class.body.body, ctor_reg, ctx)?;
// 类定义期按源码序求值全部 computed key(extends 之后、构造器闭包创建之前),
// 存数组供方法/静态字段/实例字段初始化阶段按 slot 取用。
if any_computed {
let keys_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::NEW_ARRAY,
Operand::Reg(keys_reg),
Operand::Imm(computed_slot as u16),
Operand::None,
));
for (idx, element) in elements.iter().enumerate() {
let Some(slot) = key_slots[idx] else { continue };
let key_expr = match element {
ClassElement::MethodDefinition(m) => m.key.as_expression(),
ClassElement::PropertyDefinition(p) => p.key.as_expression(),
_ => None,
};
let Some(expr) = key_expr else { continue };
let key_reg = self.emit_expression(expr, ctx)?;
let idx_reg = ctx.alloc_reg();
let idx_const = ctx.add_constant(Constant::Int(slot as i32));
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx_const));
ctx.inst(Inst::new(
OpCode::SET_ELEM,
Operand::Reg(keys_reg),
Operand::Reg(idx_reg),
Operand::Reg(key_reg),
));
}
if let Some(cell_idx) = field_key_cell {
ctx.inst(Inst::new(
OpCode::MAKE_CELL,
Operand::Reg(keys_reg),
Operand::Imm(cell_idx as u16),
Operand::None,
));
}
ctx.class_keys_reg = Some(keys_reg);
}
self.emit_class_prototype(ctor_reg, proto_reg, super_reg, ctor_sub_idx, ctx)?;
self.emit_class_methods(&class.body.body, ctor_reg, proto_reg, &self_binding, &key_slots, ctx)?;
self.emit_class_static_elements(&class.body.body, ctor_reg, &key_slots, ctx)?;
ctx.scopes.private_name_map = saved_private_names;
Ok(ctor_reg)
+14 -8
View File
@@ -1,6 +1,7 @@
//! 类静态字段/元素 emit:`emit_class_static_elements`。
use crate::{CompileCtx, Emitter};
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{ClassElement, PropertyKey};
@@ -10,14 +11,14 @@ impl Emitter {
/// static z = this.y + 1` 必须按此顺序),若全部字段先于静态块发出,
/// `z` 会在 `y` 赋值前读到它。
pub(crate) fn emit_class_static_elements(
&self, elements: &[ClassElement], ctor_reg: u32, ctx: &mut CompileCtx,
&self, elements: &[ClassElement], ctor_reg: u32, key_slots: &[Option<u8>], ctx: &mut CompileCtx,
) -> Result<(), String> {
let saved_static_this = ctx.static_block_this_reg;
// static_block_this_reg 保留 u8(this 槽语义,254 特判),ctor_reg 超 u8 界时报错而非静默截断。
ctx.static_block_this_reg = Some(
u8::try_from(ctor_reg).map_err(|_| format!("class constructor register {ctor_reg} exceeds u8 limit"))?,
);
for element in elements {
for (element, &key_slot) in elements.iter().zip(key_slots) {
match element {
ClassElement::PropertyDefinition(prop) => {
let prop = prop.as_ref();
@@ -30,13 +31,18 @@ impl Emitter {
ctx,
)?;
} else {
self.emit_public_field_init(
// 静态字段在类定义期求值:computed key 从类定义期数组取,其余用常量。
let key_reg = if prop.computed {
self.emit_class_array_key_reg(key_slot.unwrap_or(0), ctx)?
} else {
self.emit_class_key_reg(&prop.key, false, ctx)?
};
let value_reg = self.emit_field_value(prop.value.as_ref(), ctx)?;
ctx.inst(Inst::define_prop(
Operand::Reg(ctor_reg),
&prop.key,
prop.computed,
prop.value.as_ref(),
ctx,
)?;
Operand::Reg(value_reg),
Operand::Reg(key_reg),
));
}
}
}
+7 -3
View File
@@ -11,9 +11,9 @@ use oxide_parser::{ClassElement, MethodDefinitionKind, PropertyKey};
impl Emitter {
pub(crate) fn emit_class_methods(
&self, elements: &[ClassElement], ctor_reg: u32, proto_reg: u32, self_binding: &[(&str, u32)],
ctx: &mut CompileCtx,
key_slots: &[Option<u8>], ctx: &mut CompileCtx,
) -> Result<(), String> {
for element in elements {
for (element, &key_slot) in elements.iter().zip(key_slots) {
if let ClassElement::MethodDefinition(method) = element {
let method = method.as_ref();
if method.kind == MethodDefinitionKind::Constructor {
@@ -25,7 +25,11 @@ impl Emitter {
continue;
}
let home_reg = if method.r#static { ctor_reg } else { proto_reg };
let key_reg = self.emit_class_key_reg(&method.key, method.computed, ctx)?;
let key_reg = if method.computed {
self.emit_class_array_key_reg(key_slot.unwrap_or(0), ctx)?
} else {
self.emit_class_key_reg(&method.key, false, ctx)?
};
let method_name = if method.computed {
"<computed>".to_string()
} else {
+66 -1
View File
@@ -7,7 +7,7 @@
use std::collections::{BTreeMap, HashSet};
use oxide_bytecode::module::UpvalueCapture;
use oxide_parser::{Expression, Statement};
use oxide_parser::{ClassBody, ClassElement, Expression, Statement};
use crate::Emitter;
@@ -127,6 +127,15 @@ impl Emitter {
self.collect_fn_default_names(&fd.params, ref_set, shadow, out);
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
}
Statement::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::IfStatement(is) => {
self.collect_capture_names_expr(&is.test, ref_set, shadow, out);
self.collect_capture_names_stmt(&is.consequent, ref_set, shadow, out);
@@ -211,6 +220,38 @@ impl Emitter {
}
}
/// 收集类体对 `ref_set` 的引用:方法/构造器体、字段键与值、静态块。
/// 方法形参与方法体局部声明遮蔽外层绑定(捕获判定用)。
fn collect_class_capture_names(
&self, class_body: &ClassBody, ref_set: &HashSet<String>, class_shadow: &HashSet<String>,
out: &mut HashSet<String>,
) {
for element in &class_body.body {
match element {
ClassElement::MethodDefinition(method) => {
let mut inner = class_shadow.clone();
inner.extend(self.collect_fn_param_names(&method.value.params));
let body: &[Statement] = method.value.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
inner.extend(self.collect_own_binding_names(&[], body));
self.collect_fn_default_names(&method.value.params, ref_set, class_shadow, out);
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
}
ClassElement::PropertyDefinition(prop) => {
if let Some(expr) = prop.key.as_expression() {
self.collect_capture_names_expr(expr, ref_set, class_shadow, out);
}
if let Some(value) = &prop.value {
self.collect_capture_names_expr(value, ref_set, class_shadow, out);
}
}
ClassElement::StaticBlock(block) => {
self.collect_capture_names_shadowed(&block.body, ref_set, class_shadow, out);
}
_ => {}
}
}
}
/// 遍历 catch 参数解构模式:收集模式内表达式引用(默认值等),声明名写入
/// `catch_shadow` 遮蔽 catch 作用域。
fn collect_capture_names_binding_pattern(
@@ -302,6 +343,14 @@ impl Emitter {
self.collect_fn_default_names(&ae.params, ref_set, shadow, out);
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
}
Expression::ClassExpression(class) => {
// 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。
let mut class_shadow = shadow.clone();
if let Some(id) = &class.id {
class_shadow.insert(id.name.as_str().to_string());
}
self.collect_class_capture_names(&class.body, ref_set, &class_shadow, out);
}
Expression::BinaryExpression(be) => {
self.collect_capture_names_expr(&be.left, ref_set, shadow, out);
self.collect_capture_names_expr(&be.right, ref_set, shadow, out);
@@ -447,6 +496,14 @@ impl Emitter {
self.collect_fn_default_captured(&fd.params, own, out);
self.collect_capture_names(body, own, out);
}
Statement::ClassDeclaration(cd) => {
// 类构造器/方法体与字段表达式引用的父级绑定须建 cell,供子模块 upvalue 捕获。
let mut class_shadow = HashSet::new();
if let Some(id) = &cd.id {
class_shadow.insert(id.name.as_str().to_string());
}
self.collect_class_capture_names(&cd.body, own, &class_shadow, out);
}
Statement::ExpressionStatement(es) => self.collect_captured_expr(&es.expression, own, out),
Statement::ReturnStatement(rs) => {
if let Some(a) = &rs.argument {
@@ -584,6 +641,14 @@ impl Emitter {
self.collect_fn_default_captured(&ae.params, own, out);
self.collect_capture_names_shadowed(&ae.body.statements, own, &inner, out);
}
Expression::ClassExpression(class) => {
// 类表达式:构造器/方法体与字段表达式引用的父级绑定须建 cell。
let mut class_shadow = HashSet::new();
if let Some(id) = &class.id {
class_shadow.insert(id.name.as_str().to_string());
}
self.collect_class_capture_names(&class.body, own, &class_shadow, out);
}
Expression::CallExpression(ce) => {
self.collect_captured_expr(&ce.callee, own, out);
for a in &ce.arguments {
+43 -4
View File
@@ -167,6 +167,11 @@ pub struct CompileCtx {
pub(crate) in_static_method: bool,
pub(crate) static_block_this_reg: Option<u8>,
pub(crate) field_buffer: Option<FieldBuffer>,
/// 类构造器模块中 `@@field_keys` upvalue 下标(实例字段 computed key 数组)。
/// 类定义期求值一次存入 cell,构造器经此 upvalue 读取。
pub(crate) field_keys_uv: Option<u8>,
/// 类定义期全部 computed key 数组寄存器(方法/静态字段阶段按 slot 读取)。
pub(crate) class_keys_reg: Option<u32>,
pub(crate) current_upvalue_captures: Vec<UpvalueCapture>,
/// 本函数作用域声明的绑定名(参数 + 变量/函数声明,AST 收集,emit 前确定)。
pub(crate) own_bindings: HashSet<String>,
@@ -258,6 +263,8 @@ impl CompileCtx {
in_static_method: false,
static_block_this_reg: None,
field_buffer: None,
field_keys_uv: None,
class_keys_reg: None,
current_upvalue_captures: Vec::new(),
own_bindings: HashSet::new(),
captured_bindings: BTreeMap::new(),
@@ -718,6 +725,8 @@ impl Emitter {
body_context,
None::<fn(&Emitter, &mut CompileCtx) -> Result<(), String>>,
false,
&[],
&[],
)
}
@@ -733,6 +742,7 @@ impl Emitter {
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
is_expression_body: bool, extra_bindings: &[(&str, u32)], body_context: FunctionBodyContext,
mut emit_fields: Option<E>, fields_after_super: bool,
extra_capture_exprs: &[&'a Expression<'a>], extra_upvalue_names: &[(&str, u8)],
) -> Result<IRFunction, String>
where
E: FnMut(&Emitter, &mut CompileCtx) -> Result<(), String>,
@@ -788,7 +798,21 @@ impl Emitter {
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
ctx.reset_regs();
let param_base = self.emit_params_prologue(param_specs, body_stmts, parent_ctx, &mut ctx, body_context)?;
let param_base = self.emit_params_prologue(
param_specs,
body_stmts,
parent_ctx,
&mut ctx,
body_context,
extra_capture_exprs,
extra_upvalue_names,
)?;
// 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。
ctx.field_keys_uv = ctx
.current_upvalue_captures
.iter()
.position(|u| u.name == "@@field_keys")
.map(|i| i as u8);
self.predeclare_function_declarations(body_stmts, &mut ctx);
@@ -854,7 +878,8 @@ impl Emitter {
/// 参数 prologue:函数作用域 + 参数声明/解构 + 闭包捕获与 upvalue 分析。返回 param_base。
fn emit_params_prologue<'a>(
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
ctx: &mut CompileCtx, body_context: FunctionBodyContext,
ctx: &mut CompileCtx, body_context: FunctionBodyContext, extra_capture_exprs: &[&'a Expression<'a>],
extra_upvalue_names: &[(&str, u8)],
) -> Result<u32, String> {
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
let param_base = ctx.next_reg;
@@ -900,7 +925,10 @@ impl Emitter {
arguments_reg = Some(reg);
}
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &param_defaults, &ctx.own_bindings);
// 字段初始化表达式(值表达式)与参数默认值一并纳入捕获分析。
let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone();
capture_exprs.extend_from_slice(extra_capture_exprs);
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings);
// 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。
if matches!(
body_context,
@@ -908,11 +936,22 @@ impl Emitter {
) {
ctx.current_upvalue_captures = self.collect_upvalue_names(
body_stmts,
&param_defaults,
&capture_exprs,
&parent_ctx.captured_bindings,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
);
// 类字段 computed key 数组等合成捕获:直接追加 upvalue(cell_idx 由父分配)。
for (name, cell_idx) in extra_upvalue_names {
if !ctx.current_upvalue_captures.iter().any(|u| u.name == *name) {
ctx.current_upvalue_captures.push(UpvalueCapture {
name: (*name).to_string(),
enclosing_reg: 0,
cell_idx: *cell_idx,
parent_uv_idx: None,
});
}
}
}
// 创建 arguments 对象:指令须在默认参数求值前发出(默认参数可引用 arguments)。
+55 -15
View File
@@ -221,25 +221,65 @@ impl Emitter {
let store_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let name = id_ref.name.as_str();
let var_reg = ctx.lookup_or_global(name);
// 目标判定:upvalue / 被捕获 cell / 普通槽,读与写须穿透共享单元。
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
let captured_cell = ctx.captured_bindings.get(name).copied();
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(var_reg),
Operand::None,
));
if let Some(uv) = uv_idx {
ctx.inst(Inst::new(
OpCode::LOAD_UPVALUE,
Operand::Reg(result_reg),
Operand::Imm(uv as u16),
Operand::None,
));
} else if let Some(cell_idx) = captured_cell {
let a_operand = match ctx.scopes.symbols.lookup_any_binding(name) {
Some((binding, _)) => Operand::Reg(binding.reg),
None => Operand::None,
};
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(result_reg),
a_operand,
Operand::Imm(cell_idx as u16),
));
} else {
let var_reg = ctx.lookup_or_global(name);
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),
));
if let Some(uv) = uv_idx {
ctx.inst(Inst::new(
OpCode::STORE_UPVALUE,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(uv as u16),
));
} else if let Some(cell_idx) = captured_cell {
ctx.inst(Inst::new(
OpCode::CELL_SET,
Operand::None,
Operand::Reg(val_reg),
Operand::Imm(cell_idx as u16),
));
} else {
let is_const = ctx.lookup_const_flag(name);
let const_flag = if is_const { 1 } else { 0 };
let var_reg = ctx.lookup_or_global(name);
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),
+9 -7
View File
@@ -451,19 +451,20 @@ impl Emitter {
));
Ok(if update.prefix { new_reg } else { old_reg })
} else if let Some(cell_idx) = captured_cell {
// 被捕获 cell:CELL_GET + 常量 1 + ADD/SUB + CELL_SET
let val_reg = ctx.alloc_reg();
// 被捕获 cell:CELL_GET 旧值 + 常量 1 + ADD/SUB + CELL_SET。
// 后缀形式须保留旧值(结果寄存器),前缀返回新值。
let old_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(old_reg),
Operand::Reg(binding.reg),
Operand::Imm(cell_idx as u16),
));
} else {
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(val_reg),
Operand::Reg(old_reg),
Operand::None,
Operand::Imm(cell_idx as u16),
));
@@ -476,14 +477,15 @@ impl Emitter {
} else {
OpCode::SUB
};
ctx.inst(Inst::new(op, Operand::Reg(val_reg), Operand::Reg(val_reg), Operand::Reg(one_reg)));
let new_reg = ctx.alloc_reg();
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
ctx.inst(Inst::new(
OpCode::CELL_SET,
Operand::None,
Operand::Reg(val_reg),
Operand::Reg(new_reg),
Operand::Imm(cell_idx as u16),
));
Ok(val_reg)
Ok(if update.prefix { new_reg } else { old_reg })
} else {
let var_reg = ctx.lookup_or_global(name);
let result_reg = ctx.alloc_reg();
+38 -20
View File
@@ -1,43 +1,61 @@
//! 类字段初始化 emit:公有/私有实例字段与私有方法的实例化初始化。
use crate::{CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{Expression, PropertyKey};
impl Emitter {
/// 实例字段初始化:define 语义(不触发原型 setter)。
/// 非计算键用字符串常量;计算键从 `@@field_keys` upvalue 数组按 `key_slot` 取(类定义期求值一次)。
pub(crate) fn emit_public_field_init(
&self, target: Operand, key: &PropertyKey, computed: bool, value: Option<&Expression>, ctx: &mut CompileCtx,
&self, target: Operand, key: &PropertyKey, computed: bool, value: Option<&Expression>,
key_slot: Option<u8>, ctx: &mut CompileCtx,
) -> Result<(), String> {
let key_reg = self.emit_class_key_reg(key, computed, ctx)?;
let value_reg = if let Some(expr) = value {
self.emit_expression(expr, ctx)?
let key_reg = if computed {
self.emit_instance_field_key(key_slot, ctx)?
} else {
self.emit_undefined(ctx)
self.emit_class_key_reg(key, false, ctx)?
};
if computed {
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)));
}
let value_reg = self.emit_field_value(value, ctx)?;
ctx.inst(Inst::define_prop(target, Operand::Reg(value_reg), Operand::Reg(key_reg)));
Ok(())
}
/// 类定义期求值一次后存入 upvalue 数组的计算键读取:`arr[slot]`。
fn emit_instance_field_key(&self, key_slot: Option<u8>, ctx: &mut CompileCtx) -> Result<u32, String> {
let uv = ctx.field_keys_uv.expect("computed instance field without field keys upvalue");
let arr_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_UPVALUE, Operand::Reg(arr_reg), Operand::Imm(uv as u16), Operand::None));
let idx_reg = ctx.alloc_reg();
let idx = ctx.add_constant(Constant::Int(key_slot.unwrap_or(0) as i32));
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx));
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(arr_reg),
Operand::Reg(idx_reg),
Operand::Reg(key_reg),
));
Ok(key_reg)
}
/// 字段值求值:有值求表达式,无值 define undefined。
pub(crate) fn emit_field_value(&self, value: Option<&Expression>, ctx: &mut CompileCtx) -> Result<u32, String> {
if let Some(expr) = value {
self.emit_expression(expr, ctx)
} else {
Ok(self.emit_undefined(ctx))
}
}
pub(crate) fn emit_private_field_init(
&self, target: Operand, name: &str, value: Option<&Expression>, ctx: &mut CompileCtx,
) -> Result<(), String> {
let key_reg = self.emit_private_id_reg(name, ctx)?;
let value_reg = if let Some(expr) = value {
self.emit_expression(expr, ctx)?
} else {
self.emit_undefined(ctx)
};
let value_reg = self.emit_field_value(value, ctx)?;
ctx.inst(Inst::new(OpCode::INIT_PRIVATE, target, Operand::Reg(value_reg), Operand::Reg(key_reg)));
Ok(())
}
+17
View File
@@ -3,6 +3,7 @@
use crate::{CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::PropertyKey;
@@ -51,6 +52,22 @@ impl Emitter {
}
}
/// 从类定义期 computed key 数组按 slot 取键(方法/静态字段在类定义期使用)。
pub(crate) fn emit_class_array_key_reg(&self, slot: u8, ctx: &mut CompileCtx) -> Result<u32, String> {
let arr_reg = ctx.class_keys_reg.expect("class computed keys array missing");
let idx_reg = ctx.alloc_reg();
let idx = ctx.add_constant(Constant::Int(slot as i32));
ctx.inst(Inst::load_const(Operand::Reg(idx_reg), idx));
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(arr_reg),
Operand::Reg(idx_reg),
Operand::Reg(key_reg),
));
Ok(key_reg)
}
pub(crate) fn class_property_name(&self, key: &PropertyKey) -> Result<String, String> {
match key {
PropertyKey::StaticIdentifier(ident) => Ok(ident.name.as_str().to_string()),