Skip to main content

rl_lang/interpreter/stdlib/debug/
assert_approx_eq.rs

1use crate::{
2    interpreter::{evaluator::Evaluator, stdlib::debug::common::as_f64, values::Value},
3    utils::{errors::Error, span::Span},
4};
5
6pub fn func(eval: &mut Evaluator, args: Vec<Value>, span: Span) -> Result<Value, Error> {
7    // third spot IS NOT MESSAGE it is epsilon
8    if args.len() < 2 || args.len() > 3 {
9        return Err(eval.err(
10            format!(
11                "assert_approx_eq: expects 2 or 3 arguments, got {}",
12                args.len()
13            ),
14            span,
15        ));
16    }
17
18    let (a, b) = (&args[0], &args[1]);
19    let (fa, fb) = match (as_f64(a), as_f64(b)) {
20        (Some(fa), Some(fb)) => (fa, fb),
21        _ => {
22            return Err(eval.err(
23                format!(
24                    "assert_approx_eq: expects numeric arguments, got {} and {}",
25                    a.type_name(),
26                    b.type_name()
27                ),
28                span,
29            ));
30        }
31    };
32
33    let epsilon = match args.get(2) {
34        Some(v) => as_f64(v).ok_or_else(|| {
35            eval.err(
36                format!(
37                    "assert_approx_eq: expects a numeric epsilon, got {}",
38                    v.type_name()
39                ),
40                span,
41            )
42        })?,
43        None => 1e-9,
44    };
45
46    if (fa - fb).abs() > epsilon {
47        return Err(eval.err(
48            format!(
49                "assert_approx_eq failed: `{}` and `{}` differ by more than {}",
50                a, b, epsilon
51            ),
52            span,
53        ));
54    }
55
56    Ok(Value::Null)
57}