Interpreter - Initial implementation of bound methods
This commit is contained in:
parent
a2986a1342
commit
542bc56aad
2 changed files with 63 additions and 1 deletions
|
@ -2,7 +2,7 @@ use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc};
|
|||
|
||||
use crate::{
|
||||
errors::{ErrorKind, SloxError, SloxResult},
|
||||
tokens::Token,
|
||||
tokens::{Token, TokenType},
|
||||
};
|
||||
|
||||
use super::{functions::Function, Callable, InterpreterState, Value};
|
||||
|
@ -24,6 +24,13 @@ pub struct Instance {
|
|||
fields: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
/// A method bound to an instance.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoundMethod {
|
||||
instance: Value,
|
||||
method: String,
|
||||
}
|
||||
|
||||
/* -------------------- *
|
||||
* Class implementation *
|
||||
* -------------------- */
|
||||
|
@ -88,6 +95,18 @@ impl Instance {
|
|||
pub(super) fn set(&mut self, name: &Token, value: 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 {
|
||||
|
@ -95,3 +114,42 @@ 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()))?;
|
||||
self.with_method(|m| m.call(&mut this_env, arguments))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ impl Function {
|
|||
env: environment,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn name(&self) -> Option<&Token> {
|
||||
self.name.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Callable for Function {
|
||||
|
|
Loading…
Reference in a new issue