1use stak_vm::{Error, Heap, Memory, PrimitiveSet, Type};
2use winter_maybe_async::maybe_async;
3
4pub enum ListPrimitive {
6 Assq,
8 Cons,
10 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#[derive(Debug, Default)]
22pub struct ListPrimitiveSet {}
23
24impl ListPrimitiveSet {
25 pub fn new() -> Self {
27 Self::default()
28 }
29}
30
31impl<H: Heap> PrimitiveSet<H> for ListPrimitiveSet {
32 type Error = Error;
33
34 #[maybe_async]
35 fn operate(&mut self, memory: &mut Memory<H>, 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}