use std::fmt::{Debug, Display}; use std::rc::Rc; use rlox2_frontend::parser::Stmt; use crate::value::HeapedValue; use super::environment::{Environment, Scope}; use super::interpret::EvalResult; use super::{Runtime, Value}; #[derive(Debug, Clone)] pub struct LoxFunction { name: String, closure: Scope, param_names: Vec, body: Box, } impl LoxFunction { pub fn new(name: impl Into, closure: Scope, param_names: Vec, body: Stmt) -> Rc { let name = name.into(); let body = Box::new(body); let fun = LoxFunction { name, closure, param_names, body, }; Rc::new(fun) } pub fn name(&self) -> &str { &self.name } pub fn closure(&self) -> &Scope { &self.closure } pub fn param_names(&self) -> &[String] { &self.param_names } pub fn body(&self) -> &Stmt { &self.body } pub fn arity(&self) -> usize { self.param_names().len() } pub fn inject_closed_var(&mut self, name: impl Into, value: Value) { let name = name.into(); let heaped_value = HeapedValue::new(value); self.closure.insert(name, heaped_value); } } impl Display for LoxFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "", self.name) } } // slightly hacky: two functions are equal if they are stored at the same location // since a LoxFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers impl PartialEq for LoxFunction { fn eq(&self, other: &Self) -> bool { let self_ptr = self as *const LoxFunction; let other_ptr = other as *const LoxFunction; self_ptr == other_ptr } } /*====================================================================================================================*/ pub type ExternFunClosure = fn(Vec, &mut Environment) -> EvalResult; #[derive(Clone)] pub struct LoxExternFunction { name: String, arity: usize, closure: ExternFunClosure, } impl LoxExternFunction { pub fn new(name: impl Into, arity: usize, closure: ExternFunClosure) -> Self { let name = name.into(); LoxExternFunction { name, arity, closure } } pub fn name(&self) -> &str { &self.name } pub fn arity(&self) -> usize { self.arity } pub fn closure(&self) -> ExternFunClosure { self.closure } pub fn register(self, env: &mut Runtime) { let name = self.name.clone(); let fun = Value::extern_function(self); env.define_global(name, fun); } } impl Display for LoxExternFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "", self.name) } } impl Debug for LoxExternFunction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LoxExternFunction") .field("name", &self.name) .field("closure", &"") .finish() } } // slightly hacky: two extern functions are equal if they are stored at the same location // since a LoxExternFunction is always (supposed to be) behind an Rc anyways, we might as well compare their pointers impl PartialEq for LoxExternFunction { fn eq(&self, other: &Self) -> bool { let self_ptr = self as *const LoxExternFunction; let other_ptr = other as *const LoxExternFunction; self_ptr == other_ptr } }