stak_native/
equal.rs

1use stak_vm::{Error, Memory, PrimitiveSet, Type};
2
3/// An equality primitive.
4pub enum EqualPrimitive {
5    /// An `eqv` procedure.
6    Eqv,
7    /// A primitive to check equality of rib inners.
8    EqualInner,
9}
10
11impl EqualPrimitive {
12    const EQV: usize = Self::Eqv as _;
13    const EQUAL_INNER: usize = Self::EqualInner as _;
14}
15
16/// An equality primitive set.
17#[derive(Debug, Default)]
18pub struct EqualPrimitiveSet {}
19
20impl EqualPrimitiveSet {
21    /// Creates a primitive set.
22    pub fn new() -> Self {
23        Self::default()
24    }
25}
26
27impl PrimitiveSet for EqualPrimitiveSet {
28    type Error = Error;
29
30    fn operate(&mut self, memory: &mut Memory, primitive: usize) -> Result<(), Self::Error> {
31        match primitive {
32            EqualPrimitive::EQV => {
33                let [x, y] = memory.pop_many();
34
35                memory.push(
36                    memory
37                        .boolean(
38                            x == y
39                                || if let (Some(x), Some(y)) = (x.to_cons(), y.to_cons()) {
40                                    memory.cdr(x).tag() == Type::Character as _
41                                        && memory.cdr(y).tag() == Type::Character as _
42                                        && memory.car(x) == memory.car(y)
43                                } else {
44                                    false
45                                },
46                        )
47                        .into(),
48                )?;
49            }
50            EqualPrimitive::EQUAL_INNER => {
51                let [x, y] = memory.pop_many();
52
53                memory.push(
54                    memory
55                        .boolean(if let (Some(x), Some(y)) = (x.to_cons(), y.to_cons()) {
56                            // - Optimize checks for unique values.
57                            // - Optimize checks for strings and vectors where `car`s are integers.
58                            memory.cdr(x).tag() == memory.cdr(y).tag()
59                                && ![Type::Boolean as _, Type::Null as _, Type::Symbol as _]
60                                    .contains(&memory.cdr(x).tag())
61                                && (memory.car(x).is_cons() || memory.car(x) == memory.car(y))
62                        } else {
63                            false
64                        })
65                        .into(),
66                )?;
67            }
68
69            _ => return Err(Error::IllegalPrimitive),
70        }
71
72        Ok(())
73    }
74}