arithmetic_eval/fns/
std.rs

1//! Functions that require the Rust standard library.
2
3use std::fmt;
4
5use crate::{CallContext, EvalResult, ModuleId, NativeFn, SpannedValue, Value};
6use arithmetic_parser::CodeFragment;
7
8/// Acts similarly to the `dbg!` macro, outputting the argument(s) to stderr and returning
9/// them. If a single argument is provided, it's returned as-is; otherwise, the arguments
10/// are wrapped into a tuple.
11///
12/// # Examples
13///
14/// ```
15/// # use arithmetic_parser::grammars::{F32Grammar, Parse, Untyped};
16/// # use arithmetic_eval::{fns, Environment, Value, VariableMap};
17/// # fn main() -> anyhow::Result<()> {
18/// let program = "dbg(1 + 2) > 2.5";
19/// let program = Untyped::<F32Grammar>::parse_statements(program)?;
20/// let module = Environment::new()
21///     .insert_native_fn("dbg", fns::Dbg)
22///     .compile_module("test_assert", &program)?;
23///
24/// let value = module.run()?;
25/// // Should output `[test_assert:1:5] 1 + 2 = 3` to stderr.
26/// assert_eq!(value, Value::Bool(true));
27/// # Ok(())
28/// # }
29/// ```
30#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
31#[derive(Debug, Clone, Copy, Default)]
32pub struct Dbg;
33
34impl Dbg {
35    fn print_value<T: fmt::Display>(module_id: &dyn ModuleId, value: &SpannedValue<'_, T>) {
36        match value.fragment() {
37            CodeFragment::Str(code) => eprintln!(
38                "[{module}:{line}:{col}] {code} = {val}",
39                module = module_id,
40                line = value.location_line(),
41                col = value.get_column(),
42                code = code,
43                val = value.extra
44            ),
45            CodeFragment::Stripped(_) => eprintln!(
46                "[{module}:{line}:{col}] {val}",
47                module = module_id,
48                line = value.location_line(),
49                col = value.get_column(),
50                val = value.extra
51            ),
52        }
53    }
54}
55
56impl<T: fmt::Display> NativeFn<T> for Dbg {
57    fn evaluate<'a>(
58        &self,
59        mut args: Vec<SpannedValue<'a, T>>,
60        ctx: &mut CallContext<'_, 'a, T>,
61    ) -> EvalResult<'a, T> {
62        let module_id = ctx.call_span().module_id();
63        for arg in &args {
64            Self::print_value(module_id, arg);
65        }
66
67        Ok(if args.len() == 1 {
68            args.pop().unwrap().extra
69        } else {
70            Value::Tuple(args.into_iter().map(|spanned| spanned.extra).collect())
71        })
72    }
73}