robinpath 0.2.0

RobinPath - A lightweight, fast scripting language interpreter for automation and data processing
Documentation
use crate::ast::Stmt;
use crate::value::Value;
use indexmap::IndexMap;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;

pub type BuiltinFn = Box<dyn Fn(&[Value], Option<&BuiltinCallback>) -> Result<Value, String> + Send + Sync>;
pub type BuiltinCallback = Box<dyn Fn(&[Value]) -> Result<Value, String>>;

#[derive(Clone)]
pub struct UserFunction {
    pub name: String,
    pub param_names: Vec<String>,
    pub body: Vec<Stmt>,
}

pub struct EventHandler {
    pub event_name: String,
    pub body: Vec<Stmt>,
}

pub struct Environment {
    pub variables: IndexMap<String, Value>,
    pub functions: HashMap<String, UserFunction>,
    pub builtins: HashMap<String, Arc<BuiltinFn>>,
    pub constants: HashSet<String>,
    pub current_module: Option<String>,
    pub used_modules: HashSet<String>,
    pub output: Vec<String>,
    pub event_handlers: Vec<EventHandler>,
    pub metadata: HashMap<String, IndexMap<String, Value>>,
}

impl Environment {
    pub fn new() -> Self {
        Self {
            variables: IndexMap::new(),
            functions: HashMap::new(),
            builtins: HashMap::new(),
            constants: HashSet::new(),
            current_module: None,
            used_modules: HashSet::new(),
            output: Vec::new(),
            event_handlers: Vec::new(),
            metadata: HashMap::new(),
        }
    }

    pub fn register_builtin(
        &mut self,
        name: &str,
        func: impl Fn(&[Value], Option<&BuiltinCallback>) -> Result<Value, String> + Send + Sync + 'static,
    ) {
        self.builtins.insert(name.to_string(), Arc::new(Box::new(func)));
    }

    pub fn register_function(&mut self, func: UserFunction) {
        self.functions.insert(func.name.clone(), func);
    }

    pub fn resolve_function_name(&self, name: &str) -> Option<String> {
        // Direct lookup
        if self.builtins.contains_key(name) || self.functions.contains_key(name) {
            return Some(name.to_string());
        }

        // Try with current module prefix
        if let Some(ref module) = self.current_module {
            let qualified = format!("{}.{}", module, name);
            if self.builtins.contains_key(&qualified) {
                return Some(qualified);
            }
        }

        // Try all used modules
        for module in &self.used_modules {
            let qualified = format!("{}.{}", module, name);
            if self.builtins.contains_key(&qualified) {
                return Some(qualified);
            }
        }

        None
    }
}

impl Default for Environment {
    fn default() -> Self {
        Self::new()
    }
}