summaryrefslogtreecommitdiff
path: root/src/builtins
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2025-12-07 14:25:35 -0500
committerMica White <botahamec@outlook.com>2025-12-07 14:25:35 -0500
commitcfa44907065eb10e3b990506881b30c5891f0af2 (patch)
tree90e2b818376a01294c8cc96184171861035c7319 /src/builtins
First commitHEADmain
Diffstat (limited to 'src/builtins')
-rw-r--r--src/builtins/lists.rs170
-rw-r--r--src/builtins/numbers.rs227
-rw-r--r--src/builtins/pairlists.rs66
3 files changed, 463 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<[_]>>())
+}
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<Value>]) -> Arc<Value> {
+ let arg = interpreter.eval(args[0].clone());
+ delsh_bool(arg.number().is_some())
+}
+
+pub fn is_int(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ Arc::new(Value::Number(
+ interpreter
+ .eval(args[0].clone())
+ .number()
+ .expect("a number")
+ + Decimal::ONE,
+ ))
+}
+
+pub fn sub1(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ Arc::new(Value::Number(
+ interpreter
+ .eval(args[0].clone())
+ .number()
+ .expect("a number")
+ - Decimal::ONE,
+ ))
+}
+
+pub fn max(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ 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::<Box<_>>();
+
+ interpreter::vec_to_value(&pairs)
+}
+
+fn assoc_inner(key: Arc<Value>, pairs: &[Arc<Value>]) -> Option<Arc<Value>> {
+ let get_value = |pair: &Arc<Value>| {
+ 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<Value>]) -> Arc<Value> {
+ 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<Value>]) -> Arc<Value> {
+ fn sublis_inner(expression: Arc<Value>, replacements: &[Arc<Value>]) -> Arc<Value> {
+ 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)
+}