summaryrefslogtreecommitdiff
path: root/src/builtins/lists.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtins/lists.rs')
-rw-r--r--src/builtins/lists.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/builtins/lists.rs b/src/builtins/lists.rs
new file mode 100644
index 0000000..5ecf415
--- /dev/null
+++ b/src/builtins/lists.rs
@@ -0,0 +1,170 @@
+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<[_]>>())
+}