diff --git a/src/phase/evaluate.rs b/src/phase/evaluate.rs index 808d2d6..36bd61c 100644 --- a/src/phase/evaluate.rs +++ b/src/phase/evaluate.rs @@ -8,7 +8,11 @@ pub type Dictionary = HashMap; #[derive(Debug, Clone)] pub enum Value { - Closure(Dictionary, Vec, Expression), + Closure { + environment: Dictionary, + parameters: Vec, + result: Expression, + }, Boolean(bool), Integer(i64), } @@ -19,7 +23,7 @@ pub enum Error { UnboundName(Name), #[error("Tried to call a term which was not a function")] NotAFunction, - #[error("Mismatched number of function arguments and parameters: expected {0}, got {1}")] + #[error("Mismatched number of function parameters and arguments: expected {0}, got {1}")] ArgumentsMismatch(usize, usize), #[error("No function called main to run")] MissingMainFunction, @@ -39,13 +43,16 @@ impl Interpreter { } } + fn nested(environment: Dictionary) -> Self { + Interpreter { environment } + } + pub fn run(&mut self, program: &Program) -> Result { for item in program { self.interpret_item(item)?; } - if let Some(main) = self.environment.get("main") { - // should main be an expression? a standalone closure type? - todo!() + if let Some(main) = self.environment.get("main").cloned() { + self.call_closure(&main, &vec![]) } else { Err(Error::MissingMainFunction) } @@ -58,11 +65,11 @@ impl Interpreter { parameters, body, } => { - let closure = Value::Closure( - self.environment.clone(), - parameters.clone(), - Expression::Block(Box::new(body.clone())), - ); + let closure = Value::Closure { + environment: self.environment.clone(), + parameters: parameters.clone(), + result: Expression::Block(Box::new(body.clone())), + }; self.environment.insert(name.clone(), closure.clone()); Ok(closure) } @@ -87,30 +94,41 @@ impl Interpreter { .ok_or(Error::UnboundName(name.clone())) .cloned(), Expression::Block(b) => self.evaluate_block(b.as_ref()), - Expression::Lambda { parameters, result } => Ok(Value::Closure( - self.environment.clone(), - parameters.clone(), - *result.clone(), - )), - Expression::Call { callee, arguments } => match callee.as_ref() { - Expression::Lambda { parameters, result } => { - if parameters.len() != arguments.len() { - return Err(Error::ArgumentsMismatch(parameters.len(), arguments.len())); - } - let mut nested = self.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)?; - } - nested.evaluate(result) - } - _ => Err(Error::NotAFunction), - }, + Expression::Lambda { parameters, result } => Ok(Value::Closure { + environment: self.environment.clone(), + parameters: parameters.clone(), + result: *result.clone(), + }), + Expression::Call { callee, arguments } => { + let callee = self.evaluate(callee.as_ref())?; + self.call_closure(&callee, arguments) + } Expression::Boolean(b) => Ok(Value::Boolean(*b)), Expression::Integer(i) => Ok(Value::Integer(*i)), } } + fn call_closure(&mut self, callee: &Value, arguments: &Vec) -> Result { + match callee { + Value::Closure { + environment, + parameters, + result, + } => { + if parameters.len() != arguments.len() { + return Err(Error::ArgumentsMismatch(parameters.len(), arguments.len())); + } + 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)?; + } + nested.evaluate(result) + } + _ => Err(Error::NotAFunction), + } + } + fn evaluate_block(&mut self, block: &Block) -> Result { let mut nested = self.clone(); for binding in &block.bindings {