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.rs | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 src/builtins.rs (limited to 'src/builtins.rs') 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> = LazyLock::new(|| Arc::new(Value::Identifier("T".into()))); +pub static F: LazyLock> = LazyLock::new(|| Arc::new(Value::Identifier("F".into()))); +pub static NIL: LazyLock> = LazyLock::new(|| Arc::new(Value::Identifier("NIL".into()))); + +fn delsh_bool(value: bool) -> Arc { + match value { + true => T.clone(), + false => NIL.clone(), + } +} + +pub fn quote(_interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + args[0].clone() +} + +pub fn eval(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + 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]) -> Arc { + 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::>(); + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + let expression = args[0].clone(); + + loop { + interpreter.eval(expression.clone()); + } +} + +pub fn cons(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + Arc::new(Value::Pair( + interpreter.eval(args[0].clone()), + interpreter.eval(args[1].clone()), + )) +} + +pub fn ff(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + fn ff_inner(arg: Arc) -> Arc { + 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]) -> Arc { + fn subst_inner(replacement: Arc, pattern: Arc, full: Arc) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + let x = interpreter.eval(args[0].clone()); + + delsh_bool(x == *NIL) +} + +pub fn maplist(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + 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::>(); + interpreter::vec_to_value(&mapped) +} + +pub fn and(interpreter: &mut Interpreter, args: &[Arc]) -> Arc { + 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]) -> Arc { + 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]) -> Arc { + is_nil(interpreter, args) +} -- cgit v1.2.3