summaryrefslogtreecommitdiff
path: root/src/interpreter.rs
diff options
context:
space:
mode:
authorMica White <botahamec@outlook.com>2025-12-07 14:25:35 -0500
committerMica White <botahamec@outlook.com>2025-12-07 14:25:35 -0500
commitcfa44907065eb10e3b990506881b30c5891f0af2 (patch)
tree90e2b818376a01294c8cc96184171861035c7319 /src/interpreter.rs
First commitHEADmain
Diffstat (limited to 'src/interpreter.rs')
-rw-r--r--src/interpreter.rs293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/interpreter.rs b/src/interpreter.rs
new file mode 100644
index 0000000..264e634
--- /dev/null
+++ b/src/interpreter.rs
@@ -0,0 +1,293 @@
+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(),
+ }
+ }
+}