summaryrefslogtreecommitdiff
path: root/src/builtins/delsh.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/builtins/delsh.rs')
-rw-r--r--src/builtins/delsh.rs136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/builtins/delsh.rs b/src/builtins/delsh.rs
new file mode 100644
index 0000000..6c9883c
--- /dev/null
+++ b/src/builtins/delsh.rs
@@ -0,0 +1,136 @@
+use std::io::Write;
+use std::panic::{RefUnwindSafe, catch_unwind};
+use std::sync::Arc;
+use std::sync::mpsc::Receiver;
+
+use delsh::{builtins, interpreter::Interpreter, interpreter::Value};
+use happylock::ThreadKey;
+use uuid::Uuid;
+
+use crate::pipe::{Message, MessageField};
+use crate::processes::send_message;
+
+macro_rules! add_builtins {
+ ($interpreter: expr => $($name: ident)*) => {
+ $(add_builtin!($interpreter, $name);)*
+ };
+}
+
+macro_rules! add_builtin {
+ ($interpreter: expr, $name: ident) => {
+ add_builtin!($interpreter, stringify!($name), $name);
+ };
+ ($interpreter: expr, $name: expr, $builtin: ident) => {
+ $interpreter.set_atom(
+ $name.to_uppercase().into(),
+ Arc::new(Value::RustFn(builtins::$builtin)),
+ );
+ };
+}
+
+fn panic_handler(f: impl Fn() + RefUnwindSafe) {
+ loop {
+ let result = catch_unwind(&f).unwrap_err();
+ eprintln!("{result:?}");
+ }
+}
+
+fn delsh_loop() {
+ let mut interpreter = Interpreter::new();
+ interpreter.set_atom("T".into(), delsh::builtins::T.clone());
+ interpreter.set_atom("F".into(), delsh::builtins::F.clone());
+ interpreter.set_atom("NIL".into(), delsh::builtins::NIL.clone());
+ add_builtin!(interpreter, "atom?", is_atom);
+ add_builtin!(interpreter, "equal?", is_equal);
+ add_builtin!(interpreter, "==", is_equal);
+ add_builtin!(interpreter, "nil?", is_nil);
+ add_builtin!(interpreter, "member?", is_member);
+ add_builtin!(interpreter, "less?", is_less);
+ add_builtin!(interpreter, "<", is_less);
+ add_builtin!(interpreter, "greater?", is_greater);
+ add_builtin!(interpreter, ">", is_greater);
+ add_builtin!(interpreter, "zero?", is_zero);
+ add_builtin!(interpreter, "one?", is_one);
+ add_builtin!(interpreter, "negative?", is_negative);
+ add_builtin!(interpreter, "number?", is_number);
+ add_builtin!(interpreter, "int?", is_int);
+ add_builtin!(interpreter, "+", plus);
+ add_builtin!(interpreter, "add", plus);
+ add_builtin!(interpreter, "-", minus);
+ add_builtin!(interpreter, "sub", minus);
+ add_builtin!(interpreter, "subtract", minus);
+ add_builtin!(interpreter, "difference", minus);
+ add_builtin!(interpreter, "*", times);
+ add_builtin!(interpreter, "mul", times);
+ add_builtin!(interpreter, "multiply", times);
+ add_builtin!(interpreter, "/", divide);
+ add_builtin!(interpreter, "%", remainder);
+ add_builtin!(interpreter, "**", expt);
+ add_builtin!(interpreter, "if", if_function);
+ add_builtin!(interpreter, "while", while_function);
+ add_builtin!(interpreter, "loop", loop_function);
+ add_builtin!(interpreter, "do", do_function);
+ add_builtins!(interpreter => car cdr cons);
+ add_builtins!(interpreter => car cdr cons ff );
+ add_builtins!(interpreter => cadr cdar caar cddr);
+ add_builtins!(interpreter => caaar caadr cadar caddr cdaar cdadr cddar cdddr);
+ add_builtins!(interpreter => first second third fourth fifth sixth seventh eighth ninth tenth);
+ add_builtins!(interpreter => and or not);
+ add_builtins!(interpreter => pair assoc subst sublis);
+ add_builtins!(interpreter => list reverse append length efface intersection union);
+ add_builtins!(interpreter => defun lambda maplist);
+ add_builtins!(interpreter => plus minus negate times add1 sub1 max min recip quotient remainder divide expt sqrt);
+ add_builtins!(interpreter => quote set eval apply);
+
+ interpreter.set_atom(
+ "SEND-MESSAGE".into(),
+ Arc::new(Value::RustFn(|interpreter, args| {
+ let mut key = ThreadKey::get().unwrap();
+ let program = args[0].string().unwrap().parse::<Uuid>().unwrap();
+ let fields = args
+ .iter()
+ .skip(1)
+ .map(|arg| match &*interpreter.eval(arg.clone()) {
+ Value::Identifier(_)
+ | Value::RustFn(_)
+ | Value::DelshFn { .. }
+ | Value::Pair(..) => MessageField::Empty,
+ Value::Number(number) => {
+ MessageField::Bytes(number.to_string().into_bytes().into())
+ }
+ Value::String(string) => MessageField::Bytes(string.as_bytes().into()),
+ });
+ let message = Message::new(&mut key, fields.collect::<Box<_>>());
+ let response = send_message(&mut key, program, message);
+ let response = response.wait();
+ match response.unwrap() {
+ MessageField::Empty => delsh::builtins::NIL.clone(),
+ MessageField::Bytes(bytes) => {
+ Arc::new(Value::String(String::from_utf8_lossy(bytes).into()))
+ }
+ MessageField::File(_) => todo!(),
+ }
+ })),
+ );
+
+ let mut buffer = String::new();
+ let stdin = std::io::stdin();
+ loop {
+ buffer.clear();
+ print!("$ ");
+ std::io::stdout().flush().unwrap();
+ stdin.read_line(&mut buffer).unwrap();
+ let mut lexer = delsh::tokens::Lexer::new(&buffer).peekable();
+ let program = delsh::ast::parse_program(&mut lexer).unwrap();
+ for command in &*program.commands {
+ let value = interpreter.run_ast_command(command);
+ println!("{value:?}");
+ }
+ }
+}
+
+pub fn delsh(key: ThreadKey, channel: Receiver<Message>) {
+ drop(key);
+ drop(channel);
+ panic_handler(delsh_loop);
+}