diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs
index 7ec42d8..7c1c473 100644
--- a/src/interpreter/environment.rs
+++ b/src/interpreter/environment.rs
@@ -81,6 +81,25 @@ 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 {
+        if distance == 0 {
+            &self
+        } else {
+            self.enclosing.unwrap().borrow().ancestor(distance - 1)
+        }
+    }
+
     /// Assign a value to an existing variable.
     pub fn assign(&mut self, name: &Token, value: Value) -> SloxResult<()> {
         if self.values.contains_key(&name.lexeme as &str) {
diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs
index 4d916a1..c28ceed 100644
--- a/src/interpreter/interpretable.rs
+++ b/src/interpreter/interpretable.rs
@@ -48,6 +48,13 @@ impl<'a> InterpreterState<'a> {
             variables: parent.variables,
         }
     }
+
+    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),
+        }
+    }
 }
 
 /// Interpreter flow control, which may be either a value, a loop break or a