From 3e4aea0d78a1eaba08dfdc653f709817446c347b Mon Sep 17 00:00:00 2001
From: Emmanuel Benoit <tseeker@nocternity.net>
Date: Mon, 9 Jan 2023 11:19:42 +0100
Subject: [PATCH] Interpreter - Working bound methods

---
 src/interpreter/classes.rs       | 32 ++++++++++++++++++++++++++++----
 src/interpreter/interpretable.rs |  2 +-
 src/interpreter/value.rs         | 11 ++++++++++-
 3 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/src/interpreter/classes.rs b/src/interpreter/classes.rs
index 494d0a8..acf0a70 100644
--- a/src/interpreter/classes.rs
+++ b/src/interpreter/classes.rs
@@ -1,4 +1,9 @@
-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},
@@ -77,12 +82,16 @@ impl Instance {
         }
     }
 
-    pub(super) fn get(&self, name: &Token) -> SloxResult<Value> {
+    pub(super) fn get(&self, this_value: &Value, name: &Token) -> SloxResult<Value> {
         if let Some(value) = self.fields.get(&name.lexeme) {
             return Ok(value.clone());
         }
-        if let Some(method) = self.class.borrow().methods.get(&name.lexeme) {
-            return Ok(Value::from(method.clone()));
+        if self.class.borrow().methods.get(&name.lexeme).is_some() {
+            let bound_method = BoundMethod {
+                instance: this_value.clone(),
+                method: name.lexeme.clone(),
+            };
+            return Ok(Value::from(bound_method));
         }
 
         Err(SloxError::with_token(
@@ -150,6 +159,21 @@ impl Callable for BoundMethod {
             .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/interpretable.rs b/src/interpreter/interpretable.rs
index fa35f8b..e781ad7 100644
--- a/src/interpreter/interpretable.rs
+++ b/src/interpreter/interpretable.rs
@@ -539,7 +539,7 @@ impl ExprNode {
     ) -> InterpreterResult {
         let instance = get_expr.instance.interpret(itpr_state)?.result();
         instance.with_instance(
-            |instance| instance.get(&get_expr.name).map(|v| v.into()),
+            |inst| inst.get(&instance, &get_expr.name).map(|v| v.into()),
             || error(&get_expr.name, "only instances have properties"),
         )
     }
diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs
index 7f1b8cd..0de565a 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},
+    classes::{Class, ClassRef, Instance, BoundMethod},
     functions::Function,
     native_fn::NativeFunction,
     Callable,
@@ -23,6 +23,7 @@ pub enum Object {
     LoxFunction(Function),
     Class(ClassRef),
     Instance(Instance),
+    BoundMethod(BoundMethod),
 }
 
 /* -------------------- *
@@ -56,6 +57,7 @@ impl Value {
             Object::LoxFunction(func) => fok(func),
             Object::Class(class) => fok(class),
             Object::Instance(_) => ferr(),
+            Object::BoundMethod(bm) => fok(bm),
         }
     }
 
@@ -148,6 +150,12 @@ 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 *
  * --------------------- */
@@ -159,6 +167,7 @@ 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),
         }
     }
 }