uni_core/primitives/
abs.rs1use crate::compat::format;
2use crate::interpreter::Interpreter;
3use crate::value::{RuntimeError, Value};
4use num_traits::Signed;
5
6pub fn abs_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
7 let val = interp.pop()?;
8
9 let result = match val {
10 Value::Int32(i) => Value::Int32(i.abs()),
11 Value::Integer(i) => Value::Integer(i.abs()),
12 Value::Rational(r) => Value::Rational(r.abs()),
13 Value::Number(n) => Value::Number(n.abs()),
14 _ => {
15 return Err(RuntimeError::TypeError(format!(
16 "abs requires a number, got {}",
17 val.type_name()
18 )));
19 }
20 };
21
22 interp.push(result);
23 Ok(())
24}
25
26#[cfg(test)]
27mod tests {
28 use super::*;
29 use crate::value::Value;
30 use num_bigint::BigInt;
31 use num_rational::BigRational;
32
33 fn setup_interpreter() -> Interpreter {
34 Interpreter::new()
35 }
36
37 #[test]
38 fn test_abs_int32_positive() {
39 let mut interp = setup_interpreter();
40 interp.push(Value::Int32(5));
41
42 abs_builtin(&mut interp).unwrap();
43
44 let result = interp.pop().unwrap();
45 assert!(matches!(result, Value::Int32(5)));
46 }
47
48 #[test]
49 fn test_abs_int32_negative() {
50 let mut interp = setup_interpreter();
51 interp.push(Value::Int32(-5));
52
53 abs_builtin(&mut interp).unwrap();
54
55 let result = interp.pop().unwrap();
56 assert!(matches!(result, Value::Int32(5)));
57 }
58
59 #[test]
60 fn test_abs_int32_zero() {
61 let mut interp = setup_interpreter();
62 interp.push(Value::Int32(0));
63
64 abs_builtin(&mut interp).unwrap();
65
66 let result = interp.pop().unwrap();
67 assert!(matches!(result, Value::Int32(0)));
68 }
69
70 #[test]
71 fn test_abs_integer_positive() {
72 let mut interp = setup_interpreter();
73 interp.push(Value::Integer(BigInt::from(42)));
74
75 abs_builtin(&mut interp).unwrap();
76
77 let result = interp.pop().unwrap();
78 assert!(matches!(result, Value::Integer(ref i) if i == &BigInt::from(42)));
79 }
80
81 #[test]
82 fn test_abs_integer_negative() {
83 let mut interp = setup_interpreter();
84 interp.push(Value::Integer(BigInt::from(-42)));
85
86 abs_builtin(&mut interp).unwrap();
87
88 let result = interp.pop().unwrap();
89 assert!(matches!(result, Value::Integer(ref i) if i == &BigInt::from(42)));
90 }
91
92 #[test]
93 fn test_abs_rational_positive() {
94 let mut interp = setup_interpreter();
95 interp.push(Value::Rational(BigRational::new(
96 BigInt::from(3),
97 BigInt::from(4),
98 )));
99
100 abs_builtin(&mut interp).unwrap();
101
102 let result = interp.pop().unwrap();
103 assert!(matches!(result, Value::Rational(ref r) if r == &BigRational::new(BigInt::from(3), BigInt::from(4))));
104 }
105
106 #[test]
107 fn test_abs_rational_negative() {
108 let mut interp = setup_interpreter();
109 interp.push(Value::Rational(BigRational::new(
110 BigInt::from(-3),
111 BigInt::from(4),
112 )));
113
114 abs_builtin(&mut interp).unwrap();
115
116 let result = interp.pop().unwrap();
117 assert!(matches!(result, Value::Rational(ref r) if r == &BigRational::new(BigInt::from(3), BigInt::from(4))));
118 }
119
120 #[test]
121 fn test_abs_number_positive() {
122 let mut interp = setup_interpreter();
123 interp.push(Value::Number(5.0));
124
125 abs_builtin(&mut interp).unwrap();
126
127 let result = interp.pop().unwrap();
128 assert!(matches!(result, Value::Number(n) if n == 5.0));
129 }
130
131 #[test]
132 fn test_abs_number_negative() {
133 let mut interp = setup_interpreter();
134 interp.push(Value::Number(-5.0));
135
136 abs_builtin(&mut interp).unwrap();
137
138 let result = interp.pop().unwrap();
139 assert!(matches!(result, Value::Number(n) if n == 5.0));
140 }
141
142 #[test]
143 fn test_abs_number_zero() {
144 let mut interp = setup_interpreter();
145 interp.push(Value::Number(0.0));
146
147 abs_builtin(&mut interp).unwrap();
148
149 let result = interp.pop().unwrap();
150 assert!(matches!(result, Value::Number(n) if n == 0.0));
151 }
152
153 #[test]
154 fn test_abs_number_decimal() {
155 let mut interp = setup_interpreter();
156 interp.push(Value::Number(-3.14));
157
158 abs_builtin(&mut interp).unwrap();
159
160 let result = interp.pop().unwrap();
161 assert!(matches!(result, Value::Number(n) if (n - 3.14).abs() < f64::EPSILON));
162 }
163
164 #[test]
165 fn test_abs_stack_underflow() {
166 let mut interp = setup_interpreter();
167
168 let result = abs_builtin(&mut interp);
169 assert!(matches!(result, Err(RuntimeError::StackUnderflow)));
170 }
171
172 #[test]
173 fn test_abs_type_error() {
174 let mut interp = setup_interpreter();
175 interp.push(Value::String("hello".into()));
176
177 let result = abs_builtin(&mut interp);
178 assert!(matches!(result, Err(RuntimeError::TypeError(_))));
179 }
180}