Interpreter - Class properties

This commit is contained in:
Emmanuel BENOîT 2023-01-12 07:39:12 +01:00
parent 09b4b4e688
commit 0ebe2e9f22
3 changed files with 55 additions and 5 deletions

View file

@ -19,6 +19,7 @@ pub trait PropertyCarrier {
pub struct Class { pub struct Class {
name: String, name: String,
methods: HashMap<String, Function>, methods: HashMap<String, Function>,
fields: RefCell<HashMap<String, Value>>,
} }
/// Classes are mostly used through references. /// Classes are mostly used through references.
@ -47,7 +48,11 @@ fn bind_method(method: &Function, this_value: Value) -> Function {
impl Class { impl Class {
/// Create a new class, specifying its name. /// Create a new class, specifying its name.
pub fn new(name: String, methods: HashMap<String, Function>) -> Self { pub fn new(name: String, methods: HashMap<String, Function>) -> Self {
Self { name, methods } Self {
name,
methods,
fields: RefCell::new(HashMap::default()),
}
} }
} }
@ -72,7 +77,7 @@ impl Callable for ClassRef {
let inst_value = Value::from(Instance::new(self.clone())); let inst_value = Value::from(Instance::new(self.clone()));
if let Some(init) = self.borrow().methods.get("init") { if let Some(init) = self.borrow().methods.get("init") {
inst_value.with_instance( inst_value.with_instance(
|instance| { |_| {
let bound_init = bind_method(init, inst_value.clone()); let bound_init = bind_method(init, inst_value.clone());
bound_init.call(itpr_state, arguments) bound_init.call(itpr_state, arguments)
}, },
@ -84,6 +89,32 @@ impl Callable for ClassRef {
} }
} }
impl PropertyCarrier for ClassRef {
fn get(&self, name: &Token) -> SloxResult<Value> {
let class = self.borrow();
if let Some(value) = class.fields.borrow().get(&name.lexeme) {
return Ok(value.clone());
}
/*
if let Some(method) = class.methods.get(&name.lexeme) {
let bound_method = bind_method(method, Value::from(self.clone()));
return Ok(Value::from(bound_method));
}
*/
Err(SloxError::with_token(
ErrorKind::Runtime,
name,
"undefined property".to_owned(),
))
}
fn set(&self, name: &Token, value: Value) {
let class = self.borrow();
class.fields.borrow_mut().insert(name.lexeme.clone(), value);
}
}
/* ----------------------- * /* ----------------------- *
* Instance implementation * * Instance implementation *
* ----------------------- */ * ----------------------- */

View file

@ -540,7 +540,7 @@ impl ExprNode {
get_expr: &GetExpr, get_expr: &GetExpr,
) -> InterpreterResult { ) -> InterpreterResult {
let instance = get_expr.instance.interpret(itpr_state)?.result(); let instance = get_expr.instance.interpret(itpr_state)?.result();
instance.with_instance( instance.with_property_carrier(
|inst| inst.get(&get_expr.name).map(|v| v.into()), |inst| inst.get(&get_expr.name).map(|v| v.into()),
|| error(&get_expr.name, "only instances have properties"), || error(&get_expr.name, "only instances have properties"),
) )
@ -553,7 +553,7 @@ impl ExprNode {
set_expr: &SetExpr, set_expr: &SetExpr,
) -> InterpreterResult { ) -> InterpreterResult {
let instance = set_expr.instance.interpret(itpr_state)?.result(); let instance = set_expr.instance.interpret(itpr_state)?.result();
instance.with_instance( 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(&set_expr.name, value.clone());

View file

@ -1,7 +1,7 @@
use std::{cell::RefCell, fmt::Display, rc::Rc}; use std::{cell::RefCell, fmt::Display, rc::Rc};
use super::{ use super::{
classes::{Class, ClassRef, Instance, InstanceRef}, classes::{Class, ClassRef, Instance, InstanceRef, PropertyCarrier},
functions::Function, functions::Function,
native_fn::NativeFunction, native_fn::NativeFunction,
Callable, Callable,
@ -75,6 +75,25 @@ impl Value {
_ => ferr(), _ => ferr(),
} }
} }
/// Run some code against a property carrier value (either an instance
/// or a class). If the value does not contain such an object, an error
/// function will be called instead.
pub fn with_property_carrier<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
where
Fok: FnOnce(&dyn PropertyCarrier) -> Rt,
Ferr: FnOnce() -> Rt,
{
let obj = match self {
Value::Object(obj_ref) => obj_ref.borrow(),
_ => return ferr(),
};
match &*obj {
Object::Class(cls) => fok(cls),
Object::Instance(inst) => fok(inst),
_ => ferr(),
}
}
} }
impl PartialEq for Value { impl PartialEq for Value {