use std::ops::ControlFlow;
use crate::{
Context, JsValue,
builtins::async_generator::{AsyncGenerator, AsyncGeneratorState},
vm::{
CompletionRecord, GeneratorResumeKind,
opcode::{Operation, VaryingOperand},
},
};
#[derive(Debug, Clone, Copy)]
pub(crate) struct GeneratorYield;
impl GeneratorYield {
#[inline(always)]
pub(crate) fn operation(
value: VaryingOperand,
context: &mut Context,
) -> ControlFlow<CompletionRecord> {
let value = context.vm.get_register(value.into());
context.vm.set_return_value(value.clone());
context.handle_yield()
}
}
impl Operation for GeneratorYield {
const NAME: &'static str = "GeneratorYield";
const INSTRUCTION: &'static str = "INST - GeneratorYield";
const COST: u8 = 1;
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct AsyncGeneratorYield;
impl AsyncGeneratorYield {
#[inline(always)]
pub(crate) fn operation(
value: VaryingOperand,
context: &mut Context,
) -> ControlFlow<CompletionRecord> {
let async_generator_object = context
.vm
.stack
.async_generator_object(&context.vm.frame)
.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.get_register(value.into());
let completion = Ok(value.clone());
AsyncGenerator::complete_step(&async_generator_object, completion, false, None, context);
let mut r#gen = async_generator_object.borrow_mut();
if let Some(next) = r#gen.data().queue.front() {
let resume_kind = match next.completion.clone() {
CompletionRecord::Normal(val) => {
context.vm.stack.push(val);
GeneratorResumeKind::Normal
}
CompletionRecord::Return(val) => {
context.vm.stack.push(val);
GeneratorResumeKind::Return
}
CompletionRecord::Throw(err) => {
let err = err.to_opaque(context);
context.vm.stack.push(err);
GeneratorResumeKind::Throw
}
};
context.vm.stack.push(resume_kind);
return ControlFlow::Continue(());
}
r#gen.data_mut().state = AsyncGeneratorState::SuspendedYield;
context.vm.set_return_value(JsValue::undefined());
context.handle_yield()
}
}
impl Operation for AsyncGeneratorYield {
const NAME: &'static str = "AsyncGeneratorYield";
const INSTRUCTION: &'static str = "INST - AsyncGeneratorYield";
const COST: u8 = 8;
}