use crate::{GeneratorState, Value, Vm, VmError, VmErrorKind, VmHalt};
pub struct VmExecution {
vms: Vec<Vm>,
}
impl VmExecution {
pub(crate) fn of(vm: Vm) -> Self {
Self { vms: vec![vm] }
}
pub fn vm(&self) -> Result<&Vm, VmError> {
match self.vms.last() {
Some(vm) => Ok(vm),
None => {
return Err(VmError::from(VmErrorKind::NoRunningVm));
}
}
}
pub fn vm_mut(&mut self) -> Result<&mut Vm, VmError> {
match self.vms.last_mut() {
Some(vm) => Ok(vm),
None => {
return Err(VmError::from(VmErrorKind::NoRunningVm));
}
}
}
pub async fn async_complete(&mut self) -> Result<Value, VmError> {
loop {
let len = self.vms.len();
let vm = self.vm_mut()?;
match Self::run_for(vm, None)? {
VmHalt::Exited => (),
VmHalt::Awaited(awaited) => {
awaited.wait_with_vm(vm).await?;
continue;
}
VmHalt::VmCall(vm_call) => {
vm_call.into_execution(self)?;
continue;
}
halt => {
return Err(VmError::from(VmErrorKind::Halted {
halt: halt.into_info(),
}))
}
}
if len == 1 {
let value = vm.stack_mut().pop()?;
debug_assert!(vm.stack().is_empty(), "the final vm should be empty");
return Ok(value);
}
self.pop_vm()?;
}
}
pub fn complete(&mut self) -> Result<Value, VmError> {
loop {
let len = self.vms.len();
let vm = self.vm_mut()?;
match Self::run_for(vm, None)? {
VmHalt::Exited => (),
VmHalt::VmCall(vm_call) => {
vm_call.into_execution(self)?;
continue;
}
halt => {
return Err(VmError::from(VmErrorKind::Halted {
halt: halt.into_info(),
}))
}
}
if len == 1 {
let value = vm.stack_mut().pop()?;
debug_assert!(vm.stack().is_empty(), "the final vm should be empty");
return Ok(value);
}
self.pop_vm()?;
}
}
pub async fn async_resume(&mut self) -> Result<GeneratorState, VmError> {
loop {
let len = self.vms.len();
let vm = self.vm_mut()?;
match Self::run_for(vm, None)? {
VmHalt::Exited => (),
VmHalt::Awaited(awaited) => {
awaited.wait_with_vm(vm).await?;
continue;
}
VmHalt::VmCall(vm_call) => {
vm_call.into_execution(self)?;
continue;
}
VmHalt::Yielded => return Ok(GeneratorState::Yielded(vm.stack_mut().pop()?)),
halt => {
return Err(VmError::from(VmErrorKind::Halted {
halt: halt.into_info(),
}))
}
}
if len == 1 {
let value = vm.stack_mut().pop()?;
debug_assert!(vm.stack().is_empty(), "the final vm should be empty");
return Ok(GeneratorState::Complete(value));
}
self.pop_vm()?;
}
}
pub fn resume(&mut self) -> Result<GeneratorState, VmError> {
loop {
let len = self.vms.len();
let vm = self.vm_mut()?;
match Self::run_for(vm, None)? {
VmHalt::Exited => (),
VmHalt::VmCall(vm_call) => {
vm_call.into_execution(self)?;
continue;
}
VmHalt::Yielded => return Ok(GeneratorState::Yielded(vm.stack_mut().pop()?)),
halt => {
return Err(VmError::from(VmErrorKind::Halted {
halt: halt.into_info(),
}))
}
}
if len == 1 {
let value = vm.stack_mut().pop()?;
debug_assert!(vm.stack().is_empty(), "the final vm should be empty");
return Ok(GeneratorState::Complete(value));
}
self.pop_vm()?;
}
}
pub async fn step(&mut self) -> Result<Option<Value>, VmError> {
let len = self.vms.len();
let vm = self.vm_mut()?;
match Self::run_for(vm, Some(1))? {
VmHalt::Exited => (),
VmHalt::Awaited(awaited) => {
awaited.wait_with_vm(vm).await?;
return Ok(None);
}
VmHalt::VmCall(vm_call) => {
vm_call.into_execution(self)?;
return Ok(None);
}
VmHalt::Limited => return Ok(None),
halt => {
return Err(VmError::from(VmErrorKind::Halted {
halt: halt.into_info(),
}))
}
}
if len == 1 {
let value = vm.stack_mut().pop()?;
debug_assert!(vm.stack().is_empty(), "final vm stack not clean");
return Ok(Some(value));
}
self.pop_vm()?;
Ok(None)
}
pub(crate) fn push_vm(&mut self, vm: Vm) {
self.vms.push(vm);
}
fn pop_vm(&mut self) -> Result<(), VmError> {
let mut from = self
.vms
.pop()
.ok_or_else(|| VmError::from(VmErrorKind::NoRunningVm))?;
let stack = from.stack_mut();
let value = stack.pop()?;
debug_assert!(stack.is_empty(), "vm stack not clean");
let onto = self.vm_mut()?;
onto.stack_mut().push(value);
onto.advance();
Ok(())
}
#[inline]
fn run_for(vm: &mut Vm, limit: Option<usize>) -> Result<VmHalt, VmError> {
match vm.run_for(limit) {
Ok(reason) => Ok(reason),
Err(error) => Err(error.into_unwinded(vm.unit(), vm.ip())),
}
}
}