summaryrefslogtreecommitdiff
path: root/src/builtins.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtins.rs')
-rw-r--r--src/builtins.rs300
1 files changed, 300 insertions, 0 deletions
diff --git a/src/builtins.rs b/src/builtins.rs
new file mode 100644
index 0000000..201cd89
--- /dev/null
+++ b/src/builtins.rs
@@ -0,0 +1,300 @@
+use std::sync::{Arc, LazyLock};
+
+use crate::interpreter::{self, Interpreter, Value, wrap_in_quote};
+
+mod lists;
+mod numbers;
+mod pairlists;
+
+pub use lists::*;
+pub use numbers::*;
+pub use pairlists::*;
+
+pub static T: LazyLock<Arc<Value>> = LazyLock::new(|| Arc::new(Value::Identifier("T".into())));
+pub static F: LazyLock<Arc<Value>> = LazyLock::new(|| Arc::new(Value::Identifier("F".into())));
+pub static NIL: LazyLock<Arc<Value>> = LazyLock::new(|| Arc::new(Value::Identifier("NIL".into())));
+
+fn delsh_bool(value: bool) -> Arc<Value> {
+ match value {
+ true => T.clone(),
+ false => NIL.clone(),
+ }
+}
+
+pub fn quote(_interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ args[0].clone()
+}
+
+pub fn eval(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let form = interpreter.eval(args[0].clone());
+ let variables = args
+ .get(1)
+ .map(|value| interpreter.eval(value.clone()).list().expect("a pair list"));
+
+ interpreter.push_frame();
+
+ if let Some(variables) = variables {
+ for variable in variables {
+ let Some((name, value)) = variable.pair() else {
+ continue;
+ };
+ let Some(name) = name.string() else {
+ continue;
+ };
+ interpreter.set_atom(name.clone(), value.clone());
+ }
+ }
+
+ let result = interpreter.eval(form);
+
+ interpreter.pop_frame();
+ result
+}
+
+pub fn apply(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let function = interpreter.eval(args[0].clone());
+ let arguments = interpreter
+ .eval(args[1].clone())
+ .list()
+ .expect("a list of arguments")
+ .into_iter()
+ .map(wrap_in_quote)
+ .collect::<Box<_>>();
+ let variables = args.get(2).map(|value| {
+ interpreter
+ .eval(value.clone())
+ .list()
+ .expect("a list of variables")
+ });
+
+ interpreter.push_frame();
+
+ if let Some(variables) = variables {
+ for variable in variables {
+ let Some((name, value)) = variable.pair() else {
+ continue;
+ };
+ let Some(name) = name.string() else {
+ continue;
+ };
+ interpreter.set_atom(name.clone(), value.clone());
+ }
+ }
+
+ let result = interpreter.run_function(&function, &arguments);
+
+ interpreter.pop_frame();
+ result
+}
+
+pub fn define(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let definitions = args[0].list().expect("a list of definitions");
+ for definition in definitions {
+ let pair = definition.list().expect("a name-value pair");
+ let Some(name) = pair[0].string() else {
+ continue;
+ };
+
+ let value = interpreter.eval(pair[1].clone());
+ interpreter.set_atom(name.clone(), value);
+ }
+
+ NIL.clone()
+}
+
+pub fn set(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let lhs = args[0]
+ .identifier()
+ .expect("an identifier on the left side");
+ let rhs = interpreter.eval(args[1].clone());
+ interpreter.set_atom(lhs.clone(), rhs.clone());
+
+ rhs
+}
+
+pub fn lambda(_interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ Arc::new(Value::DelshFn {
+ args: args[0]
+ .list()
+ .expect("a list of argument names")
+ .into_iter()
+ .filter_map(|value| value.identifier().cloned())
+ .collect(),
+ command: args[1].clone(),
+ })
+}
+
+pub fn defun(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let Value::Identifier(function_name) = &*args[0] else {
+ return NIL.clone();
+ };
+
+ let function = Value::DelshFn {
+ args: args[1]
+ .list()
+ .expect("a list of parameter names")
+ .into_iter()
+ .filter_map(|value| value.identifier().cloned())
+ .collect(),
+ command: args[2].clone(),
+ };
+
+ let function = Arc::new(function);
+ interpreter.set_atom(function_name.clone(), function.clone());
+ function
+}
+
+pub fn do_function(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let Some(last_arg) = args.last() else {
+ return NIL.clone();
+ };
+
+ for arg in &args[..args.len() - 1] {
+ interpreter.eval(arg.clone());
+ }
+
+ interpreter.eval(last_arg.clone())
+}
+
+pub fn if_function(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let condition = interpreter.eval(args[0].clone());
+ let if_block = args[1].clone();
+ let else_block = args[2].clone();
+
+ if condition != *NIL {
+ interpreter.eval(if_block)
+ } else {
+ interpreter.eval(else_block)
+ }
+}
+
+pub fn cond_function(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ for case in args {
+ let case = case.list().expect("a list of cases");
+ let condition = interpreter.eval(case[0].clone());
+ if condition != *NIL {
+ let mut result = NIL.clone();
+ for command in &case[1..] {
+ result = interpreter.eval(command.clone());
+ }
+ return result;
+ }
+ }
+
+ NIL.clone()
+}
+
+pub fn while_function(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let condition = args[0].clone();
+ let while_block = args[1].clone();
+
+ while interpreter.eval(condition.clone()) != NIL.clone() {
+ interpreter.eval(while_block.clone());
+ }
+
+ NIL.clone()
+}
+
+pub fn loop_function(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let expression = args[0].clone();
+
+ loop {
+ interpreter.eval(expression.clone());
+ }
+}
+
+pub fn cons(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ Arc::new(Value::Pair(
+ interpreter.eval(args[0].clone()),
+ interpreter.eval(args[1].clone()),
+ ))
+}
+
+pub fn ff(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ fn ff_inner(arg: Arc<Value>) -> Arc<Value> {
+ if let Value::Pair(a, _b) = &*arg {
+ ff_inner(a.clone())
+ } else {
+ arg
+ }
+ }
+
+ ff_inner(interpreter.eval(args[0].clone()))
+}
+
+pub fn subst(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ fn subst_inner(replacement: Arc<Value>, pattern: Arc<Value>, full: Arc<Value>) -> Arc<Value> {
+ if full == pattern {
+ return replacement;
+ }
+
+ if let Value::Pair(a, b) = &*full {
+ return Arc::new(Value::Pair(
+ subst_inner(replacement.clone(), pattern.clone(), a.clone()),
+ subst_inner(replacement, pattern, b.clone()),
+ ));
+ }
+
+ full
+ }
+
+ let arg1 = interpreter.eval(args[0].clone());
+ let arg2 = interpreter.eval(args[1].clone());
+ let arg3 = interpreter.eval(args[2].clone());
+
+ subst_inner(arg1, arg2, arg3)
+}
+
+pub fn is_atom(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ match &*interpreter.eval(args[0].clone()) {
+ Value::Identifier(_) => T.clone(),
+ Value::Number(_) => T.clone(),
+ Value::String(_) => T.clone(),
+ Value::RustFn(_) => T.clone(),
+ Value::DelshFn { .. } => T.clone(),
+ Value::Pair(..) => NIL.clone(),
+ }
+}
+
+pub fn is_nil(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let x = interpreter.eval(args[0].clone());
+
+ delsh_bool(x == *NIL)
+}
+
+pub fn maplist(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ let list = interpreter.eval(args[0].clone()).list().expect("a list");
+ let mapper = interpreter.eval(args[1].clone());
+
+ let mapped = list
+ .into_iter()
+ .map(|i| interpreter.run_function(&mapper, &[i]))
+ .collect::<Box<_>>();
+ interpreter::vec_to_value(&mapped)
+}
+
+pub fn and(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ for arg in args {
+ let arg = interpreter.eval(arg.clone());
+ if arg != *NIL {
+ return arg;
+ }
+ }
+
+ NIL.clone()
+}
+
+pub fn or(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ for arg in args {
+ let arg = interpreter.eval(arg.clone());
+ if arg == *NIL {
+ return arg;
+ }
+ }
+
+ NIL.clone()
+}
+
+pub fn not(interpreter: &mut Interpreter, args: &[Arc<Value>]) -> Arc<Value> {
+ is_nil(interpreter, args)
+}