use super::{ByteCompiler, Literal, Register};
use crate::{js_string, vm::GeneratorResumeKind};
impl ByteCompiler<'_> {
pub(super) fn iterator_close(&mut self, async_: bool) {
let value = self.register_allocator.alloc();
let called = self.register_allocator.alloc();
self.bytecode
.emit_iterator_return(value.variable(), called.variable());
let early_exit = self.jump_if_false(&called);
self.register_allocator.dealloc(called);
if async_ {
self.bytecode.emit_await(value.variable());
let resume_kind = self.register_allocator.alloc();
self.pop_into_register(&resume_kind);
self.pop_into_register(&value);
self.bytecode
.emit_generator_next(resume_kind.variable(), value.variable());
self.register_allocator.dealloc(resume_kind);
}
self.bytecode.emit_is_object(value.variable());
let skip_throw = self.jump_if_true(&value);
self.register_allocator.dealloc(value);
let error_msg = self.get_or_insert_literal(Literal::String(js_string!(
"inner result was not an object"
)));
self.bytecode.emit_throw_new_type_error(error_msg.into());
self.patch_jump(skip_throw);
self.patch_jump(early_exit);
}
pub(super) fn close_active_iterators(&mut self) {
let start = self.next_opcode_location();
let empty = self.register_allocator.alloc();
self.bytecode.emit_iterator_stack_empty(empty.variable());
let exit = self.jump_if_true(&empty);
self.register_allocator.dealloc(empty);
self.iterator_close(self.is_async_generator());
self.bytecode.emit_jump(start);
self.patch_jump(exit);
}
pub(super) fn r#yield(&mut self, value: &Register) {
let resume_kind = self.register_allocator.alloc();
if self.is_async() {
self.bytecode.emit_await(value.variable());
self.pop_into_register(&resume_kind);
self.pop_into_register(value);
self.bytecode
.emit_generator_next(resume_kind.variable(), value.variable());
self.async_generator_yield(value, &resume_kind);
} else {
self.bytecode
.emit_create_iterator_result(value.variable(), false.into());
self.bytecode.emit_generator_yield(value.variable());
self.pop_into_register(&resume_kind);
self.pop_into_register(value);
}
self.bytecode
.emit_generator_next(resume_kind.variable(), value.variable());
self.register_allocator.dealloc(resume_kind);
}
pub(super) fn async_generator_yield(&mut self, value: &Register, resume_kind: &Register) {
self.bytecode.emit_async_generator_yield(value.variable());
self.pop_into_register(resume_kind);
self.pop_into_register(value);
let non_return_resume =
self.jump_if_not_resume_kind(GeneratorResumeKind::Return, resume_kind);
self.bytecode.emit_await(value.variable());
self.pop_into_register(resume_kind);
self.pop_into_register(value);
let non_normal_resume =
self.jump_if_not_resume_kind(GeneratorResumeKind::Normal, resume_kind);
self.emit_resume_kind(GeneratorResumeKind::Return, resume_kind);
self.patch_jump(non_normal_resume);
self.patch_jump(non_return_resume);
}
}