This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_emit/src/expr/object/object_literal.rs
T

116 lines
5.1 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 对象字面量 emit:`emit_object_expression` 逐属性定义(含 getter/setter/展开)。
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::{ObjectPropertyKind, PropertyKind};
impl Emitter {
pub(crate) fn emit_object_expression(
&self, obj: &oxide_parser::ObjectExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let obj_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::NEW_OBJECT, Operand::Reg(obj_reg), Operand::None, Operand::None));
for prop in &obj.properties {
let ObjectPropertyKind::SpreadProperty(spread) = prop else {
self.emit_object_property(obj_reg, prop, ctx)?;
continue;
};
// spread 展开:把源表达式的可枚举自有属性写入目标对象(原地改)。
// 顺序语义:{...b, a:1} 在 spread 之后定义 a,后者覆盖前者(从左到右求值)。
let src_reg = self.emit_expression(&spread.argument, ctx)?;
ctx.inst(Inst::spread_object(Operand::Reg(obj_reg), Operand::Reg(src_reg)));
}
Ok(obj_reg)
}
fn emit_object_property(
&self, obj_reg: u32, prop: &oxide_parser::ObjectPropertyKind, ctx: &mut CompileCtx,
) -> Result<(), String> {
let ObjectPropertyKind::ObjectProperty(p) = prop else {
return Err("unsupported object property kind".into());
};
let computed = p.computed;
let prop_name = if computed {
"<computed>".to_string()
} else {
self.class_property_name(&p.key)?
};
match p.kind {
PropertyKind::Get | PropertyKind::Set => {
// 计算键:键表达式先于访问器函数求值(规范求值序),键值运行时
// 由 DEFINE_ACCESSOR_DYNAMIC 从 key_reg 读取。
let key_reg = if computed {
Some(self.emit_expression(p.key.to_expression(), ctx)?)
} else {
None
};
let accessor_reg = self.emit_expression(&p.value, ctx)?;
if !computed {
if let Some(sub_mod) = ctx.nested.last_mut() {
// 访问器函数名带 "get "/"set " 前缀(SetFunctionName 语义)。
// 计算键的键值运行时才知,静态无法定名,保持匿名。
let fn_name = match p.kind {
PropertyKind::Get => format!("get {prop_name}"),
PropertyKind::Set => format!("set {prop_name}"),
_ => prop_name.clone(),
};
sub_mod.function_name = Some(fn_name);
}
}
let undef_reg = self.emit_undefined(ctx);
let (get_reg, set_reg) = if p.kind == PropertyKind::Get {
(accessor_reg, undef_reg)
} else {
(undef_reg, accessor_reg)
};
match key_reg {
Some(key_reg) => {
ctx.inst(Inst::define_accessor_dynamic(
Operand::Reg(obj_reg),
Operand::Reg(get_reg),
Operand::Reg(set_reg),
key_reg,
));
}
None => {
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
ctx.inst(Inst::define_accessor(
Operand::Reg(obj_reg),
Operand::Reg(get_reg),
Operand::Reg(set_reg),
idx as u32,
));
}
}
}
_ => {
let key_reg = if computed {
self.emit_expression(p.key.to_expression(), ctx)?
} else {
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
let reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
reg
};
let val_reg = self.emit_expression(&p.value, ctx)?;
if crate::is_anonymous_function_definition(&p.value) {
if let Some(sub_mod) = ctx.nested.last_mut() {
sub_mod.function_name = Some(prop_name.to_string());
}
}
let op = if computed { OpCode::SET_PROP_DYNAMIC } else { OpCode::SET_PROP };
let operands = if computed {
(Operand::Reg(key_reg), Operand::Reg(val_reg))
} else {
(Operand::Reg(val_reg), Operand::Reg(key_reg))
};
ctx.inst(Inst::new(op, Operand::Reg(obj_reg), operands.0, operands.1));
}
}
Ok(())
}
}