summaryrefslogtreecommitdiff
path: root/src/builtins/delsh.rs
blob: 6c9883cd5ff9abc34fd345c96764788e36a06ad8 (plain)
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);
}