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
+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()),