From 10223cbb4eca0630831a7b289a65ccf241f487f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Thu, 5 Jan 2023 07:54:18 +0100
Subject: [PATCH] Interpreter - WIP refactor to prepare for using resolved
 variables

---
 src/interpreter/callable.rs      |   8 +-
 src/interpreter/environment.rs   |   8 +-
 src/interpreter/functions.rs     |  32 +++++---
 src/interpreter/interpretable.rs | 125 ++++++++++++++++++-------------
 src/interpreter/mod.rs           |   4 +-
 src/interpreter/native_fn.rs     |   6 +-
 6 files changed, 104 insertions(+), 79 deletions(-)

diff --git a/src/interpreter/callable.rs b/src/interpreter/callable.rs
index 20ac38e..b84c846 100644
--- a/src/interpreter/callable.rs
+++ b/src/interpreter/callable.rs
@@ -2,17 +2,17 @@ use std::{cell::RefCell, fmt::Debug, rc::Rc};
 
 use crate::errors::SloxResult;
 
-use super::{EnvironmentRef, Value};
+use super::{InterpreterState, Value};
 
 /// A callable is some object that supports being called.
-pub trait Callable: Debug + ToString {
+pub(super) trait Callable: Debug + ToString {
     /// Return the amount of arguments supported by the callable.
     fn arity(&self) -> usize;
 
     /// Run the callable in the execution environment with the specified
     /// arguments.
-    fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value>;
+    fn call(&self, environment: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value>;
 }
 
 /// A reference to a callable.
-pub type CallableRef = Rc<RefCell<dyn Callable>>;
+pub(super) type CallableRef = Rc<RefCell<dyn Callable>>;
diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs
index f68d47a..7ec42d8 100644
--- a/src/interpreter/environment.rs
+++ b/src/interpreter/environment.rs
@@ -8,15 +8,15 @@ use crate::{
 use super::{native_fn, CallableRef, Value};
 
 /// A mutable reference to an environment.
-pub type EnvironmentRef = Rc<RefCell<Environment>>;
+pub(super) type EnvironmentRef = Rc<RefCell<Environment>>;
 
 /// A variable.
-pub type Variable = Option<Value>;
+pub(super) type Variable = Option<Value>;
 
 /// The execution environment.
 #[derive(Debug)]
-pub struct Environment {
-    enclosing: Option<EnvironmentRef>,
+pub(super) struct Environment {
+    pub(super) enclosing: Option<EnvironmentRef>,
     values: HashMap<String, Variable>,
 }
 
diff --git a/src/interpreter/functions.rs b/src/interpreter/functions.rs
index 5fab45c..1c960cf 100644
--- a/src/interpreter/functions.rs
+++ b/src/interpreter/functions.rs
@@ -2,14 +2,10 @@ use std::{cell::RefCell, rc::Rc};
 
 use itertools::izip;
 
-use crate::{
-    ast,
-    errors::SloxResult,
-    interpreter::{Environment, Interpretable, InterpreterFlowControl},
-    tokens::Token,
+use super::{
+    Callable, Environment, Interpretable, InterpreterFlowControl, InterpreterState, Value,
 };
-
-use super::{Callable, EnvironmentRef, Value};
+use crate::{ast, errors::SloxResult, tokens::Token};
 
 /// A function implemented in the Lox-ish language.
 #[derive(Debug)]
@@ -39,16 +35,28 @@ impl Callable for Function {
         self.params.len()
     }
 
-    fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value> {
+    fn call(&self, es: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> {
         assert_eq!(arguments.len(), self.arity());
-        let param_env = Environment::create_child(environment);
+        let param_env = InterpreterState {
+            environment: Environment::create_child(&es.environment),
+            globals: es.globals.clone(),
+            variables: es.variables,
+        };
         for (arg, value) in izip!(self.params.iter(), arguments.into_iter()) {
-            param_env.borrow_mut().define(arg, Some(value)).unwrap();
+            param_env
+                .environment
+                .borrow_mut()
+                .define(arg, Some(value))
+                .unwrap();
         }
 
-        let child = Environment::create_child(&param_env);
+        let mut child = InterpreterState {
+            environment: Environment::create_child(&param_env.environment),
+            globals: es.globals.clone(),
+            variables: es.variables,
+        };
         for stmt in self.body.iter() {
-            let result = stmt.interpret(&child)?;
+            let result = stmt.interpret(&mut child)?;
             match result {
                 InterpreterFlowControl::Result(_) => (),
                 InterpreterFlowControl::Return(v) => return Ok(v),
diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs
index 6f54712..3cb1dc7 100644
--- a/src/interpreter/interpretable.rs
+++ b/src/interpreter/interpretable.rs
@@ -11,13 +11,26 @@ use crate::{
 /// Evaluate an interpretable, returning its value.
 pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> {
     let env = Rc::new(RefCell::new(Environment::default()));
-    ast.interpret(&env).map(|v| v.result())
+    let mut state = InterpreterState{
+        environment: env.clone(),
+        globals: env,
+        variables: &vars,
+    };
+    ast.interpret(&mut state).map(|v| v.result())
 }
 
 /* ------- *
  * HELPERS *
  * ------- */
 
+/// The state of the interpreter.
+#[derive(Debug)]
+pub(super) struct InterpreterState<'a> {
+    pub(super) globals: EnvironmentRef,
+    pub(super) environment: EnvironmentRef,
+    pub(super) variables: &'a ResolvedVariables,
+}
+
 /// Interpreter flow control, which may be either a value, a loop break or a
 /// loop continuation.
 #[derive(Debug)]
@@ -62,7 +75,7 @@ pub(super) type InterpreterResult = SloxResult<InterpreterFlowControl>;
 
 /// An Interpretable can be evaluated and will return a value.
 pub(super) trait Interpretable {
-    fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult;
+    fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult;
 }
 
 /// Generate an error with a static message.
@@ -79,9 +92,9 @@ fn error<T>(token: &Token, message: &str) -> SloxResult<T> {
  * ----------------------------- */
 
 impl Interpretable for ast::ProgramNode {
-    fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
+    fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
         for stmt in self.0.iter() {
-            stmt.interpret(environment)?;
+            stmt.interpret(es)?;
         }
         Ok(InterpreterFlowControl::default())
     }
@@ -92,32 +105,32 @@ impl Interpretable for ast::ProgramNode {
  * ------------------------------- */
 
 impl Interpretable for ast::StmtNode {
-    fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
+    fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
         match self {
-            ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(environment, name, expr),
+            ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(es, name, expr),
             ast::StmtNode::FunDecl { name, params, body } => {
-                self.on_fun_decl(environment, name, params, body)
+                self.on_fun_decl(es, name, params, body)
             }
-            ast::StmtNode::Expression(expr) => expr.interpret(environment),
-            ast::StmtNode::Print(expr) => self.on_print(environment, expr),
-            ast::StmtNode::Block(statements) => self.on_block(environment, statements),
+            ast::StmtNode::Expression(expr) => expr.interpret(es),
+            ast::StmtNode::Print(expr) => self.on_print(es, expr),
+            ast::StmtNode::Block(statements) => self.on_block(es, statements),
             ast::StmtNode::If {
                 condition,
                 then_branch,
                 else_branch,
-            } => self.on_if_statement(environment, condition, then_branch, else_branch),
+            } => self.on_if_statement(es, condition, then_branch, else_branch),
             ast::StmtNode::Loop {
                 label,
                 condition,
                 body,
                 after_body,
-            } => self.on_loop_statement(environment, label, condition, body, after_body),
+            } => self.on_loop_statement(es, label, condition, body, after_body),
             ast::StmtNode::LoopControl {
                 is_break,
                 loop_name,
             } => self.on_loop_control_statemement(*is_break, loop_name),
             ast::StmtNode::Return { token: _, value } => {
-                self.on_return_statement(environment, value)
+                self.on_return_statement(es, value)
             }
         }
     }
@@ -125,8 +138,8 @@ impl Interpretable for ast::StmtNode {
 
 impl ast::StmtNode {
     /// Handle the `print` statement.
-    fn on_print(&self, environment: &EnvironmentRef, expr: &ast::ExprNode) -> InterpreterResult {
-        let value = expr.interpret(environment)?.result();
+    fn on_print(&self, es: &mut InterpreterState, expr: &ast::ExprNode) -> InterpreterResult {
+        let value = expr.interpret(es)?.result();
         let output = match value {
             Value::Nil => String::from("nil"),
             Value::Boolean(true) => String::from("true"),
@@ -142,38 +155,42 @@ impl ast::StmtNode {
     /// Handle a variable declaration.
     fn on_var_decl(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         name: &Token,
         initializer: &Option<ast::ExprNode>,
     ) -> InterpreterResult {
         let variable = match initializer {
-            Some(expr) => Some(expr.interpret(environment)?.result()),
+            Some(expr) => Some(expr.interpret(es)?.result()),
             None => None,
         };
-        environment.borrow_mut().define(name, variable)?;
+        es.environment.borrow_mut().define(name, variable)?;
         Ok(InterpreterFlowControl::default())
     }
 
     /// Handle a function declaration.
     fn on_fun_decl(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         name: &Token,
         params: &[Token],
         body: &[ast::StmtNode],
     ) -> InterpreterResult {
         let fun = Function::new(Some(name), params, body);
-        environment
+        es.environment
             .borrow_mut()
             .define(name, Some(Value::Callable(fun)))?;
         Ok(InterpreterFlowControl::default())
     }
 
     /// Execute the contents of a block.
-    fn on_block(&self, environment: &EnvironmentRef, stmts: &[ast::StmtNode]) -> InterpreterResult {
-        let child = Environment::create_child(environment);
+    fn on_block(&self, es: &mut InterpreterState, stmts: &[ast::StmtNode]) -> InterpreterResult {
+        let mut child = InterpreterState{
+            environment: Environment::create_child(&es.environment),
+            globals: es.globals.clone(),
+            variables: es.variables,
+        };
         for stmt in stmts.iter() {
-            let result = stmt.interpret(&child)?;
+            let result = stmt.interpret(&mut child)?;
             if result.is_flow_control() {
                 return Ok(result);
             }
@@ -184,15 +201,15 @@ impl ast::StmtNode {
     /// Execute an if statement.
     fn on_if_statement(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         condition: &ast::ExprNode,
         then_branch: &ast::StmtNode,
         else_branch: &Option<Box<ast::StmtNode>>,
     ) -> InterpreterResult {
-        if condition.interpret(environment)?.result().is_truthy() {
-            then_branch.interpret(environment)
+        if condition.interpret(es)?.result().is_truthy() {
+            then_branch.interpret(es)
         } else if let Some(else_stmt) = else_branch {
-            else_stmt.interpret(environment)
+            else_stmt.interpret(es)
         } else {
             Ok(InterpreterFlowControl::default())
         }
@@ -201,15 +218,15 @@ impl ast::StmtNode {
     /// Execute a while statement.
     fn on_loop_statement(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         label: &Option<Token>,
         condition: &ast::ExprNode,
         body: &ast::StmtNode,
         after_body: &Option<Box<ast::StmtNode>>,
     ) -> InterpreterResult {
         let ln = label.as_ref().map(|token| token.lexeme.clone());
-        while condition.interpret(environment)?.result().is_truthy() {
-            let result = body.interpret(environment)?;
+        while condition.interpret(es)?.result().is_truthy() {
+            let result = body.interpret(es)?;
             match &result {
                 InterpreterFlowControl::Result(_) => (),
                 InterpreterFlowControl::Continue(lv) if lv == &ln => (),
@@ -217,7 +234,7 @@ impl ast::StmtNode {
                 _ => return Ok(result),
             }
             if let Some(stmt) = after_body {
-                let result = stmt.interpret(environment)?;
+                let result = stmt.interpret(es)?;
                 match &result {
                     InterpreterFlowControl::Result(_) => (),
                     InterpreterFlowControl::Continue(lv) if lv == &ln => (),
@@ -246,12 +263,12 @@ impl ast::StmtNode {
     /// Execute a return statement.
     fn on_return_statement(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         value: &Option<ast::ExprNode>,
     ) -> InterpreterResult {
         let rv = match value {
             None => Value::Nil,
-            Some(expr) => expr.interpret(environment)?.result(),
+            Some(expr) => expr.interpret(es)?.result(),
         };
         Ok(InterpreterFlowControl::Return(rv))
     }
@@ -262,32 +279,32 @@ impl ast::StmtNode {
  * -------------------------------- */
 
 impl Interpretable for ast::ExprNode {
-    fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
+    fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
         match self {
             ast::ExprNode::Assignment { name, value } => {
-                let value = value.interpret(environment)?.result();
-                environment.borrow_mut().assign(name, value)?;
+                let value = value.interpret(es)?.result();
+                es.environment.borrow_mut().assign(name, value)?;
                 Ok(InterpreterFlowControl::default())
             }
             ast::ExprNode::Logical {
                 left,
                 operator,
                 right,
-            } => self.on_logic(environment, left, operator, right),
+            } => self.on_logic(es, left, operator, right),
             ast::ExprNode::Binary {
                 left,
                 operator,
                 right,
-            } => self.on_binary(environment, left, operator, right),
-            ast::ExprNode::Unary { operator, right } => self.on_unary(environment, operator, right),
-            ast::ExprNode::Grouping { expression } => expression.interpret(environment),
+            } => self.on_binary(es, left, operator, right),
+            ast::ExprNode::Unary { operator, right } => self.on_unary(es, operator, right),
+            ast::ExprNode::Grouping { expression } => expression.interpret(es),
             ast::ExprNode::Litteral { value } => self.on_litteral(value),
-            ast::ExprNode::Variable { name } => Ok(environment.borrow().get(name)?.into()),
+            ast::ExprNode::Variable { name } => Ok(es.environment.borrow().get(name)?.into()),
             ast::ExprNode::Call {
                 callee,
                 right_paren,
                 arguments,
-            } => self.on_call(environment, callee, right_paren, arguments),
+            } => self.on_call(es, callee, right_paren, arguments),
             ast::ExprNode::Lambda { params, body } => {
                 Ok(Value::Callable(Function::new(None, params, body)).into())
             }
@@ -299,31 +316,31 @@ impl ast::ExprNode {
     /// Evaluate a logical operator.
     fn on_logic(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         left: &ast::ExprNode,
         operator: &Token,
         right: &ast::ExprNode,
     ) -> InterpreterResult {
-        let left_value = left.interpret(environment)?.result();
+        let left_value = left.interpret(es)?.result();
         if operator.token_type == TokenType::Or && left_value.is_truthy()
             || operator.token_type == TokenType::And && !left_value.is_truthy()
         {
             Ok(left_value.into())
         } else {
-            right.interpret(environment)
+            right.interpret(es)
         }
     }
 
     /// Evaluate a binary operator.
     fn on_binary(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         left: &ast::ExprNode,
         operator: &Token,
         right: &ast::ExprNode,
     ) -> InterpreterResult {
-        let left_value = left.interpret(environment)?.result();
-        let right_value = right.interpret(environment)?.result();
+        let left_value = left.interpret(es)?.result();
+        let right_value = right.interpret(es)?.result();
         match operator.token_type {
             TokenType::Plus => match (left_value, right_value) {
                 (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
@@ -388,11 +405,11 @@ impl ast::ExprNode {
     /// Evaluate an unary operator.
     fn on_unary(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         operator: &Token,
         right: &ast::ExprNode,
     ) -> InterpreterResult {
-        let right_value = right.interpret(environment)?.result();
+        let right_value = right.interpret(es)?.result();
         match operator.token_type {
             TokenType::Minus => {
                 if let Value::Number(n) = right_value {
@@ -427,16 +444,16 @@ impl ast::ExprNode {
     /// Evaluate a function call.
     fn on_call(
         &self,
-        environment: &EnvironmentRef,
+        es: &mut InterpreterState,
         callee: &ast::ExprNode,
         right_paren: &Token,
         arguments: &Vec<ast::ExprNode>,
     ) -> InterpreterResult {
-        let callee = callee.interpret(environment)?.result();
+        let callee = callee.interpret(es)?.result();
         let arg_values = {
             let mut v = Vec::with_capacity(arguments.len());
             for argument in arguments.iter() {
-                v.push(argument.interpret(environment)?.result());
+                v.push(argument.interpret(es)?.result());
             }
             v
         };
@@ -453,7 +470,7 @@ impl ast::ExprNode {
                     ),
                 ))
             } else {
-                Ok(callable.call(environment, arg_values)?.into())
+                Ok(callable.call(es, arg_values)?.into())
             }
         } else {
             error(right_paren, "can only call functions and classes")
diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs
index 007ff4a..a5ca495 100644
--- a/src/interpreter/mod.rs
+++ b/src/interpreter/mod.rs
@@ -5,7 +5,7 @@ mod interpretable;
 mod native_fn;
 mod value;
 
-pub use callable::{Callable, CallableRef};
-pub use environment::*;
+pub(self) use callable::{Callable, CallableRef};
+pub(self) use environment::*;
 pub use interpretable::*;
 pub use value::*;
diff --git a/src/interpreter/native_fn.rs b/src/interpreter/native_fn.rs
index 988edb1..a0e8719 100644
--- a/src/interpreter/native_fn.rs
+++ b/src/interpreter/native_fn.rs
@@ -6,7 +6,7 @@ use std::{
 
 use crate::errors::SloxResult;
 
-use super::{Callable, CallableRef, EnvironmentRef, Value};
+use super::{Callable, CallableRef, InterpreterState, Value};
 
 /* ----------- *
  *   clock()   *
@@ -20,7 +20,7 @@ impl Callable for Clock {
         0
     }
 
-    fn call(&self, _environment: &EnvironmentRef, _arguments: Vec<Value>) -> SloxResult<Value> {
+    fn call(&self, _environment: &mut InterpreterState, _arguments: Vec<Value>) -> SloxResult<Value> {
         let now = SystemTime::now();
         let since_epoch = now
             .duration_since(UNIX_EPOCH)
@@ -35,6 +35,6 @@ impl ToString for Clock {
     }
 }
 
-pub(crate) fn clock() -> CallableRef {
+pub(super) fn clock() -> CallableRef {
     Rc::new(RefCell::new(Clock {}))
 }