Actually made "this" work in the interpreter

This commit is contained in:
Emmanuel BENOîT 2023-01-10 09:03:57 +01:00
parent 3e4aea0d78
commit 16151bd326
4 changed files with 27 additions and 89 deletions

View file

@ -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"),
)
}
}

View file

@ -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");

View file

@ -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()
}
}

View file

@ -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),
}
}
}