use crate::{
builtins::async_generator::{AsyncGenerator, AsyncGeneratorState},
vm::{opcode::Operation, CompletionRecord, CompletionType, GeneratorResumeKind},
Context, JsResult, JsValue,
};
#[derive(Debug, Clone, Copy)]
pub(crate) struct GeneratorYield;
impl Operation for GeneratorYield {
const NAME: &'static str = "GeneratorYield";
const INSTRUCTION: &'static str = "INST - GeneratorYield";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
context.vm.frame_mut().r#yield = true;
Ok(CompletionType::Return)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct AsyncGeneratorYield;
impl Operation for AsyncGeneratorYield {
const NAME: &'static str = "AsyncGeneratorYield";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorYield";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let async_gen = context
.vm
.frame()
.async_generator
.clone()
.expect("`AsyncGeneratorYield` must only be called inside async generators");
let completion = Ok(value);
let next = async_gen
.borrow_mut()
.as_async_generator_mut()
.expect("must be async generator object")
.queue
.pop_front()
.expect("must have item in queue");
AsyncGenerator::complete_step(&next, completion, false, None, context);
let mut generator_object_mut = async_gen.borrow_mut();
let gen = generator_object_mut
.as_async_generator_mut()
.expect("must be async generator object");
if let Some(next) = gen.queue.front() {
let resume_kind = match next.completion.clone() {
CompletionRecord::Normal(val) => {
context.vm.push(val);
GeneratorResumeKind::Normal
}
CompletionRecord::Return(val) => {
context.vm.push(val);
GeneratorResumeKind::Return
}
CompletionRecord::Throw(err) => {
let err = err.to_opaque(context);
context.vm.push(err);
GeneratorResumeKind::Throw
}
};
context.vm.frame_mut().generator_resume_kind = resume_kind;
Ok(CompletionType::Normal)
} else {
gen.state = AsyncGeneratorState::SuspendedYield;
context.vm.push(JsValue::undefined());
GeneratorYield::execute(context)
}
}
}