use crate::{ callable::{Callable, CallingError}, environment::Environment, instance::Instance, interpreter::Interpreter, statement::Statement, token::Token, value::Value, }; use core::fmt::Debug; use std::{cell::RefCell, fmt::Display, rc::Rc}; /// A lox function. #[derive(Debug, Clone)] pub struct Function { pub name: Token, pub is_initializer: bool, pub params: Vec, pub body: Vec, pub closure: Rc>, } 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) -> Result { 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); } Ok(interpreter .block(&self.body, env) .map_err(|e| CallingError::CallInterpretationFailed(e.to_string()))? .unwrap_or(Value::Nil)) } } impl Function { pub fn bind(&self, instance: Rc>) -> 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)), } } }