cairo_lang_sierra_to_casm/environment/
frame_state.rs1use thiserror::Error;
2
3use super::{ApTracking, ApTrackingBase};
4
5#[derive(Error, Debug, Eq, PartialEq)]
6pub enum FrameStateError {
7 #[error("InvalidTransition")]
8 InvalidTransition,
9 #[error("alloc_local is not allowed at this point.")]
10 InvalidAllocLocal(FrameState),
11 #[error("finalize_locals is not allowed at this point.")]
12 InvalidFinalizeLocals(FrameState),
13 #[error("locals were allocated but finalize_locals was not called.")]
14 FinalizeLocalsMissing(FrameState),
15}
16
17#[derive(Clone, Debug, Eq, PartialEq)]
21pub enum FrameState {
22 BeforeAllocation,
24 Allocating { allocated: usize, locals_start_ap_offset: usize },
30 Finalized { allocated: usize },
32}
33
34pub fn handle_finalize_locals(
36 frame_state: FrameState,
37 ap_tracking: ApTracking,
38) -> Result<(usize, FrameState), FrameStateError> {
39 match frame_state {
40 FrameState::BeforeAllocation => {
41 if matches!(
43 ap_tracking,
44 ApTracking::Enabled { ap_change: _, base: ApTrackingBase::FunctionStart }
45 ) {
46 Ok((0, FrameState::Finalized { allocated: 0 }))
47 } else {
48 Err(FrameStateError::InvalidFinalizeLocals(frame_state))
49 }
50 }
51 FrameState::Allocating { allocated, locals_start_ap_offset } => {
52 if matches!(
53 ap_tracking,
54 ApTracking::Enabled { ap_change, base: ApTrackingBase::FunctionStart }
55 if ap_change == locals_start_ap_offset
56 ) {
57 Ok((allocated, FrameState::Finalized { allocated }))
58 } else {
59 Err(FrameStateError::InvalidFinalizeLocals(frame_state))
60 }
61 }
62 FrameState::Finalized { .. } => Err(FrameStateError::InvalidFinalizeLocals(frame_state)),
63 }
64}
65
66pub fn handle_alloc_local(
68 frame_state: FrameState,
69 ap_tracking: ApTracking,
70 allocation_size: usize,
71) -> Result<(usize, FrameState), FrameStateError> {
72 match frame_state {
73 FrameState::BeforeAllocation => {
74 if let ApTracking::Enabled { ap_change, base: ApTrackingBase::FunctionStart } =
75 ap_tracking
76 {
77 Ok((
78 ap_change,
79 FrameState::Allocating {
80 allocated: allocation_size,
81 locals_start_ap_offset: ap_change,
82 },
83 ))
84 } else {
85 Err(FrameStateError::InvalidAllocLocal(frame_state))
86 }
87 }
88 FrameState::Allocating { allocated, locals_start_ap_offset } => {
89 if matches!(
90 ap_tracking,
91 ApTracking::Enabled { ap_change, base: ApTrackingBase::FunctionStart }
92 if ap_change == locals_start_ap_offset
93 ) {
94 Ok((
95 locals_start_ap_offset + allocated,
96 FrameState::Allocating {
97 allocated: allocated + allocation_size,
98 locals_start_ap_offset,
99 },
100 ))
101 } else {
102 Err(FrameStateError::InvalidAllocLocal(frame_state))
103 }
104 }
105 FrameState::Finalized { .. } => Err(FrameStateError::InvalidAllocLocal(frame_state)),
106 }
107}
108
109pub fn validate_final_frame_state(frame_state: &FrameState) -> Result<(), FrameStateError> {
111 if matches!(frame_state, FrameState::Allocating { .. }) {
112 Err(FrameStateError::FinalizeLocalsMissing(frame_state.clone()))
113 } else {
114 Ok(())
115 }
116}