knave-expand 0.12.2

The reading, scoping and expansion stages of knave
Documentation
use std::rc::Rc;

use rustc_hash::FxHashMap;

use crate::core::{BindingId, ModuleId, ModulePath, Namespace};
use crate::scope::{Scope, ScopeSet};

#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum LoadStatus {
    Loading,
    Loaded,
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct ModuleRecord {
    path: ModulePath,
    base_scope: Scope,
    body_scope: Scope,
    exports: FxHashMap<(Rc<str>, Namespace), BindingId>,
    status: LoadStatus,
}

impl ModuleRecord {
    pub fn path(&self) -> &ModulePath {
        &self.path
    }

    pub fn base_scope(&self) -> Scope {
        self.base_scope
    }

    pub fn body_scope(&self) -> Scope {
        self.body_scope
    }

    pub fn body_scopes(&self) -> ScopeSet {
        let mut scopes = ScopeSet::default();
        scopes.add(self.base_scope);
        scopes.add(self.body_scope);
        scopes
    }

    pub fn export(&mut self, name: Rc<str>, namespace: Namespace, binding: BindingId) {
        self.exports.insert((name, namespace), binding);
    }

    pub fn exported(&self, name: &str, namespace: Namespace) -> Option<BindingId> {
        self.exports.get(&(Rc::from(name), namespace)).copied()
    }

    pub fn exports(&self) -> impl Iterator<Item = (&Rc<str>, Namespace, BindingId)> {
        self.exports
            .iter()
            .map(|((name, namespace), binding)| (name, *namespace, *binding))
    }

    pub fn is_loading(&self) -> bool {
        self.status == LoadStatus::Loading
    }
}

#[derive(Default)]
pub struct ModuleRegistry {
    records: Vec<ModuleRecord>,
    by_path: FxHashMap<ModulePath, ModuleId>,
}

impl ModuleRegistry {
    pub fn register(&mut self, path: ModulePath, base_scope: Scope, body_scope: Scope) -> ModuleId {
        self.adopt(ModuleRecord {
            path,
            base_scope,
            body_scope,
            exports: FxHashMap::default(),
            status: LoadStatus::Loading,
        })
    }

    pub fn adopt(&mut self, record: ModuleRecord) -> ModuleId {
        let id = ModuleId::new(self.records.len());
        self.by_path.insert(record.path.clone(), id);
        self.records.push(record);
        id
    }

    pub fn into_records_after(mut self, id: ModuleId) -> Vec<ModuleRecord> {
        self.records.split_off(id.index() + 1)
    }

    pub fn find(&self, path: &ModulePath) -> Option<ModuleId> {
        self.by_path.get(path).copied()
    }

    pub fn finish_loading(&mut self, id: ModuleId) {
        self.records[id.index()].status = LoadStatus::Loaded;
    }

    pub fn loading_paths(&self) -> Vec<&ModulePath> {
        self.records
            .iter()
            .filter(|record| record.is_loading())
            .map(ModuleRecord::path)
            .collect()
    }

    pub fn with_body_scopes(&self, scopes: &ScopeSet) -> Option<ModuleId> {
        self.records
            .iter()
            .position(|record| record.body_scopes() == *scopes)
            .map(ModuleId::new)
    }

    pub fn records(&self) -> impl Iterator<Item = &ModuleRecord> {
        self.records.iter()
    }

    pub fn get(&self, id: ModuleId) -> &ModuleRecord {
        &self.records[id.index()]
    }

    pub fn get_mut(&mut self, id: ModuleId) -> &mut ModuleRecord {
        &mut self.records[id.index()]
    }
}