Interpreter - Getter/setter execution
This commit is contained in:
parent
c372979009
commit
9627f588d2
2 changed files with 61 additions and 13 deletions
|
@ -13,8 +13,8 @@ use super::{functions::Function, Callable, InterpreterState, Value};
|
||||||
/// This trait represents an object on which getters and setters
|
/// This trait represents an object on which getters and setters
|
||||||
/// must be supported.
|
/// must be supported.
|
||||||
pub trait PropertyCarrier {
|
pub trait PropertyCarrier {
|
||||||
fn get(&self, name: &Token) -> SloxResult<Value>;
|
fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult<Value>;
|
||||||
fn set(&self, name: &Token, value: Value);
|
fn set(&self, itpr_state: &mut InterpreterState, name: &Token, value: Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The key for the table of class members.
|
/// The key for the table of class members.
|
||||||
|
@ -101,12 +101,23 @@ impl Callable for ClassRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyCarrier for ClassRef {
|
impl PropertyCarrier for ClassRef {
|
||||||
fn get(&self, name: &Token) -> SloxResult<Value> {
|
fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult<Value> {
|
||||||
let class = self.borrow();
|
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) {
|
if let Some(value) = class.fields.borrow().get(&name.lexeme) {
|
||||||
return Ok(value.clone());
|
return Ok(value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for a method.
|
||||||
|
mb_key.0 = ClassMemberKind::Method;
|
||||||
if let Some(method) = class.members.get(&mb_key) {
|
if let Some(method) = class.members.get(&mb_key) {
|
||||||
let bound_method = bind_method(method, Value::from(self.clone()));
|
let bound_method = bind_method(method, Value::from(self.clone()));
|
||||||
return Ok(Value::from(bound_method));
|
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();
|
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);
|
class.fields.borrow_mut().insert(name.lexeme.clone(), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,12 +169,23 @@ impl Display for Instance {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PropertyCarrier for InstanceRef {
|
impl PropertyCarrier for InstanceRef {
|
||||||
fn get(&self, name: &Token) -> SloxResult<Value> {
|
fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult<Value> {
|
||||||
let instance = self.borrow();
|
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) {
|
if let Some(value) = instance.fields.borrow().get(&name.lexeme) {
|
||||||
return Ok(value.clone());
|
return Ok(value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for a method.
|
||||||
|
mb_key.0 = ClassMemberKind::Method;
|
||||||
if let Some(method) = instance.class.borrow().members.get(&mb_key) {
|
if let Some(method) = instance.class.borrow().members.get(&mb_key) {
|
||||||
let bound_method = bind_method(method, Value::from(self.clone()));
|
let bound_method = bind_method(method, Value::from(self.clone()));
|
||||||
return Ok(Value::from(bound_method));
|
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();
|
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
|
instance
|
||||||
.fields
|
.fields
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
ClassDecl, ClassMemberDecl, ClassMemberKind, ExprNode, FunDecl, GetExpr, ProgramNode,
|
ClassDecl, ExprNode, FunDecl, GetExpr, ProgramNode,
|
||||||
SetExpr, StmtNode, VariableExpr,
|
SetExpr, StmtNode, VariableExpr,
|
||||||
},
|
},
|
||||||
errors::{ErrorKind, SloxError, SloxResult},
|
errors::{ErrorKind, SloxError, SloxResult},
|
||||||
|
@ -556,8 +556,8 @@ impl ExprNode {
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let instance = get_expr.instance.interpret(itpr_state)?.result();
|
let instance = get_expr.instance.interpret(itpr_state)?.result();
|
||||||
instance.with_property_carrier(
|
instance.with_property_carrier(
|
||||||
|inst| inst.get(&get_expr.name).map(|v| v.into()),
|
|inst| inst.get(itpr_state, &get_expr.name).map(|v| v.into()),
|
||||||
|| error(&get_expr.name, "only instances have properties"),
|
|| error(&get_expr.name, "this object doesn't have properties"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,10 +571,10 @@ impl ExprNode {
|
||||||
instance.with_property_carrier(
|
instance.with_property_carrier(
|
||||||
|instance| {
|
|instance| {
|
||||||
let value = set_expr.value.interpret(itpr_state)?.result();
|
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())
|
Ok(value.into())
|
||||||
},
|
},
|
||||||
|| error(&set_expr.name, "only instances have properties"),
|
|| error(&set_expr.name, "this object doesn't have properties"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue