2025-02-13 12:29:31 +01:00
|
|
|
use crate::{
|
|
|
|
callable::{Callable, CallingError},
|
|
|
|
environment::Environment,
|
2025-05-25 16:04:00 +02:00
|
|
|
instance::Instance,
|
2025-02-13 12:29:31 +01:00
|
|
|
interpreter::Interpreter,
|
|
|
|
statement::Statement,
|
|
|
|
token::Token,
|
|
|
|
value::Value,
|
|
|
|
};
|
|
|
|
use core::fmt::Debug;
|
|
|
|
use std::{cell::RefCell, fmt::Display, rc::Rc};
|
|
|
|
|
2025-05-26 12:24:35 +02:00
|
|
|
/// A Lox function with name, parameters, body, and closure environment.
|
2025-02-13 12:29:31 +01:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Function {
|
|
|
|
pub name: Token,
|
2025-05-25 16:04:00 +02:00
|
|
|
pub is_initializer: bool,
|
2025-02-13 12:29:31 +01:00
|
|
|
pub params: Vec<Token>,
|
|
|
|
pub body: Vec<Statement>,
|
|
|
|
pub closure: Rc<RefCell<Environment>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Function {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self.name.lexeme)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Function {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.name == other.name && self.params == other.params && self.body == other.body
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Callable for Function {
|
|
|
|
fn name(&self) -> String {
|
|
|
|
self.name.lexeme.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn arity(&self) -> usize {
|
|
|
|
self.params.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(&self, interpreter: &mut Interpreter, args: Vec<Value>) -> Result<Value, CallingError> {
|
|
|
|
let mut env = Environment::with_enclosing(self.closure.clone());
|
|
|
|
for (i, param) in self.params.iter().enumerate() {
|
|
|
|
let arg = args
|
|
|
|
.get(i)
|
|
|
|
.ok_or(CallingError::ArgumentMismatch(
|
|
|
|
self.params.len(),
|
|
|
|
args.len(),
|
|
|
|
))?
|
|
|
|
.clone();
|
|
|
|
env.define(param.lexeme.clone(), arg);
|
|
|
|
}
|
|
|
|
|
2025-05-25 16:04:00 +02:00
|
|
|
Ok(interpreter
|
2025-02-13 12:29:31 +01:00
|
|
|
.block(&self.body, env)
|
|
|
|
.map_err(|e| CallingError::CallInterpretationFailed(e.to_string()))?
|
2025-05-25 16:04:00 +02:00
|
|
|
.unwrap_or(Value::Nil))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Function {
|
2025-05-26 12:24:35 +02:00
|
|
|
/// Bind a method to an instance, creating a new function with "this" defined in its environment.
|
|
|
|
/// This allows methods to access the instance they belong to.
|
2025-05-25 16:04:00 +02:00
|
|
|
pub fn bind(&self, instance: Rc<RefCell<Instance>>) -> Self {
|
|
|
|
let mut env = Environment::with_enclosing(self.closure.clone());
|
|
|
|
env.define("this".to_string(), Value::Instance(instance));
|
|
|
|
|
|
|
|
Self {
|
|
|
|
name: self.name.clone(),
|
|
|
|
is_initializer: self.is_initializer,
|
|
|
|
params: self.params.clone(),
|
|
|
|
body: self.body.clone(),
|
|
|
|
closure: Rc::new(RefCell::new(env)),
|
|
|
|
}
|
2025-02-13 12:29:31 +01:00
|
|
|
}
|
|
|
|
}
|