From cfa44907065eb10e3b990506881b30c5891f0af2 Mon Sep 17 00:00:00 2001 From: Mica White Date: Sun, 7 Dec 2025 14:25:35 -0500 Subject: First commit --- src/builtins/lists.rs | 170 ++++++++++++++++++++++++++++++++++ src/builtins/numbers.rs | 227 ++++++++++++++++++++++++++++++++++++++++++++++ src/builtins/pairlists.rs | 66 ++++++++++++++ 3 files changed, 463 insertions(+) create mode 100644 src/builtins/lists.rs create mode 100644 src/builtins/numbers.rs create mode 100644 src/builtins/pairlists.rs (limited to 'src/builtins') 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) -> 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::>()) +} diff --git a/src/builtins/numbers.rs b/src/builtins/numbers.rs new file mode 100644 index 0000000..86e159a --- /dev/null +++ b/src/builtins/numbers.rs @@ -0,0 +1,227 @@ +use std::sync::Arc; + +use rust_decimal::{Decimal, MathematicalOps}; + +use crate::interpreter::{Interpreter, Value}; + +use super::{NIL, delsh_bool}; + +pub fn is_number(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let arg = interpreter.eval(args[0].clone()); + delsh_bool(arg.number().is_some()) +} + +pub fn is_int(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let arg = interpreter.eval(args[0].clone()); + delsh_bool(arg.number().is_some_and(|num| num.is_integer())) +} + +pub fn is_equal(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let a = interpreter.eval(args[0].clone()); + let b = interpreter.eval(args[1].clone()); + + delsh_bool(a == b) +} + +pub fn is_less(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let a = *interpreter + .eval(args[0].clone()) + .number() + .expect("two numbers"); + let b = *interpreter + .eval(args[1].clone()) + .number() + .expect("two numbers"); + + delsh_bool(a < b) +} + +pub fn is_greater(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let a = *interpreter + .eval(args[0].clone()) + .number() + .expect("two numbers"); + let b = *interpreter + .eval(args[1].clone()) + .number() + .expect("two numbers"); + + delsh_bool(a > b) +} + +pub fn is_zero(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let arg = interpreter.eval(args[0].clone()); + delsh_bool(arg.number().is_some_and(|num| *num == Decimal::ZERO)) +} + +pub fn is_one(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let arg = interpreter.eval(args[0].clone()); + delsh_bool(arg.number().is_some_and(|num| *num == Decimal::ONE)) +} + +pub fn is_negative(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let arg = interpreter.eval(args[0].clone()); + delsh_bool(arg.number().is_some_and(|num| num.is_sign_negative())) +} + +pub fn plus(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let mut total = Decimal::ZERO; + for arg in args { + let arg = interpreter.eval(arg.clone()); + match &*arg { + Value::Number(num) => total += num, + _ => panic!("Expected a number"), + } + } + + Arc::new(Value::Number(total)) +} + +pub fn minus(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + if args.len() == 1 { + let Value::Number(arg) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + Arc::new(Value::Number(-arg)) + } else if args.len() == 2 { + let Value::Number(a) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + let Value::Number(b) = &*interpreter.eval(args[1].clone()) else { + panic!("expected a number") + }; + return Arc::new(Value::Number(a - b)); + } else { + panic!("expected one or two arguments") + } +} + +pub fn negate(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let Value::Number(arg) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + + Arc::new(Value::Number(-arg)) +} + +pub fn times(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let mut total = Decimal::ONE; + + for arg in args { + let Value::Number(arg) = &*interpreter.eval(arg.clone()) else { + panic!("expected a number") + }; + + total *= arg; + } + + Arc::new(Value::Number(total)) +} + +pub fn divide(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let Value::Number(arg1) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + let Value::Number(arg2) = &*interpreter.eval(args[1].clone()) else { + panic!("expected a number") + }; + + Arc::new(Value::Number(arg1 / arg2)) +} + +pub fn quotient(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let numerator = interpreter.eval(args[0].clone()); + let numerator = numerator.number().expect("two numbers"); + let denominator = interpreter.eval(args[1].clone()); + let denominator = denominator.number().expect("two numbers"); + + Arc::new(Value::Number((numerator / denominator).floor())) +} + +pub fn remainder(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let Value::Number(arg1) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + let Value::Number(arg2) = &*interpreter.eval(args[1].clone()) else { + panic!("expected a number") + }; + + Arc::new(Value::Number(arg1 % arg2)) +} + +pub fn add1(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + Arc::new(Value::Number( + interpreter + .eval(args[0].clone()) + .number() + .expect("a number") + + Decimal::ONE, + )) +} + +pub fn sub1(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + Arc::new(Value::Number( + interpreter + .eval(args[0].clone()) + .number() + .expect("a number") + - Decimal::ONE, + )) +} + +pub fn max(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let max = interpreter.eval(args[0].clone()); + let mut max = *max.number().expect("all args to be numbers"); + + for arg in &args[1..] { + let arg = interpreter.eval(arg.clone()); + let arg = arg.number().expect("all args to be numbers"); + max = max.max(*arg); + } + + Arc::new(Value::Number(max)) +} + +pub fn min(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let min = interpreter.eval(args[0].clone()); + let mut min = *min.number().expect("all args to be numbers"); + + for arg in &args[1..] { + let arg = interpreter.eval(arg.clone()); + let arg = arg.number().expect("all args to be numbers"); + min = min.min(*arg); + } + + Arc::new(Value::Number(min)) +} + +pub fn recip(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let number = interpreter.eval(args[0].clone()); + let number = number.number().expect("a number"); + Arc::new(Value::Number(Decimal::ONE / number)) +} + +pub fn expt(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let x = *interpreter + .eval(args[0].clone()) + .number() + .expect("two numbers"); + let y = *interpreter + .eval(args[0].clone()) + .number() + .expect("two numbers"); + + Arc::new(Value::Number(x.powd(y))) +} + +pub fn sqrt(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let Value::Number(arg) = &*interpreter.eval(args[0].clone()) else { + panic!("expected a number") + }; + + let Some(sqrt) = arg.sqrt() else { + return NIL.clone(); + }; + + Arc::new(Value::Number(sqrt)) +} diff --git a/src/builtins/pairlists.rs b/src/builtins/pairlists.rs new file mode 100644 index 0000000..1c18810 --- /dev/null +++ b/src/builtins/pairlists.rs @@ -0,0 +1,66 @@ +use std::sync::Arc; + +use crate::interpreter::{self, Interpreter, Value}; + +pub fn pair(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let keys = interpreter + .eval(args[0].clone()) + .list() + .expect("a list of keys"); + let vals = interpreter + .eval(args[1].clone()) + .list() + .expect("a list of values"); + + let pairs = keys + .into_iter() + .zip(vals) + .map(|(key, value)| Arc::new(Value::Pair(key, value))) + .collect::>(); + + interpreter::vec_to_value(&pairs) +} + +fn assoc_inner(key: Arc, pairs: &[Arc]) -> Option> { + let get_value = |pair: &Arc| { + if let Value::Pair(k, v) = &**pair { + (k == &key).then(|| v.clone()) + } else { + None + } + }; + + pairs.iter().filter_map(get_value).next() +} + +pub fn assoc(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + let key = interpreter.eval(args[0].clone()); + let pairs = interpreter.eval(args[1].clone()).list().expect("a list"); + + assoc_inner(key, &pairs).unwrap() +} + +pub fn sublis(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + fn sublis_inner(expression: Arc, replacements: &[Arc]) -> Arc { + if let Some(value) = assoc_inner(expression.clone(), replacements) { + return value.clone(); + } + + if let Value::Pair(a, b) = &*expression { + return Arc::new(Value::Pair( + sublis_inner(a.clone(), replacements), + sublis_inner(b.clone(), replacements), + )); + } + + expression + } + + let expression = interpreter.eval(args[1].clone()); + let replacements = interpreter + .eval(args[0].clone()) + .list() + .expect("a list of replacements"); + + sublis_inner(expression, &replacements) +} -- cgit v1.2.3