uni_core/primitives/
abs.rs

1use 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}