summaryrefslogtreecommitdiff
path: root/src/builtins/pairlists.rs
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/pairlists.rs
First commitHEADmain
Diffstat (limited to 'src/builtins/pairlists.rs')
-rw-r--r--src/builtins/pairlists.rs66
1 files changed, 66 insertions, 0 deletions
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)
+}