1use crate::interpreter::Interpreter;
4use crate::value::{RuntimeError, Value};
5use crate::compat::Rc;
6
7pub fn eq_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
10 let b = interp.pop()?;
11 let a = interp.pop()?;
12
13 let result = match (&a, &b) {
14 (Value::Int32(i1), Value::Int32(i2)) => i1 == i2,
16 (Value::Number(n1), Value::Number(n2)) => n1 == n2,
17 (Value::Integer(i1), Value::Integer(i2)) => i1 == i2,
18 (Value::Rational(r1), Value::Rational(r2)) => r1 == r2,
19 #[cfg(feature = "complex_numbers")]
20 (Value::GaussianInt(re1, im1), Value::GaussianInt(re2, im2)) => re1 == re2 && im1 == im2,
21 #[cfg(feature = "complex_numbers")]
22 (Value::Complex(c1), Value::Complex(c2)) => c1 == c2,
23
24 (Value::String(s1), Value::String(s2)) => s1 == s2,
26 (Value::Atom(a1), Value::Atom(a2)) => a1 == a2,
27 (Value::QuotedAtom(a1), Value::QuotedAtom(a2)) => a1 == a2,
28 (Value::Boolean(b1), Value::Boolean(b2)) => b1 == b2,
29 (Value::Null, Value::Null) => true,
30 (Value::Nil, Value::Nil) => true,
31 (Value::Pair(car1, cdr1), Value::Pair(car2, cdr2)) => {
33 eq_values(car1, car2) && eq_values(cdr1, cdr2)
35 }
36 (Value::I16Buffer(buf1), Value::I16Buffer(buf2)) => Rc::ptr_eq(buf1, buf2),
38 _ => false,
40 };
41
42 interp.push(Value::Boolean(result));
43 Ok(())
44}
45
46fn eq_values(a: &Rc<Value>, b: &Rc<Value>) -> bool {
49 match (a.as_ref(), b.as_ref()) {
50 (Value::Int32(i1), Value::Int32(i2)) => i1 == i2,
52 (Value::Number(n1), Value::Number(n2)) => n1 == n2,
53 (Value::Integer(i1), Value::Integer(i2)) => i1 == i2,
54 (Value::Rational(r1), Value::Rational(r2)) => r1 == r2,
55 #[cfg(feature = "complex_numbers")]
56 (Value::GaussianInt(re1, im1), Value::GaussianInt(re2, im2)) => re1 == re2 && im1 == im2,
57 #[cfg(feature = "complex_numbers")]
58 (Value::Complex(c1), Value::Complex(c2)) => c1 == c2,
59
60 (Value::String(s1), Value::String(s2)) => s1 == s2,
62 (Value::Atom(a1), Value::Atom(a2)) => a1 == a2,
63 (Value::QuotedAtom(a1), Value::QuotedAtom(a2)) => a1 == a2,
64 (Value::Boolean(b1), Value::Boolean(b2)) => b1 == b2,
65 (Value::Null, Value::Null) => true,
66 (Value::Nil, Value::Nil) => true,
67 (Value::Pair(car1, cdr1), Value::Pair(car2, cdr2)) => {
68 eq_values(car1, car2) && eq_values(cdr1, cdr2)
69 }
70 (Value::I16Buffer(buf1), Value::I16Buffer(buf2)) => Rc::ptr_eq(buf1, buf2),
72 _ => false,
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::value::Value;
80
81 fn setup_interpreter() -> Interpreter {
82 Interpreter::new()
83 }
84
85 #[test]
86 fn test_eq_builtin_numbers() {
87 let mut interp = setup_interpreter();
88
89 interp.push(Value::Number(42.0));
91 interp.push(Value::Number(42.0));
92 eq_builtin(&mut interp).unwrap();
93 let result = interp.pop().unwrap();
94 assert!(matches!(result, Value::Boolean(true)));
95
96 interp.push(Value::Number(3.0));
98 interp.push(Value::Number(5.0));
99 eq_builtin(&mut interp).unwrap();
100 let result = interp.pop().unwrap();
101 assert!(matches!(result, Value::Boolean(false)));
102 }
103
104 #[test]
105 fn test_eq_builtin_strings() {
106 let mut interp = setup_interpreter();
107
108 interp.push(Value::String("hello".into()));
110 interp.push(Value::String("hello".into()));
111 eq_builtin(&mut interp).unwrap();
112 let result = interp.pop().unwrap();
113 assert!(matches!(result, Value::Boolean(true)));
114
115 interp.push(Value::String("hello".into()));
117 interp.push(Value::String("world".into()));
118 eq_builtin(&mut interp).unwrap();
119 let result = interp.pop().unwrap();
120 assert!(matches!(result, Value::Boolean(false)));
121 }
122
123 #[test]
124 fn test_eq_builtin_booleans() {
125 let mut interp = setup_interpreter();
126
127 interp.push(Value::Boolean(true));
129 interp.push(Value::Boolean(true));
130 eq_builtin(&mut interp).unwrap();
131 let result = interp.pop().unwrap();
132 assert!(matches!(result, Value::Boolean(true)));
133
134 interp.push(Value::Boolean(true));
136 interp.push(Value::Boolean(false));
137 eq_builtin(&mut interp).unwrap();
138 let result = interp.pop().unwrap();
139 assert!(matches!(result, Value::Boolean(false)));
140 }
141
142 #[test]
143 fn test_eq_builtin_null() {
144 let mut interp = setup_interpreter();
145
146 interp.push(Value::Null);
148 interp.push(Value::Null);
149 eq_builtin(&mut interp).unwrap();
150 let result = interp.pop().unwrap();
151 assert!(matches!(result, Value::Boolean(true)));
152
153 interp.push(Value::Null);
155 interp.push(Value::Boolean(false));
156 eq_builtin(&mut interp).unwrap();
157 let result = interp.pop().unwrap();
158 assert!(matches!(result, Value::Boolean(false)));
159 }
160
161 #[test]
162 fn test_eq_builtin_different_types() {
163 let mut interp = setup_interpreter();
164
165 interp.push(Value::Number(42.0));
167 interp.push(Value::String("42".into()));
168 eq_builtin(&mut interp).unwrap();
169 let result = interp.pop().unwrap();
170 assert!(matches!(result, Value::Boolean(false)));
171
172 interp.push(Value::Boolean(true));
174 interp.push(Value::Number(1.0));
175 eq_builtin(&mut interp).unwrap();
176 let result = interp.pop().unwrap();
177 assert!(matches!(result, Value::Boolean(false)));
178 }
179
180 #[test]
181 fn test_eq_builtin_lists() {
182 let mut interp = setup_interpreter();
183
184 let list1 = interp.make_list(vec![Value::Number(1.0), Value::Number(2.0)]);
186 let list2 = interp.make_list(vec![Value::Number(1.0), Value::Number(2.0)]);
187
188 interp.push(list1);
189 interp.push(list2);
190 eq_builtin(&mut interp).unwrap();
191 let result = interp.pop().unwrap();
192 assert!(matches!(result, Value::Boolean(true)));
193
194 let list3 = interp.make_list(vec![Value::Number(1.0), Value::Number(2.0)]);
196 let list4 = interp.make_list(vec![Value::Number(1.0), Value::Number(3.0)]);
197
198 interp.push(list3);
199 interp.push(list4);
200 eq_builtin(&mut interp).unwrap();
201 let result = interp.pop().unwrap();
202 assert!(matches!(result, Value::Boolean(false)));
203 }
204
205 #[test]
206 fn test_eq_builtin_stack_underflow() {
207 let mut interp = setup_interpreter();
208
209 let result = eq_builtin(&mut interp);
211 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
212
213 interp.push(Value::Number(5.0));
215 let result = eq_builtin(&mut interp);
216 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
217 }
218
219 #[test]
220 fn test_eq_builtin_edge_cases_boolean_null() {
221 let mut interp = setup_interpreter();
222
223 interp.push(Value::Null);
225 interp.push(Value::Boolean(false));
226 eq_builtin(&mut interp).unwrap();
227 let result = interp.pop().unwrap();
228 assert!(matches!(result, Value::Boolean(false)));
229
230 interp.push(Value::Null);
232 interp.push(Value::Number(0.0));
233 eq_builtin(&mut interp).unwrap();
234 let result = interp.pop().unwrap();
235 assert!(matches!(result, Value::Boolean(false)));
236
237 interp.push(Value::Boolean(true));
239 interp.push(Value::Number(1.0));
240 eq_builtin(&mut interp).unwrap();
241 let result = interp.pop().unwrap();
242 assert!(matches!(result, Value::Boolean(false)));
243 }
244}