ion-core 0.2.1

Embeddable scripting language with a bytecode VM
Documentation
use indexmap::IndexMap;

use crate::value::{BuiltinFn, Value};

/// A named collection of functions and values that can be registered
/// with an Engine and accessed via `module::name` syntax in Ion scripts.
pub struct Module {
    pub name: String,
    functions: IndexMap<String, (String, BuiltinFn)>,
    values: IndexMap<String, Value>,
    submodules: IndexMap<String, Module>,
}

impl Module {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            functions: IndexMap::new(),
            values: IndexMap::new(),
            submodules: IndexMap::new(),
        }
    }

    /// Register a builtin function in this module.
    pub fn register_fn(&mut self, name: &str, func: BuiltinFn) {
        let qualified = format!("{}::{}", self.name, name);
        self.functions.insert(name.to_string(), (qualified, func));
    }

    /// Register a constant value in this module.
    pub fn set(&mut self, name: &str, value: Value) {
        self.values.insert(name.to_string(), value);
    }

    /// Register a submodule (e.g., `net::http`).
    pub fn register_submodule(&mut self, sub: Module) {
        self.submodules.insert(sub.name.clone(), sub);
    }

    /// Convert this module into a `Value::Dict` for use in the interpreter env.
    /// Functions become `Value::BuiltinFn`, submodules become nested dicts.
    pub fn to_value(&self) -> Value {
        let mut map = IndexMap::new();

        for (name, (qualified, func)) in &self.functions {
            map.insert(name.clone(), Value::BuiltinFn(qualified.clone(), *func));
        }

        for (name, value) in &self.values {
            map.insert(name.clone(), value.clone());
        }

        for (name, sub) in &self.submodules {
            map.insert(name.clone(), sub.to_value());
        }

        Value::Dict(map)
    }

    /// Get all exported names (for `use mod::*`).
    pub fn names(&self) -> Vec<String> {
        let mut names: Vec<String> = self.functions.keys().cloned().collect();
        names.extend(self.values.keys().cloned());
        names.extend(self.submodules.keys().cloned());
        names
    }
}