mtots_core 0.1.2

Core implementation of the mtots scripting language
Documentation
use super::*;
use std::fs;
use std::path::Path;
use std::path::PathBuf;

impl Globals {
    pub fn load(&mut self, name: &RcStr) -> Result<&Rc<Module>> {
        if !self.module_map.contains_key(name) {
            self.load_uncached(name)?;
        }
        Ok(self.module_map.get(name).unwrap())
    }
    fn load_uncached(&mut self, name: &RcStr) -> Result<Rc<Module>> {
        if let Some(native_module) = self.native_modules.remove(name) {
            let data = native_module.data(self);
            let module = Rc::new(Module::new(
                name.clone(),
                data.fields,
                data.doc,
                Rc::new(data.docmap),
            ));
            self.register_module(module.clone())?;
            (data.init)(self, module.map())?;
            return Ok(module);
        }
        if let Some(source) = self.find_source(name)? {
            self.exec(source)
        } else {
            Err(rterr!("Module {:?} not found", name))
        }
    }
    fn find_source(&self, name: &RcStr) -> Result<Option<Rc<Source>>> {
        if let Some(path) = self.find_source_path(name) {
            let data = fs::read_to_string(path.clone())?;
            let srcpath = Some(path.into());
            Ok(Some(Source::new(name.clone(), srcpath, data.into()).into()))
        } else {
            Ok(None)
        }
    }
    fn find_source_path(&self, name: &RcStr) -> Option<PathBuf> {
        let relpaths = vec![
            {
                let mut path = PathBuf::new();
                for part in name.split('.') {
                    path.push(part);
                }
                path.push("__init.u");
                path
            },
            {
                let mut path = PathBuf::new();
                let mut iter = name.split('.').peekable();
                while let Some(part) = iter.next() {
                    if iter.peek().is_some() {
                        path.push(part);
                    } else {
                        path.push(format!("{}.u", part));
                    }
                }
                path
            },
        ];
        for root in &self.source_roots {
            for relpath in &relpaths {
                let path = Path::new(root.str()).join(relpath);
                if path.is_file() {
                    return Some(path);
                }
            }
        }
        None
    }
}