diff options
Diffstat (limited to 'src/interpreter.rs')
| -rw-r--r-- | src/interpreter.rs | 293 |
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(), + } + } +} |
