Classes - Support using members from superclasses
* This includes methods, as per the book, but also getters and setters
This commit is contained in:
parent
9307fde4b3
commit
896b0deef7
1 changed files with 41 additions and 10 deletions
|
@ -106,15 +106,38 @@ impl Callable for ClassRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to find some member, identified by a key, inside a class hierarchy. If the member is
|
||||||
|
/// found, the specified function is exectued with the member as its argument, and its return value
|
||||||
|
/// is passed back to the caller. If the member is not found, None is returned.
|
||||||
|
fn with_class_member<F, Rt>(class: &ClassRef, mb_key: &ClassMemberKey, f: F) -> Option<Rt>
|
||||||
|
where
|
||||||
|
F: FnOnce(&Function) -> Rt,
|
||||||
|
{
|
||||||
|
let mut cls = class.clone();
|
||||||
|
loop {
|
||||||
|
if let Some(member) = cls.borrow().members.get(&mb_key) {
|
||||||
|
return Some(f(member));
|
||||||
|
}
|
||||||
|
let nclr = if let Some(sc) = &cls.borrow().superclass {
|
||||||
|
sc.clone()
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
cls = nclr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PropertyCarrier for ClassRef {
|
impl PropertyCarrier for ClassRef {
|
||||||
fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult<Value> {
|
fn get(&self, itpr_state: &mut InterpreterState, name: &Token) -> SloxResult<Value> {
|
||||||
let class = self.borrow();
|
let class = self.borrow();
|
||||||
|
|
||||||
// Check for a property getter and execute it if found.
|
// Check for a property getter and execute it if found.
|
||||||
let mut mb_key = (ClassMemberKind::Getter, true, name.lexeme.clone());
|
let mut mb_key = (ClassMemberKind::Getter, true, name.lexeme.clone());
|
||||||
if let Some(getter) = class.members.get(&mb_key) {
|
if let Some(value) = with_class_member(self, &mb_key, |getter| {
|
||||||
let bound_method = bind_method(getter, Value::from(self.clone()));
|
let bound_method = bind_method(getter, Value::from(self.clone()));
|
||||||
return bound_method.call(itpr_state, vec![]);
|
return bound_method.call(itpr_state, vec![]);
|
||||||
|
}) {
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an actual field.
|
// Check for an actual field.
|
||||||
|
@ -124,9 +147,11 @@ impl PropertyCarrier for ClassRef {
|
||||||
|
|
||||||
// Check for a method.
|
// Check for a method.
|
||||||
mb_key.0 = ClassMemberKind::Method;
|
mb_key.0 = ClassMemberKind::Method;
|
||||||
if let Some(method) = class.members.get(&mb_key) {
|
if let Some(method) = with_class_member(self, &mb_key, |method| {
|
||||||
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));
|
||||||
|
}) {
|
||||||
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(SloxError::with_token(
|
Err(SloxError::with_token(
|
||||||
|
@ -141,12 +166,13 @@ impl PropertyCarrier for ClassRef {
|
||||||
|
|
||||||
// Check for a property setter.
|
// Check for a property setter.
|
||||||
let mb_key = (ClassMemberKind::Setter, true, name.lexeme.clone());
|
let mb_key = (ClassMemberKind::Setter, true, name.lexeme.clone());
|
||||||
if let Some(setter) = class.members.get(&mb_key) {
|
let lookup = with_class_member(self, &mb_key, |setter| {
|
||||||
// Bind and execute the property setter
|
|
||||||
let bound_method = bind_method(setter, Value::from(self.clone()));
|
let bound_method = bind_method(setter, Value::from(self.clone()));
|
||||||
bound_method
|
bound_method
|
||||||
.call(itpr_state, vec![value])
|
.call(itpr_state, vec![value.clone()])
|
||||||
.expect("failed to execute setter");
|
.expect("failed to execute setter");
|
||||||
|
});
|
||||||
|
if lookup.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,9 +206,11 @@ impl PropertyCarrier for InstanceRef {
|
||||||
|
|
||||||
// Check for a property getter and execute it if found.
|
// Check for a property getter and execute it if found.
|
||||||
let mut mb_key = (ClassMemberKind::Getter, false, name.lexeme.clone());
|
let mut mb_key = (ClassMemberKind::Getter, false, name.lexeme.clone());
|
||||||
if let Some(getter) = instance.class.borrow().members.get(&mb_key) {
|
if let Some(value) = with_class_member(&instance.class, &mb_key, |getter| {
|
||||||
let bound_method = bind_method(getter, Value::from(self.clone()));
|
let bound_method = bind_method(getter, Value::from(self.clone()));
|
||||||
return bound_method.call(itpr_state, vec![]);
|
return bound_method.call(itpr_state, vec![]);
|
||||||
|
}) {
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an actual field.
|
// Check for an actual field.
|
||||||
|
@ -192,9 +220,11 @@ impl PropertyCarrier for InstanceRef {
|
||||||
|
|
||||||
// Check for a method.
|
// Check for a method.
|
||||||
mb_key.0 = ClassMemberKind::Method;
|
mb_key.0 = ClassMemberKind::Method;
|
||||||
if let Some(method) = instance.class.borrow().members.get(&mb_key) {
|
if let Some(method) = with_class_member(&instance.class, &mb_key, |method| {
|
||||||
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));
|
||||||
|
}) {
|
||||||
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(SloxError::with_token(
|
Err(SloxError::with_token(
|
||||||
|
@ -209,12 +239,13 @@ impl PropertyCarrier for InstanceRef {
|
||||||
|
|
||||||
// Check for a property setter.
|
// Check for a property setter.
|
||||||
let mb_key = (ClassMemberKind::Setter, false, name.lexeme.clone());
|
let mb_key = (ClassMemberKind::Setter, false, name.lexeme.clone());
|
||||||
if let Some(setter) = instance.class.borrow().members.get(&mb_key) {
|
let lookup = with_class_member(&instance.class, &mb_key, |setter| {
|
||||||
// Bind and execute the property setter
|
|
||||||
let bound_method = bind_method(setter, Value::from(self.clone()));
|
let bound_method = bind_method(setter, Value::from(self.clone()));
|
||||||
bound_method
|
bound_method
|
||||||
.call(itpr_state, vec![value])
|
.call(itpr_state, vec![value.clone()])
|
||||||
.expect("failed to execute setter");
|
.expect("failed to execute setter");
|
||||||
|
});
|
||||||
|
if lookup.is_some() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue