use std::rc::Rc; use crate::environment::Environment; use super::{symbol::Symbol, Node, NodeEnum, Precedence}; pub type NativeFunctionType = fn(&Vec>, env: &mut Environment) -> Result, String>; #[derive(Debug, Clone, PartialEq, PartialOrd)] pub enum FunctionType { Native(&'static str, NativeFunctionType), UserFunction(Rc, Vec), } #[derive(Debug, Clone, PartialEq, PartialOrd)] pub struct Function { function: FunctionType, } impl Node for Function { fn evaluate(&self, _env: &mut Environment) -> Result, String> { Ok(Rc::new(self.clone().into())) // Ok(Rc::new( // Self { // function: match &self.function { // FunctionType::Native(_, _) => self.function.clone(), // FunctionType::UserFunction(node_enum, symbols) => { // env.disable_calls(); // let evaluated = node_enum.evaluate(env)?; // env.enable_calls(); // FunctionType::UserFunction(evaluated, symbols.clone()) // } // }, // } // .into(), // )) } fn as_string(&self, env: Option<&Environment>) -> String { match &self.function { FunctionType::Native(name, _) => format!("(Native Function `{name}`)"), FunctionType::UserFunction(body, args) => format!( "([{}] -> {})", args.iter() .map(|x| x.as_string(env)) .reduce(|acc, e| format!("{acc}, {e}")) .unwrap_or("[]".to_owned()), body.as_string(env) ), } } fn precedence(&self) -> Precedence { Precedence::Call } } impl Function { pub fn new(t: FunctionType) -> Rc { Rc::new(Self { function: t }.into()) } pub fn get_body(&self) -> &FunctionType { &self.function } }