mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
feat: 异步生成器 yield* 走异步迭代协议按规范结算
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use oxide_builtins::iterator::make_iter_result;
|
||||
use oxide_builtins::iterator::{is_callable, make_iter_result};
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
use oxide_types::object::{Cell, JsObject, NativeFnPtr, PropAttributes};
|
||||
@@ -46,6 +46,19 @@ pub(crate) struct AsyncGenRequest {
|
||||
pub reject: JsValue,
|
||||
}
|
||||
|
||||
/// `yield*` 委托协议步(异步生成器):内层 next/return/throw 的 promise 结算后,
|
||||
/// 步进取续闭包按步推进协议状态机。纯枚举(零 JsValue 字段,零 GC 面):
|
||||
/// 结算值经反应实参传递,跨微任务存活由 job 队列 GC 根保证。
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum DelegateStep {
|
||||
/// 等内层 next(v) 或 throw(e) 的 promise 结算(两者结算逻辑同构)。
|
||||
Inner,
|
||||
/// 等内层 return(v) 的 promise 结算(外层 return 请求)。
|
||||
Return,
|
||||
/// 等内层 return()(close)的 promise 结算(外层 throw 请求,内层无 throw 方法)。
|
||||
Close,
|
||||
}
|
||||
|
||||
/// 异步生成器挂起时的完整执行上下文快照 + 请求队列。
|
||||
///
|
||||
/// 存在异步生成器对象 `native_data`(`Box`),跨 next()/微任务存活;其中所有
|
||||
@@ -64,6 +77,8 @@ pub(crate) struct AsyncGeneratorState {
|
||||
pub queue: VecDeque<AsyncGenRequest>,
|
||||
/// 正在处理的请求:yield 让出 / await 挂起 / 完成时结算。
|
||||
pub current: Option<AsyncGenRequest>,
|
||||
/// 委托协议步:步进取续闭包消费后恢复;恢复入口恒为 None(纯枚举,零 GC 面)。
|
||||
pub delegate_pending: Option<DelegateStep>,
|
||||
/// 挂起时的执行上下文(regs/pc/bytecode/各栈段/迭代器/在途异常)。
|
||||
pub suspended: crate::suspended::SuspendedFrame,
|
||||
}
|
||||
@@ -74,6 +89,8 @@ const AG_REJECT_PROP: &str = "__oxide_async_gen_reject__";
|
||||
const AG_YIELD_PROMISE_PROP: &str = "__oxide_async_gen_yield_promise__";
|
||||
/// yield 值 unwrap 恢复闭包上区分委托透传(raw)的属性名。
|
||||
const AG_YIELD_RAW_PROP: &str = "__oxide_async_gen_yield_raw__";
|
||||
/// 委托步进取续闭包上存协议步的属性名。
|
||||
const AG_STEP_PROP: &str = "__oxide_async_gen_delegate_step__";
|
||||
|
||||
impl Vm {
|
||||
/// 调用异步生成器函数返回的迭代器对象:创建异步生成器实例、挂状态并执行
|
||||
@@ -96,6 +113,7 @@ impl Vm {
|
||||
result: JsValue::undefined(),
|
||||
queue: VecDeque::new(),
|
||||
current: None,
|
||||
delegate_pending: None,
|
||||
suspended: crate::suspended::SuspendedFrame::new_empty(),
|
||||
});
|
||||
obj_ref.set_native_data(Box::into_raw(state) as *mut u8);
|
||||
@@ -185,7 +203,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
/// 取出异步生成器对象的状态指针(调用方须先校验 `is_async_generator_obj`)。
|
||||
fn async_gen_state_ptr(&self, gen_val: JsValue) -> *mut AsyncGeneratorState {
|
||||
pub(crate) fn async_gen_state_ptr(&self, gen_val: JsValue) -> *mut AsyncGeneratorState {
|
||||
unsafe { (*gen_val.as_js_object_ptr()).native_data() as *mut AsyncGeneratorState }
|
||||
}
|
||||
|
||||
@@ -324,9 +342,12 @@ impl Vm {
|
||||
return Err("async generator suspended across runs is no longer valid".into());
|
||||
}
|
||||
state.phase = AsyncGenPhase::Running;
|
||||
// 入口不变量:步进取续闭包先消费协议步再调本函数。
|
||||
debug_assert!(state.delegate_pending.is_none());
|
||||
}
|
||||
|
||||
// 委托恢复:把 next/return/throw 请求转发给内层迭代器。
|
||||
// 委托恢复:把 next/return/throw 请求转发给内层异步迭代器,登记步进取续
|
||||
// 闭包等 promise 结算后经快照分支挂起(AwaitSuspended)。
|
||||
if self.delegated_iterator.is_some() {
|
||||
let mode = {
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
@@ -336,7 +357,7 @@ impl Vm {
|
||||
.map(|c| c.mode)
|
||||
.unwrap_or(GeneratorResumeMode::Next(JsValue::undefined()))
|
||||
};
|
||||
let forwarded = self.delegate_forward(mode);
|
||||
let forwarded = self.delegate_forward_async(mode, gen_val);
|
||||
match forwarded {
|
||||
Err(e) => {
|
||||
let exc = self
|
||||
@@ -346,29 +367,14 @@ impl Vm {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
return self.finish_async_gen_exc(state_ptr, saved, gen_val, exc);
|
||||
}
|
||||
Ok(DelegateOutcome::Suspend { value }) => {
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
// AsyncGeneratorYield:委托让出值经 promise unwrap 后原样透传。
|
||||
let value_promise = if self.is_promise_value(value) {
|
||||
value
|
||||
} else {
|
||||
let (p, _, _) = self.new_promise_capability();
|
||||
let _ = self.resolve_promise(p, value);
|
||||
p
|
||||
};
|
||||
let request = {
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
state.current.take()
|
||||
};
|
||||
// 委托让出同样在 unwrap 前不可恢复(AsyncGeneratorYield 先 Await)。
|
||||
Ok(DelegateOutcome::Suspend { .. }) => {
|
||||
// 协议步等待(delegate_pending 已置):内层 promise 结算前 body 不得
|
||||
// 继续,快照挂起状态后返回,等步进取续闭包(微任务)恢复。本分支在
|
||||
// dispatch 之前返回,调度标志须在此恢复(dispatch 后的恢复不会执行)。
|
||||
unsafe { (*state_ptr).phase = AsyncGenPhase::AwaitSuspended };
|
||||
self.snapshot_async_generator(state_ptr)?;
|
||||
self.restore_async_gen_flags(prev_ctx, prev_gen_ctx, prev_gd, prev_ad, prev_agd);
|
||||
self.restore_inline_state(saved);
|
||||
if let Some(req) = request {
|
||||
let fulfill_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, true, false);
|
||||
let reject_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, true, true);
|
||||
let _ = self.perform_promise_then(value_promise, fulfill_fn, reject_fn);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
Ok(DelegateOutcome::Continue { value }) => {
|
||||
@@ -428,7 +434,6 @@ impl Vm {
|
||||
|
||||
// YIELD 让出:快照挂起状态,让出值经 promise unwrap 后结算当前请求。
|
||||
if let Some(value) = self.generator_suspended.take() {
|
||||
let delegating = self.delegated_iterator.is_some();
|
||||
// AsyncGeneratorYield:让出值 PromiseResolve 包装后 await 展开
|
||||
// (yield 一个 rejected promise 时 next() 的 promise 被 reject)。
|
||||
let value_promise = if self.is_promise_value(value) {
|
||||
@@ -449,8 +454,8 @@ impl Vm {
|
||||
self.snapshot_async_generator(state_ptr)?;
|
||||
self.restore_inline_state(saved);
|
||||
if let Some(req) = request {
|
||||
let fulfill_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, delegating, false);
|
||||
let reject_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, delegating, true);
|
||||
let fulfill_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, false, false);
|
||||
let reject_fn = self.make_async_gen_yield_unwrap_fn(gen_val, req.promise, false, true);
|
||||
let _ = self.perform_promise_then(value_promise, fulfill_fn, reject_fn);
|
||||
}
|
||||
return Ok(());
|
||||
@@ -478,6 +483,95 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
/// `yield*` 委托单步转发(异步生成器):把外层请求转发给内层异步迭代器,
|
||||
/// 登记步进取续闭包等 promise 结算。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. Next/Throw:取内层 next/throw 方法并以请求值调用;无 throw 方法时回退
|
||||
/// 内层 return()(无参 close),再无 return 方法时抛 TypeError 入 body。
|
||||
/// 2. Return:取内层 return 方法;缺失时以请求值直接完成(Complete);
|
||||
/// 可调用时调用。
|
||||
/// 3. 调用结果 promise 直通或 PromiseResolve 包装,登记步进取续闭包
|
||||
/// (Inner/Return/Close),置 `delegate_pending`。
|
||||
///
|
||||
/// # 返回值
|
||||
/// - `Ok(Suspend)`:协议步等待(`delegate_pending` 已置,调用方经快照分支挂起);
|
||||
/// - `Ok(Complete)`:内层无 return 方法,外层以请求值直接完成;
|
||||
/// - `Ok(Unwind)`:TypeError 已抛入 body(内层无 throw/return 方法),继续 dispatch;
|
||||
/// - `Err`:内层调用同步抛错,调用方走既有 Err 通道。
|
||||
fn delegate_forward_async(
|
||||
&mut self, mode: GeneratorResumeMode, gen_val: JsValue,
|
||||
) -> Result<DelegateOutcome, String> {
|
||||
let iterator = match self.delegated_iterator {
|
||||
Some(it) => it,
|
||||
None => return Ok(DelegateOutcome::Unwind),
|
||||
};
|
||||
let (method, arg, mut step) = match mode {
|
||||
GeneratorResumeMode::Next(v) => ("next", v, DelegateStep::Inner),
|
||||
GeneratorResumeMode::Throw(e) => ("throw", e, DelegateStep::Inner),
|
||||
GeneratorResumeMode::Return(v) => ("return", v, DelegateStep::Return),
|
||||
};
|
||||
let iter_obj = unsafe { &*iterator.as_js_object_ptr() };
|
||||
let method_si = self.kernel_core.perm_interner().intern(method).0;
|
||||
let method_fn = self.ordinary_get(iter_obj, method_si, iterator)?;
|
||||
let inner_result = if is_callable(method_fn) {
|
||||
self.call_function_sync(method_fn, iterator, &[arg])?
|
||||
} else {
|
||||
match mode {
|
||||
GeneratorResumeMode::Next(_) => {
|
||||
return Err(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(_) => {
|
||||
// 内层无 throw 方法:回退内层 return()(无参 close),步为 Close。
|
||||
let ret_si = self.kernel_core.perm_interner().intern("return").0;
|
||||
let ret_fn = self.ordinary_get(iter_obj, ret_si, iterator)?;
|
||||
if !is_callable(ret_fn) {
|
||||
// 内层亦无 return 方法:close 为 no-op,抛 TypeError 入 body(协议违规)。
|
||||
self.delegated_iterator = None;
|
||||
let exc = oxide_builtins::error::create_type_error(
|
||||
self,
|
||||
"yield* protocol violation: iterator does not have a throw method",
|
||||
);
|
||||
self.exception_value = Some(exc);
|
||||
self.pending_error_kind = Some(self.thrown_error_kind(exc));
|
||||
return match self.unwind() {
|
||||
Ok(()) => Ok(DelegateOutcome::Unwind),
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
}
|
||||
// 步为 Close:close 成功后抛 TypeError 入 body,拒绝则抛拒绝原因入 body。
|
||||
step = DelegateStep::Close;
|
||||
self.call_function_sync(ret_fn, iterator, &[])?
|
||||
}
|
||||
}
|
||||
};
|
||||
// Await:结果 promise 直通,非 promise 经 PromiseResolve 包装。
|
||||
let result_promise = if self.is_promise_value(inner_result) {
|
||||
inner_result
|
||||
} else {
|
||||
match self.promise_resolve(inner_result) {
|
||||
Ok(p) => p,
|
||||
Err(exc) => {
|
||||
self.last_uncaught_value = Some(exc);
|
||||
return Err(String::new());
|
||||
}
|
||||
}
|
||||
};
|
||||
// 登记步进取续闭包;先 Call 再置 pending(同步抛错不悬挂)。
|
||||
let fulfill_fn = self.make_delegate_step_closure(gen_val, step, false);
|
||||
let reject_fn = self.make_delegate_step_closure(gen_val, step, true);
|
||||
let _ = self.perform_promise_then(result_promise, fulfill_fn, reject_fn);
|
||||
self.delegated_iterator = Some(iterator);
|
||||
let state = unsafe { &mut *self.async_gen_state_ptr(gen_val) };
|
||||
state.delegate_pending = Some(step);
|
||||
Ok(DelegateOutcome::Suspend { value: JsValue::undefined() })
|
||||
}
|
||||
|
||||
/// 恢复嵌套 dispatch 覆盖的 VM 标志(dispatch 前提前返回的路径用)。
|
||||
fn restore_async_gen_flags(
|
||||
&mut self, prev_ctx: Option<JsValue>, prev_gen_ctx: Option<JsValue>, prev_gd: bool, prev_ad: bool,
|
||||
@@ -599,6 +693,26 @@ impl Vm {
|
||||
self.add_fn_name_length(obj, "", 1);
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
|
||||
/// 构造委托步进取续闭包:携带目标异步生成器上下文、协议步与 fulfill/reject 角色。
|
||||
pub(crate) fn make_delegate_step_closure(&mut self, ctx: JsValue, step: DelegateStep, reject_role: bool) -> JsValue {
|
||||
let fn_proto = self.session.builtin_world().fn_proto_val();
|
||||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||||
func.set_function(true);
|
||||
// SAFETY: async_gen_delegate_step_closure 是 NativeFn 函数项。
|
||||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_gen_delegate_step_closure as *const ()) }));
|
||||
func.set_native_arg_count(1);
|
||||
let ptr = self.alloc_object(func);
|
||||
let obj = unsafe { &mut *ptr };
|
||||
let ctx_si = self.kernel_core.perm_interner().intern(crate::async_func::ASYNC_CTX_PROP).0;
|
||||
self.set_or_create_prop_value(obj, ctx_si, ctx);
|
||||
let step_si = self.kernel_core.perm_interner().intern(AG_STEP_PROP).0;
|
||||
self.set_or_create_prop_value(obj, step_si, JsValue::int(step as i32));
|
||||
let role_si = self.kernel_core.perm_interner().intern(AG_REJECT_PROP).0;
|
||||
self.set_or_create_prop_value(obj, role_si, JsValue::bool(reject_role));
|
||||
self.add_fn_name_length(obj, "", 1);
|
||||
JsValue::from_js_object(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// await 恢复闭包:读自身 prop 的异步生成器上下文与角色,恢复异步生成器继续执行。
|
||||
@@ -695,6 +809,231 @@ fn async_gen_yield_unwrap_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
|
||||
/// 委托步进取续闭包:内层 next/return/throw 的 promise 结算时推进委托协议一步。
|
||||
///
|
||||
/// 读自身 prop 的协议步与角色,校验状态盒 `delegate_pending` 匹配(防陈旧闭包),
|
||||
/// 再按步分支(规范:`yield*` 交付值不做二次 Await,失败一律抛入 body 可 catch):
|
||||
/// - Inner:结算值判 done——done 时委托值注入 body 恢复;未 done 时委托值原样
|
||||
/// 让出(`{value, done:false}` 结算当前请求);非对象或拒绝原因抛入 body。
|
||||
/// - Return:done 时以委托值完成生成器(return completion);未 done 时委托值
|
||||
/// 原样让出;拒绝原因 / 非对象抛入 body。
|
||||
/// - Close:close 结算后抛 TypeError 入 body(协议违规);close 拒绝则抛拒绝原因。
|
||||
fn async_gen_delegate_step_closure(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let callee = vm.reg(254);
|
||||
if !callee.is_object() {
|
||||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "delegate step handler is invalid"));
|
||||
}
|
||||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||||
let ctx_si = vm.kernel_core.perm_interner().intern(crate::async_func::ASYNC_CTX_PROP).0;
|
||||
let ctx = vm.resolve_property(callee_obj, ctx_si).unwrap_or(JsValue::undefined());
|
||||
let step_si = vm.kernel_core.perm_interner().intern(AG_STEP_PROP).0;
|
||||
let step = match vm.resolve_property(callee_obj, step_si) {
|
||||
Some(v) if v.is_int() => v.as_int(),
|
||||
_ => return NativeResult::Ok(JsValue::undefined()),
|
||||
};
|
||||
let step = match step {
|
||||
0 => DelegateStep::Inner,
|
||||
1 => DelegateStep::Return,
|
||||
2 => DelegateStep::Close,
|
||||
_ => return NativeResult::Ok(JsValue::undefined()),
|
||||
};
|
||||
let role_si = vm.kernel_core.perm_interner().intern(AG_REJECT_PROP).0;
|
||||
let is_reject = vm
|
||||
.resolve_property(callee_obj, role_si)
|
||||
.is_some_and(oxide_runtime_api::to_boolean);
|
||||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||
if !ctx.is_object() {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
let obj = unsafe { &*ctx.as_js_object_ptr() };
|
||||
if !obj.is_async_generator_obj() {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
let state_ptr = vm.async_gen_state_ptr(ctx);
|
||||
// 陈旧防御:状态盒的在途协议步必须与本闭包一致。
|
||||
if unsafe { (*state_ptr).delegate_pending } != Some(step) {
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
match step {
|
||||
DelegateStep::Inner => {
|
||||
// 失败子路径:拒绝原因 / 非对象结算值 / done 或 value getter 抛错,
|
||||
// 均抛入 body(body 的 try/catch 可捕获)。
|
||||
let failure = if is_reject {
|
||||
Some(value)
|
||||
} else if !value.is_object() {
|
||||
Some(oxide_builtins::error::create_type_error(vm, "iterator result is not an object"))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(exc) = failure {
|
||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
let result_obj = unsafe { &*value.as_js_object_ptr() };
|
||||
let done_si = vm.kernel_core.perm_interner().intern("done").0;
|
||||
let done = match vm.ordinary_get(result_obj, done_si, value) {
|
||||
Ok(d) => oxide_runtime_api::to_boolean(d),
|
||||
Err(e) => {
|
||||
let exc = vm.last_uncaught_value.take().unwrap_or_else(|| {
|
||||
oxide_builtins::error::create_from_text(vm, &e)
|
||||
});
|
||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
};
|
||||
let value_si = vm.kernel_core.perm_interner().intern("value").0;
|
||||
let inner_value = match vm.ordinary_get(result_obj, value_si, value) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
let exc = vm.last_uncaught_value.take().unwrap_or_else(|| {
|
||||
oxide_builtins::error::create_from_text(vm, &e)
|
||||
});
|
||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
};
|
||||
if done {
|
||||
// 委托 done:委托值注入 body,body 从 yield* 续点继续。清挂起帧的
|
||||
// 委托迭代器(restore_into 会把它写回 VM,不清则恢复后再走 S0 转发)。
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
if let Some(req) = state.current.as_mut() {
|
||||
req.mode = GeneratorResumeMode::Next(inner_value);
|
||||
}
|
||||
state.delegate_pending = None;
|
||||
state.suspended.delegated_iterator = None;
|
||||
match vm.resume_async_generator(ctx) {
|
||||
Ok(()) => NativeResult::Ok(JsValue::undefined()),
|
||||
Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
|
||||
}
|
||||
} else {
|
||||
// 委托未 done:交付值原样让出(规范 yield* 不对值 Await),委托持续。
|
||||
delegate_yield_raw(vm, ctx, state_ptr, inner_value);
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
}
|
||||
DelegateStep::Return => {
|
||||
// return 分支:拒绝原因 / 非对象结算值 / getter 抛错均抛入 body;
|
||||
// done:true 以委托值完成生成器;done:false 原样让出委托值。
|
||||
let (done, inner_value) = match read_delegate_result(vm, value) {
|
||||
DelegateResult::Failure(exc) => {
|
||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||
return NativeResult::Ok(JsValue::undefined());
|
||||
}
|
||||
DelegateResult::Ok(done, inner_value) => (done, inner_value),
|
||||
};
|
||||
if done {
|
||||
// 以委托值完成(return completion,finally 穿越):改写请求模式为
|
||||
// Return(委托值) 后恢复,注入路径走 complete_generator_return。
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
if let Some(req) = state.current.as_mut() {
|
||||
req.mode = GeneratorResumeMode::Return(inner_value);
|
||||
}
|
||||
state.delegate_pending = None;
|
||||
state.suspended.delegated_iterator = None;
|
||||
match vm.resume_async_generator(ctx) {
|
||||
Ok(()) => NativeResult::Ok(JsValue::undefined()),
|
||||
Err(e) => NativeResult::Err(oxide_builtins::error::create_from_text(vm, &e)),
|
||||
}
|
||||
} else {
|
||||
delegate_yield_raw(vm, ctx, state_ptr, inner_value);
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
}
|
||||
DelegateStep::Close => {
|
||||
// close 分支(内层无 throw 方法):close 结算后抛 TypeError 入 body
|
||||
// (协议违规);close 拒绝则抛拒绝原因入 body。
|
||||
let exc = if is_reject {
|
||||
value
|
||||
} else {
|
||||
oxide_builtins::error::create_type_error(
|
||||
vm,
|
||||
"yield* protocol violation: iterator does not have a throw method",
|
||||
)
|
||||
};
|
||||
throw_delegate_into_body(vm, ctx, state_ptr, exc);
|
||||
NativeResult::Ok(JsValue::undefined())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 委托结算值读取:done 与 value 的 getter 抛错经 `last_uncaught_value` 取原值。
|
||||
enum DelegateResult {
|
||||
/// 结算值读取成功(done 标志与委托值)。
|
||||
Ok(bool, JsValue),
|
||||
/// 结算值读取失败(须抛入 body 的异常值)。
|
||||
Failure(JsValue),
|
||||
}
|
||||
|
||||
fn read_delegate_result(vm: &mut Vm, value: JsValue) -> DelegateResult {
|
||||
if !value.is_object() {
|
||||
return DelegateResult::Failure(oxide_builtins::error::create_type_error(
|
||||
vm,
|
||||
"iterator result is not an object",
|
||||
));
|
||||
}
|
||||
let result_obj = unsafe { &*value.as_js_object_ptr() };
|
||||
let done_si = vm.kernel_core.perm_interner().intern("done").0;
|
||||
let done = match vm.ordinary_get(result_obj, done_si, value) {
|
||||
Ok(d) => oxide_runtime_api::to_boolean(d),
|
||||
Err(e) => {
|
||||
let exc = vm
|
||||
.last_uncaught_value
|
||||
.take()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||||
return DelegateResult::Failure(exc);
|
||||
}
|
||||
};
|
||||
let value_si = vm.kernel_core.perm_interner().intern("value").0;
|
||||
let inner_value = match vm.ordinary_get(result_obj, value_si, value) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
let exc = vm
|
||||
.last_uncaught_value
|
||||
.take()
|
||||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||||
return DelegateResult::Failure(exc);
|
||||
}
|
||||
};
|
||||
DelegateResult::Ok(done, inner_value)
|
||||
}
|
||||
|
||||
/// 委托让出:内层值原样交付(规范 `yield*` 不对交付值 Await),以 `{value, done:false}`
|
||||
/// 结算当前请求、恢复可让出状态、驱动队列。
|
||||
///
|
||||
/// 微任务上下文专用:不恢复生成器执行(生成器已让出,等待下一个 next/return/throw)。
|
||||
fn delegate_yield_raw(vm: &mut Vm, ctx: JsValue, state_ptr: *mut AsyncGeneratorState, value: JsValue) {
|
||||
{
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
state.delegate_pending = None;
|
||||
if unsafe { (*state_ptr).phase } == AsyncGenPhase::AwaitSuspended {
|
||||
unsafe { (*state_ptr).phase = AsyncGenPhase::YieldSuspended };
|
||||
}
|
||||
}
|
||||
let request = unsafe { (*state_ptr).current.take() };
|
||||
if let Some(req) = request {
|
||||
let result = make_iter_result(vm, value, false);
|
||||
let _ = vm.resolve_promise(req.promise, result);
|
||||
}
|
||||
if !unsafe { (*state_ptr).queue.is_empty() } {
|
||||
let _ = vm.async_generator_start(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/// 把委托协议异常抛入 body:当前请求改写为 Throw(exc)、清协议状态后恢复
|
||||
/// (body 的 catch 可捕获;无 catch 时既有 finish 通道 reject 请求并完成)。
|
||||
fn throw_delegate_into_body(vm: &mut Vm, ctx: JsValue, state_ptr: *mut AsyncGeneratorState, exc: JsValue) {
|
||||
{
|
||||
let state = unsafe { &mut *state_ptr };
|
||||
if let Some(req) = state.current.as_mut() {
|
||||
req.mode = GeneratorResumeMode::Throw(exc);
|
||||
}
|
||||
state.delegate_pending = None;
|
||||
// 清挂起帧的委托迭代器(restore_into 会把它写回 VM,不清则恢复后再走 S0 转发)。
|
||||
state.suspended.delegated_iterator = None;
|
||||
}
|
||||
let _ = vm.resume_async_generator(ctx);
|
||||
}
|
||||
|
||||
/// `%AsyncGeneratorPrototype%.next`:入队 next 请求并返回其结果 Promise。
|
||||
pub(crate) fn async_generator_next(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
@@ -1188,6 +1527,7 @@ pub(crate) fn clone_async_generator_native_with_rewrite(
|
||||
resolve: rewrite(req.resolve),
|
||||
reject: rewrite(req.reject),
|
||||
}),
|
||||
delegate_pending: state.delegate_pending,
|
||||
suspended: state.suspended.clone_with_rewrite(rewrite),
|
||||
};
|
||||
new.set_native_data(Box::into_raw(Box::new(cloned)) as *mut u8);
|
||||
|
||||
@@ -77,6 +77,9 @@ pub(crate) enum YieldStarOutcome {
|
||||
Continue(JsValue),
|
||||
/// 异常已展开到外层 catch/finally:继续 dispatch。
|
||||
Unwind,
|
||||
/// 异步生成器委托:内层迭代已登记微任务队列,外层挂起让出
|
||||
/// (数据经 async_gen_suspended 信号与状态盒 delegate_pending 传递)。
|
||||
AsyncSuspend,
|
||||
}
|
||||
|
||||
/// `yield*` 委托转发(生成器恢复时)的结局。
|
||||
@@ -429,6 +432,11 @@ impl Vm {
|
||||
/// - 内层 next 同步执行,可能压入/弹出调用帧。
|
||||
/// - 挂起时设置 `delegated_iterator`,由 snapshot_generator 存入生成器状态。
|
||||
pub(crate) fn dispatch_yield_star(&mut self, rd: usize) -> Result<YieldStarOutcome, String> {
|
||||
// 异步生成器委托走异步迭代协议(GetAsyncIterator + promise 结算),
|
||||
// 同步路径原样保留。
|
||||
if self.async_gen_dispatch {
|
||||
return self.dispatch_yield_star_async(rd);
|
||||
}
|
||||
let inner = self.regs[rd];
|
||||
let iterator = match oxide_builtins::iterator::make_iterator_for_value_without_return(self, inner) {
|
||||
Ok(it) => it,
|
||||
@@ -475,6 +483,71 @@ impl Vm {
|
||||
}
|
||||
}
|
||||
|
||||
/// `yield*` 异步委托首次推进:GetAsyncIterator 取内层异步迭代器并推进一次。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 经 GetAsyncIterator 取内层迭代器(`@@asyncIterator` 优先,缺失回退同步
|
||||
/// 迭代器包 AsyncFromSyncIterator)。
|
||||
/// 2. 调内层 next(undefined) 得结果 R0。
|
||||
/// 3. Await 结算:R0 为 promise 时直通,否则 PromiseResolve 包装。
|
||||
/// 4. 登记步进取续闭包(Inner 步)到结果 promise,置
|
||||
/// `delegated_iterator` 与 `delegate_pending` 并挂起。
|
||||
///
|
||||
/// # 边界
|
||||
/// - 任一步同步抛错经 `yield_star_raise` 展开(可被 body catch);
|
||||
/// 顺序约束为先 Call 再置 pending 与挂起标志,同步抛错不悬挂。
|
||||
///
|
||||
/// # 副作用
|
||||
/// - 内层 next 同步执行,可能压入/弹出调用帧。
|
||||
/// - 登记步进取续闭包(微任务队列 GC 根持有)。
|
||||
/// - 置 `delegated_iterator`、`delegate_pending` 与 `async_gen_suspended`。
|
||||
pub(crate) fn dispatch_yield_star_async(&mut self, rd: usize) -> Result<YieldStarOutcome, String> {
|
||||
let inner = self.regs[rd];
|
||||
let iterator = match crate::async_from_sync::make_async_iterator(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"));
|
||||
};
|
||||
// Await:结果 promise 直通,非 promise 经 PromiseResolve 包装。
|
||||
let result_promise = if self.is_promise_value(result) {
|
||||
result
|
||||
} else {
|
||||
match self.promise_resolve(result) {
|
||||
Ok(p) => p,
|
||||
Err(exc) => {
|
||||
self.last_uncaught_value = Some(exc);
|
||||
return self.yield_star_raise(String::new());
|
||||
}
|
||||
}
|
||||
};
|
||||
// 登记步进取续闭包(Inner 步);先 Call 再置 pending 与挂起标志。
|
||||
let gen_val = self.async_gen_context.expect("async yield* outside async generator");
|
||||
let fulfill_fn = self.make_delegate_step_closure(gen_val, crate::async_generator::DelegateStep::Inner, false);
|
||||
let reject_fn = self.make_delegate_step_closure(gen_val, crate::async_generator::DelegateStep::Inner, true);
|
||||
let _ = self.perform_promise_then(result_promise, fulfill_fn, reject_fn);
|
||||
self.delegated_iterator = Some(iterator);
|
||||
let state = unsafe { &mut *self.async_gen_state_ptr(gen_val) };
|
||||
state.delegate_pending = Some(crate::async_generator::DelegateStep::Inner);
|
||||
self.async_gen_suspended = true;
|
||||
Ok(YieldStarOutcome::AsyncSuspend)
|
||||
}
|
||||
|
||||
/// `yield*` 委托单步转发:把外层恢复请求转发给内层迭代器。
|
||||
///
|
||||
/// # 步骤
|
||||
|
||||
@@ -830,7 +830,8 @@ impl Vm {
|
||||
OpCode::YIELD_STAR => {
|
||||
// `yield*` 委托:取内层迭代器并推进一步。
|
||||
// 未 done → 挂起让出(存委托迭代器);done → 委托完成值写 reg 0 继续外层;
|
||||
// unwind 捕获到异常 → 继续 dispatch(已展开到 catch/finally)。
|
||||
// unwind 捕获到异常 → 继续 dispatch(已展开到 catch/finally);
|
||||
// 异步委托 → 内层迭代已登记微任务队列,内嵌 dispatch 返回。
|
||||
match self.dispatch_yield_star(rd)? {
|
||||
crate::generator::YieldStarOutcome::Suspend(value) => {
|
||||
self.generator_suspended = Some(value);
|
||||
@@ -841,6 +842,10 @@ impl Vm {
|
||||
self.regs[0] = value;
|
||||
}
|
||||
crate::generator::YieldStarOutcome::Unwind => {}
|
||||
crate::generator::YieldStarOutcome::AsyncSuspend => {
|
||||
self.profiling.set_instruction_count(steps);
|
||||
return Ok(JsValue::undefined());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
//! 异步生成器 `yield*` 委托协议运行时测试:GetAsyncIterator 取迭代器、
|
||||
//! 内层 next/return/throw 的 promise 结算、交付值二次 Await 展开、
|
||||
//! return/throw 转发与失败路径(拒绝替换、TypeError 抛入 body 可 catch)。
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use oxide_compiler::compiler::Compiler;
|
||||
use oxide_parser::Allocator;
|
||||
use oxide_vm::promise::promise_settled_value;
|
||||
use oxide_vm::vm::Vm;
|
||||
|
||||
/// 执行源码并格式化顶层结果;Promise 结果取其 drain 后的结算值。
|
||||
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(&Arc::new(module)) {
|
||||
Ok(result) => format_value(&vm, result),
|
||||
Err(e) => format!("vm error: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
fn format_value(vm: &Vm, val: oxide_vm::JsValue) -> String {
|
||||
if val.is_string() {
|
||||
format!("\"{}\"", vm.lookup_str(val).unwrap_or_default())
|
||||
} else if val.is_object() {
|
||||
let obj = unsafe { &*val.as_js_object_ptr() };
|
||||
if obj.is_promise_obj() {
|
||||
match promise_settled_value(obj) {
|
||||
Some((true, v)) => format_value(vm, v),
|
||||
Some((false, v)) => format!("<rejected {}>", format_value(vm, v)),
|
||||
None => "<pending>".to_string(),
|
||||
}
|
||||
} else if obj.is_array() {
|
||||
"[array]".to_string()
|
||||
} else {
|
||||
"[object]".to_string()
|
||||
}
|
||||
} else {
|
||||
format!("{val}")
|
||||
}
|
||||
}
|
||||
|
||||
// T1:基本委托——首个 next() 交付数字 7(非 IteratorResult 对象、非 promise),
|
||||
// 第二个 next() 委托完成。
|
||||
#[test]
|
||||
fn t1_basic_async_iterable() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 7, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
return() { return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); const r1 = await it.next(); \
|
||||
const r2 = await it.next(); \
|
||||
return [r1.value, typeof r1.value, r1.done, r2.value, r2.done].join(','); })()"
|
||||
),
|
||||
"\"7,number,false,,true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T2:多元素异步可迭代(顺序 promise 链),逐元素交付后 done。
|
||||
#[test]
|
||||
fn t2_multi_element_async_iterable() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
const items = [1, 2]; let i = 0; return { \
|
||||
next() { if (i < items.length) { return Promise.resolve({ value: items[i++], done: false }); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); \
|
||||
const a = (await it.next()).value; const b = (await it.next()).value; \
|
||||
const c = (await it.next()).done; return a + ',' + b + ',' + c; })()"
|
||||
),
|
||||
"\"1,2,true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T3:同步可迭代进异步生成器——AsyncFromSyncIterator 回退路径同语义。
|
||||
#[test]
|
||||
fn t3_sync_iterable_fallback() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* [1, 2, 3]; } \
|
||||
(async function run() { const it = g(); \
|
||||
const a = (await it.next()).value; const b = (await it.next()).value; \
|
||||
const c = (await it.next()).value; const d = (await it.next()).done; \
|
||||
return a + ',' + b + ',' + c + ',' + d; })()"
|
||||
),
|
||||
"\"1,2,3,true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T4:二次 await——内层 next 交付 {value: Promise.resolve(5), done: false},
|
||||
// next() 交付展开后的 5。
|
||||
#[test]
|
||||
fn t4_double_await_unwraps_value() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; \
|
||||
return Promise.resolve({ value: Promise.resolve(5), done: false }); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); return (await it.next()).value; })()"
|
||||
),
|
||||
"5"
|
||||
);
|
||||
}
|
||||
|
||||
// T5:交付值为拒绝 promise——yield* 不对值 Await,值原样让出,next() 以
|
||||
// {value: 拒绝promise, done: false} 结算(不拒绝)。
|
||||
#[test]
|
||||
fn t5_rejected_yield_value_yielded_as_is() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; \
|
||||
return Promise.resolve({ value: Promise.reject('e5'), done: false }); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); const r1 = await it.next(); \
|
||||
return r1.done + ':' + (r1.value instanceof Promise); })()"
|
||||
),
|
||||
"\"false:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T6:内层 next 拒绝且 body catch——拒绝原因抛入委托 body,可被捕获。
|
||||
#[test]
|
||||
fn t6_inner_next_reject_thrown_into_body() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.reject('e6'); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
catch (e) { return 'caught:' + e; } yield 'never'; } \
|
||||
(async function run() { const it = g(); const r = await it.next(); \
|
||||
return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:e6:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T7:内层结果非对象——TypeError 抛入委托 body,可被捕获。
|
||||
#[test]
|
||||
fn t7_non_object_result_thrown_into_body() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve(42); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
catch (e) { return 'caught:' + e.name; } } \
|
||||
(async function run() { const it = g(); const r = await it.next(); \
|
||||
return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:TypeError:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T8:.return(v) 转发——内层有 return 方法时以请求值调用,done 时生成器以
|
||||
// 委托值(内层 return 结果值)完成(非请求值)。
|
||||
#[test]
|
||||
fn t8_return_forwarded_completes_with_inner_value() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"var log = []; \
|
||||
async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
return(v) { log.push('ret:' + v); return Promise.resolve({ value: 'inner', done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.return(9); return r.value + ':' + r.done + ':' + log.join(','); })()"
|
||||
),
|
||||
"\"inner:true:ret:9\""
|
||||
);
|
||||
}
|
||||
|
||||
// T9:.return(v) 内层无 return 方法——同步完成路径,直接以请求值完成。
|
||||
#[test]
|
||||
fn t9_return_without_inner_return() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.return(9); return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"9:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T10:.throw(e) 转发——内层有 throw 方法时以 e 调用,未 done 时交付内层值。
|
||||
#[test]
|
||||
fn t10_throw_forwarded_to_inner() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
throw(e) { return Promise.resolve({ value: 'x:' + e, done: false }); } }; } }; } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.throw('e10'); return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"x:e10:false\""
|
||||
);
|
||||
}
|
||||
|
||||
// T11:.throw(e) 内层无 throw 方法——close 成功后抛 TypeError 入 body(协议违规,
|
||||
// 非原异常),可 catch。
|
||||
#[test]
|
||||
fn t11_throw_without_inner_throw_close_then_typeerror() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
return() { return Promise.resolve({ done: true }); } }; } }; } \
|
||||
catch (e) { return 'caught:' + e.name; } } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.throw('e11'); return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:TypeError:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T12:close 拒绝——.throw(e) 内层无 throw 方法且内层 return() 拒绝时,拒绝原因
|
||||
// 抛入 body(可 catch),生成器以 catch 返回值完成,throw 请求以该值结算。
|
||||
#[test]
|
||||
fn t12_close_rejection_thrown_into_body() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
return() { return Promise.reject('r12'); } }; } }; } \
|
||||
catch (e) { return 'caught:' + e; } } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.throw('e12'); return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:r12:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// T13:return 分支 done:false——内层 return 结果非 done 时,委托值原样让出
|
||||
// (return 请求以 {value: 9, done: false} 结算)。
|
||||
#[test]
|
||||
fn t13_return_not_done_yields_inner_value() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; return Promise.resolve({ value: 1, done: false }); } \
|
||||
return Promise.resolve({ done: true }); }, \
|
||||
return(v) { return Promise.resolve({ value: 9, done: false }); } }; } }; } \
|
||||
(async function run() { const it = g(); await it.next(); \
|
||||
const r = await it.return(5); return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"9:false\""
|
||||
);
|
||||
}
|
||||
|
||||
// T14:微任务时序——内层结算先于外层 next() 结算(push 序数组断言交错)。
|
||||
#[test]
|
||||
fn t14_microtask_ordering() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"var order = []; \
|
||||
async function* g() { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; \
|
||||
return new Promise(r => { order.push('inner'); r({ value: 1, done: false }); }); } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
(async function run() { const it = g(); const p = it.next(); \
|
||||
order.push('req'); const r = await p; order.push('outer'); \
|
||||
return order.join(','); })()"
|
||||
),
|
||||
"\"inner,req,outer\""
|
||||
);
|
||||
}
|
||||
|
||||
// 边界:委托不可迭代值——TypeError 抛入委托 body,可被捕获。
|
||||
#[test]
|
||||
fn t15_yield_star_non_iterable_thrown_into_body() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* 42; } catch (e) { return 'caught:' + e.name; } } \
|
||||
(async function run() { const it = g(); const r = await it.next(); \
|
||||
return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:TypeError:true\""
|
||||
);
|
||||
}
|
||||
|
||||
// 边界:内层 next 同步抛错(非 promise 拒绝)——异常抛入委托 body,可被捕获。
|
||||
#[test]
|
||||
fn t16_inner_next_sync_throw_thrown_into_body() {
|
||||
assert_eq!(
|
||||
eval(
|
||||
"async function* g() { try { yield* { [Symbol.asyncIterator]() { \
|
||||
let first = true; return { \
|
||||
next() { if (first) { first = false; throw 'sync-e'; } \
|
||||
return Promise.resolve({ done: true }); } }; } }; } \
|
||||
catch (e) { return 'caught:' + e; } } \
|
||||
(async function run() { const it = g(); const r = await it.next(); \
|
||||
return r.value + ':' + r.done; })()"
|
||||
),
|
||||
"\"caught:sync-e:true\""
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user