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)
}
|