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) -> Arc { let Value::Pair(a, _b) = &*list else { panic!("expected a list") }; a.clone() } fn cdr_inner(list: Arc) -> Arc { let Value::Pair(_a, b) = &*list else { panic!("expected a list") }; b.clone() } pub fn is_member(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { let pattern = interpreter.eval(args[0].clone()); let full = interpreter.eval(args[1].clone()); fn is_among_inner(pattern: Arc, full: Arc) -> 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]) -> Arc { 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]) -> Arc { 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]) -> Arc { vec_to_value( &(args .iter() .map(|a| interpreter.eval(a.clone())) .collect::>()), ) } pub fn reverse(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { 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]) -> Arc { 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]) -> Arc { 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]) -> Arc { 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]) -> Arc { 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::>()) } pub fn intersection(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { 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::>(); common_values.retain(|element| arg.contains(element)); } interpreter::vec_to_value(&common_values.into_iter().collect::>()) }