From b01ae10d09ffdf9781fa264cb51ddc70d244127f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Tue, 17 Jan 2023 07:13:09 +0100
Subject: [PATCH] Classes - Refactored super handling

---
 src/interpreter/classes.rs | 96 ++++++++++++++++++--------------------
 1 file changed, 45 insertions(+), 51 deletions(-)

diff --git a/src/interpreter/classes.rs b/src/interpreter/classes.rs
index 593573b..ccfc295 100644
--- a/src/interpreter/classes.rs
+++ b/src/interpreter/classes.rs
@@ -48,9 +48,9 @@ pub struct Instance {
 /// Helper type used to refer to instances.
 pub type InstanceRef = Rc<RefCell<Instance>>;
 
-/* -------------------- *
- * Class implementation *
- * -------------------- */
+/* --------------- *
+ * Various helpers *
+ * --------------- */
 
 lazy_static! {
     static ref INIT_METHOD_KEY: ClassMemberKey =
@@ -63,6 +63,46 @@ fn bind_method(method: &Function, this_value: Value) -> Function {
     bm
 }
 
+fn get_super<T>(
+    on_ref: &T,
+    is_static: bool,
+    itpr_state: &mut InterpreterState,
+    super_expr: &SuperExpr,
+    distance: usize,
+) -> SloxResult<Value>
+where
+    T: Clone + Into<Value>,
+{
+    let mb_key = (
+        ClassMemberKind::Method,
+        is_static,
+        super_expr.method.lexeme.clone(),
+    );
+
+    let sc_value = itpr_state
+        .environment
+        .borrow()
+        .get_at(distance, &super_expr.keyword.token)?;
+    let class = sc_value.as_class_ref().expect("class reference expected");
+
+    if let Some(method) = with_class_member(&class, &mb_key, |method| {
+        let bound_method = bind_method(method, on_ref.clone().into());
+        Ok(Value::from(bound_method))
+    }) {
+        method
+    } else {
+        Err(SloxError::with_token(
+            ErrorKind::Runtime,
+            &super_expr.method,
+            "undefined property".to_owned(),
+        ))
+    }
+}
+
+/* -------------------- *
+ * Class implementation *
+ * -------------------- */
+
 impl Class {
     /// Create a new class, specifying its name.
     pub fn new(
@@ -192,30 +232,7 @@ impl PropertyCarrier for ClassRef {
         super_expr: &SuperExpr,
         distance: usize,
     ) -> SloxResult<Value> {
-        let mb_key = (
-            ClassMemberKind::Method,
-            true,
-            super_expr.method.lexeme.clone(),
-        );
-
-        let sc_value = itpr_state
-            .environment
-            .borrow()
-            .get_at(distance, &super_expr.keyword.token)?;
-        let class = sc_value.as_class_ref().expect("class reference expected");
-
-        if let Some(method) = with_class_member(&class, &mb_key, |method| {
-            let bound_method = bind_method(method, Value::from(self.clone()));
-            Ok(Value::from(bound_method))
-        }) {
-            method
-        } else {
-            Err(SloxError::with_token(
-                ErrorKind::Runtime,
-                &super_expr.method,
-                "undefined property".to_owned(),
-            ))
-        }
+        get_super(self, true, itpr_state, super_expr, distance)
     }
 }
 
@@ -300,29 +317,6 @@ impl PropertyCarrier for InstanceRef {
         super_expr: &SuperExpr,
         distance: usize,
     ) -> SloxResult<Value> {
-        let mb_key = (
-            ClassMemberKind::Method,
-            false,
-            super_expr.method.lexeme.clone(),
-        );
-
-        let sc_value = itpr_state
-            .environment
-            .borrow()
-            .get_at(distance, &super_expr.keyword.token)?;
-        let class = sc_value.as_class_ref().expect("class reference expected");
-
-        if let Some(method) = with_class_member(&class, &mb_key, |method| {
-            let bound_method = bind_method(method, Value::from(self.clone()));
-            Ok(Value::from(bound_method))
-        }) {
-            method
-        } else {
-            Err(SloxError::with_token(
-                ErrorKind::Runtime,
-                &super_expr.method,
-                "undefined property".to_owned(),
-            ))
-        }
+        get_super(self, false, itpr_state, super_expr, distance)
     }
 }