summaryrefslogtreecommitdiff
path: root/src/interpreter.rs
blob: 264e6341892f45c8f8f0dfa2541480ace5cf7980 (plain)
use std::{
	collections::{HashMap, HashSet},
	fmt::Debug,
	sync::Arc,
};

use rust_decimal::Decimal;

use crate::{
	ast::{self, Expression, List},
	builtins::NIL,
};

type NativeFunction = fn(&mut Interpreter, &[Arc<Value>]) -> Arc<Value>;

#[derive(Debug, Default)]
pub struct Interpreter {
	stack: Vec<HashMap<Arc<str>, Arc<Value>>>,
}

#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Value {
	Identifier(Arc<str>),
	Number(Decimal),
	String(Arc<str>),
	Pair(Arc<Value>, Arc<Value>),
	RustFn(NativeFunction),
	DelshFn {
		args: Arc<[Arc<str>]>,
		command: Arc<Value>,
	},
}

impl Debug for Value {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		fn fmt_pair(
			f: &mut std::fmt::Formatter<'_>,
			a: Arc<Value>,
			b: Arc<Value>,
		) -> std::fmt::Result {
			a.fmt(f)?;

			if let Value::Pair(a, b) = &*b {
				f.write_str(" ")?;
				fmt_pair(f, a.clone(), b.clone())
			} else if b == NIL.clone() {
				f.write_str(")")
			} else {
				f.write_str(" . ")?;
				b.fmt(f)?;
				f.write_str(")")
			}
		}

		match self {
			Value::Identifier(identifier) => f.write_str(identifier),
			Value::Number(number) => write!(f, "{number}"),
			Value::String(string) => write!(f, "\"{string}\""),
			Value::Pair(a, b) => {
				f.write_str("(")?;
				fmt_pair(f, a.clone(), b.clone())
			}
			Value::RustFn(_) => f.write_str("builtin function"),
			Value::DelshFn { .. } => f.write_str("function"),
		}
	}
}

impl Value {
	pub fn identifier(&self) -> Option<&Arc<str>> {
		if let Value::Identifier(identifier) = self {
			Some(identifier)
		} else {
			None
		}
	}

	pub fn number(&self) -> Option<&Decimal> {
		if let Value::Number(number) = self {
			Some(number)
		} else {
			None
		}
	}

	pub fn string(&self) -> Option<&Arc<str>> {
		if let Value::String(string) = self {
			Some(string)
		} else {
			None
		}
	}

	pub fn pair(&self) -> Option<(&Arc<Value>, &Arc<Value>)> {
		if let Value::Pair(a, b) = self {
			Some((a, b))
		} else {
			None
		}
	}

	pub fn list(&self) -> Option<Vec<Arc<Value>>> {
		let mut list = self;
		let mut builder = Vec::new();
		loop {
			if let Value::Pair(head, rest) = &list {
				builder.push(head.clone());
				list = rest;
			} else if list == &**NIL {
				return Some(builder);
			} else {
				return None;
			}
		}
	}

	pub fn set(&self) -> Option<HashSet<Arc<Value>>> {
		let mut head = self;
		let mut builder = HashSet::new();
		loop {
			if let Value::Pair(car, cdr) = &head {
				builder.insert(car.clone());
				head = cdr;
			} else if head == &**NIL {
				return Some(builder);
			} else {
				return None;
			}
		}
	}

	pub fn rust_fn(&self) -> Option<&NativeFunction> {
		if let Value::RustFn(func) = self {
			Some(func)
		} else {
			None
		}
	}

	pub fn is_function(&self) -> bool {
		matches!(self, Value::RustFn(_) | Value::DelshFn { .. })
	}
}

pub fn wrap_in_quote(value: Arc<Value>) -> Arc<Value> {
	Arc::new(Value::Pair(
		Arc::new(Value::Identifier("QUOTE".into())),
		Arc::new(Value::Pair(value, NIL.clone())),
	))
}

pub fn vec_to_value(list: &[Arc<Value>]) -> Arc<Value> {
	if list.is_empty() {
		NIL.clone()
	} else if list.len() == 1 {
		Arc::new(Value::Pair(list[0].clone(), NIL.clone()))
	} else {
		Arc::new(Value::Pair(list[0].clone(), vec_to_value(&list[1..])))
	}
}

impl Interpreter {
	pub fn new() -> Self {
		Self {
			stack: vec![HashMap::new()],
		}
	}

	fn current_stack_frame_mut(&mut self) -> &mut HashMap<Arc<str>, Arc<Value>> {
		self.stack
			.last_mut()
			.expect("there should always be at least one stack frame")
	}

	pub fn push_frame(&mut self) {
		self.stack.push(HashMap::new());
	}

	pub fn pop_frame(&mut self) {
		if self.stack.len() == 1 {
			return;
		}

		self.stack.pop();
	}

	pub fn get_atom(&self, name: &str) -> Option<Arc<Value>> {
		for frame in self.stack.iter().rev() {
			if let Some(value) = frame.get(name) {
				return Some(value.clone());
			}
		}

		None
	}

	pub fn set_atom(&mut self, name: Arc<str>, value: Arc<Value>) {
		self.current_stack_frame_mut()
			.insert(name.to_uppercase().into(), value);
	}

	pub fn run_function(&mut self, function: &Value, arguments: &[Arc<Value>]) -> Arc<Value> {
		match function {
			Value::RustFn(func) => func(self, arguments),
			Value::DelshFn { args, command } => {
				self.push_frame();
				for (name, value) in args.iter().zip(arguments) {
					let value = self.eval(value.clone());
					self.set_atom(name.clone(), value);
				}

				let return_value = self.eval(command.clone());
				self.pop_frame();
				return_value
			}
			_ => panic!("expected a function"),
		}
	}

	pub fn eval(&mut self, value: Arc<Value>) -> Arc<Value> {
		match &*value {
			Value::Identifier(identifier) => {
				self.get_atom(identifier).expect("a defined atom").clone()
			}
			Value::Pair(function, arguments) => {
				let function = self.eval(function.clone());
				let arguments = arguments.list().expect("arguments to be a list");
				self.run_function(&function, &arguments)
			}
			_ => value,
		}
	}

	fn ast_list_to_value(&mut self, list: &List) -> Arc<Value> {
		let contains_dot = list.items.iter().any(|item| item.dot().is_some());
		let mut head = (!contains_dot).then(|| NIL.clone());
		for item in list.items.iter().rev() {
			let Some(item) = item.expression() else {
				continue;
			};
			let Some(head) = head.as_mut() else {
				head = Some(self.ast_expression_value(item));
				continue;
			};

			*head = Arc::new(Value::Pair(self.ast_expression_value(item), head.clone()));
		}

		head.unwrap_or_else(|| NIL.clone())
	}

	pub fn ast_expression_value(&mut self, expr: &Expression) -> Arc<Value> {
		let suffix_value = match &expr.suffix {
			ast::ExpressionSuffix::Nothing => NIL.clone(),
			ast::ExpressionSuffix::Number { value, .. } => Arc::new(Value::Number(*value)),
			ast::ExpressionSuffix::String { value, .. } => Arc::new(Value::String(value.clone())),
			ast::ExpressionSuffix::Identifier { name, .. } => {
				Arc::new(Value::Identifier(name.clone()))
			}
			ast::ExpressionSuffix::List(list) => self.ast_list_to_value(list),
		};

		if expr.is_quoted() {
			wrap_in_quote(suffix_value)
		} else {
			suffix_value
		}
	}

	pub fn run_ast_command(&mut self, command: &ast::Command) -> Arc<Value> {
		match command {
			ast::Command::Statement(statement) => {
				let function_name = &statement.function_name;
				let function = self
					.get_atom(function_name)
					.expect("expected a defined value")
					.clone();
				let arguments = statement
					.args
					.iter()
					.map(|arg| self.ast_expression_value(arg))
					.collect::<Box<_>>();

				self.run_function(&function, &arguments)
			}
			ast::Command::Expression(expression) => {
				let value = self.ast_expression_value(expression);
				self.eval(value)
			}
			ast::Command::PanicMode(_) => NIL.clone(),
		}
	}
}