essential_vm/
total_control_flow.rs1use essential_types::convert::bool_from_word;
2
3use crate::{
4 error::{OpSyncError, OpSyncResult, StackError, TotalControlFlowError},
5 Stack,
6};
7
8#[cfg(test)]
9mod tests;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub enum ProgramControlFlow {
14 Pc(usize),
16 Halt,
18}
19
20pub fn jump_if(stack: &mut Stack, pc: usize) -> OpSyncResult<Option<ProgramControlFlow>> {
21 let [dist, cond] = stack.pop2()?;
22 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidJumpForwardIfCondition)?;
23 if cond {
24 let neg = dist < 0;
25 let dist = usize::try_from(dist.abs()).map_err(|_| StackError::IndexOutOfBounds)?;
26 if dist == 0 {
27 return Err(TotalControlFlowError::JumpedToSelf.into());
28 }
29 if neg {
30 let pc = pc.checked_sub(dist).ok_or(OpSyncError::PcOverflow)?;
31 Ok(Some(ProgramControlFlow::Pc(pc)))
32 } else {
33 let pc = pc.checked_add(dist).ok_or(OpSyncError::PcOverflow)?;
34 Ok(Some(ProgramControlFlow::Pc(pc)))
35 }
36 } else {
37 Ok(None)
38 }
39}
40
41pub fn halt_if(stack: &mut Stack) -> OpSyncResult<Option<ProgramControlFlow>> {
42 let cond = stack.pop()?;
43 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidHaltIfCondition)?;
44 if cond {
45 Ok(Some(ProgramControlFlow::Halt))
46 } else {
47 Ok(None)
48 }
49}
50
51pub fn panic_if(stack: &mut Stack) -> OpSyncResult<()> {
53 let cond = stack.pop()?;
54 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidPanicIfCondition)?;
55 if cond {
56 let stack = stack.iter().copied().collect();
57 Err(TotalControlFlowError::Panic(stack).into())
58 } else {
59 Ok(())
60 }
61}