use crate::builtins::meta::type_of;
use crate::calcit::{Calcit, CalcitErr, CalcitErrKind, CalcitList, CalcitProc, format_proc_examples_hint};
pub fn new_set(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
let mut ys = rpds::HashTrieSet::new_sync();
for x in xs {
ys.insert_mut(x.to_owned());
}
Ok(Calcit::Set(ys))
}
pub fn call_include(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(xs)), Some(a)) => {
let mut ys = xs.to_owned();
ys.insert_mut(a.to_owned());
Ok(Calcit::Set(ys))
}
(Some(_), None) => {
let msg = format!("&include requires 2 arguments, but received: {} arguments", xs.len());
let hint = format_proc_examples_hint(&CalcitProc::NativeInclude).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Arity, msg, hint)
}
(Some(a), Some(_)) => {
let msg = format!("&include requires a set, but received: {}", type_of(&[a.to_owned()])?.lisp_str());
let hint = format_proc_examples_hint(&CalcitProc::NativeInclude).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(a, b) => {
let msg = format!(
"&include requires 2 arguments, but received: {} arguments",
if a.is_none() && b.is_none() { 0 } else { 1 }
);
let hint = format_proc_examples_hint(&CalcitProc::NativeInclude).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Arity, msg, hint)
}
}
}
pub fn call_exclude(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(xs)), Some(a)) => {
let mut ys = xs.to_owned();
ys.remove_mut(a);
Ok(Calcit::Set(ys))
}
(Some(_), None) => {
let msg = format!(
"&exclude expected 2 arguments, but received: {} arguments",
if xs.is_empty() { 0 } else { 1 }
);
let hint = format_proc_examples_hint(&CalcitProc::NativeExclude).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Arity, msg, hint)
}
(Some(a), Some(_)) => {
let msg = format!("&exclude requires a set, but received: {}", type_of(&[a.to_owned()])?.lisp_str());
let hint = format_proc_examples_hint(&CalcitProc::NativeExclude).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(a, b) => CalcitErr::err_str(
CalcitErrKind::Arity,
format!("&exclude expected 2 arguments, but received: {a:?} {b:?}"),
),
}
}
pub fn call_difference(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(a)), Some(Calcit::Set(b))) => {
let mut ys = a.to_owned();
for item in b {
ys.remove_mut(item);
}
Ok(Calcit::Set(ys))
}
(Some(a), Some(b)) => {
let msg = format!(
"&difference requires 2 sets, but received: {} and {}",
type_of(&[a.to_owned()])?.lisp_str(),
type_of(&[b.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeDifference).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(a, b) => CalcitErr::err_str(
CalcitErrKind::Arity,
format!("&difference expected 2 arguments, but received: {a:?} {b:?}"),
),
}
}
pub fn call_union(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(a)), Some(Calcit::Set(b))) => {
let mut c = a.to_owned();
for x in b.iter() {
c.insert_mut(x.to_owned());
}
Ok(Calcit::Set(c))
}
(Some(a), Some(b)) => {
let msg = format!(
"&union requires 2 sets, but received: {} and {}",
type_of(&[a.to_owned()])?.lisp_str(),
type_of(&[b.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeUnion).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(a, b) => CalcitErr::err_str(
CalcitErrKind::Arity,
format!("&union expected 2 arguments, but received: {a:?} {b:?}"),
),
}
}
pub fn call_intersection(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(a)), Some(Calcit::Set(b))) => {
let mut c: rpds::HashTrieSetSync<Calcit> = rpds::HashTrieSet::new_sync();
for x in a.iter() {
if b.contains(x) {
c.insert_mut(x.to_owned())
}
}
Ok(Calcit::Set(c))
}
(Some(a), Some(b)) => {
let msg = format!(
"&set:intersection requires 2 sets, but received: {} and {}",
type_of(&[a.to_owned()])?.lisp_str(),
type_of(&[b.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeSetIntersection).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(a, b) => CalcitErr::err_str(
CalcitErrKind::Arity,
format!("&set:intersection expected 2 arguments, but received: {a:?} {b:?}"),
),
}
}
pub fn set_to_list(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match xs.first() {
Some(Calcit::Set(xs)) => {
let mut ys = vec![];
for x in xs {
ys.push(x.to_owned());
}
Ok(Calcit::from(ys))
}
Some(a) => {
let msg = format!(
"&set:to-list requires a set, but received: {}",
type_of(&[a.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeSetToList).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
None => CalcitErr::err_str(CalcitErrKind::Arity, "&set:to-list expected 1 argument, but received none"),
}
}
pub fn count(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match xs.first() {
Some(Calcit::Set(ys)) => Ok(Calcit::Number(ys.size() as f64)),
Some(a) => {
let msg = format!("&set:count requires a set, but received: {}", type_of(&[a.to_owned()])?.lisp_str());
let hint = format_proc_examples_hint(&CalcitProc::NativeSetCount).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
None => CalcitErr::err_str(CalcitErrKind::Arity, "&set:count expected 1 argument, but received none"),
}
}
pub fn empty_ques(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match xs.first() {
Some(Calcit::Set(ys)) => Ok(Calcit::Bool(ys.is_empty())),
Some(a) => {
let msg = format!("&set:empty? requires a set, but received: {}", type_of(&[a.to_owned()])?.lisp_str());
let hint = format_proc_examples_hint(&CalcitProc::NativeSetEmpty).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
None => CalcitErr::err_str(CalcitErrKind::Arity, "&set:empty? expected 1 argument, but received none"),
}
}
pub fn includes_ques(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match (xs.first(), xs.get(1)) {
(Some(Calcit::Set(xs)), Some(a)) => Ok(Calcit::Bool(xs.contains(a))),
(Some(_), None) => {
let hint = format_proc_examples_hint(&CalcitProc::NativeSetIncludes).unwrap_or_default();
CalcitErr::err_nodes_with_hint(CalcitErrKind::Arity, "&set:includes? expected 2 arguments, but received:", xs, hint)
}
(Some(a), Some(_)) => {
let msg = format!(
"&set:includes? requires a set, but received: {}",
type_of(&[a.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeSetIncludes).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
(None, ..) => CalcitErr::err_nodes(CalcitErrKind::Arity, "&set:includes? expected 2 arguments, but received:", xs),
}
}
pub fn destruct(xs: &[Calcit]) -> Result<Calcit, CalcitErr> {
match xs.first() {
Some(Calcit::Set(ys)) => match ys.iter().next() {
Some(y0) => {
let mut zs = ys.to_owned();
zs.remove_mut(y0);
Ok(Calcit::from(CalcitList::from(&[y0.to_owned(), Calcit::Set(zs)])))
}
None => Ok(Calcit::Nil),
},
Some(a) => {
let msg = format!(
"&set:destruct requires a set, but received: {}",
type_of(&[a.to_owned()])?.lisp_str()
);
let hint = format_proc_examples_hint(&CalcitProc::NativeSetDestruct).unwrap_or_default();
CalcitErr::err_str_with_hint(CalcitErrKind::Type, msg, hint)
}
None => CalcitErr::err_str(CalcitErrKind::Arity, "&set:destruct expected 1 argument, but received none"),
}
}