1use crate::error::ExecErrorType;
2use arrow_parser::symbol::Symbol;
3use arrowc::bytecode::BytecodeOp;
4use arrowc::compile::Constant;
5use arrowc::compile::IdentifierId;
6use arrowc::compile::Program;
7use itertools::Itertools;
8use ordered_float::OrderedFloat;
9use rustc_hash::FxHashMap;
10use std::io::Write;
11use std::rc::Rc;
12use std::sync::mpsc::channel;
13use std::sync::mpsc::Receiver;
14use std::sync::mpsc::Sender;
15use std::sync::Arc;
16
17struct OperandStack {
18 stack: Vec<Value>,
19}
20
21impl OperandStack {
22 pub fn new() -> OperandStack {
23 OperandStack { stack: Vec::new() }
24 }
25
26 pub fn len(&self) -> usize {
27 self.stack.len()
28 }
29
30 pub fn peek(&self) -> &Value {
31 self.stack.last().unwrap()
32 }
33
34 pub fn pop(&mut self) -> Value {
35 self.stack.pop().unwrap()
36 }
37
38 pub fn pop_2(&mut self) -> (Value, Value) {
40 let right = self.pop();
41 let left = self.pop();
42 (left, right)
43 }
44
45 pub fn pop_n(&mut self, n: usize) -> Vec<Value> {
47 let len = self.stack.len();
48 assert!(len >= n);
49 self.stack.split_off(len - n)
50 }
51
52 pub fn push(&mut self, v: Value) {
53 self.stack.push(v);
54 }
55}
56
57#[derive(Clone)]
59pub enum Value {
60 Boolean(bool),
61 Closure { closure_id: usize }, Float(OrderedFloat<f64>),
63 Int(i64),
64 Native(Rc<dyn NativeValue>), NativeCallable(&'static NativeCallable),
66 None,
67 Object { object_id: usize, impl_id: i16 }, String(Arc<Vec<u8>>), Vec { vec_id: usize }, }
71
72struct Frame {
73 box_ids: FxHashMap<Symbol, usize>, func_id: usize,
75 op_stack: OperandStack,
76 pc: usize,
77 vars: Vec<Value>,
78}
79
80impl Frame {
81 fn set_up(program: &Program, func_id: usize) -> Frame {
82 let func = &program.funcs[func_id];
83 Frame {
84 box_ids: FxHashMap::default(),
85 func_id,
86 op_stack: OperandStack::new(),
87 pc: 0,
88 vars: vec![Value::None; func.var_ids.len()],
89 }
90 }
91}
92
93struct Closure {
94 bound_args: Vec<Value>,
95 bound_offset: usize,
96 captured_box_ids: FxHashMap<Symbol, usize>,
97 func_id: usize,
98}
99
100pub type NativeCallable = fn(vm: &mut VM, args: Vec<Value>) -> NativeResult<Value>;
101
102struct Object {
103 fields: FxHashMap<Arc<Vec<u8>>, Value>,
104}
105
106pub trait NativeValue {
108 fn call_method(
109 &self,
110 vm: &mut VM,
111 method_id: IdentifierId,
113 args: Vec<Value>,
114 ) -> NativeResult<Value>;
115
116 #[allow(unused_variables)]
117 fn operator_add(&self, vm: &mut VM, other: Value) -> NativeResult<Value> {
118 unimplemented!();
119 }
120
121 #[allow(unused_variables)]
122 fn iterate(&self, vm: &mut VM) -> NativeResult<Value> {
123 unimplemented!();
124 }
125
126 #[allow(unused_variables)]
127 fn iterator_next(&self, vm: &mut VM) -> NativeResult<Option<Value>> {
128 unimplemented!();
129 }
130}
131
132struct Heap<T> {
133 entries: FxHashMap<usize, T>,
135 next_id: usize,
136}
137
138impl<T> Heap<T> {
139 pub fn new() -> Heap<T> {
140 Heap {
141 entries: FxHashMap::default(),
142 next_id: 0,
143 }
144 }
145
146 pub fn allocate(&mut self, v: T) -> usize {
147 let id = self.next_id;
148 self.next_id += 1;
149 self.entries.insert(id, v);
150 id
151 }
152
153 pub fn set(&mut self, id: usize, val: T) {
154 self.entries.insert(id, val).unwrap();
155 }
156
157 pub fn get(&self, id: usize) -> &T {
158 self.entries.get(&id).unwrap()
159 }
160
161 pub fn get_mut(&mut self, id: usize) -> &mut T {
162 self.entries.get_mut(&id).unwrap()
163 }
164}
165
166enum CoroutineWaitedOnBy {
167 Coroutine(CoroutineId),
168 CtlRequest(CtlRequestId),
169}
170
171struct Coroutine {
172 program: Arc<Program>,
173 stack_frames: Vec<Frame>,
174 waited_on_by: CoroutineWaitedOnBy,
175}
176
177pub type CoroutineId = usize;
178
179pub enum ThreadSafeValue {
181 Boolean(bool),
182 Float(OrderedFloat<f64>),
183 Int(i64),
184 Native(Box<dyn NativeValue + Send + Sync>),
185 None,
186 String(Arc<Vec<u8>>),
187 Vec(Vec<ThreadSafeValue>),
188}
189
190impl ThreadSafeValue {
191 pub fn into_value(self, vm: &mut VM) -> Value {
192 match self {
193 ThreadSafeValue::Boolean(v) => Value::Boolean(v),
194 ThreadSafeValue::Float(v) => Value::Float(v),
195 ThreadSafeValue::Int(v) => Value::Int(v),
196 ThreadSafeValue::Native(v) => Value::Native({
197 let v: Box<dyn NativeValue> = v;
198 let v: Rc<dyn NativeValue> = v.into();
199 v
200 }),
201 ThreadSafeValue::None => Value::None,
202 ThreadSafeValue::String(v) => Value::String(v),
203 ThreadSafeValue::Vec(v) => {
204 let vec = v.into_iter().map(|v| v.into_value(vm)).collect_vec();
205 Value::Vec {
206 vec_id: vm.vecs.allocate(vec),
207 }
208 }
209 }
210 }
211
212 pub fn from_value(vm: &VM, v: Value) -> CtlResponse {
213 CtlResponse::Ok(match v {
214 Value::Boolean(v) => ThreadSafeValue::Boolean(v),
215 Value::Float(v) => ThreadSafeValue::Float(v),
216 Value::Int(v) => ThreadSafeValue::Int(v),
217 Value::None => ThreadSafeValue::None,
218 Value::String(v) => ThreadSafeValue::String(v),
219 Value::Vec { vec_id } => {
220 let mut vec = vec![];
221 for v in vm.vecs.get(vec_id) {
222 match ThreadSafeValue::from_value(vm, v.clone()) {
223 CtlResponse::Ok(v) => vec.push(v),
224 res => return res,
225 };
226 }
227 ThreadSafeValue::Vec(vec)
228 }
229 _ => return CtlResponse::ValueUnserialisable,
230 })
231 }
232}
233
234enum Event {
235 CompletedPromise {
236 coroutine_id: CoroutineId,
237 value: ThreadSafeValue,
238 },
239 CtlRequest {
240 id: CtlRequestId,
241 request: CtlRequest,
242 },
243}
244
245pub type CtlRequestId = usize;
246
247pub enum CtlRequest {
248 Execute {
249 program: Arc<Program>,
250 },
251 Call {
252 module_var_name: String,
253 args: Vec<ThreadSafeValue>,
254 },
255}
256
257pub enum CtlResponse {
258 ExecError(ExecErrorType),
259 Ok(ThreadSafeValue),
260 ValueUnserialisable,
261}
262
263pub struct Promise {
264 coroutine_id: CoroutineId,
265 sender: Sender<Event>,
266}
267
268impl Promise {
269 pub fn complete(self, value: ThreadSafeValue) {
270 self
271 .sender
272 .send(Event::CompletedPromise {
273 coroutine_id: self.coroutine_id,
274 value,
275 })
276 .unwrap();
277 }
278}
279
280pub enum NativeResult<T> {
281 ExecError(ExecErrorType),
282 Value(T),
283 Promise,
284}
285
286pub struct VM {
287 boxes: Heap<Value>,
288 closures: Heap<Closure>,
289 suspended_coroutines: FxHashMap<CoroutineId, Coroutine>,
290 ctl_sender: Sender<(usize, CtlResponse)>,
291 current_coroutine_id: Option<CoroutineId>,
292 event_receiver: Receiver<Event>,
293 event_sender: Sender<Event>,
294 host_vars: FxHashMap<IdentifierId, Value>,
295 next_coroutine_id: CoroutineId,
296 objects: Heap<Object>,
297 #[cfg(feature = "tokio")]
298 tokio: tokio::runtime::Handle,
299 vecs: Heap<Vec<Value>>,
300}
301
302pub struct VMCtl {
303 receiver: Receiver<(usize, CtlResponse)>,
304 sender: Sender<Event>,
305}
306
307impl VM {
308 #[cfg(feature = "tokio")]
309 pub fn tokio(&self) -> tokio::runtime::Handle {
310 self.tokio.clone()
311 }
312
313 pub fn promise(&mut self) -> Promise {
315 Promise {
316 coroutine_id: self.current_coroutine_id.unwrap(),
317 sender: self.event_sender.clone(),
318 }
319 }
320
321 fn new_vm_only(
322 native_callables: &[(IdentifierId, &'static NativeCallable)],
323 ctl_sender: Sender<(usize, CtlResponse)>,
324 event_receiver: Receiver<Event>,
325 event_sender: Sender<Event>,
326 #[cfg(feature = "tokio")] tokio: tokio::runtime::Handle,
327 ) -> VM {
328 let mut host_vars = FxHashMap::<IdentifierId, Value>::default();
329
330 for (name, func) in native_callables {
331 host_vars.insert(*name, Value::NativeCallable(func));
332 }
333
334 VM {
335 boxes: Heap::new(),
336 closures: Heap::new(),
337 suspended_coroutines: FxHashMap::default(),
338 ctl_sender,
339 current_coroutine_id: None,
340 event_receiver,
341 event_sender,
342 host_vars,
343 next_coroutine_id: 0,
344 objects: Heap::new(),
345 #[cfg(feature = "tokio")]
346 tokio,
347 vecs: Heap::new(),
348 }
349 }
350
351 pub fn new_with_background_thread(
353 native_callables: &'static [(IdentifierId, &'static NativeCallable)],
354 #[cfg(feature = "tokio")] tokio: tokio::runtime::Handle,
355 ) -> VMCtl {
356 let (event_sender, event_receiver) = channel();
357 let (ctl_sender, ctl_receiver) = channel();
358
359 let vm_ctl = VMCtl {
360 sender: event_sender.clone(),
361 receiver: ctl_receiver,
362 };
363 std::thread::spawn(move || {
364 let mut vm = VM::new_vm_only(
365 native_callables,
366 ctl_sender,
367 event_receiver,
368 event_sender,
369 #[cfg(feature = "tokio")]
370 tokio,
371 );
372 vm.start_execution_loop();
373 });
374 vm_ctl
375 }
376
377 pub fn new(
379 native_callables: &[(IdentifierId, &'static NativeCallable)],
380 #[cfg(feature = "tokio")] tokio: tokio::runtime::Handle,
381 ) -> (VM, VMCtl) {
382 let (event_sender, event_receiver) = channel();
383 let (ctl_sender, ctl_receiver) = channel();
384
385 let vm = VM::new_vm_only(
386 native_callables,
387 ctl_sender,
388 event_receiver,
389 event_sender.clone(),
390 #[cfg(feature = "tokio")]
391 tokio,
392 );
393 let vm_ctl = VMCtl {
394 sender: event_sender.clone(),
395 receiver: ctl_receiver,
396 };
397 (vm, vm_ctl)
398 }
399
400 pub fn start_execution_loop(&mut self) {
402 loop {
403 match self.event_receiver.recv().unwrap() {
404 Event::CompletedPromise {
405 coroutine_id,
406 value,
407 } => {
408 let mut coroutine = self.suspended_coroutines.remove(&coroutine_id).unwrap();
409 coroutine
410 .stack_frames
411 .last_mut()
412 .unwrap()
413 .op_stack
414 .push(value.into_value(self));
415 self.execute_coroutine(coroutine_id, coroutine).unwrap();
416 }
417 Event::CtlRequest { id, request } => {
418 match request {
419 CtlRequest::Execute { program } => {
420 let frame = Frame::set_up(&program, program.funcs.len() - 1);
421 let coroutine = Coroutine {
422 program,
423 stack_frames: vec![frame],
424 waited_on_by: CoroutineWaitedOnBy::CtlRequest(id),
425 };
426 let coroutine_id: CoroutineId = self.next_coroutine_id;
427 self.next_coroutine_id += 1;
428 self.execute_coroutine(coroutine_id, coroutine).unwrap();
429 }
430 CtlRequest::Call {
431 module_var_name,
432 args,
433 } => todo!(),
434 };
435 }
436 };
437 }
438 }
439
440 fn execute_coroutine(
445 &mut self,
446 coroutine_id: CoroutineId,
447 mut coroutine: Coroutine,
448 ) -> Result<(), ExecErrorType> {
449 self.current_coroutine_id = Some(coroutine_id);
450
451 let mut module_vars = FxHashMap::<IdentifierId, Value>::default();
452 let program = &coroutine.program;
453
454 let mut f = coroutine.stack_frames.pop().unwrap();
456 loop {
457 let func = &program.funcs[f.func_id];
458 let code = &func.code;
459 let mut next_frame = None;
461 loop {
462 let mut call_function =
464 |next_func_id: usize, args: Vec<Value>, captured_box_ids: FxHashMap<Symbol, usize>| {
465 let mut new_frame = Frame::set_up(program, next_func_id);
466 assert_eq!(program.funcs[next_func_id].argc, args.len());
468 for arg in args.into_iter().rev() {
469 new_frame.op_stack.push(arg);
470 }
471 new_frame.box_ids = captured_box_ids;
472 next_frame = Some(new_frame);
473 };
474 let inst = code[f.pc];
475 f.pc += 1;
477 match inst {
478 BytecodeOp::Add => {
479 let (left, right) = f.op_stack.pop_2();
480 let op = match (left, right) {
481 (Value::Float(l), Value::Float(r)) => Value::Float(l + r),
482 (Value::Int(l), Value::Int(r)) => Value::Int(l + r),
483 (Value::String(l), Value::String(r)) => {
484 let mut res = l.to_vec();
485 res.extend_from_slice(r.as_slice());
486 Value::String(Arc::new(res))
487 }
488 _ => panic!("invalid operands"),
489 };
490 f.op_stack.push(op);
491 }
492 BytecodeOp::AllocateBox { symbol } => {
493 let box_id = self.boxes.allocate(Value::None);
494 f.box_ids.insert(symbol, box_id);
495 }
496 BytecodeOp::BindImplMethod {
497 func_id,
498 bound_argc,
499 } => {
500 let bound_args = f.op_stack.pop_n(bound_argc.into());
501 let closure_id = self.closures.allocate(Closure {
502 bound_args,
503 bound_offset: 1,
504 captured_box_ids: FxHashMap::default(),
505 func_id,
506 });
507 f.op_stack.push(Value::Closure { closure_id });
508 }
509 BytecodeOp::Call { argc } => {
510 let mut args = f.op_stack.pop_n(argc.into());
511 let callable = f.op_stack.pop();
512 match callable {
513 Value::Closure { closure_id } => {
514 let Closure {
515 bound_args,
516 bound_offset,
517 captured_box_ids,
518 func_id,
519 } = self.closures.get(closure_id);
520 args.splice(bound_offset..bound_offset, bound_args.iter().cloned());
521 call_function(*func_id, args, captured_box_ids.clone());
522 break;
523 }
524 Value::NativeCallable(func) => {
525 match func(self, args) {
526 NativeResult::ExecError(_) => todo!(),
527 NativeResult::Value(retval) => f.op_stack.push(retval),
528 NativeResult::Promise => {
529 coroutine.stack_frames.push(f);
530 self.suspended_coroutines.insert(coroutine_id, coroutine);
531 return Ok(());
533 }
534 };
535 }
536 _ => panic!("not a callable"),
537 };
538 }
539 BytecodeOp::CallMethod {
540 argc,
541 method_identifier_id,
542 } => {
543 let mut args = f.op_stack.pop_n(argc.into());
544 let obj = f.op_stack.pop();
545 match obj {
546 Value::Object { impl_id, .. } => {
547 args.insert(0, obj.clone());
548 let impl_ = &program.impls[usize::try_from(impl_id).unwrap()];
549 let func_id = impl_.methods.get(&method_identifier_id).unwrap();
550 call_function(*func_id, args, FxHashMap::default());
551 break;
552 }
553 Value::Native(nv) => {
554 match nv.call_method(self, method_identifier_id.into(), args) {
555 NativeResult::ExecError(_) => todo!(),
556 NativeResult::Value(retval) => f.op_stack.push(retval),
557 NativeResult::Promise => {
558 coroutine.stack_frames.push(f);
559 self.suspended_coroutines.insert(coroutine_id, coroutine);
560 return Ok(());
562 }
563 };
564 }
565 _ => panic!("cannot call method"),
567 };
568 }
569 BytecodeOp::CastObjectToImpl { impl_id } => {
570 let obj = f.op_stack.pop();
571 let Value::Object { object_id, .. } = obj else {
572 panic!("not an object");
573 };
574 f.op_stack.push(Value::Object {
575 object_id,
576 impl_id: i16::try_from(impl_id).unwrap(),
577 });
578 }
579 BytecodeOp::CopyTopOfStack => {
580 let val = f.op_stack.peek();
581 f.op_stack.push(val.clone());
582 }
583 BytecodeOp::Eq => {
584 let (left, right) = f.op_stack.pop_2();
585 let op = match (left, right) {
586 (Value::Float(l), Value::Float(r)) => Value::Boolean(l == r),
587 (Value::Int(l), Value::Int(r)) => Value::Boolean(l == r),
588 (Value::String(l), Value::String(r)) => Value::Boolean(l == r),
589 _ => panic!("invalid operands"),
590 };
591 f.op_stack.push(op);
592 }
593 BytecodeOp::GetIterator => {
594 let iterable = f.op_stack.pop();
595 let iterator = match iterable {
596 Value::Native(v) => match v.iterate(self) {
597 NativeResult::ExecError(_) => todo!(),
598 NativeResult::Value(next) => next,
599 NativeResult::Promise => todo!(),
600 },
601 _ => panic!("not iterable"),
602 };
603 f.op_stack.push(iterator);
604 }
605 BytecodeOp::GetNextOfIteratorOrGoto(pc) => {
606 let iterator = f.op_stack.peek();
607 let next = match iterator {
608 Value::Native(v) => match v.iterator_next(self) {
609 NativeResult::ExecError(_) => todo!(),
610 NativeResult::Value(next) => next,
611 NativeResult::Promise => todo!(),
612 },
613 _ => panic!("not an iterable"),
614 };
615 match next {
616 Some(v) => f.op_stack.push(v),
617 None => f.pc = pc,
618 };
619 }
620 BytecodeOp::Goto(loc) => {
621 f.pc = loc;
622 }
623 BytecodeOp::GotoIfFalse(loc) => {
624 let cond = f.op_stack.pop();
625 let Value::Boolean(cond) = cond else {
626 panic!("condition is not boolean");
627 };
628 if !cond {
629 f.pc = loc;
630 };
631 }
632 BytecodeOp::GotoIfNone(loc) => {
633 let val = f.op_stack.peek();
634 if let Value::None = val {
635 f.op_stack.pop();
636 f.pc = loc;
637 };
638 }
639 BytecodeOp::Index => {
640 let (obj_val, idx) = f.op_stack.pop_2();
641 match (&obj_val, &idx) {
642 (Value::Vec { vec_id }, Value::Int(idx)) => {
643 let vec = self.vecs.get(*vec_id);
644 let Some(val) = usize::try_from(*idx).ok().and_then(|idx| vec.get(idx)) else {
645 panic!("out of bounds");
646 };
647 f.op_stack.push(val.clone());
648 }
649 _ => panic!("cannot index"),
650 };
651 }
652 BytecodeOp::IndexAssign => todo!(),
653 BytecodeOp::InitialiseObjectField {
654 field_name_string_const_id,
655 } => {
656 let (obj_val, value) = f.op_stack.pop_2();
657 let Value::Object { object_id, .. } = obj_val else {
658 panic!("not an object");
659 };
660 let field_name = program
661 .constants
662 .get(field_name_string_const_id)
663 .unwrap()
664 .string();
665 self
666 .objects
667 .get_mut(object_id)
668 .fields
669 .insert(field_name, value);
670 f.op_stack.push(obj_val);
671 }
672 BytecodeOp::LoadBool(v) => {
673 f.op_stack.push(Value::Boolean(v));
674 }
675 BytecodeOp::LoadBox { symbol } => {
676 let box_id = *f.box_ids.get(&symbol).unwrap();
677 let val = self.boxes.get(box_id).clone();
678 f.op_stack.push(val);
679 }
680 BytecodeOp::LoadClosure(func_id) => {
681 let cfg = &program.funcs[func_id];
682 let mut captured_box_ids = FxHashMap::default();
683 for symbol in cfg.box_captures.iter() {
684 captured_box_ids.insert(*symbol, *f.box_ids.get(&symbol).unwrap());
685 }
686 let closure_id = self.closures.allocate(Closure {
687 func_id,
688 captured_box_ids,
689 bound_args: vec![],
690 bound_offset: 0,
691 });
692 f.op_stack.push(Value::Closure { closure_id });
693 }
694 BytecodeOp::LoadConstant(constant_id) => {
695 f.op_stack
696 .push(match program.constants[constant_id].clone() {
697 Constant::Float(v) => Value::Float(v),
698 Constant::Int(v) => Value::Int(v),
699 Constant::String(v) => Value::String(v.clone()),
700 });
701 }
702 BytecodeOp::LoadField {
703 field_name_string_const_id,
704 } => {
705 let Value::Object { object_id, .. } = f.op_stack.pop() else {
706 panic!("not an object");
707 };
708 let obj = self.objects.get(object_id);
709 let field_name = program
710 .constants
711 .get(field_name_string_const_id)
712 .unwrap()
713 .string();
714 let val = obj.fields.get(&field_name).unwrap().clone();
715 f.op_stack.push(val);
716 }
717 BytecodeOp::LoadHostVar(id) => {
718 let val = self.host_vars.get(&id).unwrap().clone();
719 f.op_stack.push(val);
720 }
721 BytecodeOp::LoadModuleVar(id) => {
722 let val = module_vars.get(&id).unwrap().clone();
723 f.op_stack.push(val);
724 }
725 BytecodeOp::LoadNone => {
726 f.op_stack.push(Value::None);
727 }
728 BytecodeOp::LoadVar(var_id) => {
729 f.op_stack.push(f.vars[var_id].clone());
730 }
731 BytecodeOp::NewArray { argc: _ } => todo!(),
732 BytecodeOp::NewObject => {
733 let object_id = self.objects.allocate(Object {
734 fields: FxHashMap::default(),
735 });
736 f.op_stack.push(Value::Object {
737 object_id,
738 impl_id: -1,
739 });
740 }
741 BytecodeOp::NewString { argc } => {
742 let mut res = Vec::new();
743 for part in f.op_stack.pop_n(argc.into()) {
744 match part {
745 Value::Boolean(v) => write!(res, "{}", v).unwrap(),
746 Value::Float(v) => write!(res, "{}", v).unwrap(),
747 Value::None => res.extend_from_slice(b"None"),
748 Value::Int(v) => write!(res, "{}", v).unwrap(),
749 Value::String(v) => res.extend_from_slice(&v),
750 _ => panic!("cannot convert to string"),
751 };
752 }
753 f.op_stack.push(Value::String(Arc::new(res)));
754 }
755 BytecodeOp::Not => {
756 let val = f.op_stack.pop();
757 let res = match val {
758 Value::Boolean(b) => Value::Boolean(!b),
759 _ => panic!("invalid operand"),
760 };
761 f.op_stack.push(res);
762 }
763 BytecodeOp::PopStack => {
764 f.op_stack.pop();
765 }
766 BytecodeOp::Return => {
767 break;
768 }
769 BytecodeOp::StoreBox { symbol } => {
770 let val = f.op_stack.pop();
771 let box_id = *f.box_ids.get(&symbol).unwrap();
772 self.boxes.set(box_id, val);
773 }
774 BytecodeOp::StoreField {
775 field_name_string_const_id,
776 } => {
777 let val = f.op_stack.pop();
778 let Value::Object { object_id, .. } = f.op_stack.pop() else {
779 panic!("not an object");
780 };
781 let field_name = program
782 .constants
783 .get(field_name_string_const_id)
784 .unwrap()
785 .string();
786 self
787 .objects
788 .get_mut(object_id)
789 .fields
790 .insert(field_name, val);
791 }
792 BytecodeOp::StoreModuleVar(id) => {
793 let val = f.op_stack.pop();
794 module_vars.insert(id, val);
795 }
796 BytecodeOp::StoreVar(var_id) => {
797 let val = f.op_stack.pop();
798 f.vars[var_id] = val;
799 }
800 BytecodeOp::SwapTop2OfStack => {
801 let (op0, op1) = f.op_stack.pop_2();
802 f.op_stack.push(op1);
803 f.op_stack.push(op0);
804 }
805 };
806 }
807
808 match next_frame {
809 Some(next_frame) => {
810 coroutine
811 .stack_frames
812 .push(std::mem::replace(&mut f, next_frame));
813 }
814 None => {
815 assert_eq!(f.op_stack.len(), 1);
816 let retval = f.op_stack.pop();
817 if coroutine.stack_frames.is_empty() {
818 match coroutine.waited_on_by {
819 CoroutineWaitedOnBy::Coroutine(_) => todo!(),
820 CoroutineWaitedOnBy::CtlRequest(request_id) => {
821 self
822 .ctl_sender
823 .send((request_id, ThreadSafeValue::from_value(self, retval)))
824 .unwrap();
825 }
826 };
827 self.current_coroutine_id = None;
828 return Ok(());
829 };
830 f = coroutine.stack_frames.pop().unwrap();
831 f.op_stack.push(retval);
832 }
833 };
834 }
835 }
836}
837
838impl VMCtl {
839 pub fn request(&self, id: usize, request: CtlRequest) {
840 self.sender.send(Event::CtlRequest { id, request }).unwrap();
841 }
842
843 pub fn receiver(&self) -> &Receiver<(usize, CtlResponse)> {
844 &self.receiver
845 }
846}