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";
const COST: u8 = 1;
fn execute(context: &mut Context) -> JsResult<CompletionType> {
let value = context.vm.pop();
context.vm.set_return_value(value);
Ok(CompletionType::Yield)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct AsyncGeneratorYield;
impl Operation for AsyncGeneratorYield {
const NAME: &'static str = "AsyncGeneratorYield";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorYield";
const COST: u8 = 8;
fn execute(context: &mut Context) -> JsResult<CompletionType> {
let async_generator_object = context
.vm
.frame()
.async_generator_object(&context.vm.stack)
.expect("`AsyncGeneratorYield` must only be called inside async generators");
let async_generator_object = async_generator_object
.downcast::<AsyncGenerator>()
.expect("must be async generator object");
let value = context.vm.pop();
let completion = Ok(value);
AsyncGenerator::complete_step(&async_generator_object, completion, false, None, context);
let mut gen = async_generator_object.borrow_mut();
if let Some(next) = gen.data.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.push(resume_kind);
return Ok(CompletionType::Normal);
}
gen.data.state = AsyncGeneratorState::SuspendedYield;
context.vm.set_return_value(JsValue::undefined());
Ok(CompletionType::Yield)
}
}