feat: 实现 yield* 委托语法(内层迭代器 next/return/throw 转发)

This commit is contained in:
爱特每羊队
2026-08-09 20:00:16 +08:00
parent 9787208c69
commit c4e7080883
9 changed files with 543 additions and 54 deletions
+75 -43
View File
@@ -3,7 +3,7 @@ use oxide_types::object::JsObject;
use oxide_types::private_key::make_well_known_symbol_key;
use oxide_types::value::JsValue;
use oxide_runtime_api::{NativeResult, VmHost};
use oxide_runtime_api::{to_object, NativeResult, VmHost};
const INNER_PROP: &str = "__inner__";
const INDEX_PROP: &str = "__index__";
@@ -26,7 +26,17 @@ pub fn iterator_from<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
/// 为任意值创建统一迭代器包装对象:String/Array/Map/Set 直接支持索引遍历,
/// 其它对象则要求提供可调用的 `next`。不可迭代时返回 TypeError。
pub fn make_iterator_for_value<H: VmHost>(vm: &mut H, value: JsValue) -> Result<JsValue, JsValue> {
match try_make_iterator(vm, value) {
match try_make_iterator_inner(vm, value, true) {
Ok(Some(iterator)) => Ok(iterator),
Ok(None) => Err(crate::error::create_type_error(vm, "value is not iterable")),
Err(err) => Err(err),
}
}
/// 同 [`make_iterator_for_value`],但包装器不绑定 `return` 方法(`yield*` 委托专用):
/// 委托转发对内层迭代器延迟 GetMethod,避免创建包装器时访问内层 return getter。
pub fn make_iterator_for_value_without_return<H: VmHost>(vm: &mut H, value: JsValue) -> Result<JsValue, JsValue> {
match try_make_iterator_inner(vm, value, false) {
Ok(Some(iterator)) => Ok(iterator),
Ok(None) => Err(crate::error::create_type_error(vm, "value is not iterable")),
Err(err) => Err(err),
@@ -38,13 +48,17 @@ pub fn make_iterator_for_value<H: VmHost>(vm: &mut H, value: JsValue) -> Result<
/// # 步骤
/// 1. 经迭代协议取内层迭代器(String/Array/Map/Set 直接作为内层,其余对象调用
/// `@@iterator` 或回退可调用的 `next`)。
/// 2. 包装成统一迭代器对象(带 `next` 与 `return`),供调用方逐个取元素。
/// 2. 包装成统一迭代器对象(带 `next` 与可选 `return`),供调用方逐个取元素。
///
/// # 返回值
/// - `Ok(Some(iterator))`:可迭代,返回包装器;
/// - `Ok(None)`:不可迭代(调用方回退 array-like 路径);
/// - `Err`:`@@iterator` getter/call 抛错,透传原异常值。
pub(crate) fn try_make_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<JsValue>, JsValue> {
/// - `bind_return` 控制是否暴露 `return` 方法(for-of/解构的 IteratorClose 需要,
/// `yield*` 委托不需要且须避免创建时访问内层 return getter)。
pub(crate) fn try_make_iterator_inner<H: VmHost>(
vm: &mut H, value: JsValue, bind_return: bool,
) -> Result<Option<JsValue>, JsValue> {
let inner = match get_iterator(vm, value) {
Ok(Some(inner)) => inner,
Ok(None) => return Ok(None),
@@ -65,12 +79,10 @@ pub(crate) fn try_make_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result
let next_fn = make_native_function(vm, "next", iterator_wrapper_next::<H> as *const (), 0);
vm.set_or_create_prop_value(wrapper_obj, next_si, next_fn);
// 把 IteratorClose 转发给内层迭代器,使 for-of 异常退出时可清理。
// 仅当内层提供可调用的 return 方法时包装器才暴露 return:内建集合
// (数组/字符串等索引迭代)无 return 方法,此时 GetMethod 应返回 undefined
// (IteratorClose 跳过),否则 return() 结果 undefined 会被误判为非对象报错。
// for-of/解构的 IteratorClose 需要 return 方法:条件暴露(内层有可调用 return 时)。
// `yield*` 委托(bind_return=false)不绑定,转发时对内层延迟 GetMethod。
let return_si = vm.kernel_core().perm_interner().intern("return").0;
if inner.is_object() {
if bind_return && inner.is_object() {
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
if let Ok(return_fn) = vm.ordinary_get(inner_obj, return_si, inner) {
if is_callable(return_fn) {
@@ -94,13 +106,16 @@ fn iterator_wrapper_return<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
Ok(inner) if inner.is_object() => inner,
_ => return NativeResult::Ok(JsValue::undefined()),
};
// 延迟 GetMethod:内层无 return 方法时返回 undefined(IteratorClose 跳过)。
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
let return_si = vm.kernel_core().perm_interner().intern("return").0;
let return_fn = match vm.ordinary_get(inner_obj, return_si, inner) {
Ok(f) if is_callable(f) => f,
_ => return NativeResult::Ok(JsValue::undefined()),
};
match vm.call_function_sync(return_fn, inner, &[]) {
// 转发调用实参(`yield*` 委托的 return(v) 语义),缺省为 undefined。
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
match vm.call_function_sync(return_fn, inner, &[arg]) {
Ok(result) => NativeResult::Ok(result),
Err(err) => match vm.take_uncaught_value() {
Some(original) => NativeResult::Err(original),
@@ -136,9 +151,17 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
let next_si = vm.kernel_core().perm_interner().intern("next").0;
let next = match vm.ordinary_get(inner_obj, next_si, inner) {
Ok(next) => next,
Err(err) => return NativeResult::Err(crate::error::create_type_error(vm, &err)),
Err(err) => {
// GetMethod 的 next getter 抛错:透传原异常,不重新包装成 TypeError。
return match vm.take_uncaught_value() {
Some(original) => NativeResult::Err(original),
None => NativeResult::Err(crate::error::create_type_error(vm, &err)),
};
}
};
return match vm.call_function_sync(next, inner, &[]) {
// 转发调用实参(`yield*` 委托的 next(v) 语义),缺省为 undefined。
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
return match vm.call_function_sync(next, inner, &[arg]) {
Ok(result) => NativeResult::Ok(result),
// 透传原始抛出的值(任意类型)而非重新包装成 TypeError,
// 使外围 try/catch 能看到真正的错误。
@@ -203,44 +226,53 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<Option<JsValue>
return Ok(Some(value));
}
if value.is_object() {
let obj = unsafe { &*value.as_js_object_ptr() };
// 迭代协议:GetIterator 先取 value[Symbol.iterator] 并调用。
let sym_iter_si = make_well_known_symbol_key(0);
let method = match vm.ordinary_get(obj, sym_iter_si, value) {
Ok(m) => m,
// 非字符串 primitive(boolean/number/symbol/bigint):GetIterator 先 ToObject,
// 再走迭代协议(如 `yield* true` 委托 Boolean.prototype[Symbol.iterator])。
// null/undefined 的 ToObject 失败按不可迭代处理。
let obj_value = if value.is_object() {
value
} else {
match to_object(value, vm) {
Ok(obj) => obj,
Err(_) => return Ok(None),
}
};
let obj = unsafe { &*obj_value.as_js_object_ptr() };
// 迭代协议:GetIterator 先取 value[Symbol.iterator] 并调用。
let sym_iter_si = make_well_known_symbol_key(0);
let method = match vm.ordinary_get(obj, sym_iter_si, obj_value) {
Ok(m) => m,
Err(err) => {
// GetMethod 取 @@iterator 时 getter 抛出:透传原值,不落入鸭子回退。
let exc = vm
.take_uncaught_value()
.unwrap_or_else(|| crate::error::create_type_error(vm, &err));
return Err(exc);
}
};
if is_callable(method) {
let iterator = match vm.call_function_sync(method, obj_value, &[]) {
Ok(it) => it,
Err(err) => {
// GetMethod 取 @@iterator 时 getter 抛出:透传原值,不落入鸭子回退。
let exc = vm
.take_uncaught_value()
.unwrap_or_else(|| crate::error::create_type_error(vm, &err));
return Err(exc);
}
};
if is_callable(method) {
let iterator = match vm.call_function_sync(method, value, &[]) {
Ok(it) => 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(Some(iterator));
if !iterator.is_object() {
return Err(crate::error::create_type_error(
vm,
"Result of the Symbol.iterator method is not an object",
));
}
// 鸭子回退:对象自身有可调用 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) {
return Ok(Some(value));
}
return Ok(Some(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, obj_value) {
if is_callable(next) {
return Ok(Some(obj_value));
}
}
@@ -366,7 +398,7 @@ fn is_typed_array_value(value: JsValue) -> bool {
}
/// 判断值是否为可调用对象(native 或字节码函数)。
pub(crate) fn is_callable(value: JsValue) -> bool {
pub fn is_callable(value: JsValue) -> bool {
if !value.is_object() {
return false;
}
+3 -1
View File
@@ -197,10 +197,12 @@ define_opcodes! {
INIT_PRIVATE = 0x74 => "INIT_PRIVATE",
PRIVATE_BRAND_IN = 0x75 => "PRIVATE_BRAND_IN",
// ── 生成器 (0x76-0x77) ──
// ── 生成器 (0x76-0x78) ──
YIELD = 0x76 => "YIELD", // rd=被让出的值(结果经 reg 0 交付,见 contract.rs)
// 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 next() 从这继续。
SUSPEND_BODY = 0x77 => "SUSPEND_BODY",
// `yield*` 委托:rd=内层可迭代对象;委托完成值经 reg 0 交付(与 YIELD 同协议)。
YIELD_STAR = 0x78 => "YIELD_STAR",
// ── 位运算 (0x80-0x8F) ──
BIT_AND = 0x80 => "BIT_AND",
+8 -2
View File
@@ -9,9 +9,15 @@ use oxide_parser::YieldExpression;
impl Emitter {
pub(crate) fn emit_yield_expression(&self, ye: &YieldExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
// 未支持:`yield*` 委托迭代,后续按 IteratorYield 协议实现。
// `yield*` 委托:求值内层可迭代对象后发 YIELD_STAR,运行时转发 next/return/throw。
// 委托完成值(内层 done 的 value)经 reg 0 交付,与普通 `yield` 同协议。
if ye.delegate {
return Err("yield* not yet supported".into());
let arg = ye.argument.as_ref().ok_or_else(|| "yield* requires an argument".to_string())?;
let inner_reg = self.emit_expression(arg, ctx)?;
ctx.inst(Inst::yield_star(Operand::Reg(inner_reg)));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None));
return Ok(result_reg);
}
// 求值被让出的值(`yield` 无参数时让出 undefined)。
let value_reg = if let Some(arg) = &ye.argument {
+4 -4
View File
@@ -19,8 +19,8 @@ impl Inst {
match self.op {
// CALL 系:结果隐式写 reg 0,rd 是 callee 的 use
OpCode::CALL | OpCode::CALL_NATIVE | OpCode::CALL_SPREAD => Some(0),
// YIELD:恢复时 next(v) 的 v 经 reg 0 交付(与 CALL 同协议)
OpCode::YIELD => Some(0),
// YIELD/YIELD_STAR:恢复时 next(v) 的 v / 委托完成值经 reg 0 交付(与 CALL 同协议)
OpCode::YIELD | OpCode::YIELD_STAR => Some(0),
// GET_PROP 系:结果写 a/b 槽而非 rd
OpCode::GET_PROP | OpCode::IC_GET_PROP => reg_of(&self.a),
OpCode::GET_PROP_DYNAMIC => reg_of(&self.b),
@@ -228,8 +228,8 @@ impl Inst {
}
// HALT:隐式读 reg 0(顶层返回值)
OpCode::HALT => uses.push(0),
// RETURN/THROW/YIELD:读 rd(None→0)
OpCode::RETURN | OpCode::THROW | OpCode::YIELD => push_operand(&mut uses, &self.rd),
// RETURN/THROW/YIELD/YIELD_STAR:读 rd(None→0)
OpCode::RETURN | OpCode::THROW | OpCode::YIELD | OpCode::YIELD_STAR => push_operand(&mut uses, &self.rd),
// 加载族:a 槽是 Const/Imm 立即数,无寄存器 use
OpCode::LOAD_CONST
| OpCode::CREATE_CLOSURE
+6
View File
@@ -273,6 +273,12 @@ impl Inst {
Self::new(OpCode::YIELD, src, Operand::None, Operand::None)
}
/// `yield*` 委托:`rd` 为内层可迭代对象。运行时取迭代器并转发 next/return/throw,
/// 委托完成值(内层 done 的 value)经 reg 0 交付,与 `yield_value` 同协议。
pub fn yield_star(src: Operand) -> Self {
Self::new(OpCode::YIELD_STAR, src, Operand::None, Operand::None)
}
/// 生成器 body 起点标记:调用时参数初始化完成后挂起于此,首次 `next()` 继续。
pub fn suspend_body() -> Self {
Self::new(OpCode::SUSPEND_BODY, Operand::None, Operand::None, Operand::None)
+313 -4
View File
@@ -8,10 +8,10 @@
use std::sync::Arc;
use oxide_builtins::iterator::make_iter_result;
use oxide_builtins::iterator::{is_callable, make_iter_result};
use oxide_bytecode::opcode;
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
use oxide_runtime_api::NativeResult;
use oxide_runtime_api::{to_boolean, NativeResult};
use oxide_types::mem::P;
use oxide_types::object::{Cell, JsObject, NativeFnPtr};
use oxide_types::value::JsValue;
@@ -62,6 +62,8 @@ pub(crate) struct GeneratorState {
pub for_in_iters: Vec<*mut ForInIter<'static>>,
pub for_of_iters: Vec<JsValue>,
pub last_for_of_result: JsValue,
/// `yield*` 委托中的内层迭代器:Some = 挂起在委托点,恢复时转发 next/return/throw。
pub delegated_iterator: Option<JsValue>,
pub saved_bytecode_stack: Vec<Vec<opcode::Instr>>,
pub saved_immutables_stack: Vec<*const [JsValue]>,
/// 在途异常/完成(throw 穿越 finally 挂起时保留,恢复后继续展开)。
@@ -86,12 +88,37 @@ pub(crate) enum GeneratorResumeMode {
pub(crate) enum GeneratorStep {
/// 让出:`value` 为 `yield` 的值,生成器仍可继续。
Suspended { value: JsValue },
/// `yield*` 委托让出:`value` 为内层迭代器的原始结果对象,外层 next() 原样返回
/// (透传内层 done/value 字段,spec GeneratorYield 语义)。
SuspendedRaw { value: JsValue },
/// 完成:`value` 为返回值。
Completed { value: JsValue },
/// 未捕获异常逃逸:`value` 为原异常值,调用方须重新抛出。
Thrown { value: JsValue },
}
/// `yield*` 首次推进(YIELD_STAR dispatch)的结局。
pub(crate) enum YieldStarOutcome {
/// 内层未 done:挂起外层,让出内层原始结果对象(原样透传)。
Suspend(JsValue),
/// 内层 done:委托完成,value 为委托值(写 reg 0 继续外层)。
Continue(JsValue),
/// 异常已展开到外层 catch/finally:继续 dispatch。
Unwind,
}
/// `yield*` 委托转发(生成器恢复时)的结局。
enum DelegateOutcome {
/// 内层未 done:保持委托挂起,让出 value。
Suspend { value: JsValue },
/// 内层消化 next/throw 后 done:委托结束,外层继续,value 为委托值。
Continue { value: JsValue },
/// 内层消化 return 后 done / 无 return 方法:委托结束,外层完成,value 为返回值。
Complete { value: JsValue },
/// 内层调用抛错且已展开到外层 catch/finally:委托终止,继续 dispatch。
Unwind,
}
impl Vm {
/// 调用生成器函数返回的迭代器对象:创建生成器实例、挂状态并执行调用时参数初始化。
///
@@ -124,6 +151,7 @@ impl Vm {
for_in_iters: Vec::new(),
for_of_iters: Vec::new(),
last_for_of_result: JsValue::undefined(),
delegated_iterator: None,
saved_bytecode_stack: Vec::new(),
saved_immutables_stack: Vec::new(),
exception_value: None,
@@ -313,6 +341,7 @@ impl Vm {
self.iters.for_in_iters.clear();
self.iters.for_of_iters.clear();
self.iters.last_for_of_result = JsValue::undefined();
self.delegated_iterator = None;
self.spill_stack.clear();
self.save_stack.clear();
self.saved_bytecode_stack.clear();
@@ -362,6 +391,7 @@ impl Vm {
self.iters.for_in_iters = std::mem::take(&mut state.for_in_iters);
self.iters.for_of_iters = std::mem::take(&mut state.for_of_iters);
self.iters.last_for_of_result = state.last_for_of_result;
self.delegated_iterator = state.delegated_iterator.take();
self.saved_bytecode_stack = std::mem::take(&mut state.saved_bytecode_stack);
self.saved_immutables_stack = std::mem::take(&mut state.saved_immutables_stack);
self.exception_value = state.exception_value.take();
@@ -371,8 +401,64 @@ impl Vm {
self.inline_callee = None;
state.phase = GeneratorPhase::Running;
// 注入模式:next(v) 写 reg 0;throw(e) 恢复异常上下文;return(v) 完成穿越。
match mode {
// `yield*` 委托恢复:把 next/return/throw 请求转发给内层迭代器,按内层
// 结局决定挂起透传 / 外层继续 / 外层完成 / 异常传播。
// 委托分支处置完毕后直接进入 dispatch,不再执行注入模式(reg 0 已就位)。
if self.delegated_iterator.is_some() {
let forwarded = self.delegate_forward(mode);
match forwarded {
Err(e) => {
// 委托期间异常逃逸(unwind 失败,已弹出全部帧):标记完成并交付 Thrown。
let exc = self
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_error(self, &e));
self.restore_inline_state(saved);
self.native_call_depth -= 1;
let state = unsafe { &mut *state_ptr };
state.phase = GeneratorPhase::Completed;
state.result = JsValue::undefined();
return Ok(GeneratorStep::Thrown { value: exc });
}
Ok(DelegateOutcome::Suspend { value }) => {
let state = unsafe { &mut *state_ptr };
state.phase = GeneratorPhase::Suspended;
self.snapshot_generator(state)?;
self.restore_inline_state(saved);
self.native_call_depth -= 1;
// 委托让出原样透传内层结果对象,不二次包装。
return Ok(GeneratorStep::SuspendedRaw { value });
}
Ok(DelegateOutcome::Continue { value }) => {
// 委托结束(内层消化 next/throw 后 done):yield* 表达式值为
// value,外层继续执行。
self.regs[0] = value;
}
Ok(DelegateOutcome::Complete { value }) => {
// 委托结束(内层消化 return 后 done 或无 return 方法):外层完成,
// 交付值为内层结果,穿越自身 finally。
let prev_dispatch = self.generator_dispatch;
self.generator_dispatch = true;
let completed = self.complete_generator_return(value);
self.generator_dispatch = prev_dispatch;
if let Some(completed) = completed? {
self.restore_inline_state(saved);
self.native_call_depth -= 1;
let state = unsafe { &mut *state_ptr };
state.phase = GeneratorPhase::Completed;
state.result = completed;
return Ok(GeneratorStep::Completed { value: completed });
}
// 进入 finally 穿越:继续 dispatch。
}
Ok(DelegateOutcome::Unwind) => {
// 内层调用抛错且已展开到外层 catch/finally:委托终止,继续 dispatch。
self.delegated_iterator = None;
}
}
} else {
// 注入模式:next(v) 写 reg 0;throw(e) 恢复异常上下文;return(v) 完成穿越。
match mode {
GeneratorResumeMode::Next(arg) => {
self.regs[0] = arg;
}
@@ -403,6 +489,7 @@ impl Vm {
return Ok(GeneratorStep::Completed { value: completed });
}
}
}
}
}
@@ -415,8 +502,13 @@ impl Vm {
// YIELD 让出:快照挂起状态。
if let Some(value) = self.generator_suspended.take() {
let state = unsafe { &mut *state_ptr };
// 委托挂起时 value 是内层原始结果对象,原样透传;普通 yield 才二次包装。
let delegating = self.delegated_iterator.is_some();
self.snapshot_generator(state)?;
self.restore_inline_state(saved);
if delegating {
return Ok(GeneratorStep::SuspendedRaw { value });
}
return Ok(GeneratorStep::Suspended { value });
}
@@ -443,6 +535,216 @@ impl Vm {
}
}
/// `yield*` 委托首次进入:GetIterator 取内层迭代器并推进一步。
///
/// # 步骤
/// 1. 经迭代协议把内层值包装为迭代器(不可迭代抛 TypeError)。
/// 2. 调内层 next(undefined) 得 {value, done}。
/// 3. done → 委托完成值交付(外层继续);未 done → 挂起,委托迭代器存入
/// `self.delegated_iterator`。
///
/// # 副作用
/// - 内层 next 同步执行,可能压入/弹出调用帧。
/// - 挂起时设置 `delegated_iterator`,由 snapshot_generator 存入生成器状态。
pub(crate) fn dispatch_yield_star(&mut self, rd: usize) -> Result<YieldStarOutcome, String> {
let inner = self.regs[rd];
let iterator = match oxide_builtins::iterator::make_iterator_for_value_without_return(self, inner) {
Ok(it) => it,
Err(exc) => {
self.last_uncaught_value = Some(exc);
return self.yield_star_raise(String::new());
}
};
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
let next_si = self.kernel_core.perm_interner().intern("next").0;
let next_fn = match self.ordinary_get(iter_obj, next_si, iterator) {
Ok(f) => f,
Err(e) => return self.yield_star_raise(e),
};
let result = if is_callable(next_fn) {
match self.call_function_sync(next_fn, iterator, &[JsValue::undefined()]) {
Ok(r) => r,
Err(e) => return self.yield_star_raise(e),
}
} else {
return self.yield_star_raise(self.error_message_text("TypeError", "iterator.next is not callable"));
};
if !result.is_object() {
return self.yield_star_raise(self.error_message_text("TypeError", "iterator result is not an object"));
}
let result_obj = unsafe { &*result.as_js_object_ptr() };
let done_si = self.kernel_core.perm_interner().intern("done").0;
let value_si = self.kernel_core.perm_interner().intern("value").0;
let done = to_boolean(match self.ordinary_get(result_obj, done_si, result) {
Ok(v) => v,
Err(e) => return self.yield_star_raise(e),
});
// done 时才读取 value(委托完成值);done=false 直接让出原始结果对象。
if done {
let value = match self.ordinary_get(result_obj, value_si, result) {
Ok(v) => v,
Err(e) => return self.yield_star_raise(e),
};
Ok(YieldStarOutcome::Continue(value))
} else {
self.delegated_iterator = Some(iterator);
// 挂起让出内层原始结果对象:外层 next() 原样透传(done 字段保持内层值)。
Ok(YieldStarOutcome::Suspend(result))
}
}
/// `yield*` 委托单步转发:把外层恢复请求转发给内层迭代器。
///
/// # 步骤
/// 1. next 走统一包装器(数组/字符串按索引、对象委托自身 next,方法内置不提前绑定);
/// return/throw 对内层迭代器延迟 GetMethod(wrapper 不应在创建时访问内层方法)。
/// 2. 方法缺失时按语义兜底:next → TypeError;return → 外层直接完成(值为请求值);
/// throw → 先 IteratorClose(调内层 return,其抛错以该错为准)再补抛原异常。
/// 3. 调内层方法得结果对象,读 done/value 判定委托结局。
///
/// # 副作用
/// - 内层调用抛错时经 unwind 展开(可被外层 catch/finally 捕获,返回 Unwind)。
/// - 委托结束时清空 `self.delegated_iterator`,挂起透传时保留。
fn delegate_forward(&mut self, mode: GeneratorResumeMode) -> Result<DelegateOutcome, String> {
let iterator = match self.delegated_iterator {
Some(it) => it,
None => return Ok(DelegateOutcome::Unwind),
};
let (method, arg) = match mode {
GeneratorResumeMode::Next(v) => ("next", v),
GeneratorResumeMode::Return(v) => ("return", v),
GeneratorResumeMode::Throw(e) => ("throw", e),
};
// return/throw 的 receiver 与 GetMethod 目标都是内层迭代器(包装器统一 next)。
let inner = if matches!(mode, GeneratorResumeMode::Next(_)) {
iterator
} else {
self.iterator_inner(iterator)
};
let iter_obj = unsafe { &*inner.as_js_object_ptr() };
let method_si = self.kernel_core.perm_interner().intern(method).0;
let method_fn = match self.ordinary_get(iter_obj, method_si, inner) {
Ok(f) => f,
Err(e) => return self.delegate_raise(e),
};
let inner_result = if is_callable(method_fn) {
match self.call_function_sync(method_fn, inner, &[arg]) {
Ok(r) => r,
Err(e) => return self.delegate_raise(e),
}
} else {
match mode {
GeneratorResumeMode::Next(_) => {
return self.delegate_raise(self.error_message_text("TypeError", "iterator.next is not callable"))
}
GeneratorResumeMode::Return(v) => {
// 内层无 return 方法:外层直接完成,值为请求值。
self.delegated_iterator = None;
return Ok(DelegateOutcome::Complete { value: v });
}
GeneratorResumeMode::Throw(_e) => {
// 内层无 throw 方法:先 IteratorClose(GetMethod 内层 return,getter 抛错
// 传播、调用抛错传播、结果非对象抛 TypeError),再抛 TypeError(协议违规)。
let ret_si = self.kernel_core.perm_interner().intern("return").0;
let ret_fn = match self.ordinary_get(iter_obj, ret_si, inner) {
Ok(f) => f,
Err(e) => return self.delegate_raise(e),
};
if is_callable(ret_fn) {
let close_result = match self.call_function_sync(ret_fn, inner, &[]) {
Ok(r) => r,
Err(e) => return self.delegate_raise(e),
};
if !close_result.is_object() {
return self.delegate_raise(
self.error_message_text("TypeError", "IteratorResult is not an object"),
);
}
}
self.delegated_iterator = None;
return self.delegate_raise(self.error_message_text(
"TypeError",
"yield* protocol violation: iterator does not have a throw method",
));
}
}
};
if !inner_result.is_object() {
return self.delegate_raise(self.error_message_text("TypeError", "iterator result is not an object"));
}
let result_obj = unsafe { &*inner_result.as_js_object_ptr() };
let done_si = self.kernel_core.perm_interner().intern("done").0;
let value_si = self.kernel_core.perm_interner().intern("value").0;
let done = to_boolean(match self.ordinary_get(result_obj, done_si, inner_result) {
Ok(v) => v,
Err(e) => return self.delegate_raise(e),
});
// done 时才读取 value(委托完成值);done=false 直接让出原始结果对象。
if done {
let value = match self.ordinary_get(result_obj, value_si, inner_result) {
Ok(v) => v,
Err(e) => return self.delegate_raise(e),
};
// 委托结束:next/throw 被内层消化后外层继续,return 被内层消化后外层完成。
self.delegated_iterator = None;
match mode {
GeneratorResumeMode::Next(_) | GeneratorResumeMode::Throw(_) => Ok(DelegateOutcome::Continue { value }),
GeneratorResumeMode::Return(_) => Ok(DelegateOutcome::Complete { value }),
}
} else {
// 转发期间内层生成器的恢复会覆盖 `self.delegated_iterator`,须重新存回
// 委托迭代器,使外层挂起快照保留委托状态。让出内层原始结果对象。
self.delegated_iterator = Some(iterator);
Ok(DelegateOutcome::Suspend { value: inner_result })
}
}
/// 从统一包装器中取内层迭代器(`__inner__` 槽),兜底返回包装器自身。
fn iterator_inner(&mut self, wrapper: JsValue) -> JsValue {
if !wrapper.is_object() {
return wrapper;
}
let obj = unsafe { &*wrapper.as_js_object_ptr() };
let inner_si = self.kernel_core.perm_interner().intern("__inner__").0;
match self.ordinary_get(obj, inner_si, wrapper) {
Ok(v) if !v.is_undefined() => v,
_ => wrapper,
}
}
/// 委托期间的异常注入:恢复原始异常值并经 unwind 展开。
///
/// # 返回值
/// - `Ok(Unwind)`:异常被外层 catch/finally 捕获,可继续 dispatch;
/// - `Err`:异常逃逸出外层(unwind 失败),调用方按 Thrown 交付。
fn delegate_raise(&mut self, msg: String) -> Result<DelegateOutcome, String> {
let exc = self
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_type_error(self, &msg));
self.exception_value = Some(exc);
self.pending_error_kind = Some(self.thrown_error_kind(exc));
match self.unwind() {
Ok(()) => Ok(DelegateOutcome::Unwind),
Err(e) => Err(e),
}
}
/// `yield*` 首次推进的异常注入:与 [`delegate_raise`] 同路径,结局为
/// [`YieldStarOutcome`] 的 Unwind。
fn yield_star_raise(&mut self, msg: String) -> Result<YieldStarOutcome, String> {
let exc = self
.last_uncaught_value
.take()
.unwrap_or_else(|| oxide_builtins::error::create_type_error(self, &msg));
self.exception_value = Some(exc);
self.pending_error_kind = Some(self.thrown_error_kind(exc));
match self.unwind() {
Ok(()) => Ok(YieldStarOutcome::Unwind),
Err(e) => Err(e),
}
}
/// 把当前 VM 执行状态(生成器 body 刚在嵌套 dispatch 中让出)快照进状态盒。
///
/// 生成器帧弹出存 `frame`,其余栈段整段搬入(嵌套循环期间这些栈只含生成器数据)。
@@ -469,6 +771,7 @@ impl Vm {
state.for_in_iters = std::mem::take(&mut self.iters.for_in_iters);
state.for_of_iters = std::mem::take(&mut self.iters.for_of_iters);
state.last_for_of_result = self.iters.last_for_of_result;
state.delegated_iterator = self.delegated_iterator.take();
state.saved_bytecode_stack = std::mem::take(&mut self.saved_bytecode_stack);
state.saved_immutables_stack = std::mem::take(&mut self.saved_immutables_stack);
state.exception_value = self.exception_value.take();
@@ -535,8 +838,10 @@ pub(crate) fn generator_symbol_iterator(vm: &mut Vm, args: &[u8]) -> NativeResul
}
/// 把恢复结局折叠为迭代器结果 `{value, done}` 或传播异常。
/// 委托让出(SuspendedRaw)原样透传内层结果对象,不做二次包装。
fn generator_step_result(vm: &mut Vm, step: Result<GeneratorStep, String>) -> NativeResult {
match step {
Ok(GeneratorStep::SuspendedRaw { value }) => NativeResult::Ok(value),
Ok(GeneratorStep::Suspended { value }) | Ok(GeneratorStep::Completed { value }) => {
let done = matches!(step, Ok(GeneratorStep::Completed { .. }));
NativeResult::Ok(make_iter_result(vm, value, done))
@@ -684,6 +989,9 @@ pub(crate) fn generator_native_edges(obj: &JsObject) -> Vec<JsValue> {
}
edges.extend(state.for_of_iters.iter().copied().filter(|v| v.is_object()));
push(state.last_for_of_result, &mut edges);
if let Some(iter) = state.delegated_iterator {
push(iter, &mut edges);
}
edges
}
@@ -726,6 +1034,7 @@ pub(crate) fn rewrite_generator_native(obj: &JsObject, mut rewrite: impl FnMut(J
*v = rewrite(*v);
}
state.last_for_of_result = rewrite(state.last_for_of_result);
state.delegated_iterator = state.delegated_iterator.map(&mut rewrite);
}
/// 释放生成器状态盒(对象被 GC 回收时),返回释放字节数。
+20
View File
@@ -285,6 +285,9 @@ pub struct Vm {
/// 生成器体 `dispatch()` 让出时的信号:YIELD 置 Some(让出值),恢复方(
/// generator 内嵌 dispatch 循环)取走并判定挂起。None = 正常返回/异常。
pub(crate) generator_suspended: Option<JsValue>,
/// `yield*` 委托中的内层迭代器:YIELD_STAR 让出时置入,恢复时转发 next/return/throw
/// 后按结局清空。随生成器挂起/恢复经 GeneratorState 传递(snapshot/rewrite 共管)。
pub(crate) delegated_iterator: Option<JsValue>,
/// 当前是否处于生成器内嵌 dispatch 循环:生成器帧弹出且 frames 清空时,
/// `do_return` 据此把结果交付给恢复方(而非当作普通顶层返回继续执行)。
pub(crate) generator_dispatch: bool,
@@ -1511,6 +1514,23 @@ impl Vm {
return Ok(JsValue::undefined());
}
OpCode::YIELD_STAR => {
// `yield*` 委托:取内层迭代器并推进一步。
// 未 done → 挂起让出(存委托迭代器);done → 委托完成值写 reg 0 继续外层;
// unwind 捕获到异常 → 继续 dispatch(已展开到 catch/finally)。
match self.dispatch_yield_star(rd)? {
crate::generator::YieldStarOutcome::Suspend(value) => {
self.generator_suspended = Some(value);
self.profiling.set_instruction_count(steps);
return Ok(JsValue::undefined());
}
crate::generator::YieldStarOutcome::Continue(value) => {
self.regs[0] = value;
}
crate::generator::YieldStarOutcome::Unwind => {}
}
}
OpCode::SUSPEND_BODY => {
// 生成器调用时参数初始化结束:挂起在 body 起点;正常 next() 恢复时直接穿过。
if self.generator_init_step {
+3
View File
@@ -54,6 +54,7 @@ impl Vm {
accessor_frame_target_reg: None,
inline_callee: None,
generator_suspended: None,
delegated_iterator: None,
generator_dispatch: false,
generator_init_step: false,
generator_body_started: false,
@@ -127,6 +128,7 @@ impl Vm {
accessor_frame_target_reg: None,
inline_callee: None,
generator_suspended: None,
delegated_iterator: None,
generator_dispatch: false,
generator_init_step: false,
generator_body_started: false,
@@ -251,6 +253,7 @@ impl Vm {
self.pending_error_kind = None;
self.pending_completion = None;
self.generator_suspended = None;
self.delegated_iterator = None;
self.generator_dispatch = false;
self.generator_init_step = false;
self.generator_body_started = false;
@@ -0,0 +1,111 @@
//! `yield*` 委托语法运行时测试:委托数组/字符串/生成器,next/return/throw 转发,
//! 委托完成值传递与空委托场景。
use oxide_compiler::compiler::Compiler;
use oxide_parser::Allocator;
use oxide_vm::vm::Vm;
fn eval(source: &str) -> String {
let allocator = Allocator::default();
let program = match oxide_parser::parse(&allocator, source) {
Ok(p) => p,
Err(e) => return format!("parse error: {}", e[0].message),
};
let module = match Compiler::new().compile(&program) {
Ok(m) => m,
Err(e) => return format!("compile error: {e}"),
};
let mut vm = Vm::new();
match vm.run(&module) {
Ok(result) => {
if result.is_string() {
vm.lookup_str(result).unwrap_or_default()
} else {
format!("{result}")
}
}
Err(e) => format!("vm error: {e}"),
}
}
// 委托数组:逐元素让出。
#[test]
fn yield_star_array() {
assert_eq!(eval("function* g(){ yield* [1,2,3] } Array.from(g()).join(',')"), "1,2,3");
}
// 委托字符串:按码元让出。
#[test]
fn yield_star_string() {
assert_eq!(eval("function* g(){ yield* 'ab' } Array.from(g()).join(',')"), "a,b");
}
// 委托完成值作为 yield* 表达式结果,外层继续执行。
#[test]
fn yield_star_completion_value() {
assert_eq!(
eval("function* inner(){ yield 1; yield 2; return 3 } function* outer(){ var r = yield* inner(); yield r } var it=outer(); [it.next().value, it.next().value, it.next().value, it.next().done].join(',')"),
"1,2,3,true"
);
}
// 委托夹在普通 yield 之间,保持顺序。
#[test]
fn yield_star_mixed_with_plain_yield() {
assert_eq!(
eval("function* g(){ yield 0; yield* [1,2]; yield 3 } Array.from(g()).join(',')"),
"0,1,2,3"
);
}
// 嵌套委托(yield* 内再 yield*)。
#[test]
fn yield_star_nested() {
assert_eq!(
eval("function* a(){ yield 1 } function* b(){ yield* a() } function* c(){ yield* b() } Array.from(c()).join(',')"),
"1"
);
}
// 空委托:立即继续外层。
#[test]
fn yield_star_empty() {
assert_eq!(eval("function* g(){ yield* [] ; yield 5 } Array.from(g()).join(',')"), "5");
}
// 外层 return() 转发给内层:内层完成值交付。
#[test]
fn yield_star_return_forward() {
assert_eq!(
eval("function* inner(){ yield 1 } function* outer(){ yield* inner() } var it=outer(); it.next(); it.return(9).value"),
"9"
);
}
// 外层 throw() 转发给内层:内层消化后外层继续。
#[test]
fn yield_star_throw_forward() {
assert_eq!(
eval("function* inner(){ try { yield 1 } catch(e) { return 'handled:'+e } } function* outer(){ var r = yield* inner(); yield 'got: ' + r } var it=outer(); var a=it.next(); var b=it.throw('x'); [a.value, b.value].join(',')"),
"1,got: handled:x"
);
}
// 委托不可迭代值:经外层 catch 捕获。
#[test]
fn yield_star_not_iterable_throws() {
assert_eq!(
eval("function* outer(){ try { yield* 42 } catch(e) { yield 'err' } } Array.from(outer()).join(',')"),
"err"
);
}
// 内层无 return 方法:外层 return() 直接完成(值为请求值)。
#[test]
fn yield_star_inner_without_return() {
assert_eq!(
eval("var inner = { [Symbol.iterator]() { return this; }, next() { return {value:1, done:false}; } }; function* outer(){ yield* inner; yield 5 } var it=outer(); var a=it.next(); var b=it.return(9); [a.value, b.value, b.done].join(',')"),
"1,9,true"
);
}