Interpreter - Refactored getter/setter support as a trait on an instance ref
This commit is contained in:
parent
8b19f546c8
commit
09b4b4e688
3 changed files with 48 additions and 25 deletions
|
@ -7,6 +7,13 @@ use crate::{
|
||||||
|
|
||||||
use super::{functions::Function, Callable, InterpreterState, Value};
|
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<Value>;
|
||||||
|
fn set(&self, name: &Token, value: Value);
|
||||||
|
}
|
||||||
|
|
||||||
/// A Lox class.
|
/// A Lox class.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Class {
|
pub struct Class {
|
||||||
|
@ -24,10 +31,19 @@ pub struct Instance {
|
||||||
fields: RefCell<HashMap<String, Value>>,
|
fields: RefCell<HashMap<String, Value>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper type used to refer to instances.
|
||||||
|
pub type InstanceRef = Rc<RefCell<Instance>>;
|
||||||
|
|
||||||
/* -------------------- *
|
/* -------------------- *
|
||||||
* Class implementation *
|
* Class implementation *
|
||||||
* -------------------- */
|
* -------------------- */
|
||||||
|
|
||||||
|
fn bind_method(method: &Function, this_value: Value) -> Function {
|
||||||
|
let bm = method.copy_with_child_env();
|
||||||
|
bm.env().set("this", this_value);
|
||||||
|
bm
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -57,7 +73,7 @@ impl Callable for ClassRef {
|
||||||
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| {
|
|instance| {
|
||||||
let bound_init = instance.bind_method(init, &inst_value);
|
let bound_init = bind_method(init, inst_value.clone());
|
||||||
bound_init.call(itpr_state, arguments)
|
bound_init.call(itpr_state, arguments)
|
||||||
},
|
},
|
||||||
|| panic!("Instance is not an instance, wtf"),
|
|| panic!("Instance is not an instance, wtf"),
|
||||||
|
@ -79,13 +95,22 @@ impl Instance {
|
||||||
fields: RefCell::new(HashMap::default()),
|
fields: RefCell::new(HashMap::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn get(&self, this_value: &Value, name: &Token) -> SloxResult<Value> {
|
impl Display for Instance {
|
||||||
if let Some(value) = self.fields.borrow().get(&name.lexeme) {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_fmt(format_args!("<Instance of {}>", self.class.borrow(),))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PropertyCarrier for InstanceRef {
|
||||||
|
fn get(&self, name: &Token) -> SloxResult<Value> {
|
||||||
|
let instance = self.borrow();
|
||||||
|
if let Some(value) = instance.fields.borrow().get(&name.lexeme) {
|
||||||
return Ok(value.clone());
|
return Ok(value.clone());
|
||||||
}
|
}
|
||||||
if let Some(method) = self.class.borrow().methods.get(&name.lexeme) {
|
if let Some(method) = instance.class.borrow().methods.get(&name.lexeme) {
|
||||||
let bound_method = self.bind_method(method, this_value);
|
let bound_method = bind_method(method, Value::from(self.clone()));
|
||||||
return Ok(Value::from(bound_method));
|
return Ok(Value::from(bound_method));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,19 +121,11 @@ impl Instance {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set(&self, name: &Token, value: Value) {
|
fn set(&self, name: &Token, value: Value) {
|
||||||
self.fields.borrow_mut().insert(name.lexeme.clone(), value);
|
let instance = self.borrow();
|
||||||
}
|
instance
|
||||||
|
.fields
|
||||||
fn bind_method(&self, method: &Function, this_value: &Value) -> Function {
|
.borrow_mut()
|
||||||
let bm = method.copy_with_child_env();
|
.insert(name.lexeme.clone(), value);
|
||||||
bm.env().set("this", this_value.clone());
|
|
||||||
bm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Instance {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_fmt(format_args!("<Instance of {}>", self.class.borrow(),))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
tokens::{Token, TokenType},
|
tokens::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{classes::Class, functions::Function, Environment, EnvironmentRef, Value};
|
use super::{classes::{Class, PropertyCarrier}, functions::Function, Environment, EnvironmentRef, Value};
|
||||||
|
|
||||||
/// Evaluate an interpretable, returning its value.
|
/// Evaluate an interpretable, returning its value.
|
||||||
pub fn evaluate(ast: &ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> {
|
pub fn evaluate(ast: &ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> {
|
||||||
|
@ -541,7 +541,7 @@ impl ExprNode {
|
||||||
) -> 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_instance(
|
||||||
|inst| inst.get(&instance, &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"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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},
|
classes::{Class, ClassRef, Instance, InstanceRef},
|
||||||
functions::Function,
|
functions::Function,
|
||||||
native_fn::NativeFunction,
|
native_fn::NativeFunction,
|
||||||
Callable,
|
Callable,
|
||||||
|
@ -22,7 +22,7 @@ pub enum Object {
|
||||||
NativeFunction(NativeFunction),
|
NativeFunction(NativeFunction),
|
||||||
LoxFunction(Function),
|
LoxFunction(Function),
|
||||||
Class(ClassRef),
|
Class(ClassRef),
|
||||||
Instance(Instance),
|
Instance(InstanceRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------- *
|
/* -------------------- *
|
||||||
|
@ -63,7 +63,7 @@ impl Value {
|
||||||
/// contain an instance, an error function will be called instead.
|
/// contain an instance, an error function will be called instead.
|
||||||
pub fn with_instance<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
|
pub fn with_instance<Fok, Ferr, Rt>(&self, fok: Fok, ferr: Ferr) -> Rt
|
||||||
where
|
where
|
||||||
Fok: FnOnce(&Instance) -> Rt,
|
Fok: FnOnce(&InstanceRef) -> Rt,
|
||||||
Ferr: FnOnce() -> Rt,
|
Ferr: FnOnce() -> Rt,
|
||||||
{
|
{
|
||||||
let obj = match self {
|
let obj = match self {
|
||||||
|
@ -127,6 +127,12 @@ impl From<ClassRef> for Value {
|
||||||
|
|
||||||
impl From<Instance> for Value {
|
impl From<Instance> for Value {
|
||||||
fn from(value: Instance) -> Self {
|
fn from(value: Instance) -> Self {
|
||||||
|
Value::from(Rc::new(RefCell::new(value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<InstanceRef> for Value {
|
||||||
|
fn from(value: InstanceRef) -> Self {
|
||||||
Value::Object(Rc::new(RefCell::new(Object::Instance(value))))
|
Value::Object(Rc::new(RefCell::new(Object::Instance(value))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +147,7 @@ impl Display for Object {
|
||||||
Object::NativeFunction(func) => func.fmt(f),
|
Object::NativeFunction(func) => func.fmt(f),
|
||||||
Object::LoxFunction(func) => func.fmt(f),
|
Object::LoxFunction(func) => func.fmt(f),
|
||||||
Object::Class(cls) => cls.borrow().fmt(f),
|
Object::Class(cls) => cls.borrow().fmt(f),
|
||||||
Object::Instance(inst) => inst.fmt(f),
|
Object::Instance(inst) => inst.borrow().fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue