diff --git a/crates/core/src/eval.rs b/crates/core/src/eval.rs
index e5791bf..bd5d229 100644
--- a/crates/core/src/eval.rs
+++ b/crates/core/src/eval.rs
@@ -88,7 +88,7 @@ impl Vm {
}
let mut frames = vec![frame];
let result = self
- .eval_frames(&mut frames, limits, &mut executed, usize::MAX)
+ .eval_frames(&mut frames, limits, &mut executed, usize::MAX, false)
.map(|value| value.expect("unbounded slice completes or fails"));
if result.is_err() {
self.last_traceback = frames
@@ -189,7 +189,13 @@ impl Vm {
.suspended_call
.take()
.ok_or(VmError::InvalidArgument("no suspended call"))?;
- let result = self.eval_frames(&mut call.frames, call.limits, &mut call.executed, slice_end);
+ let result = self.eval_frames(
+ &mut call.frames,
+ call.limits,
+ &mut call.executed,
+ slice_end,
+ false,
+ );
if let Ok(None) = result {
let instructions = call.executed;
self.suspended_call = Some(call);
@@ -376,8 +382,14 @@ impl Vm {
_ => unreachable!(),
};
let slice_end = executed.saturating_add(slice);
- let result = self.eval_frames(&mut frames, limits, &mut executed, slice_end);
+ let result = self.eval_frames(&mut frames, limits, &mut executed, slice_end, true);
if let Ok(None) = result {
+ let waiting = frames.last().filter(|frame| frame.waiting).map(|frame| {
+ match Self::top_value(frame).expect("await operand remains on stack") {
+ Value::Object(reference) => reference,
+ _ => unreachable!(),
+ }
+ });
let frames = std::sync::Arc::new(frames);
let mut roots = Vec::new();
for frame in frames.iter() {
@@ -395,6 +407,12 @@ impl Vm {
self.release(root)?;
}
published?;
+ if let Some(awaitable) = waiting {
+ return Ok(CoroutineProgress::Waiting {
+ awaitable,
+ instructions: executed,
+ });
+ }
return Ok(CoroutineProgress::Pending {
instructions: executed,
});
@@ -596,6 +614,7 @@ impl Vm {
name: data.name().into(),
instruction_offset: 0,
current_offset: 0,
+ waiting: false,
localsplus: vec![None; executable.slot_count()],
stack: Vec::with_capacity(executable.stack_size()),
executable,
@@ -981,6 +1000,7 @@ impl Vm {
limits: ExecutionLimits,
executed: &mut usize,
slice_end: usize,
+ allow_wait: bool,
) -> Result