From 16151bd3262d549859b0e8ed3d6a31c0cca21423 Mon Sep 17 00:00:00 2001 From: Emmanuel Benoit Date: Tue, 10 Jan 2023 09:03:57 +0100 Subject: [PATCH] Actually made "this" work in the interpreter --- src/interpreter/classes.rs | 85 ++++------------------------------ src/interpreter/environment.rs | 5 ++ src/interpreter/functions.rs | 15 ++++-- src/interpreter/value.rs | 11 +---- 4 files changed, 27 insertions(+), 89 deletions(-) diff --git a/src/interpreter/classes.rs b/src/interpreter/classes.rs index acf0a70..bde5c2d 100644 --- a/src/interpreter/classes.rs +++ b/src/interpreter/classes.rs @@ -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(&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!("", self.class.borrow(),)) } } - -/* --------------------------- * - * Bound method implementation * - * --------------------------- */ - -impl BoundMethod { - fn with_method(&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) -> SloxResult { - 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!( - "", - self.method, instance - )) - }, - || panic!("Instance value does not contain an instance"), - ) - } -} diff --git a/src/interpreter/environment.rs b/src/interpreter/environment.rs index c8dbce2..b493d46 100644 --- a/src/interpreter/environment.rs +++ b/src/interpreter/environment.rs @@ -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"); diff --git a/src/interpreter/functions.rs b/src/interpreter/functions.rs index 1813719..23d98e2 100644 --- a/src/interpreter/functions.rs +++ b/src/interpreter/functions.rs @@ -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 { + self.env.borrow_mut() } } diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs index 0de565a..7f1b8cd 100644 --- a/src/interpreter/value.rs +++ b/src/interpreter/value.rs @@ -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 for Value { } } -impl From 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), } } }