use crate::{
TulispConvertible, TulispObject, TulispValue,
context::TulispContext,
error::Error,
eval::{Eval, eval_form},
number::Number,
};
pub(crate) trait EvalInto<T: TulispConvertible> {
fn eval_into(&self, ctx: &mut TulispContext) -> Result<T, Error>;
}
impl EvalInto<Number> for TulispObject {
#[inline(always)]
fn eval_into(&self, ctx: &mut TulispContext) -> Result<Number, Error> {
let inner = self.inner_ref();
match &inner.0 {
TulispValue::Number { value, .. } => Ok(*value),
TulispValue::Symbol { value: sym, .. } => {
if sym.is_constant() {
return Err(Error::type_mismatch(format!(
"Expected number, got: {}",
self
)));
}
sym.get_as_number().map_err(|e| e.with_trace(self.clone()))
}
TulispValue::LexicalBinding { value: sym, .. } => {
sym.get_as_number().map_err(|e| e.with_trace(self.clone()))
}
TulispValue::List { .. } => eval_form::<Eval>(ctx, self)
.map_err(|e| e.with_trace(self.clone()))?
.as_number(),
_ => Err(Error::type_mismatch(format!(
"Expected number, got: {}",
self
))),
}
}
}
impl EvalInto<bool> for TulispObject {
#[inline(always)]
fn eval_into(&self, ctx: &mut TulispContext) -> Result<bool, Error> {
let inner = self.inner_ref();
match &inner.0 {
TulispValue::Nil => Ok(false),
TulispValue::Symbol { value: sym, .. } => {
if sym.is_constant() {
return Ok(true);
}
sym.get_as_bool().map_err(|e| e.with_trace(self.clone()))
}
TulispValue::List { .. } => Ok(eval_form::<Eval>(ctx, self)
.map_err(|e| e.with_trace(self.clone()))?
.is_truthy()),
_ => Ok(true),
}
}
}