diff options
Diffstat (limited to 'src/builtins/lists.rs')
| -rw-r--r-- | src/builtins/lists.rs | 170 |
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<[_]>>()) +} |
