Interpreter - Initial implementation of bound methods

This commit is contained in:
Emmanuel BENOîT 2023-01-09 10:50:04 +01:00
parent a2986a1342
commit 542bc56aad
2 changed files with 63 additions and 1 deletions

View file

@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
use crate::{ use crate::{
errors::{ErrorKind, SloxError, SloxResult}, errors::{ErrorKind, SloxError, SloxResult},
tokens::Token, tokens::{Token, TokenType},
}; };
use super::{functions::Function, Callable, InterpreterState, Value}; use super::{functions::Function, Callable, InterpreterState, Value};
@ -24,6 +24,13 @@ pub struct Instance {
fields: HashMap<String, Value>, fields: HashMap<String, Value>,
} }
/// A method bound to an instance.
#[derive(Debug, Clone)]
pub struct BoundMethod {
instance: Value,
method: String,
}
/* -------------------- * /* -------------------- *
* Class implementation * * Class implementation *
* -------------------- */ * -------------------- */
@ -88,6 +95,18 @@ impl Instance {
pub(super) fn set(&mut self, name: &Token, value: Value) { pub(super) fn set(&mut self, name: &Token, value: Value) {
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
where
F: FnOnce(&Function) -> Rt,
{
let cls = self.class.borrow();
let method = cls
.methods
.get(name)
.expect(&format!("Method {} not found", name));
f(method)
}
} }
impl Display for Instance { impl Display for Instance {
@ -95,3 +114,42 @@ 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()))?;
self.with_method(|m| m.call(&mut this_env, arguments))
}
}

View file

@ -31,6 +31,10 @@ impl Function {
env: environment, env: environment,
} }
} }
pub(super) fn name(&self) -> Option<&Token> {
self.name.as_ref()
}
} }
impl Callable for Function { impl Callable for Function {