uni_core/primitives/
null.rs1use crate::interpreter::Interpreter;
4use crate::value::{RuntimeError, Value};
5
6pub fn null_predicate_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
10 let value = interp.pop()?;
11 let is_null = interp.is_null(&value);
12 interp.push(Value::Boolean(is_null));
13 Ok(())
14}
15
16#[cfg(test)]
17mod tests {
18 use super::*;
19 use crate::value::Value;
20 use crate::compat::Rc;
21
22 fn setup_interpreter() -> Interpreter {
23 Interpreter::new()
24 }
25
26 #[test]
27 fn test_null_predicate_builtin() {
28 let mut interp = setup_interpreter();
29
30 interp.push(Value::Null);
32 null_predicate_builtin(&mut interp).unwrap();
33 let result = interp.pop().unwrap();
34 assert!(matches!(result, Value::Boolean(true)));
35
36 let test_cases = vec![
38 Value::Boolean(false),
39 Value::Boolean(true),
40 Value::Number(0.0),
41 Value::Number(42.0),
42 Value::String("".into()),
43 Value::String("hello".into()),
44 Value::Nil, Value::Atom(interp.intern_atom("test")),
46 Value::QuotedAtom(interp.intern_atom("quoted")),
47 Value::Pair(Rc::new(Value::Number(1.0)), Rc::new(Value::Nil)),
48 ];
49
50 for (i, test_value) in test_cases.into_iter().enumerate() {
51 interp.push(test_value.clone());
52 null_predicate_builtin(&mut interp).unwrap();
53 let result = interp.pop().unwrap();
54 assert!(
55 matches!(result, Value::Boolean(false)),
56 "Expected false for non-null value #{}: {:?}",
57 i,
58 test_value
59 );
60 }
61 }
62
63 #[test]
64 fn test_null_predicate_null_vs_nil_distinction() {
65 let mut interp = setup_interpreter();
66
67 interp.push(Value::Null);
69 null_predicate_builtin(&mut interp).unwrap();
70 let result = interp.pop().unwrap();
71 assert!(matches!(result, Value::Boolean(true)));
72
73 interp.push(Value::Nil);
75 null_predicate_builtin(&mut interp).unwrap();
76 let result = interp.pop().unwrap();
77 assert!(matches!(result, Value::Boolean(false)));
78
79 interp.push(Value::Boolean(false));
81 null_predicate_builtin(&mut interp).unwrap();
82 let result = interp.pop().unwrap();
83 assert!(matches!(result, Value::Boolean(false)));
84
85 interp.push(Value::Number(0.0));
87 null_predicate_builtin(&mut interp).unwrap();
88 let result = interp.pop().unwrap();
89 assert!(matches!(result, Value::Boolean(false)));
90
91 interp.push(Value::String("".into()));
93 null_predicate_builtin(&mut interp).unwrap();
94 let result = interp.pop().unwrap();
95 assert!(matches!(result, Value::Boolean(false)));
96 }
97
98 #[test]
99 fn test_null_predicate_edge_cases() {
100 let mut interp = setup_interpreter();
101
102 let edge_cases = vec![
104 Value::Number(-0.0), Value::Number(f64::NAN), Value::Number(f64::INFINITY), Value::String("null".into()), Value::String("false".into()), ];
110
111 for (i, test_value) in edge_cases.into_iter().enumerate() {
112 interp.push(test_value.clone());
113 null_predicate_builtin(&mut interp).unwrap();
114 let result = interp.pop().unwrap();
115 assert!(
116 matches!(result, Value::Boolean(false)),
117 "Expected false for edge case #{}: {:?}",
118 i,
119 test_value
120 );
121 }
122 }
123
124 #[test]
125 fn test_null_predicate_list_with_null() {
126 let mut interp = setup_interpreter();
127
128 let list_with_null = interp.make_list(vec![Value::Null, Value::Number(1.0)]);
130 interp.push(list_with_null);
131 null_predicate_builtin(&mut interp).unwrap();
132 let result = interp.pop().unwrap();
133 assert!(matches!(result, Value::Boolean(false)));
134
135 interp.push(Value::Nil);
137 null_predicate_builtin(&mut interp).unwrap();
138 let result = interp.pop().unwrap();
139 assert!(matches!(result, Value::Boolean(false)));
140 }
141
142 #[test]
143 fn test_null_predicate_atom_types() {
144 let mut interp = setup_interpreter();
145
146 let atom = interp.intern_atom("null");
148 interp.push(Value::Atom(atom));
149 null_predicate_builtin(&mut interp).unwrap();
150 let result = interp.pop().unwrap();
151 assert!(matches!(result, Value::Boolean(false)));
152
153 let quoted_atom = interp.intern_atom("null");
155 interp.push(Value::QuotedAtom(quoted_atom));
156 null_predicate_builtin(&mut interp).unwrap();
157 let result = interp.pop().unwrap();
158 assert!(matches!(result, Value::Boolean(false)));
159 }
160
161 #[test]
162 fn test_null_predicate_stack_underflow() {
163 let mut interp = setup_interpreter();
164
165 let result = null_predicate_builtin(&mut interp);
167 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
168 }
169
170 #[test]
171 fn test_null_predicate_multiple_calls() {
172 let mut interp = setup_interpreter();
173
174 interp.push(Value::Null);
176 interp.push(Value::Number(42.0));
177 interp.push(Value::Null);
178
179 null_predicate_builtin(&mut interp).unwrap();
181 let result = interp.pop().unwrap();
182 assert!(matches!(result, Value::Boolean(true)));
183
184 null_predicate_builtin(&mut interp).unwrap();
186 let result = interp.pop().unwrap();
187 assert!(matches!(result, Value::Boolean(false)));
188
189 null_predicate_builtin(&mut interp).unwrap();
191 let result = interp.pop().unwrap();
192 assert!(matches!(result, Value::Boolean(true)));
193 }
194}