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