1use crate::ast::{DuTypeDef, Expr, RecordTypeDef};
28use crate::types::TypeEnv;
29use std::collections::HashMap;
30
31#[derive(Debug, Clone)]
36pub struct ModuleRegistry {
37 modules: HashMap<String, Module>,
39}
40
41#[derive(Debug, Clone)]
43pub struct Module {
44 pub name: String,
46 pub bindings: HashMap<String, Expr>,
48 pub types: HashMap<String, TypeDefinition>,
50 pub type_env: TypeEnv,
52}
53
54#[derive(Debug, Clone)]
56pub enum TypeDefinition {
57 Record(RecordTypeDef),
59 Du(DuTypeDef),
61}
62
63impl ModuleRegistry {
64 pub fn new() -> Self {
66 ModuleRegistry {
67 modules: HashMap::new(),
68 }
69 }
70
71 pub fn with_stdlib() -> Self {
73 let mut registry = Self::new();
74 registry.register_stdlib_modules();
75 registry
76 }
77
78 fn register_stdlib_modules(&mut self) {
85 let make_global_ref =
87 |qualified_name: &str| -> Expr { Expr::Var(qualified_name.to_string()) };
88
89 let mut list_bindings = HashMap::new();
91 list_bindings.insert("length".to_string(), make_global_ref("List.length"));
92 list_bindings.insert("head".to_string(), make_global_ref("List.head"));
93 list_bindings.insert("tail".to_string(), make_global_ref("List.tail"));
94 list_bindings.insert("reverse".to_string(), make_global_ref("List.reverse"));
95 list_bindings.insert("isEmpty".to_string(), make_global_ref("List.isEmpty"));
96 list_bindings.insert("append".to_string(), make_global_ref("List.append"));
97 list_bindings.insert("concat".to_string(), make_global_ref("List.concat"));
98 list_bindings.insert("map".to_string(), make_global_ref("List.map"));
99 self.register_module("List".to_string(), list_bindings, HashMap::new());
100
101 let mut string_bindings = HashMap::new();
103 string_bindings.insert("length".to_string(), make_global_ref("String.length"));
104 string_bindings.insert("trim".to_string(), make_global_ref("String.trim"));
105 string_bindings.insert("toLower".to_string(), make_global_ref("String.toLower"));
106 string_bindings.insert("toUpper".to_string(), make_global_ref("String.toUpper"));
107 string_bindings.insert("split".to_string(), make_global_ref("String.split"));
108 string_bindings.insert("concat".to_string(), make_global_ref("String.concat"));
109 string_bindings.insert("contains".to_string(), make_global_ref("String.contains"));
110 string_bindings.insert(
111 "startsWith".to_string(),
112 make_global_ref("String.startsWith"),
113 );
114 string_bindings.insert("endsWith".to_string(), make_global_ref("String.endsWith"));
115 self.register_module("String".to_string(), string_bindings, HashMap::new());
116
117 let mut map_bindings = HashMap::new();
119 map_bindings.insert("empty".to_string(), make_global_ref("Map.empty"));
120 map_bindings.insert("add".to_string(), make_global_ref("Map.add"));
121 map_bindings.insert("remove".to_string(), make_global_ref("Map.remove"));
122 map_bindings.insert("find".to_string(), make_global_ref("Map.find"));
123 map_bindings.insert("tryFind".to_string(), make_global_ref("Map.tryFind"));
124 map_bindings.insert(
125 "containsKey".to_string(),
126 make_global_ref("Map.containsKey"),
127 );
128 map_bindings.insert("isEmpty".to_string(), make_global_ref("Map.isEmpty"));
129 map_bindings.insert("count".to_string(), make_global_ref("Map.count"));
130 map_bindings.insert("ofList".to_string(), make_global_ref("Map.ofList"));
131 map_bindings.insert("toList".to_string(), make_global_ref("Map.toList"));
132 self.register_module("Map".to_string(), map_bindings, HashMap::new());
133
134 let mut option_bindings = HashMap::new();
136 option_bindings.insert("isSome".to_string(), make_global_ref("Option.isSome"));
137 option_bindings.insert("isNone".to_string(), make_global_ref("Option.isNone"));
138 option_bindings.insert(
139 "defaultValue".to_string(),
140 make_global_ref("Option.defaultValue"),
141 );
142 option_bindings.insert(
143 "defaultWith".to_string(),
144 make_global_ref("Option.defaultWith"),
145 );
146 option_bindings.insert("map".to_string(), make_global_ref("Option.map"));
147 option_bindings.insert("bind".to_string(), make_global_ref("Option.bind"));
148 option_bindings.insert("iter".to_string(), make_global_ref("Option.iter"));
149 option_bindings.insert("map2".to_string(), make_global_ref("Option.map2"));
150 option_bindings.insert("orElse".to_string(), make_global_ref("Option.orElse"));
151 self.register_module("Option".to_string(), option_bindings, HashMap::new());
152
153 let mut system_collections_generic_bindings = HashMap::new();
156 system_collections_generic_bindings.insert("List".to_string(), make_global_ref("List"));
158 system_collections_generic_bindings
159 .insert("Dictionary".to_string(), make_global_ref("Map"));
160 self.register_module(
161 "System.Collections.Generic".to_string(),
162 system_collections_generic_bindings,
163 HashMap::new(),
164 );
165
166 let mut system_collections_bindings = HashMap::new();
168 system_collections_bindings.insert(
169 "Generic".to_string(),
170 make_global_ref("System.Collections.Generic"),
171 );
172 self.register_module(
173 "System.Collections".to_string(),
174 system_collections_bindings,
175 HashMap::new(),
176 );
177
178 let mut system_bindings = HashMap::new();
180 system_bindings.insert(
181 "Collections".to_string(),
182 make_global_ref("System.Collections"),
183 );
184 self.register_module("System".to_string(), system_bindings, HashMap::new());
185 }
186
187 pub fn register_module(
195 &mut self,
196 name: String,
197 bindings: HashMap<String, Expr>,
198 types: HashMap<String, TypeDefinition>,
199 ) {
200 let module = Module {
201 name: name.clone(),
202 bindings,
203 types,
204 type_env: TypeEnv::new(),
205 };
206 self.modules.insert(name, module);
207 }
208
209 pub fn resolve_qualified(&self, module_name: &str, binding_name: &str) -> Option<&Expr> {
215 self.modules
216 .get(module_name)
217 .and_then(|m| m.bindings.get(binding_name))
218 }
219
220 pub fn get_module_bindings(&self, module_name: &str) -> Option<&HashMap<String, Expr>> {
226 self.modules.get(module_name).map(|m| &m.bindings)
227 }
228
229 pub fn get_module_types(&self, module_name: &str) -> Option<&HashMap<String, TypeDefinition>> {
235 self.modules.get(module_name).map(|m| &m.types)
236 }
237
238 pub fn has_module(&self, name: &str) -> bool {
240 self.modules.contains_key(name)
241 }
242
243 pub fn get_module(&self, name: &str) -> Option<&Module> {
245 self.modules.get(name)
246 }
247
248 pub fn module_names(&self) -> Vec<&str> {
250 self.modules.keys().map(|s| s.as_str()).collect()
251 }
252}
253
254impl Default for ModuleRegistry {
255 fn default() -> Self {
256 Self::new()
257 }
258}
259
260#[derive(Debug, Clone, PartialEq, Eq)]
264pub struct ModulePath {
265 pub components: Vec<String>,
267}
268
269impl ModulePath {
270 pub fn new(components: Vec<String>) -> Self {
272 ModulePath { components }
273 }
274
275 pub fn single(name: String) -> Self {
277 ModulePath {
278 components: vec![name],
279 }
280 }
281
282 pub fn qualified_name(&self) -> String {
284 self.components.join(".")
285 }
286
287 pub fn last(&self) -> Option<&str> {
289 self.components.last().map(|s| s.as_str())
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use super::*;
296 use crate::ast::{Literal, TypeExpr};
297
298 #[test]
299 fn test_module_registry_new() {
300 let registry = ModuleRegistry::new();
301 assert_eq!(registry.module_names().len(), 0);
302 }
303
304 #[test]
305 fn test_module_registry_with_stdlib() {
306 let registry = ModuleRegistry::with_stdlib();
307
308 assert!(registry.has_module("List"));
310 assert!(registry.has_module("String"));
311 assert!(registry.has_module("Map"));
312 assert!(registry.has_module("Option"));
313 assert!(registry.has_module("System"));
314 assert!(registry.has_module("System.Collections"));
315 assert!(registry.has_module("System.Collections.Generic"));
316
317 assert!(registry.resolve_qualified("List", "length").is_some());
319 assert!(registry.resolve_qualified("String", "trim").is_some());
320 assert!(registry.resolve_qualified("Map", "empty").is_some());
321 assert!(registry.resolve_qualified("Option", "isSome").is_some());
322 }
323
324 #[test]
325 fn test_register_and_resolve_module() {
326 let mut registry = ModuleRegistry::new();
327
328 let mut bindings = HashMap::new();
330 bindings.insert(
331 "add".to_string(),
332 Expr::Lambda {
333 param: "x".to_string(),
334 body: Box::new(Expr::Lambda {
335 param: "y".to_string(),
336 body: Box::new(Expr::BinOp {
337 op: crate::ast::BinOp::Add,
338 left: Box::new(Expr::Var("x".to_string())),
339 right: Box::new(Expr::Var("y".to_string())),
340 }),
341 }),
342 },
343 );
344
345 registry.register_module("Math".to_string(), bindings, HashMap::new());
346
347 assert!(registry.has_module("Math"));
349 assert_eq!(registry.module_names().len(), 1);
350
351 let expr = registry.resolve_qualified("Math", "add");
353 assert!(expr.is_some());
354 assert!(expr.unwrap().is_lambda());
355 }
356
357 #[test]
358 fn test_get_module_bindings() {
359 let mut registry = ModuleRegistry::new();
360
361 let mut bindings = HashMap::new();
362 bindings.insert("x".to_string(), Expr::Lit(Literal::Int(42)));
363 bindings.insert("y".to_string(), Expr::Lit(Literal::Int(100)));
364
365 registry.register_module("Test".to_string(), bindings, HashMap::new());
366
367 let module_bindings = registry.get_module_bindings("Test");
368 assert!(module_bindings.is_some());
369 assert_eq!(module_bindings.unwrap().len(), 2);
370 }
371
372 #[test]
373 fn test_resolve_nonexistent_module() {
374 let registry = ModuleRegistry::new();
375 assert!(!registry.has_module("Nonexistent"));
376 assert!(registry.resolve_qualified("Nonexistent", "add").is_none());
377 }
378
379 #[test]
380 fn test_module_path() {
381 let path = ModulePath::new(vec!["Math".to_string(), "Geometry".to_string()]);
382 assert_eq!(path.qualified_name(), "Math.Geometry");
383 assert_eq!(path.last(), Some("Geometry"));
384
385 let single = ModulePath::single("Math".to_string());
386 assert_eq!(single.qualified_name(), "Math");
387 assert_eq!(single.last(), Some("Math"));
388 }
389
390 #[test]
391 fn test_module_with_types() {
392 let mut registry = ModuleRegistry::new();
393
394 let mut types = HashMap::new();
395 types.insert(
396 "Person".to_string(),
397 TypeDefinition::Record(RecordTypeDef {
398 name: "Person".to_string(),
399 fields: vec![
400 ("name".to_string(), TypeExpr::Named("string".to_string())),
401 ("age".to_string(), TypeExpr::Named("int".to_string())),
402 ],
403 }),
404 );
405
406 registry.register_module("Data".to_string(), HashMap::new(), types);
407
408 let module_types = registry.get_module_types("Data");
409 assert!(module_types.is_some());
410 assert_eq!(module_types.unwrap().len(), 1);
411 assert!(module_types.unwrap().contains_key("Person"));
412 }
413}