From e84b351daa86ee45ab7345d502f1880f38f55e44 Mon Sep 17 00:00:00 2001 From: mat ess Date: Mon, 24 Jul 2023 12:22:57 -0400 Subject: [PATCH] Reorganize --- src/{phase => }/evaluate.rs | 60 ++++++++++++++++++++++++---- src/lib.rs | 4 +- src/{phase => }/parse.rs | 4 +- src/{phase => }/parse/parser.lalrpop | 1 + src/phase.rs | 7 ---- 5 files changed, 59 insertions(+), 17 deletions(-) rename src/{phase => }/evaluate.rs (68%) rename src/{phase => }/parse.rs (69%) rename src/{phase => }/parse/parser.lalrpop (97%) delete mode 100644 src/phase.rs diff --git a/src/phase/evaluate.rs b/src/evaluate.rs similarity index 68% rename from src/phase/evaluate.rs rename to src/evaluate.rs index 36bd61c..27ed287 100644 --- a/src/phase/evaluate.rs +++ b/src/evaluate.rs @@ -1,13 +1,15 @@ -use std::collections::HashMap; +use std::{collections::HashMap, fmt::Display}; use thiserror::Error; +use crate::builtins::{self, Builtin}; use crate::syntax::{Block, Expression, InteractiveEntry, Item, Name, Program}; pub type Dictionary = HashMap; #[derive(Debug, Clone)] pub enum Value { + Builtin(Builtin), Closure { environment: Dictionary, parameters: Vec, @@ -15,6 +17,19 @@ pub enum Value { }, Boolean(bool), Integer(i64), + Unit, +} + +impl Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Builtin(b) => write!(f, ""), + Value::Closure { parameters, .. } => write!(f, "", parameters.join(", ")), + Value::Boolean(b) => write!(f, "{b}"), + Value::Integer(i) => write!(f, "{i}"), + Value::Unit => write!(f, "()"), + } + } } #[derive(Debug, Error)] @@ -27,9 +42,11 @@ pub enum Error { ArgumentsMismatch(usize, usize), #[error("No function called main to run")] MissingMainFunction, + #[error("Problem with builtin call: {0}")] + BuiltinError(#[from] builtins::Error), } -pub type Result = std::result::Result; +type Result = std::result::Result; #[derive(Debug, Clone)] pub struct Interpreter { @@ -39,7 +56,7 @@ pub struct Interpreter { impl Interpreter { pub fn new() -> Self { Interpreter { - environment: Dictionary::new(), + environment: Builtin::dictionary(), } } @@ -52,7 +69,7 @@ impl Interpreter { self.interpret_item(item)?; } if let Some(main) = self.environment.get("main").cloned() { - self.call_closure(&main, &vec![]) + self.apply_call(&main, &vec![]) } else { Err(Error::MissingMainFunction) } @@ -101,14 +118,15 @@ impl Interpreter { }), Expression::Call { callee, arguments } => { let callee = self.evaluate(callee.as_ref())?; - self.call_closure(&callee, arguments) + self.apply_call(&callee, arguments) } Expression::Boolean(b) => Ok(Value::Boolean(*b)), Expression::Integer(i) => Ok(Value::Integer(*i)), + Expression::Unit => Ok(Value::Unit), } } - fn call_closure(&mut self, callee: &Value, arguments: &Vec) -> Result { + fn apply_call(&mut self, callee: &Value, arguments: &Vec) -> Result { match callee { Value::Closure { environment, @@ -121,10 +139,27 @@ impl Interpreter { let mut nested = Interpreter::nested(environment.clone()); for (name, argument) in parameters.iter().zip(arguments) { // we don't want arguments to refer to each other, so use the parent interpreter - nested.bind(name.clone(), argument)?; + self.bind_nested(name.clone(), argument, &mut nested)?; } nested.evaluate(result) } + Value::Builtin(b) => { + if arguments.len() < b.min_parameters() { + return Err(Error::ArgumentsMismatch( + b.min_parameters(), + arguments.len(), + )); + } else if let Some(max) = b.max_parameters() { + if arguments.len() > max { + return Err(Error::ArgumentsMismatch(max, arguments.len())); + } + } + let arguments = arguments + .iter() + .map(|term| self.evaluate(term)) + .collect::>>()?; + b.call(arguments).map_err(Error::BuiltinError) + } _ => Err(Error::NotAFunction), } } @@ -142,6 +177,17 @@ impl Interpreter { self.environment.insert(name, value.clone()); Ok(value) } + + fn bind_nested( + &mut self, + name: Name, + term: &Expression, + nested: &mut Interpreter, + ) -> Result { + let value = self.evaluate(term)?; + nested.environment.insert(name, value.clone()); + Ok(value) + } } impl Default for Interpreter { diff --git a/src/lib.rs b/src/lib.rs index b90dd89..43bfecd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +pub mod builtins; pub mod cli; -pub mod phase; +pub mod evaluate; +pub mod parse; pub mod syntax; diff --git a/src/phase/parse.rs b/src/parse.rs similarity index 69% rename from src/phase/parse.rs rename to src/parse.rs index 540668c..6152f99 100644 --- a/src/phase/parse.rs +++ b/src/parse.rs @@ -2,9 +2,9 @@ use lalrpop_util::{lalrpop_mod, lexer::Token, ParseError}; use crate::syntax::{InteractiveEntry, Program}; -lalrpop_mod!(parser, "/phase/parse/parser.rs"); +lalrpop_mod!(parser, "/parse/parser.rs"); -pub type Result<'input, T> = std::result::Result, &'static str>>; +type Result<'input, T> = std::result::Result, &'static str>>; pub fn parse_program(input: &str) -> Result { parser::ProgramParser::new().parse(input) diff --git a/src/phase/parse/parser.lalrpop b/src/parse/parser.lalrpop similarity index 97% rename from src/phase/parse/parser.lalrpop rename to src/parse/parser.lalrpop index cffb5b7..78f3b5d 100644 --- a/src/phase/parse/parser.lalrpop +++ b/src/parse/parser.lalrpop @@ -41,6 +41,7 @@ Atom: Expression = { Integer => Expression::Integer(<>), Boolean => Expression::Boolean(<>), "(" ")", + "(" ")" => Expression::Unit, }; BlockBinding = ";"; diff --git a/src/phase.rs b/src/phase.rs deleted file mode 100644 index 222657c..0000000 --- a/src/phase.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod parse; -// | -// | -// syntax -// | -// v -pub mod evaluate;