1use crate::{
2 Effect, Memory, OperandStack,
3 script::{Operator, OperatorIndex, Script},
4};
5
6#[derive(Debug, Default)]
26pub struct Eval {
27 next_operator: OperatorIndex,
28 call_stack: Vec<OperatorIndex>,
29 effect: Option<(Effect, OperatorIndex)>,
30
31 pub operand_stack: OperandStack,
50
51 pub memory: Memory,
69}
70
71impl Eval {
72 pub fn new() -> Self {
77 Self::default()
78 }
79
80 pub fn call_stack(&self) -> impl Iterator<Item = OperatorIndex> {
89 self.call_stack.iter().copied().rev().map(|index| {
90 let Some(value) = index.value.checked_sub(1) else {
91 unreachable!(
92 "Operator indices on call stack identify the operator to \
93 return to after the call, which is the operator _after_ \
94 the calling operator. Hence, an operator before that one \
95 exists, and subtracting from the index of the call stack \
96 cannot overflow."
97 );
98 };
99
100 OperatorIndex { value }
101 })
102 }
103
104 pub fn run(&mut self, script: &Script) -> (Effect, OperatorIndex) {
115 loop {
116 if let Some(effect) = self.step(script) {
117 return effect;
118 }
119 }
120 }
121
122 pub fn step(&mut self, script: &Script) -> Option<(Effect, OperatorIndex)> {
135 let operator = self.next_operator;
136 self.next_operator.value += 1;
137
138 if self.effect.is_none()
139 && let Err(effect) = self.evaluate_operator(operator, script)
140 {
141 self.effect = Some((effect, operator));
142 }
143
144 self.effect
145 }
146
147 pub fn clear_effect(&mut self) -> Option<(Effect, OperatorIndex)> {
155 self.effect.take()
156 }
157
158 fn evaluate_operator(
159 &mut self,
160 operator: OperatorIndex,
161 script: &Script,
162 ) -> Result<(), Effect> {
163 let operator = script.get_operator(operator)?;
164
165 match operator {
166 Operator::Identifier { value: identifier } => {
167 if identifier == "*" {
168 let b = self.operand_stack.pop()?.to_i32();
169 let a = self.operand_stack.pop()?.to_i32();
170
171 self.operand_stack.push(a.wrapping_mul(b));
172 } else if identifier == "+" {
173 let b = self.operand_stack.pop()?.to_i32();
174 let a = self.operand_stack.pop()?.to_i32();
175
176 self.operand_stack.push(a.wrapping_add(b));
177 } else if identifier == "-" {
178 let b = self.operand_stack.pop()?.to_i32();
179 let a = self.operand_stack.pop()?.to_i32();
180
181 self.operand_stack.push(a.wrapping_sub(b));
182 } else if identifier == "/" {
183 let b = self.operand_stack.pop()?.to_i32();
184 let a = self.operand_stack.pop()?.to_i32();
185
186 if b == 0 {
187 return Err(Effect::DivisionByZero);
188 }
189 if a == i32::MIN && b == -1 {
190 return Err(Effect::IntegerOverflow);
191 }
192
193 self.operand_stack.push(a / b);
194 self.operand_stack.push(a % b);
195 } else if identifier == "<" {
196 let b = self.operand_stack.pop()?.to_i32();
197 let a = self.operand_stack.pop()?.to_i32();
198
199 self.operand_stack.push(a < b);
200 } else if identifier == "<=" {
201 let b = self.operand_stack.pop()?.to_i32();
202 let a = self.operand_stack.pop()?.to_i32();
203
204 self.operand_stack.push(a <= b);
205 } else if identifier == "=" {
206 let b = self.operand_stack.pop()?.to_i32();
207 let a = self.operand_stack.pop()?.to_i32();
208
209 self.operand_stack.push(a == b);
210 } else if identifier == ">" {
211 let b = self.operand_stack.pop()?.to_i32();
212 let a = self.operand_stack.pop()?.to_i32();
213
214 self.operand_stack.push(a > b);
215 } else if identifier == ">=" {
216 let b = self.operand_stack.pop()?.to_i32();
217 let a = self.operand_stack.pop()?.to_i32();
218
219 self.operand_stack.push(a >= b);
220 } else if identifier == "and" {
221 let b = self.operand_stack.pop()?.to_i32();
222 let a = self.operand_stack.pop()?.to_i32();
223
224 self.operand_stack.push(a & b);
225 } else if identifier == "or" {
226 let b = self.operand_stack.pop()?.to_i32();
227 let a = self.operand_stack.pop()?.to_i32();
228
229 self.operand_stack.push(a | b);
230 } else if identifier == "xor" {
231 let b = self.operand_stack.pop()?.to_i32();
232 let a = self.operand_stack.pop()?.to_i32();
233
234 self.operand_stack.push(a ^ b);
235 } else if identifier == "count_ones" {
236 let a = self.operand_stack.pop()?.to_i32();
237
238 self.operand_stack.push(a.count_ones());
239 } else if identifier == "leading_zeros" {
240 let a = self.operand_stack.pop()?.to_i32();
241
242 self.operand_stack.push(a.leading_zeros());
243 } else if identifier == "trailing_zeros" {
244 let a = self.operand_stack.pop()?.to_i32();
245
246 self.operand_stack.push(a.trailing_zeros());
247 } else if identifier == "rotate_left" {
248 let num_positions = self.operand_stack.pop()?.to_u32();
249 let a = self.operand_stack.pop()?.to_i32();
250
251 self.operand_stack.push(a.rotate_left(num_positions));
252 } else if identifier == "rotate_right" {
253 let num_positions = self.operand_stack.pop()?.to_u32();
254 let a = self.operand_stack.pop()?.to_i32();
255
256 self.operand_stack.push(a.rotate_right(num_positions));
257 } else if identifier == "shift_left" {
258 let num_positions = self.operand_stack.pop()?.to_i32();
259 let a = self.operand_stack.pop()?.to_i32();
260
261 self.operand_stack.push(a << num_positions);
262 } else if identifier == "shift_right" {
263 let num_positions = self.operand_stack.pop()?.to_i32();
264 let a = self.operand_stack.pop()?.to_i32();
265
266 self.operand_stack.push(a >> num_positions);
267 } else if identifier == "copy" {
268 let index_from_top = self.operand_stack.pop()?.to_u32();
269 let index_from_bottom = convert_operand_stack_index(
270 &self.operand_stack,
271 index_from_top,
272 )?;
273
274 let Some(value) = self
275 .operand_stack
276 .values
277 .get(index_from_bottom)
278 .copied()
279 else {
280 unreachable!(
281 "We computed the index from the top, based on the \
282 number of values on the stack. Since that did not \
283 result in an integer overflow, it's not possible \
284 that we ended up with an out-of-range index."
285 );
286 };
287
288 self.operand_stack.push(value);
289 } else if identifier == "drop" {
290 let index_from_top = self.operand_stack.pop()?.to_u32();
291 let index_from_bottom = convert_operand_stack_index(
292 &self.operand_stack,
293 index_from_top,
294 )?;
295
296 self.operand_stack.values.remove(index_from_bottom);
300 } else if identifier == "jump" {
301 let index = self.operand_stack.pop()?.to_u32();
302
303 self.next_operator.value = index;
304 } else if identifier == "jump_if" {
305 let index = self.operand_stack.pop()?.to_u32();
306 let condition = self.operand_stack.pop()?.to_bool();
307
308 if condition {
309 self.next_operator.value = index;
310 }
311 } else if identifier == "call" {
312 self.call_stack.push(self.next_operator);
313
314 let index = self.operand_stack.pop()?.to_u32();
315
316 self.next_operator.value = index;
317 } else if identifier == "call_either" {
318 self.call_stack.push(self.next_operator);
319
320 let else_ = self.operand_stack.pop()?.to_u32();
321 let then = self.operand_stack.pop()?.to_u32();
322 let condition = self.operand_stack.pop()?.to_bool();
323
324 self.next_operator = {
325 let value = if condition { then } else { else_ };
326 OperatorIndex { value }
327 };
328 } else if identifier == "return" {
329 let Some(index) = self.call_stack.pop() else {
330 return Err(Effect::Return);
331 };
332
333 self.next_operator = index;
334 } else if identifier == "assert" {
335 let condition = self.operand_stack.pop()?.to_bool();
336
337 if !condition {
338 return Err(Effect::AssertionFailed);
339 }
340 } else if identifier == "yield" {
341 return Err(Effect::Yield);
342 } else if identifier == "read" {
343 let address = self.operand_stack.pop()?.to_u32();
344
345 let value = self.memory.read(address)?;
346
347 self.operand_stack.push(value);
348 } else if identifier == "write" {
349 let value = self.operand_stack.pop()?;
350 let address = self.operand_stack.pop()?.to_u32();
351
352 self.memory.write(address, value)?;
353 } else {
354 return Err(Effect::UnknownIdentifier);
355 }
356 }
357 Operator::Integer { value } => {
358 self.operand_stack.push(*value);
359 }
360 Operator::Reference { name } => {
361 let operator = script.resolve_reference(name)?;
362 self.operand_stack.push(operator.value);
363 }
364 }
365
366 Ok(())
367 }
368}
369
370fn convert_operand_stack_index(
371 operand_stack: &OperandStack,
372 index_from_top: u32,
373) -> Result<usize, Effect> {
374 let Ok(index_from_top): Result<usize, _> = index_from_top.try_into() else {
375 return Err(Effect::InvalidOperandStackIndex);
379 };
380
381 let index_from_bottom = operand_stack
382 .values
383 .len()
384 .checked_sub(1)
385 .and_then(|index| index.checked_sub(index_from_top));
386
387 index_from_bottom.ok_or(Effect::InvalidOperandStackIndex)
388}