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]) -> Arc; #[derive(Debug, Default)] pub struct Interpreter { stack: Vec, Arc>>, } #[derive(Clone, PartialEq, Eq, Hash)] pub enum Value { Identifier(Arc), Number(Decimal), String(Arc), Pair(Arc, Arc), RustFn(NativeFunction), DelshFn { args: Arc<[Arc]>, command: Arc, }, } 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, b: Arc, ) -> 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> { 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> { if let Value::String(string) = self { Some(string) } else { None } } pub fn pair(&self) -> Option<(&Arc, &Arc)> { if let Value::Pair(a, b) = self { Some((a, b)) } else { None } } pub fn list(&self) -> Option>> { 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>> { 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) -> Arc { Arc::new(Value::Pair( Arc::new(Value::Identifier("QUOTE".into())), Arc::new(Value::Pair(value, NIL.clone())), )) } pub fn vec_to_value(list: &[Arc]) -> Arc { 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> { 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> { 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, value: Arc) { self.current_stack_frame_mut() .insert(name.to_uppercase().into(), value); } pub fn run_function(&mut self, function: &Value, arguments: &[Arc]) -> Arc { 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) -> Arc { 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 { 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 { 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 { 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::>(); self.run_function(&function, &arguments) } ast::Command::Expression(expression) => { let value = self.ast_expression_value(expression); self.eval(value) } ast::Command::PanicMode(_) => NIL.clone(), } } }