feat: class 公有字段 define 语义 + computed key 类定义期求值一次
This commit is contained in:
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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()),
|
||||
|
||||
Reference in New Issue
Block a user