use boa_gc::{Gc, GcRefCell};
use crate::{
builtins::{generator::GeneratorContext, Promise},
native_function::NativeFunction,
object::FunctionObjectBuilder,
vm::{opcode::Operation, CompletionType, GeneratorResumeKind},
Context, JsArgs, JsResult, JsValue,
};
#[derive(Debug, Clone, Copy)]
pub(crate) struct Await;
impl Operation for Await {
const NAME: &'static str = "Await";
const INSTRUCTION: &'static str = "INST - Await";
fn execute(context: &mut Context<'_>) -> JsResult<CompletionType> {
let value = context.vm.pop();
let promise = Promise::promise_resolve(
&context.intrinsics().constructors().promise().constructor(),
value,
context,
)?;
let gen = GeneratorContext::from_current(context);
let captures = Gc::new(GcRefCell::new(Some(gen)));
let on_fulfilled = FunctionObjectBuilder::new(
context,
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
let mut gen = captures.borrow_mut().take().expect("should only run once");
gen.resume(
Some(args.get_or_undefined(0).clone()),
GeneratorResumeKind::Normal,
context,
);
if let Some(async_generator) = gen
.call_frame
.as_ref()
.and_then(|f| f.async_generator.clone())
{
async_generator
.borrow_mut()
.as_async_generator_mut()
.expect("must be async generator")
.context = Some(gen);
}
Ok(JsValue::undefined())
},
captures.clone(),
),
)
.name("")
.length(1)
.build();
let on_rejected = FunctionObjectBuilder::new(
context,
NativeFunction::from_copy_closure_with_captures(
|_this, args, captures, context| {
let mut gen = captures.borrow_mut().take().expect("should only run once");
gen.resume(
Some(args.get_or_undefined(0).clone()),
GeneratorResumeKind::Throw,
context,
);
if let Some(async_generator) = gen
.call_frame
.as_ref()
.and_then(|f| f.async_generator.clone())
{
async_generator
.borrow_mut()
.as_async_generator_mut()
.expect("must be async generator")
.context = Some(gen);
}
Ok(JsValue::undefined())
},
captures,
),
)
.name("")
.length(1)
.build();
Promise::perform_promise_then(
&promise,
Some(on_fulfilled),
Some(on_rejected),
None,
context,
);
context.vm.push(JsValue::undefined());
context.vm.frame_mut().r#yield = true;
Ok(CompletionType::Return)
}
}