baedeker_core/validate/
state.rs1use alloc::{vec, vec::Vec};
10
11use crate::types::{BlockType, ValType};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub enum OperandType {
16 Typed(ValType),
17 Bottom,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum Reachability {
23 Reachable,
24 Unreachable,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum ControlKind {
30 Function,
31 Block,
32 Loop,
33 If,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct ControlFrame {
39 pub kind: ControlKind,
40 pub block_type: BlockType,
41 pub outer_height: usize,
42 pub stack_floor: usize,
43 pub start_types: Vec<ValType>,
44 pub end_types: Vec<ValType>,
45 pub local_inits: Vec<bool>,
46 pub has_else: bool,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Default)]
51pub struct TypeStack {
52 values: Vec<OperandType>,
53}
54
55impl TypeStack {
56 pub fn new() -> Self {
57 Self::default()
58 }
59
60 pub fn len(&self) -> usize {
61 self.values.len()
62 }
63
64 pub fn is_empty(&self) -> bool {
65 self.values.is_empty()
66 }
67
68 pub fn truncate(&mut self, len: usize) {
69 self.values.truncate(len);
70 }
71
72 pub fn push(&mut self, value: ValType) {
73 self.values.push(OperandType::Typed(value));
74 }
75
76 pub fn push_bottom(&mut self) {
77 self.values.push(OperandType::Bottom);
78 }
79
80 pub fn pop(&mut self) -> Option<OperandType> {
81 self.values.pop()
82 }
83
84 pub fn as_slice(&self) -> &[OperandType] {
85 &self.values
86 }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct ValidationState {
92 pub operands: TypeStack,
93 pub controls: Vec<ControlFrame>,
94 pub locals: Vec<ValType>,
95 pub local_inits: Vec<bool>,
96 pub reachability: Reachability,
97}
98
99impl ValidationState {
100 pub fn new(locals: Vec<ValType>, local_inits: Vec<bool>, result_types: Vec<ValType>) -> Self {
101 Self {
102 operands: TypeStack::new(),
103 controls: vec![ControlFrame {
104 kind: ControlKind::Function,
105 block_type: BlockType::Empty,
106 outer_height: 0,
107 stack_floor: 0,
108 start_types: Vec::new(),
109 end_types: result_types,
110 local_inits: local_inits.clone(),
111 has_else: false,
112 }],
113 locals,
114 local_inits,
115 reachability: Reachability::Reachable,
116 }
117 }
118
119 pub fn current_frame(&self) -> &ControlFrame {
120 self.controls
121 .last()
122 .expect("validation state must always contain a function frame")
123 }
124
125 pub fn current_frame_mut(&mut self) -> &mut ControlFrame {
126 self.controls
127 .last_mut()
128 .expect("validation state must always contain a function frame")
129 }
130
131 pub fn push_frame(
132 &mut self,
133 kind: ControlKind,
134 block_type: BlockType,
135 start_types: Vec<ValType>,
136 end_types: Vec<ValType>,
137 ) {
138 let outer_height = self.operands.len();
139 for ty in &start_types {
140 self.operands.push(*ty);
141 }
142 let stack_floor = self.operands.len();
143
144 self.controls.push(ControlFrame {
145 kind,
146 block_type,
147 outer_height,
148 stack_floor,
149 start_types,
150 end_types,
151 local_inits: self.local_inits.clone(),
152 has_else: false,
153 });
154 }
155
156 pub fn pop_frame(&mut self) -> Option<ControlFrame> {
157 if self.controls.len() > 1 {
158 self.controls.pop()
159 } else {
160 None
161 }
162 }
163
164 pub fn current_label_types(&self, depth: u32) -> Option<&[ValType]> {
165 let frame = self.controls.iter().rev().nth(depth as usize)?;
166 Some(match frame.kind {
167 ControlKind::Loop => frame.start_types.as_slice(),
168 _ => frame.end_types.as_slice(),
169 })
170 }
171
172 pub fn enter_unreachable(&mut self) {
173 let floor = self.current_frame().outer_height;
174 self.operands.truncate(floor);
175 self.reachability = Reachability::Unreachable;
176 }
177}