1use crate::{
4 asm::Word,
5 error::{LenWordsError, StackError},
6 StackResult,
7};
8use essential_types::convert::bool_from_word;
9
10#[cfg(test)]
11mod frame_tests;
12
13#[derive(Clone, Debug, PartialEq, Default)]
18pub struct Stack(Vec<Word>);
19
20impl Stack {
21 pub const SIZE_LIMIT: usize = 4096;
23
24 pub fn push(&mut self, word: Word) -> StackResult<()> {
28 if self.len() >= Self::SIZE_LIMIT {
29 return Err(StackError::Overflow);
30 }
31 self.0.push(word);
32 Ok(())
33 }
34
35 pub fn extend(&mut self, words: impl IntoIterator<Item = Word>) -> StackResult<()> {
39 for word in words {
40 self.push(word)?;
41 }
42 Ok(())
43 }
44
45 pub(crate) fn reserve_zeroed(&mut self) -> StackResult<()> {
47 let len = self.pop()?;
48 let len = usize::try_from(len).map_err(|_| StackError::IndexOutOfBounds)?;
49 let new_len = self.len().saturating_add(len);
50 if new_len > Self::SIZE_LIMIT {
51 return Err(StackError::IndexOutOfBounds);
52 }
53 self.0.resize(new_len, 0);
54 Ok(())
55 }
56
57 pub(crate) fn load(&mut self) -> StackResult<()> {
59 let ix = self.pop()?;
60 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
61 let word = self
62 .0
63 .get(ix)
64 .copied()
65 .ok_or(StackError::IndexOutOfBounds)?;
66 self.push(word)
67 }
68
69 pub(crate) fn store(&mut self) -> StackResult<()> {
71 let [ix, word] = self.pop2()?;
72 let ix = usize::try_from(ix).map_err(|_| StackError::IndexOutOfBounds)?;
73 let Some(w) = self.0.get_mut(ix) else {
74 return Err(StackError::IndexOutOfBounds);
75 };
76 *w = word;
77 Ok(())
78 }
79
80 pub(crate) fn dup_from(&mut self) -> StackResult<()> {
82 let rev_ix_w = self.pop()?;
83 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
84 let ix = self
85 .len()
86 .checked_sub(rev_ix)
87 .and_then(|i| i.checked_sub(1))
88 .ok_or(StackError::IndexOutOfBounds)?;
89 let w = *self.get(ix).ok_or(StackError::IndexOutOfBounds)?;
90 self.push(w)?;
91 Ok(())
92 }
93
94 pub(crate) fn swap_index(&mut self) -> StackResult<()> {
96 let rev_ix_w = self.pop()?;
97 let top_ix = self
98 .len()
99 .checked_sub(1)
100 .ok_or(StackError::IndexOutOfBounds)?;
101 let rev_ix = usize::try_from(rev_ix_w).map_err(|_| StackError::IndexOutOfBounds)?;
102 let ix = top_ix
103 .checked_sub(rev_ix)
104 .ok_or(StackError::IndexOutOfBounds)?;
105 self.0.swap(ix, top_ix);
106 Ok(())
107 }
108
109 pub(crate) fn select(&mut self) -> StackResult<()> {
111 self.pop().and_then(|cond_w| {
112 self.pop2_push1(|w0, w1| {
113 Ok(
114 if bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))? {
115 w1
116 } else {
117 w0
118 },
119 )
120 })
121 })?;
122 Ok(())
123 }
124
125 pub(crate) fn select_range(&mut self) -> StackResult<()> {
127 let cond_w = self.pop()?;
128 let cond = bool_from_word(cond_w).ok_or(StackError::InvalidCondition(cond_w))?;
129 let len = self.pop_len()?;
130 if len == 0 {
131 return Ok(());
132 }
133 self.len()
135 .checked_sub(len.checked_mul(2).ok_or(StackError::IndexOutOfBounds)?)
136 .ok_or(StackError::IndexOutOfBounds)?;
137 let arr_b_index = self.len() - len;
139 if cond {
140 let arr_a_index = arr_b_index - len;
142 self.0
143 .copy_within(arr_b_index..(arr_b_index + len), arr_a_index);
144 }
145 self.0.truncate(arr_b_index);
147 Ok(())
148 }
149
150 pub fn pop(&mut self) -> StackResult<Word> {
152 self.0.pop().ok_or(StackError::Empty)
153 }
154
155 pub fn pop2(&mut self) -> StackResult<[Word; 2]> {
159 let w1 = self.pop()?;
160 let w0 = self.pop()?;
161 Ok([w0, w1])
162 }
163
164 pub fn pop3(&mut self) -> StackResult<[Word; 3]> {
168 let w2 = self.pop()?;
169 let [w0, w1] = self.pop2()?;
170 Ok([w0, w1, w2])
171 }
172
173 pub fn pop4(&mut self) -> StackResult<[Word; 4]> {
177 let w3 = self.pop()?;
178 let [w0, w1, w2] = self.pop3()?;
179 Ok([w0, w1, w2, w3])
180 }
181
182 pub fn pop8(&mut self) -> StackResult<[Word; 8]> {
186 let [w4, w5, w6, w7] = self.pop4()?;
187 let [w0, w1, w2, w3] = self.pop4()?;
188 Ok([w0, w1, w2, w3, w4, w5, w6, w7])
189 }
190
191 pub fn pop1_push1<F, E>(&mut self, f: F) -> Result<(), E>
193 where
194 F: FnOnce(Word) -> Result<Word, E>,
195 E: From<StackError>,
196 {
197 let w = self.pop()?;
198 let x = f(w)?;
199 self.push(x)?;
200 Ok(())
201 }
202
203 pub fn pop2_push1<F, E>(&mut self, f: F) -> Result<(), E>
205 where
206 F: FnOnce(Word, Word) -> Result<Word, E>,
207 E: From<StackError>,
208 {
209 let [w0, w1] = self.pop2()?;
210 let x = f(w0, w1)?;
211 self.push(x)?;
212 Ok(())
213 }
214
215 pub fn pop8_push1<F, E>(&mut self, f: F) -> Result<(), E>
217 where
218 F: FnOnce([Word; 8]) -> Result<Word, E>,
219 E: From<StackError>,
220 {
221 let ws = self.pop8()?;
222 let x = f(ws)?;
223 self.push(x)?;
224 Ok(())
225 }
226
227 pub fn pop1_push2<F, E>(&mut self, f: F) -> Result<(), E>
229 where
230 F: FnOnce(Word) -> Result<[Word; 2], E>,
231 E: From<StackError>,
232 {
233 let w = self.pop()?;
234 let xs = f(w)?;
235 self.extend(xs)?;
236 Ok(())
237 }
238
239 pub fn pop2_push2<F, E>(&mut self, f: F) -> Result<(), E>
241 where
242 F: FnOnce(Word, Word) -> Result<[Word; 2], E>,
243 E: From<StackError>,
244 {
245 let [w0, w1] = self.pop2()?;
246 let xs = f(w0, w1)?;
247 self.extend(xs)?;
248 Ok(())
249 }
250
251 pub fn pop2_push4<F, E>(&mut self, f: F) -> Result<(), E>
253 where
254 F: FnOnce(Word, Word) -> Result<[Word; 4], E>,
255 E: From<StackError>,
256 {
257 let [w0, w1] = self.pop2()?;
258 let xs = f(w0, w1)?;
259 self.extend(xs)?;
260 Ok(())
261 }
262
263 pub fn pop_len(&mut self) -> StackResult<usize> {
265 let len_word = self.pop()?;
266 let len = usize::try_from(len_word).map_err(|_| StackError::IndexOutOfBounds)?;
267 Ok(len)
268 }
269
270 pub fn pop_len_words<F, O, E>(&mut self, f: F) -> Result<O, E>
273 where
274 F: FnOnce(&[Word]) -> Result<O, E>,
275 E: From<StackError>,
276 {
277 let (rest, slice) = slice_split_len_words(self).map_err(StackError::LenWords)?;
278 let out = f(slice)?;
279 self.0.truncate(rest.len());
280 Ok(out)
281 }
282
283 pub fn pop_words<F, O, E>(&mut self, num_words: usize, f: F) -> Result<O, E>
286 where
287 F: FnOnce(&[Word]) -> Result<O, E>,
288 E: From<StackError>,
289 {
290 let (rest, slice) = slice_split_len(self, num_words).map_err(StackError::LenWords)?;
291 let out = f(slice)?;
292 self.0.truncate(rest.len());
293 Ok(out)
294 }
295
296 pub fn pop_len_words2<F, O, E>(&mut self, f: F) -> Result<O, E>
300 where
301 F: FnOnce(&[Word], &[Word]) -> Result<O, E>,
302 E: From<StackError>,
303 {
304 let (rest, rhs) = slice_split_len_words(self).map_err(StackError::LenWords)?;
305 let (rest, lhs) = slice_split_len_words(rest).map_err(StackError::LenWords)?;
306 let out = f(lhs, rhs)?;
307 self.0.truncate(rest.len());
308 Ok(out)
309 }
310
311 pub fn reserve(&mut self, additional: usize) {
314 self.0.reserve(additional);
315 }
316}
317
318fn slice_split_len_words(slice: &[Word]) -> Result<(&[Word], &[Word]), LenWordsError> {
326 let (len, rest) = slice.split_last().ok_or(LenWordsError::MissingLength)?;
327 let len = usize::try_from(*len).map_err(|_| LenWordsError::InvalidLength(*len))?;
328 slice_split_len(rest, len)
329}
330
331fn slice_split_len(slice: &[Word], len: usize) -> Result<(&[Word], &[Word]), LenWordsError> {
332 let ix = slice
333 .len()
334 .checked_sub(len)
335 .ok_or(LenWordsError::OutOfBounds(len as Word))?;
336 Ok(slice.split_at(ix))
337}
338
339impl From<Stack> for Vec<Word> {
340 fn from(stack: Stack) -> Self {
341 stack.0
342 }
343}
344
345impl From<Vec<Word>> for Stack {
346 fn from(vec: Vec<Word>) -> Self {
347 Self(vec)
348 }
349}
350
351impl core::ops::Deref for Stack {
352 type Target = Vec<Word>;
353 fn deref(&self) -> &Self::Target {
354 &self.0
355 }
356}
357
358#[cfg(test)]
359mod tests {
360 use crate::{
361 asm::Stack,
362 error::{ConstraintError, OpError, StackError},
363 eval_ops, exec_ops,
364 test_util::*,
365 };
366
367 #[test]
368 fn dup_from_1() {
369 let ops = &[
370 Stack::Push(42).into(),
371 Stack::Push(2).into(),
372 Stack::Push(1).into(),
373 Stack::Push(0).into(),
374 Stack::Push(3).into(), Stack::DupFrom.into(),
376 ];
377 let stack = exec_ops(ops, *test_access()).unwrap();
378 assert_eq!(&stack[..], &[42, 2, 1, 0, 42]);
379 }
380
381 #[test]
382 fn dup_from_2() {
383 let ops = &[
384 Stack::Push(3).into(),
385 Stack::Push(2).into(),
386 Stack::Push(1).into(),
387 Stack::Push(42).into(),
388 Stack::Push(0).into(), Stack::DupFrom.into(),
390 ];
391 let stack = exec_ops(ops, *test_access()).unwrap();
392 assert_eq!(&stack[..], &[3, 2, 1, 42, 42]);
393 }
394
395 #[test]
396 fn push1() {
397 let ops = &[Stack::Push(42).into()];
398 let stack = exec_ops(ops, *test_access()).unwrap();
399 assert_eq!(&stack[..], &[42]);
400 }
401
402 #[test]
403 fn push2_pop_push() {
404 let ops = &[
405 Stack::Push(1).into(),
406 Stack::Push(2).into(),
407 Stack::Pop.into(),
408 Stack::Push(3).into(),
409 ];
410 let stack = exec_ops(ops, *test_access()).unwrap();
411 assert_eq!(&stack[..], &[1, 3]);
412 }
413
414 #[test]
415 fn pop_empty() {
416 let ops = &[Stack::Pop.into()];
417 match eval_ops(ops, *test_access()) {
418 Err(ConstraintError::Op(0, OpError::Stack(StackError::Empty))) => (),
419 _ => panic!("expected empty stack error"),
420 }
421 }
422
423 #[test]
424 fn index_oob() {
425 let ops = &[Stack::Push(0).into(), Stack::DupFrom.into()];
426 match eval_ops(ops, *test_access()) {
427 Err(ConstraintError::Op(1, OpError::Stack(StackError::IndexOutOfBounds))) => (),
428 _ => panic!("expected index out-of-bounds stack error"),
429 }
430 }
431
432 #[test]
433 fn swap_index() {
434 let ops = &[
435 Stack::Push(3).into(),
436 Stack::Push(4).into(),
437 Stack::Push(5).into(),
438 Stack::Push(42).into(),
439 Stack::Push(2).into(), Stack::SwapIndex.into(),
441 ];
442 let stack = exec_ops(ops, *test_access()).unwrap();
443 assert_eq!(&stack[..], &[3, 42, 5, 4]);
444 }
445
446 #[test]
447 fn swap_index_oob() {
448 let ops = &[
449 Stack::Push(3).into(),
450 Stack::Push(4).into(),
451 Stack::Push(2).into(), Stack::SwapIndex.into(),
453 ];
454 match eval_ops(ops, *test_access()) {
455 Err(ConstraintError::Op(3, OpError::Stack(StackError::IndexOutOfBounds))) => (),
456 _ => panic!("expected index out-of-bounds stack error"),
457 }
458 }
459
460 #[test]
461 fn select() {
462 let ops = &[
463 Stack::Push(3).into(),
464 Stack::Push(4).into(),
465 Stack::Push(1).into(),
466 Stack::Select.into(),
467 ];
468 let stack = exec_ops(ops, *test_access()).unwrap();
469 assert_eq!(&stack[..], &[4]);
470 }
471
472 #[test]
473 fn select_range_cond_1() {
474 let ops = &[
475 Stack::Push(4).into(),
476 Stack::Push(4).into(),
477 Stack::Push(4).into(),
478 Stack::Push(5).into(),
479 Stack::Push(5).into(),
480 Stack::Push(5).into(),
481 Stack::Push(3).into(), Stack::Push(1).into(), Stack::SelectRange.into(),
484 ];
485 let stack = exec_ops(ops, *test_access()).unwrap();
486 assert_eq!(&stack[..], &[5, 5, 5]);
487 }
488
489 #[test]
490 fn select_range_cond_0() {
491 let ops = &[
492 Stack::Push(4).into(),
493 Stack::Push(4).into(),
494 Stack::Push(4).into(),
495 Stack::Push(5).into(),
496 Stack::Push(5).into(),
497 Stack::Push(5).into(),
498 Stack::Push(3).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
501 ];
502 let stack = exec_ops(ops, *test_access()).unwrap();
503 assert_eq!(&stack[..], &[4, 4, 4]);
504 }
505
506 #[test]
507 fn select_range_cond_invalid() {
508 let ops = &[
509 Stack::Push(4).into(),
510 Stack::Push(5).into(),
511 Stack::Push(1).into(), Stack::Push(42).into(), Stack::SelectRange.into(),
514 ];
515 match eval_ops(ops, *test_access()) {
516 Err(ConstraintError::Op(4, OpError::Stack(StackError::InvalidCondition(42)))) => (),
517 _ => panic!("expected invalid condition stack error"),
518 }
519 }
520
521 #[test]
522 fn select_range_len_0() {
523 let ops = &[
524 Stack::Push(4).into(),
525 Stack::Push(5).into(),
526 Stack::Push(0).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
529 ];
530 let stack = exec_ops(ops, *test_access()).unwrap();
531 assert_eq!(&stack[..], &[4, 5]);
532 }
533
534 #[test]
535 fn select_range_len_negative() {
536 let ops = &[
537 Stack::Push(-42).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
540 ];
541 match eval_ops(ops, *test_access()) {
542 Err(ConstraintError::Op(2, OpError::Stack(StackError::IndexOutOfBounds))) => (),
543 _ => panic!("expected index out of bounds stack error"),
544 }
545 }
546
547 #[test]
548 fn select_range_len_too_big() {
549 let ops = &[
550 Stack::Push(4).into(),
551 Stack::Push(4).into(),
552 Stack::Push(5).into(),
553 Stack::Push(2).into(), Stack::Push(0).into(), Stack::SelectRange.into(),
556 ];
557 match eval_ops(ops, *test_access()) {
558 Err(ConstraintError::Op(5, OpError::Stack(StackError::IndexOutOfBounds))) => (),
559 _ => panic!("expected index out of bounds stack error"),
560 }
561 }
562}