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 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}