feat(iter): 迭代协议支持对象字面量 computed key 与 upvalue 捕获
This commit is contained in:
@@ -491,6 +491,66 @@ impl Emitter {
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ObjectExpression(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
self.collect_captured_expr(&p.value, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::NewExpression(ne) => {
|
||||
self.collect_captured_expr(&ne.callee, own, out);
|
||||
for a in &ne.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ComputedMemberExpression(m) => {
|
||||
self.collect_captured_expr(&m.object, own, out);
|
||||
self.collect_captured_expr(&m.expression, own, out);
|
||||
}
|
||||
Expression::StaticMemberExpression(m) => self.collect_captured_expr(&m.object, own, out),
|
||||
Expression::PrivateFieldExpression(m) => self.collect_captured_expr(&m.object, own, out),
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
for e in &tl.expressions {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
self.collect_captured_expr(&tt.tag, own, out);
|
||||
for e in &tt.quasi.expressions {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => self.collect_captured_expr(&p.expression, own, out),
|
||||
Expression::ChainExpression(c) => self.collect_captured_chain(&c.expression, own, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_captured_chain(
|
||||
&self, element: &oxide_parser::ChainElement, own: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
match element {
|
||||
oxide_parser::ChainElement::StaticMemberExpression(m) => {
|
||||
self.collect_captured_expr(&m.object, own, out);
|
||||
}
|
||||
oxide_parser::ChainElement::ComputedMemberExpression(m) => {
|
||||
self.collect_captured_expr(&m.object, own, out);
|
||||
self.collect_captured_expr(&m.expression, own, out);
|
||||
}
|
||||
oxide_parser::ChainElement::PrivateFieldExpression(m) => {
|
||||
self.collect_captured_expr(&m.object, own, out);
|
||||
}
|
||||
oxide_parser::ChainElement::CallExpression(c) => {
|
||||
self.collect_captured_expr(&c.callee, own, out);
|
||||
for a in &c.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use oxide_bytecode::module::Constant;
|
||||
use oxide_bytecode::opcode::OpCode;
|
||||
use oxide_ir::inst::Inst;
|
||||
use oxide_ir::operand::Operand;
|
||||
use oxide_parser::{Expression, ObjectPropertyKind, PropertyKey, PropertyKind};
|
||||
use oxide_parser::{Expression, ObjectPropertyKind, PropertyKind};
|
||||
|
||||
impl Emitter {
|
||||
pub(crate) fn emit_object_expression(
|
||||
@@ -17,13 +17,17 @@ impl Emitter {
|
||||
let ObjectPropertyKind::ObjectProperty(p) = prop else {
|
||||
return Err("spread properties not yet supported".into());
|
||||
};
|
||||
let prop_name = match &p.key {
|
||||
PropertyKey::StaticIdentifier(ident) => ident.name.as_str().to_string(),
|
||||
PropertyKey::StringLiteral(s) => s.value.to_string(),
|
||||
_ => return Err("unsupported object property key type".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 => {
|
||||
if computed {
|
||||
return Err("computed object accessors not yet supported".into());
|
||||
}
|
||||
let accessor_reg = self.emit_expression(&p.value, ctx)?;
|
||||
if let Some(sub_mod) = ctx.nested.last_mut() {
|
||||
sub_mod.function_name = Some(prop_name.to_string());
|
||||
@@ -43,20 +47,31 @@ impl Emitter {
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
let idx = ctx.add_constant(Constant::String(prop_name.to_string()));
|
||||
let key_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
|
||||
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 matches!(&p.value, Expression::ArrowFunctionExpression(_)) {
|
||||
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(
|
||||
OpCode::SET_PROP,
|
||||
op,
|
||||
Operand::Reg(obj_reg),
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Reg(key_reg),
|
||||
operands.0,
|
||||
operands.1,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,11 +261,12 @@ impl Emitter {
|
||||
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
|
||||
let captured_cell = ctx.captured_bindings.get(name).copied();
|
||||
if let Some(uv) = uv_idx {
|
||||
// upvalue:LOAD_UPVALUE + 常量 1 + ADD/SUB + STORE_UPVALUE
|
||||
let val_reg = ctx.alloc_reg();
|
||||
// upvalue:LOAD_UPVALUE + 常量 1 + ADD/SUB + STORE_UPVALUE;
|
||||
// 后缀形式返回旧值(前缀返回新值)。
|
||||
let old_reg = ctx.alloc_reg();
|
||||
ctx.inst(Inst::new(
|
||||
OpCode::LOAD_UPVALUE,
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Reg(old_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
Operand::None,
|
||||
));
|
||||
@@ -277,14 +278,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::STORE_UPVALUE,
|
||||
Operand::None,
|
||||
Operand::Reg(val_reg),
|
||||
Operand::Reg(new_reg),
|
||||
Operand::Imm(uv as u16),
|
||||
));
|
||||
Ok(val_reg)
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user