From 16151bd3262d549859b0e8ed3d6a31c0cca21423 Mon Sep 17 00:00:00 2001
From: Emmanuel Benoit <tseeker@nocternity.net>
Date: Tue, 10 Jan 2023 09:03:57 +0100
Subject: [PATCH] Actually made "this" work in the interpreter

---
 src/interpreter/classes.rs     | 85 ++++------------------------------
 src/interpreter/environment.rs |  5 ++
 src/interpreter/functions.rs   | 15 ++++--
 src/interpreter/value.rs       | 11 +----
 4 files changed, 27 insertions(+), 89 deletions(-)

diff --git a/src/interpreter/classes.rs b/src/interpreter/classes.rs
index acf0a70..bde5c2d 100644
--- a/src/interpreter/classes.rs
+++ b/src/interpreter/classes.rs
@@ -1,16 +1,12 @@
-use std::{
-    cell::RefCell,
-    collections::HashMap,
-    fmt::Display,
-    rc::Rc,
-};
+use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
 
 use crate::{
     errors::{ErrorKind, SloxError, SloxResult},
+    interpreter::EnvironmentRef,
     tokens::{Token, TokenType},
 };
 
-use super::{functions::Function, Callable, InterpreterState, Value};
+use super::{functions::Function, Callable, Environment, InterpreterState, Value};
 
 /// A Lox class.
 #[derive(Debug, Clone)]
@@ -86,11 +82,8 @@ impl Instance {
         if let Some(value) = self.fields.get(&name.lexeme) {
             return Ok(value.clone());
         }
-        if self.class.borrow().methods.get(&name.lexeme).is_some() {
-            let bound_method = BoundMethod {
-                instance: this_value.clone(),
-                method: name.lexeme.clone(),
-            };
+        if let Some(method) = self.class.borrow().methods.get(&name.lexeme) {
+            let bound_method = self.bind_method(method, this_value);
             return Ok(Value::from(bound_method));
         }
 
@@ -105,16 +98,10 @@ impl Instance {
         self.fields.insert(name.lexeme.clone(), value);
     }
 
-    fn with_method<F, Rt>(&self, name: &str, f: F) -> Rt
-    where
-        F: FnOnce(&Function) -> Rt,
-    {
-        let cls = self.class.borrow();
-        let method = cls
-            .methods
-            .get(name)
-            .expect(&format!("Method {} not found", name));
-        f(method)
+    fn bind_method(&self, method: &Function, this_value: &Value) -> Function {
+        let bm = method.copy_with_child_env();
+        bm.env().set("this", this_value.clone());
+        bm
     }
 }
 
@@ -123,57 +110,3 @@ impl Display for Instance {
         f.write_fmt(format_args!("<Instance of {}>", self.class.borrow(),))
     }
 }
-
-/* --------------------------- *
- * Bound method implementation *
- * --------------------------- */
-
-impl BoundMethod {
-    fn with_method<F, Rt>(&self, f: F) -> Rt
-    where
-        F: FnOnce(&Function) -> Rt,
-    {
-        self.instance.with_instance(
-            |instance| instance.with_method(&self.method, f),
-            || panic!("Instance value does not contain an instance"),
-        )
-    }
-
-    fn this_token(&self) -> Token {
-        Token {
-            token_type: TokenType::This,
-            lexeme: "this".to_owned(),
-            line: self.with_method(|method| method.name().expect("Method has no name").line),
-        }
-    }
-}
-
-impl Callable for BoundMethod {
-    fn arity(&self) -> usize {
-        self.with_method(|m| m.arity())
-    }
-
-    fn call(&self, itpr_state: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> {
-        let mut this_env = InterpreterState::create_child(itpr_state);
-        this_env
-            .environment
-            .borrow_mut()
-            .define(&self.this_token(), Some(self.instance.clone()))?;
-        println!("{:?}", this_env.locals);
-        self.with_method(|m| m.call(&mut this_env, arguments))
-    }
-}
-
-impl Display for BoundMethod {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.instance.with_instance(
-            |instance| {
-                f.write_fmt(format_args!(
-                    "<Bound method {} of {}>",
-                    self.method, instance
-                ))
-            },
-            || panic!("Instance value does not contain an instance"),
-        )
-    }
-}
diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs
index c8dbce2..b493d46 100644
--- a/src/interpreter/environment.rs
+++ b/src/interpreter/environment.rs
@@ -117,6 +117,11 @@ impl Environment {
         }
     }
 
+    /// Set a variable in an environment, directly, without any checks.
+    pub fn set(&mut self, name: &str, value: Value) {
+        self.values.insert(name.to_owned(), Some(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");
diff --git a/src/interpreter/functions.rs b/src/interpreter/functions.rs
index 1813719..23d98e2 100644
--- a/src/interpreter/functions.rs
+++ b/src/interpreter/functions.rs
@@ -1,4 +1,4 @@
-use std::fmt::Display;
+use std::{fmt::Display, cell::RefMut};
 
 use itertools::izip;
 
@@ -32,8 +32,17 @@ impl Function {
         }
     }
 
-    pub(super) fn name(&self) -> Option<&Token> {
-        self.name.as_ref()
+    pub(super) fn copy_with_child_env(&self) -> Self {
+        Self {
+            name: self.name.clone(),
+            params: self.params.clone(),
+            body: self.body.clone(),
+            env: Environment::create_child(&self.env),
+        }
+    }
+
+    pub(super) fn env(&self) -> RefMut<Environment> {
+        self.env.borrow_mut()
     }
 }
 
diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs
index 0de565a..7f1b8cd 100644
--- a/src/interpreter/value.rs
+++ b/src/interpreter/value.rs
@@ -1,7 +1,7 @@
 use std::{cell::RefCell, fmt::Display, rc::Rc};
 
 use super::{
-    classes::{Class, ClassRef, Instance, BoundMethod},
+    classes::{Class, ClassRef, Instance},
     functions::Function,
     native_fn::NativeFunction,
     Callable,
@@ -23,7 +23,6 @@ pub enum Object {
     LoxFunction(Function),
     Class(ClassRef),
     Instance(Instance),
-    BoundMethod(BoundMethod),
 }
 
 /* -------------------- *
@@ -57,7 +56,6 @@ impl Value {
             Object::LoxFunction(func) => fok(func),
             Object::Class(class) => fok(class),
             Object::Instance(_) => ferr(),
-            Object::BoundMethod(bm) => fok(bm),
         }
     }
 
@@ -150,12 +148,6 @@ impl From<Instance> for Value {
     }
 }
 
-impl From<BoundMethod> for Value {
-    fn from(value: BoundMethod) -> Self {
-        Value::Object(Rc::new(RefCell::new(Object::BoundMethod(value))))
-    }
-}
-
 /* --------------------- *
  * Object implementation *
  * --------------------- */
@@ -167,7 +159,6 @@ impl Display for Object {
             Object::LoxFunction(func) => func.fmt(f),
             Object::Class(cls) => cls.borrow().fmt(f),
             Object::Instance(inst) => inst.fmt(f),
-            Object::BoundMethod(bm) => bm.fmt(f),
         }
     }
 }