From 3117dfeac5bb2991980856221873d1cac72dacad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Sat, 7 Jan 2023 08:24:27 +0100
Subject: [PATCH] Interpreter - Lookups and assignment based on resolver
 results

  * Does not work. Using pointers was a bad idea.
---
 src/interpreter/environment.rs   | 39 +++++++++++++++++++++-----------
 src/interpreter/interpretable.rs | 20 ++++++++++++----
 2 files changed, 41 insertions(+), 18 deletions(-)

diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs
index 7c1c473..02ff2f0 100644
--- a/src/interpreter/environment.rs
+++ b/src/interpreter/environment.rs
@@ -82,21 +82,11 @@ impl Environment {
     }
 
     /// Access a variable at a specified distance in a parent environment.
-    pub fn get_at(&self, distance: usize, name: &Token) -> Value {
-        self.ancestor(distance)
-            .values
-            .get(&name.lexeme as &str)
-            .unwrap()
-            .unwrap()
-            .clone()
-    }
-
-    /// Access the ancestor environment at a specified distance from the current one.
-    fn ancestor(&self, distance: usize) -> &Self {
+    pub fn get_at(&self, distance: usize, name: &Token) -> SloxResult<Value> {
         if distance == 0 {
-            &self
+            self.get(name)
         } else {
-            self.enclosing.unwrap().borrow().ancestor(distance - 1)
+            self.ancestor(distance).borrow().get(name)
         }
     }
 
@@ -116,4 +106,27 @@ impl Environment {
             }
         }
     }
+
+    /// Set a variable at a specified distance in a parent environment.
+    pub fn assign_at(&mut self, distance: usize, name: &Token, value: Value) -> SloxResult<()> {
+        if distance == 0 {
+            self.assign(name, value)
+        } else {
+            self.ancestor(distance).borrow_mut().assign(name, value)
+        }
+    }
+
+    /// Read an ancestor from the chain of enclosing environments.
+    fn ancestor(&self, distance: usize) -> EnvironmentRef {
+        let mut ancestor = self.enclosing.clone().expect("ancestor() called at root");
+        for _ in 1..distance {
+            let ap = ancestor
+                .borrow()
+                .enclosing
+                .clone()
+                .expect("ancestor() called with too high a distance");
+            ancestor = ap;
+        }
+        ancestor
+    }
 }
diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs
index c28ceed..f5c547f 100644
--- a/src/interpreter/interpretable.rs
+++ b/src/interpreter/interpretable.rs
@@ -49,10 +49,20 @@ impl<'a> InterpreterState<'a> {
         }
     }
 
-    fn lookup_var(&self, name: &Token, expr : &ast::ExprNode) -> SloxResult<Value> {
+    fn lookup_var(&self, name: &Token, expr: &ast::ExprNode) -> SloxResult<Value> {
         match self.variables.get(&(expr as *const ast::ExprNode)) {
-            Some(distance) => Ok(self.environment.borrow().get_at(*distance, name)),
-            None => self.environment.borrow().get(name),
+            Some(distance) => self.environment.borrow().get_at(*distance, name),
+            None => self.globals.borrow().get(name),
+        }
+    }
+
+    fn assign_var(&self, name: &Token, expr: &ast::ExprNode, value: Value) -> SloxResult<()> {
+        match self.variables.get(&(expr as *const ast::ExprNode)) {
+            Some(distance) => self
+                .environment
+                .borrow_mut()
+                .assign_at(*distance, name, value),
+            None => self.globals.borrow_mut().assign(name, value),
         }
     }
 }
@@ -303,7 +313,7 @@ impl Interpretable for ast::ExprNode {
         match self {
             ast::ExprNode::Assignment { name, value } => {
                 let value = value.interpret(es)?.result();
-                es.environment.borrow_mut().assign(name, value)?;
+                es.assign_var(name, &self, value)?;
                 Ok(InterpreterFlowControl::default())
             }
             ast::ExprNode::Logical {
@@ -319,7 +329,7 @@ impl Interpretable for ast::ExprNode {
             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(es.environment.borrow().get(name)?.into()),
+            ast::ExprNode::Variable { name } => Ok(es.lookup_var(name, &self)?.into()),
             ast::ExprNode::Call {
                 callee,
                 right_paren,