use core::fmt;
use crate::{
alloc::{format, Vec},
error::AuxErrorInfo,
CallContext, ErrorKind, EvalResult, NativeFn, SpannedValue, Value,
};
use arithmetic_parser::CodeFragment;
#[derive(Debug, Clone, Copy, Default)]
pub struct Assert;
impl<T> NativeFn<T> for Assert {
fn evaluate<'a>(
&self,
args: Vec<SpannedValue<'a, T>>,
ctx: &mut CallContext<'_, 'a, T>,
) -> EvalResult<'a, T> {
ctx.check_args_count(&args, 1)?;
match args[0].extra {
Value::Bool(true) => Ok(Value::void()),
Value::Bool(false) => {
let err = if let CodeFragment::Str(code) = args[0].fragment() {
ErrorKind::native(format!("Assertion failed: {}", code))
} else {
ErrorKind::native("Assertion failed")
};
Err(ctx.call_site_error(err))
}
_ => {
let err = ErrorKind::native("`assert` requires a single boolean argument");
Err(ctx
.call_site_error(err)
.with_span(&args[0], AuxErrorInfo::InvalidArg))
}
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct AssertEq;
impl<T: fmt::Display> NativeFn<T> for AssertEq {
fn evaluate<'a>(
&self,
args: Vec<SpannedValue<'a, T>>,
ctx: &mut CallContext<'_, 'a, T>,
) -> EvalResult<'a, T> {
ctx.check_args_count(&args, 2)?;
let is_equal = args[0]
.extra
.eq_by_arithmetic(&args[1].extra, ctx.arithmetic());
if is_equal {
Ok(Value::void())
} else {
let err = if let (CodeFragment::Str(lhs), CodeFragment::Str(rhs)) =
(args[0].fragment(), args[1].fragment())
{
ErrorKind::native(format!("Assertion failed: {} == {}", lhs, rhs))
} else {
ErrorKind::native("Equality assertion failed")
};
Err(ctx
.call_site_error(err)
.with_span(&args[0], AuxErrorInfo::arg_value(&args[0].extra))
.with_span(&args[1], AuxErrorInfo::arg_value(&args[1].extra)))
}
}
}