stak_native/
list.rs

1use stak_vm::{Error, Memory, PrimitiveSet, Type};
2use winter_maybe_async::maybe_async;
3
4/// A list primitive.
5pub enum ListPrimitive {
6    /// An `assq` procedure.
7    Assq,
8    /// A `cons` procedure.
9    Cons,
10    /// A `memq` procedure.
11    Memq,
12}
13
14impl ListPrimitive {
15    const ASSQ: usize = Self::Assq as _;
16    const CONS: usize = Self::Cons as _;
17    const MEMQ: usize = Self::Memq as _;
18}
19
20/// A list primitive set.
21#[derive(Debug, Default)]
22pub struct ListPrimitiveSet {}
23
24impl ListPrimitiveSet {
25    /// Creates a primitive set.
26    pub fn new() -> Self {
27        Self::default()
28    }
29}
30
31impl PrimitiveSet for ListPrimitiveSet {
32    type Error = Error;
33
34    #[maybe_async]
35    fn operate(&mut self, memory: &mut Memory<'_>, primitive: usize) -> Result<(), Self::Error> {
36        match primitive {
37            ListPrimitive::ASSQ => {
38                let [x, xs] = memory.pop_many();
39                let mut xs = xs.assume_cons();
40                let mut y = memory.boolean(false);
41
42                while xs != memory.null() {
43                    let cons = memory.car(xs).assume_cons();
44
45                    if x == memory.car(cons) {
46                        y = cons;
47                        break;
48                    }
49
50                    xs = memory.cdr(xs).assume_cons();
51                }
52
53                memory.push(y.into())?;
54            }
55            ListPrimitive::CONS => {
56                let [car, cdr] = memory.pop_many();
57
58                let rib = memory.allocate(car, cdr.set_tag(Type::Pair as _))?;
59                memory.push(rib.into())?;
60            }
61            ListPrimitive::MEMQ => {
62                let [x, xs] = memory.pop_many();
63                let mut xs = xs.assume_cons();
64                let mut y = memory.boolean(false);
65
66                while xs != memory.null() {
67                    if x == memory.car(xs) {
68                        y = xs;
69                        break;
70                    }
71
72                    xs = memory.cdr(xs).assume_cons();
73                }
74
75                memory.push(y.into())?;
76            }
77            _ => return Err(Error::IllegalPrimitive),
78        }
79
80        Ok(())
81    }
82}