use std::{collections::HashSet, sync::Arc};
use rust_decimal::Decimal;
use crate::{
builtins::delsh_bool,
interpreter::{self, Interpreter, Value, vec_to_value},
};
use super::NIL;
fn car_inner(list: Arc<Value>) -> Arc<Value> {
let Value::Pair(a, _b) = &*list else {
panic!("expected a list")
};
a.clone()
}
fn cdr_inner(list: Arc<Value>) -> Arc<Value> {
let Value::Pair(_a, b) = &*list else {
panic!("expected a list")
};
b.clone()
}
pub fn is_member(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let pattern = interpreter.eval(args[0].clone());
let full = interpreter.eval(args[1].clone());
fn is_among_inner(pattern: Arc<Value>, full: Arc<Value>) -> bool {
if pattern == full {
return true;
}
if let Some((a, b)) = full.pair() {
return is_among_inner(pattern.clone(), a.clone())
|| is_among_inner(pattern, b.clone());
}
false
}
delsh_bool(is_among_inner(pattern, full))
}
macro_rules! cr {
($name: ident => $($cr: expr),*) => {
pub fn $name(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let list = interpreter.eval(args[0].clone());
$(let list = $cr(list);)*
list
}
};
}
cr!(car => car_inner);
cr!(cdr => cdr_inner);
cr!(caar => car_inner, car_inner);
cr!(cadr => cdr_inner, car_inner);
cr!(cdar => car_inner, cdr_inner);
cr!(cddr => cdr_inner, cdr_inner);
cr!(caaar => car_inner, car_inner, car_inner);
cr!(caadr => cdr_inner, car_inner, car_inner);
cr!(cadar => car_inner, cdr_inner, car_inner);
cr!(caddr => cdr_inner, cdr_inner, car_inner);
cr!(cdaar => car_inner, car_inner, cdr_inner);
cr!(cdadr => cdr_inner, car_inner, cdr_inner);
cr!(cddar => car_inner, cdr_inner, cdr_inner);
cr!(cdddr => cdr_inner, cdr_inner, cdr_inner);
macro_rules! index {
(fn $fn_name: ident => $index: expr) => {
pub fn $fn_name(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let list = interpreter
.eval(args[0].clone())
.list()
.expect("a list to index");
list[$index].clone()
}
};
}
index!(fn first => 0);
index!(fn second => 1);
index!(fn third => 2);
index!(fn fourth => 3);
index!(fn fifth => 4);
index!(fn sixth => 5);
index!(fn seventh => 6);
index!(fn eighth => 7);
index!(fn ninth => 8);
index!(fn tenth => 9);
pub fn list(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
vec_to_value(
&(args
.iter()
.map(|a| interpreter.eval(a.clone()))
.collect::<Box<_>>()),
)
}
pub fn reverse(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let mut list = interpreter.eval(args[0].clone()).list().expect("a list");
list.reverse();
interpreter::vec_to_value(&list)
}
pub fn append(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let mut new_list = Vec::new();
for arg in args {
let arg = interpreter.eval(arg.clone()).list().expect("a list");
new_list.extend(arg);
}
vec_to_value(&new_list)
}
pub fn length(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let list = interpreter.eval(args[0].clone()).list().expect("a list");
Arc::new(Value::Number(Decimal::from(list.len())))
}
pub fn efface(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let element = interpreter.eval(args[0].clone());
let mut list = interpreter.eval(args[1].clone()).list().expect("a list");
let Some(index_to_remove) = list.iter().position(|i| *i == element) else {
return NIL.clone();
};
list.remove(index_to_remove);
interpreter::vec_to_value(&list)
}
pub fn union(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let mut unique_values = HashSet::new();
for arg in args {
let arg = interpreter
.eval(arg.clone())
.set()
.expect("all arguments to be lists");
for value in arg {
unique_values.insert(value);
}
}
interpreter::vec_to_value(&unique_values.into_iter().collect::<Box<[_]>>())
}
pub fn intersection(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
let mut common_values = Vec::new();
for arg in args {
let arg = interpreter
.eval(arg.clone())
.list()
.expect("all arguments to be lists");
let arg = arg.into_iter().collect::<HashSet<_>>();
common_values.retain(|element| arg.contains(element));
}
interpreter::vec_to_value(&common_values.into_iter().collect::<Box<[_]>>())
}
|