essential_constraint_vm/
total_control_flow.rs1use essential_types::convert::bool_from_word;
2
3use crate::{
4 error::{OpError, StackError, TotalControlFlowError},
5 OpResult, 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_forward_if(stack: &mut Stack, pc: usize) -> OpResult<Option<ProgramControlFlow>> {
21 let [dist, cond] = stack.pop2()?;
22 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidJumpForwardIfCondition)?;
23 if cond {
24 let dist = usize::try_from(dist).map_err(|_| StackError::IndexOutOfBounds)?;
25 if dist == 0 {
26 return Err(TotalControlFlowError::JumpedToSelf.into());
27 }
28 let pc = pc.checked_add(dist).ok_or(OpError::PcOverflow)?;
29 Ok(Some(ProgramControlFlow::Pc(pc)))
30 } else {
31 Ok(None)
32 }
33}
34
35pub fn halt_if(stack: &mut Stack) -> OpResult<Option<ProgramControlFlow>> {
36 let cond = stack.pop()?;
37 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidHaltIfCondition)?;
38 if cond {
39 Ok(Some(ProgramControlFlow::Halt))
40 } else {
41 Ok(None)
42 }
43}
44
45pub fn panic_if(stack: &mut Stack) -> OpResult<()> {
47 let cond = stack.pop()?;
48 let cond = bool_from_word(cond).ok_or(TotalControlFlowError::InvalidPanicIfCondition)?;
49 if cond {
50 let stack = stack.iter().copied().collect();
51 Err(TotalControlFlowError::Panic(stack).into())
52 } else {
53 Ok(())
54 }
55}