Actually made "this" work in the interpreter
This commit is contained in:
parent
3e4aea0d78
commit
16151bd326
4 changed files with 27 additions and 89 deletions
|
@ -1,16 +1,12 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
errors::{ErrorKind, SloxError, SloxResult},
|
||||
interpreter::EnvironmentRef,
|
||||
tokens::{Token, TokenType},
|
||||
};
|
||||
|
||||
use super::{functions::Function, Callable, InterpreterState, Value};
|
||||
use super::{functions::Function, Callable, Environment, InterpreterState, Value};
|
||||
|
||||
/// A Lox class.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -86,11 +82,8 @@ impl Instance {
|
|||
if let Some(value) = self.fields.get(&name.lexeme) {
|
||||
return Ok(value.clone());
|
||||
}
|
||||
if self.class.borrow().methods.get(&name.lexeme).is_some() {
|
||||
let bound_method = BoundMethod {
|
||||
instance: this_value.clone(),
|
||||
method: name.lexeme.clone(),
|
||||
};
|
||||
if let Some(method) = self.class.borrow().methods.get(&name.lexeme) {
|
||||
let bound_method = self.bind_method(method, this_value);
|
||||
return Ok(Value::from(bound_method));
|
||||
}
|
||||
|
||||
|
@ -105,16 +98,10 @@ impl Instance {
|
|||
self.fields.insert(name.lexeme.clone(), value);
|
||||
}
|
||||
|
||||
fn with_method<F, Rt>(&self, name: &str, f: F) -> Rt
|
||||
where
|
||||
F: FnOnce(&Function) -> Rt,
|
||||
{
|
||||
let cls = self.class.borrow();
|
||||
let method = cls
|
||||
.methods
|
||||
.get(name)
|
||||
.expect(&format!("Method {} not found", name));
|
||||
f(method)
|
||||
fn bind_method(&self, method: &Function, this_value: &Value) -> Function {
|
||||
let bm = method.copy_with_child_env();
|
||||
bm.env().set("this", this_value.clone());
|
||||
bm
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,57 +110,3 @@ impl Display for Instance {
|
|||
f.write_fmt(format_args!("<Instance of {}>", self.class.borrow(),))
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------- *
|
||||
* Bound method implementation *
|
||||
* --------------------------- */
|
||||
|
||||
impl BoundMethod {
|
||||
fn with_method<F, Rt>(&self, f: F) -> Rt
|
||||
where
|
||||
F: FnOnce(&Function) -> Rt,
|
||||
{
|
||||
self.instance.with_instance(
|
||||
|instance| instance.with_method(&self.method, f),
|
||||
|| panic!("Instance value does not contain an instance"),
|
||||
)
|
||||
}
|
||||
|
||||
fn this_token(&self) -> Token {
|
||||
Token {
|
||||
token_type: TokenType::This,
|
||||
lexeme: "this".to_owned(),
|
||||
line: self.with_method(|method| method.name().expect("Method has no name").line),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Callable for BoundMethod {
|
||||
fn arity(&self) -> usize {
|
||||
self.with_method(|m| m.arity())
|
||||
}
|
||||
|
||||
fn call(&self, itpr_state: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> {
|
||||
let mut this_env = InterpreterState::create_child(itpr_state);
|
||||
this_env
|
||||
.environment
|
||||
.borrow_mut()
|
||||
.define(&self.this_token(), Some(self.instance.clone()))?;
|
||||
println!("{:?}", this_env.locals);
|
||||
self.with_method(|m| m.call(&mut this_env, arguments))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BoundMethod {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.instance.with_instance(
|
||||
|instance| {
|
||||
f.write_fmt(format_args!(
|
||||
"<Bound method {} of {}>",
|
||||
self.method, instance
|
||||
))
|
||||
},
|
||||
|| panic!("Instance value does not contain an instance"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,11 @@ impl Environment {
|
|||
}
|
||||
}
|
||||
|
||||
/// Set a variable in an environment, directly, without any checks.
|
||||
pub fn set(&mut self, name: &str, value: Value) {
|
||||
self.values.insert(name.to_owned(), Some(value));
|
||||
}
|
||||
|
||||
/// Read an ancestor from the chain of enclosing environments.
|
||||
fn ancestor(&self, distance: usize) -> EnvironmentRef {
|
||||
let mut ancestor = self.enclosing.clone().expect("ancestor() called at root");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::fmt::Display;
|
||||
use std::{fmt::Display, cell::RefMut};
|
||||
|
||||
use itertools::izip;
|
||||
|
||||
|
@ -32,8 +32,17 @@ impl Function {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn name(&self) -> Option<&Token> {
|
||||
self.name.as_ref()
|
||||
pub(super) fn copy_with_child_env(&self) -> Self {
|
||||
Self {
|
||||
name: self.name.clone(),
|
||||
params: self.params.clone(),
|
||||
body: self.body.clone(),
|
||||
env: Environment::create_child(&self.env),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn env(&self) -> RefMut<Environment> {
|
||||
self.env.borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cell::RefCell, fmt::Display, rc::Rc};
|
||||
|
||||
use super::{
|
||||
classes::{Class, ClassRef, Instance, BoundMethod},
|
||||
classes::{Class, ClassRef, Instance},
|
||||
functions::Function,
|
||||
native_fn::NativeFunction,
|
||||
Callable,
|
||||
|
@ -23,7 +23,6 @@ pub enum Object {
|
|||
LoxFunction(Function),
|
||||
Class(ClassRef),
|
||||
Instance(Instance),
|
||||
BoundMethod(BoundMethod),
|
||||
}
|
||||
|
||||
/* -------------------- *
|
||||
|
@ -57,7 +56,6 @@ impl Value {
|
|||
Object::LoxFunction(func) => fok(func),
|
||||
Object::Class(class) => fok(class),
|
||||
Object::Instance(_) => ferr(),
|
||||
Object::BoundMethod(bm) => fok(bm),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,12 +148,6 @@ impl From<Instance> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<BoundMethod> for Value {
|
||||
fn from(value: BoundMethod) -> Self {
|
||||
Value::Object(Rc::new(RefCell::new(Object::BoundMethod(value))))
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------- *
|
||||
* Object implementation *
|
||||
* --------------------- */
|
||||
|
@ -167,7 +159,6 @@ impl Display for Object {
|
|||
Object::LoxFunction(func) => func.fmt(f),
|
||||
Object::Class(cls) => cls.borrow().fmt(f),
|
||||
Object::Instance(inst) => inst.fmt(f),
|
||||
Object::BoundMethod(bm) => bm.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue