From 9627f588d2c55cbb35dca37d1ce3fb9fcb15820d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 14 Jan 2023 16:07:40 +0100 Subject: [PATCH] Interpreter - Getter/setter execution --- src/interpreter/classes.rs | 64 ++++++++++++++++++++++++++++---- src/interpreter/interpretable.rs | 10 ++--- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/interpreter/classes.rs b/src/interpreter/classes.rs index a7cf1ba..7f946e8 100644 --- a/src/interpreter/classes.rs +++ b/src/interpreter/classes.rs @@ -13,8 +13,8 @@ use super::{functions::Function, Callable, InterpreterState, Value}; /// This trait represents an object on which getters and setters /// must be supported. pub trait PropertyCarrier { - fn get(&self, name: &Token) -> SloxResult; - fn set(&self, name: &Token, value: Value); + fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult; + fn set(&self, itpr_state: &mut InterpreterState, name: &Token, value: Value); } /// The key for the table of class members. @@ -101,12 +101,23 @@ impl Callable for ClassRef { } impl PropertyCarrier for ClassRef { - fn get(&self, name: &Token) -> SloxResult { + fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult { let class = self.borrow(); - let mut mb_key = (ClassMemberKind::Method, true, name.lexeme.clone()); + + // Check for a property getter and execute it if found. + let mut mb_key = (ClassMemberKind::Getter, true, name.lexeme.clone()); + if let Some(getter) = class.members.get(&mb_key) { + let bound_method = bind_method(getter, Value::from(self.clone())); + return bound_method.call(itpr_state, vec![]); + } + + // Check for an actual field. if let Some(value) = class.fields.borrow().get(&name.lexeme) { return Ok(value.clone()); } + + // Check for a method. + mb_key.0 = ClassMemberKind::Method; if let Some(method) = class.members.get(&mb_key) { let bound_method = bind_method(method, Value::from(self.clone())); return Ok(Value::from(bound_method)); @@ -119,8 +130,21 @@ impl PropertyCarrier for ClassRef { )) } - fn set(&self, name: &Token, value: Value) { + fn set(&self, itpr_state: &mut InterpreterState, name: &Token, value: Value) { let class = self.borrow(); + + // Check for a property setter. + let mb_key = (ClassMemberKind::Setter, false, name.lexeme.clone()); + if let Some(setter) = class.members.get(&mb_key) { + // Bind and execute the property setter + let bound_method = bind_method(setter, Value::from(self.clone())); + bound_method + .call(itpr_state, vec![value]) + .expect("failed to execute setter"); + return; + } + + // Set the property directly class.fields.borrow_mut().insert(name.lexeme.clone(), value); } } @@ -145,12 +169,23 @@ impl Display for Instance { } impl PropertyCarrier for InstanceRef { - fn get(&self, name: &Token) -> SloxResult { + fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult { let instance = self.borrow(); - let mut mb_key = (ClassMemberKind::Method, false, name.lexeme.clone()); + + // Check for a property getter and execute it if found. + let mut mb_key = (ClassMemberKind::Getter, false, name.lexeme.clone()); + if let Some(getter) = instance.class.borrow().members.get(&mb_key) { + let bound_method = bind_method(getter, Value::from(self.clone())); + return bound_method.call(itpr_state, vec![]); + } + + // Check for an actual field. if let Some(value) = instance.fields.borrow().get(&name.lexeme) { return Ok(value.clone()); } + + // Check for a method. + mb_key.0 = ClassMemberKind::Method; if let Some(method) = instance.class.borrow().members.get(&mb_key) { let bound_method = bind_method(method, Value::from(self.clone())); return Ok(Value::from(bound_method)); @@ -163,8 +198,21 @@ impl PropertyCarrier for InstanceRef { )) } - fn set(&self, name: &Token, value: Value) { + fn set(&self, itpr_state: &mut InterpreterState, name: &Token, value: Value) { let instance = self.borrow(); + + // Check for a property setter. + let mb_key = (ClassMemberKind::Setter, false, name.lexeme.clone()); + if let Some(setter) = instance.class.borrow().members.get(&mb_key) { + // Bind and execute the property setter + let bound_method = bind_method(setter, Value::from(self.clone())); + bound_method + .call(itpr_state, vec![value]) + .expect("failed to execute setter"); + return; + } + + // Set the property directly instance .fields .borrow_mut() diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs index e36db33..e120078 100644 --- a/src/interpreter/interpretable.rs +++ b/src/interpreter/interpretable.rs @@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc}; use crate::{ ast::{ - ClassDecl, ClassMemberDecl, ClassMemberKind, ExprNode, FunDecl, GetExpr, ProgramNode, + ClassDecl, ExprNode, FunDecl, GetExpr, ProgramNode, SetExpr, StmtNode, VariableExpr, }, errors::{ErrorKind, SloxError, SloxResult}, @@ -556,8 +556,8 @@ impl ExprNode { ) -> InterpreterResult { let instance = get_expr.instance.interpret(itpr_state)?.result(); instance.with_property_carrier( - |inst| inst.get(&get_expr.name).map(|v| v.into()), - || error(&get_expr.name, "only instances have properties"), + |inst| inst.get(itpr_state, &get_expr.name).map(|v| v.into()), + || error(&get_expr.name, "this object doesn't have properties"), ) } @@ -571,10 +571,10 @@ impl ExprNode { instance.with_property_carrier( |instance| { let value = set_expr.value.interpret(itpr_state)?.result(); - instance.set(&set_expr.name, value.clone()); + instance.set(itpr_state, &set_expr.name, value.clone()); Ok(value.into()) }, - || error(&set_expr.name, "only instances have properties"), + || error(&set_expr.name, "this object doesn't have properties"), ) } }