runmat_vm/ops/
control_flow.rs1use crate::interpreter::stack::pop_value;
2use runmat_builtins::Value;
3use runmat_runtime::RuntimeError;
4
5pub enum ControlFlowAction {
6 Next,
7 Jump(usize),
8 Return,
9}
10
11#[inline]
12pub fn and_and(stack: &mut Vec<Value>, target: usize) -> Result<ControlFlowAction, RuntimeError> {
13 let lhs: f64 = (&pop_value(stack)?).try_into()?;
14 if lhs == 0.0 {
15 Ok(ControlFlowAction::Jump(target))
16 } else {
17 Ok(ControlFlowAction::Next)
18 }
19}
20
21#[inline]
22pub fn or_or(stack: &mut Vec<Value>, target: usize) -> Result<ControlFlowAction, RuntimeError> {
23 let lhs: f64 = (&pop_value(stack)?).try_into()?;
24 if lhs != 0.0 {
25 Ok(ControlFlowAction::Jump(target))
26 } else {
27 Ok(ControlFlowAction::Next)
28 }
29}
30
31#[inline]
32pub fn jump_if_false(cond: bool, target: usize) -> ControlFlowAction {
33 if cond {
34 ControlFlowAction::Next
35 } else {
36 ControlFlowAction::Jump(target)
37 }
38}
39
40#[inline]
41pub fn jump(target: usize) -> ControlFlowAction {
42 ControlFlowAction::Jump(target)
43}
44
45#[inline]
46pub fn enter_try(
47 try_stack: &mut Vec<(usize, Option<usize>)>,
48 catch_pc: usize,
49 catch_var: Option<usize>,
50) {
51 try_stack.push((catch_pc, catch_var));
52}
53
54#[inline]
55pub fn pop_try(try_stack: &mut Vec<(usize, Option<usize>)>) {
56 let _ = try_stack.pop();
57}
58
59#[inline]
60pub fn enter_scope(locals: &mut Vec<Value>, local_count: usize) {
61 for _ in 0..local_count {
62 locals.push(Value::Num(0.0));
63 }
64}
65
66pub fn exit_scope<OnPop>(locals: &mut Vec<Value>, local_count: usize, mut on_pop: OnPop)
67where
68 OnPop: FnMut(&Value),
69{
70 for _ in 0..local_count {
71 if let Some(value) = locals.pop() {
72 on_pop(&value);
73 }
74 }
75}
76
77#[inline]
78pub fn return_value(stack: &mut Vec<Value>) -> Result<ControlFlowAction, RuntimeError> {
79 let value = pop_value(stack)?;
80 stack.push(value);
81 Ok(ControlFlowAction::Return)
82}
83
84#[inline]
85pub fn return_void() -> ControlFlowAction {
86 ControlFlowAction::Return
87}