use std::{collections::HashMap, marker::PhantomData}; use crate::{ env::Env, statement::Statement, value::{FromValue, Value}, }; mod function_impl; #[derive(Debug, Clone, Copy)] enum FunctionType { Native, Interpreter, } #[derive(Default)] pub struct FunctionMap(HashMap, FunctionType)>); impl FunctionMap { pub fn new() -> Self { Default::default() } pub fn insert_native(&mut self, name: S, f: F) where S: ToString, P: 'static, F: 'static + NativeFunction

, { self.0.insert( name.to_string(), (Box::new(f.into_function()), FunctionType::Native), ); } pub fn insert_interpreter(&mut self, name: &str, params: Vec, body: Vec) { self.0.insert( name.to_string(), ( Box::new(InterpreterFunction::new(params, body)), FunctionType::Interpreter, ), ); } pub fn call(&self, name: &str, env: &Env, args: &[Value]) -> Result { let (f, t) = self .0 .get(name) .ok_or_else(|| format!("Function {} not found", name))?; println!("Calling {:?} function {}", t, name); f.execute(env, self, args) } } pub trait NativeFunction

: Sized { fn native_execute(&self, env: &Env, args: &[Value]) -> Result; fn into_function(self) -> IntoFunction { IntoFunction::new(self) } } pub struct IntoFunction { func: F, _phantom: PhantomData

, } impl IntoFunction { fn new(func: F) -> Self { IntoFunction { func, _phantom: PhantomData, } } } impl, P> Function for IntoFunction { fn execute(&self, env: &Env, _: &FunctionMap, args: &[Value]) -> Result { self.func.native_execute(env, args) } } pub struct InterpreterFunction { parameters: Vec, body: Vec, } impl InterpreterFunction { pub fn new(parameters: Vec, body: Vec) -> Self { InterpreterFunction { parameters, body } } } impl Function for InterpreterFunction { fn execute(&self, env: &Env, map: &FunctionMap, args: &[Value]) -> Result { let sub_env = Env::new_with_parent(env); for (name, value) in self.parameters.iter().zip(args) { sub_env.set(name, value.clone()); } for stmt in self.body.iter() { stmt.eval(&sub_env, map); } Ok(Value::Nothing) } } pub trait Function { fn execute(&self, env: &Env, map: &FunctionMap, args: &[Value]) -> Result; }