Interpreter - Class properties
This commit is contained in:
parent
09b4b4e688
commit
0ebe2e9f22
3 changed files with 55 additions and 5 deletions
|
@ -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 *
|
||||||
* ----------------------- */
|
* ----------------------- */
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue