use crate::{
TulispContext, TulispObject,
eval::{DummyEval, funcall},
list, lists,
};
use std::cmp::Ordering;
pub(crate) fn add(ctx: &mut TulispContext) {
ctx.defun("length", |list: TulispObject| {
lists::length(&list).map(TulispObject::from)
});
ctx.defun(
"seq-map",
|ctx: &mut TulispContext, func: TulispObject, seq: TulispObject| ctx.map(&func, &seq),
);
ctx.defun(
"seq-reduce",
|ctx: &mut TulispContext, func: TulispObject, seq: TulispObject, initial: TulispObject| {
ctx.reduce(&func, &seq, &initial)
},
);
ctx.defun(
"seq-filter",
|ctx: &mut TulispContext, func: TulispObject, seq: TulispObject| ctx.filter(&func, &seq),
);
ctx.defun(
"seq-find",
|ctx: &mut TulispContext,
func: TulispObject,
seq: TulispObject,
default: Option<TulispObject>| {
let func = ctx.eval(&func)?;
for item in seq.base_iter() {
if funcall::<DummyEval>(ctx, &func, &list!(item.clone())?)?.is_truthy() {
return Ok(item);
}
}
Ok(default.unwrap_or_else(TulispObject::nil))
},
);
ctx.defun(
"sort",
|ctx: &mut TulispContext, seq: TulispObject, pred: TulispObject| {
let pred = ctx.eval(&pred)?;
let mut vec: Vec<_> = seq.base_iter().collect();
let mut err = None;
vec.sort_by(|v1, v2| {
if funcall::<DummyEval>(ctx, &pred, &list!(v1.clone(), v2.clone()).unwrap())
.map(|v| v.null())
.unwrap_or_else(|x| {
err = Some(x);
false
})
{
Ordering::Less
} else {
Ordering::Greater
}
});
if let Some(err) = err {
return Err(err);
}
let ret = vec.iter().fold(TulispObject::nil(), |v1, v2| {
TulispObject::cons(v2.clone(), v1)
});
Ok(ret)
},
);
}