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::{
|
use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
|
||||||
cell::RefCell,
|
|
||||||
collections::HashMap,
|
|
||||||
fmt::Display,
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
errors::{ErrorKind, SloxError, SloxResult},
|
errors::{ErrorKind, SloxError, SloxResult},
|
||||||
|
interpreter::EnvironmentRef,
|
||||||
tokens::{Token, TokenType},
|
tokens::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{functions::Function, Callable, InterpreterState, Value};
|
use super::{functions::Function, Callable, Environment, InterpreterState, Value};
|
||||||
|
|
||||||
/// A Lox class.
|
/// A Lox class.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -86,11 +82,8 @@ impl Instance {
|
||||||
if let Some(value) = self.fields.get(&name.lexeme) {
|
if let Some(value) = self.fields.get(&name.lexeme) {
|
||||||
return Ok(value.clone());
|
return Ok(value.clone());
|
||||||
}
|
}
|
||||||
if self.class.borrow().methods.get(&name.lexeme).is_some() {
|
if let Some(method) = self.class.borrow().methods.get(&name.lexeme) {
|
||||||
let bound_method = BoundMethod {
|
let bound_method = self.bind_method(method, this_value);
|
||||||
instance: this_value.clone(),
|
|
||||||
method: name.lexeme.clone(),
|
|
||||||
};
|
|
||||||
return Ok(Value::from(bound_method));
|
return Ok(Value::from(bound_method));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,16 +98,10 @@ impl Instance {
|
||||||
self.fields.insert(name.lexeme.clone(), value);
|
self.fields.insert(name.lexeme.clone(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_method<F, Rt>(&self, name: &str, f: F) -> Rt
|
fn bind_method(&self, method: &Function, this_value: &Value) -> Function {
|
||||||
where
|
let bm = method.copy_with_child_env();
|
||||||
F: FnOnce(&Function) -> Rt,
|
bm.env().set("this", this_value.clone());
|
||||||
{
|
bm
|
||||||
let cls = self.class.borrow();
|
|
||||||
let method = cls
|
|
||||||
.methods
|
|
||||||
.get(name)
|
|
||||||
.expect(&format!("Method {} not found", name));
|
|
||||||
f(method)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,57 +110,3 @@ impl Display for Instance {
|
||||||
f.write_fmt(format_args!("<Instance of {}>", self.class.borrow(),))
|
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.
|
/// Read an ancestor from the chain of enclosing environments.
|
||||||
fn ancestor(&self, distance: usize) -> EnvironmentRef {
|
fn ancestor(&self, distance: usize) -> EnvironmentRef {
|
||||||
let mut ancestor = self.enclosing.clone().expect("ancestor() called at root");
|
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;
|
use itertools::izip;
|
||||||
|
|
||||||
|
@ -32,8 +32,17 @@ impl Function {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn name(&self) -> Option<&Token> {
|
pub(super) fn copy_with_child_env(&self) -> Self {
|
||||||
self.name.as_ref()
|
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 std::{cell::RefCell, fmt::Display, rc::Rc};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
classes::{Class, ClassRef, Instance, BoundMethod},
|
classes::{Class, ClassRef, Instance},
|
||||||
functions::Function,
|
functions::Function,
|
||||||
native_fn::NativeFunction,
|
native_fn::NativeFunction,
|
||||||
Callable,
|
Callable,
|
||||||
|
@ -23,7 +23,6 @@ pub enum Object {
|
||||||
LoxFunction(Function),
|
LoxFunction(Function),
|
||||||
Class(ClassRef),
|
Class(ClassRef),
|
||||||
Instance(Instance),
|
Instance(Instance),
|
||||||
BoundMethod(BoundMethod),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------- *
|
/* -------------------- *
|
||||||
|
@ -57,7 +56,6 @@ impl Value {
|
||||||
Object::LoxFunction(func) => fok(func),
|
Object::LoxFunction(func) => fok(func),
|
||||||
Object::Class(class) => fok(class),
|
Object::Class(class) => fok(class),
|
||||||
Object::Instance(_) => ferr(),
|
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 *
|
* Object implementation *
|
||||||
* --------------------- */
|
* --------------------- */
|
||||||
|
@ -167,7 +159,6 @@ impl Display for Object {
|
||||||
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.fmt(f),
|
||||||
Object::BoundMethod(bm) => bm.fmt(f),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue