diff --git a/crates/oxide_builtins/src/iterator.rs b/crates/oxide_builtins/src/iterator.rs index 4e36137f..5a207f86 100644 --- a/crates/oxide_builtins/src/iterator.rs +++ b/crates/oxide_builtins/src/iterator.rs @@ -123,6 +123,30 @@ fn get_iterator(vm: &mut H, value: JsValue) -> Result it, + Err(err) => { + let exc = vm + .take_uncaught_value() + .unwrap_or_else(|| crate::error::create_type_error(vm, &err)); + return Err(exc); + } + }; + if !iterator.is_object() { + return Err(crate::error::create_type_error( + vm, + "Result of the Symbol.iterator method is not an object", + )); + } + return Ok(iterator); + } + } + // 鸭子回退:对象自身有可调用 next(Map/Set 迭代器包装等既有用法)。 let next_si = vm.kernel_core().perm_interner().intern("next").0; if let Ok(next) = vm.ordinary_get(obj, next_si, value) { if is_callable(next) { diff --git a/crates/oxide_emit/src/closure.rs b/crates/oxide_emit/src/closure.rs index 074c2027..bddc5a43 100644 --- a/crates/oxide_emit/src/closure.rs +++ b/crates/oxide_emit/src/closure.rs @@ -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, out: &mut HashSet, + ) { + 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); + } + } + } _ => {} } } diff --git a/crates/oxide_emit/src/expr/object/object_literal.rs b/crates/oxide_emit/src/expr/object/object_literal.rs index e5e69c4a..01047d4e 100644 --- a/crates/oxide_emit/src/expr/object/object_literal.rs +++ b/crates/oxide_emit/src/expr/object/object_literal.rs @@ -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 { + "".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, )); } } diff --git a/crates/oxide_emit/src/expr/operator/mod.rs b/crates/oxide_emit/src/expr/operator/mod.rs index c6b84b72..d62d754c 100644 --- a/crates/oxide_emit/src/expr/operator/mod.rs +++ b/crates/oxide_emit/src/expr/operator/mod.rs @@ -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();