Skip to main content

rexlang_engine/modules/
types.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt;
3use std::path::{Path, PathBuf};
4
5use rexlang_ast::expr::{Symbol, intern};
6use rexlang_typesystem::Type;
7
8use crate::Pointer;
9
10#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub enum ModuleId {
12    Local { path: PathBuf },
13    Remote(String),
14    Virtual(String),
15}
16
17impl fmt::Display for ModuleId {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            ModuleId::Local { path } => write!(f, "file:{}", path.display()),
21            ModuleId::Remote(url) => write!(f, "{url}"),
22            ModuleId::Virtual(name) => write!(f, "virtual:{name}"),
23        }
24    }
25}
26
27#[derive(Clone, Debug)]
28pub struct ResolveRequest {
29    pub module_name: String,
30    pub importer: Option<ModuleId>,
31}
32
33#[derive(Clone, Debug)]
34pub struct ResolvedModule {
35    pub id: ModuleId,
36    pub source: String,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
40pub struct ModuleKey(u64);
41
42impl ModuleKey {
43    pub fn as_u64(self) -> u64 {
44        self.0
45    }
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
49pub enum SymbolKind {
50    Value,
51    Type,
52    Class,
53}
54
55#[derive(Clone, Debug, PartialEq, Eq, Hash)]
56pub struct CanonicalSymbol {
57    pub module: ModuleKey,
58    pub kind: SymbolKind,
59    pub local: Symbol,
60    symbol: Symbol,
61}
62
63impl CanonicalSymbol {
64    pub fn new(module: ModuleKey, kind: SymbolKind, local: Symbol) -> Self {
65        let symbol = intern(&format!(
66            "{}.{}",
67            prefix_for_module_key(module),
68            local.as_ref()
69        ));
70        Self {
71            module,
72            kind,
73            local,
74            symbol,
75        }
76    }
77
78    pub fn from_symbol(module: ModuleKey, kind: SymbolKind, local: Symbol, symbol: Symbol) -> Self {
79        Self {
80            module,
81            kind,
82            local,
83            symbol,
84        }
85    }
86
87    pub fn symbol(&self) -> &Symbol {
88        &self.symbol
89    }
90}
91
92#[derive(Clone)]
93pub struct ModuleExports {
94    pub values: HashMap<Symbol, CanonicalSymbol>,
95    pub types: HashMap<Symbol, CanonicalSymbol>,
96    pub classes: HashMap<Symbol, CanonicalSymbol>,
97}
98
99#[derive(Clone, Default)]
100pub struct ReplState {
101    pub(crate) alias_exports: HashMap<Symbol, ModuleExports>,
102    pub(crate) imported_values: HashMap<Symbol, CanonicalSymbol>,
103    pub(crate) defined_values: HashSet<Symbol>,
104    pub(crate) importer_path: Option<PathBuf>,
105}
106
107impl ReplState {
108    pub fn new() -> Self {
109        Self::default()
110    }
111
112    pub fn with_importer_path(path: impl AsRef<Path>) -> Self {
113        Self {
114            importer_path: Some(path.as_ref().to_path_buf()),
115            ..Self::default()
116        }
117    }
118}
119
120#[derive(Clone)]
121pub struct ModuleInstance {
122    pub id: ModuleId,
123    pub exports: ModuleExports,
124    pub init_value: Pointer,
125    pub init_type: Type,
126    pub source_fingerprint: Option<String>,
127}
128
129pub(crate) fn module_key_for_module(id: &ModuleId) -> ModuleKey {
130    // Use a stable hash over stable identity bytes so canonical internal symbols
131    // are deterministic across process runs/toolchains.
132    // FNV-1a reference:
133    // - Fowler, Noll, Vo hash function (public domain), 64-bit variant.
134    let mut hash: u64 = 0xcbf29ce484222325;
135    hash_module_identity(&mut hash, id);
136    ModuleKey(hash)
137}
138
139fn hash_module_identity(state: &mut u64, id: &ModuleId) {
140    fn hash_bytes(state: &mut u64, bytes: &[u8]) {
141        for b in bytes {
142            *state ^= u64::from(*b);
143            *state = state.wrapping_mul(0x0000_0100_0000_01B3);
144        }
145    }
146
147    match id {
148        ModuleId::Local { path } => {
149            hash_bytes(state, b"local:");
150            hash_bytes(state, path.as_os_str().as_encoded_bytes());
151        }
152        ModuleId::Remote(url) => {
153            hash_bytes(state, b"remote:");
154            hash_bytes(state, url.as_bytes());
155        }
156        ModuleId::Virtual(name) => {
157            hash_bytes(state, b"virtual:");
158            hash_bytes(state, name.as_bytes());
159        }
160    }
161}
162
163pub(crate) fn prefix_for_module_key(key: ModuleKey) -> String {
164    format!("@m{:016x}", key.as_u64())
165}
166
167pub(crate) fn prefix_for_module(id: &ModuleId) -> String {
168    prefix_for_module_key(module_key_for_module(id))
169}
170
171pub(crate) fn qualify(prefix: &str, name: &Symbol) -> Symbol {
172    intern(&format!("{prefix}.{}", name.as_ref()))
173}
174
175pub fn virtual_export_name(module: &str, export: &str) -> String {
176    let id = ModuleId::Virtual(module.to_string());
177    let key = module_key_for_module(&id);
178    CanonicalSymbol::new(key, SymbolKind::Value, intern(export))
179        .symbol()
180        .to_string()
181}