Skip to main content

oxilean_parse/module/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::Decl;
6use std::collections::{HashMap, HashSet};
7
8/// A module containing declarations.
9#[derive(Debug, Clone)]
10pub struct Module {
11    /// Module name
12    pub name: String,
13    /// Module path
14    pub path: Vec<String>,
15    /// Declarations in this module
16    pub decls: Vec<Decl>,
17    /// Imported modules
18    pub imports: Vec<String>,
19    /// Exported names
20    pub exports: Vec<String>,
21    /// Import specifications
22    pub import_specs: Vec<ImportSpec>,
23    /// Export specification
24    pub export_spec: Option<ExportSpec>,
25    /// Namespace scopes
26    pub namespaces: Vec<NamespaceScope>,
27    /// Open directives
28    pub opens: Vec<OpenDirective>,
29    /// Name visibility information
30    pub visibility_map: HashMap<String, Visibility>,
31    /// Module configuration
32    pub config: ModuleConfig,
33}
34impl Module {
35    /// Create a new module.
36    pub fn new(name: String) -> Self {
37        Self {
38            name,
39            path: Vec::new(),
40            decls: Vec::new(),
41            imports: Vec::new(),
42            exports: Vec::new(),
43            import_specs: Vec::new(),
44            export_spec: None,
45            namespaces: Vec::new(),
46            opens: Vec::new(),
47            visibility_map: HashMap::new(),
48            config: ModuleConfig {
49                allow_circular: false,
50                private_by_default: false,
51                allow_shadowing: false,
52            },
53        }
54    }
55    /// Create a module with configuration.
56    pub fn with_config(name: String, config: ModuleConfig) -> Self {
57        let mut module = Self::new(name);
58        module.config = config;
59        module
60    }
61    /// Add a declaration to this module.
62    pub fn add_decl(&mut self, decl: Decl) {
63        self.decls.push(decl);
64    }
65    /// Add an import.
66    pub fn add_import(&mut self, module: String) {
67        self.imports.push(module);
68    }
69    /// Add an export.
70    pub fn add_export(&mut self, name: String) {
71        self.exports.push(name);
72    }
73    /// Get the full path of this module.
74    pub fn full_path(&self) -> String {
75        if self.path.is_empty() {
76            self.name.clone()
77        } else {
78            format!("{}.{}", self.path.join("."), self.name)
79        }
80    }
81    /// Resolve a name within this module.
82    ///
83    /// Checks local declarations first, then imported modules via import specs,
84    /// then namespace aliases.
85    #[allow(dead_code)]
86    pub fn resolve_name(&self, name: &str) -> ResolvedName {
87        let local_names = self.declared_names();
88        if local_names.contains(&name.to_string()) {
89            return ResolvedName::Local(name.to_string());
90        }
91        for ns in &self.namespaces {
92            if let Some(full) = ns.aliases.get(name) {
93                return ResolvedName::Local(full.clone());
94            }
95        }
96        let mut found_sources: Vec<String> = Vec::new();
97        for spec in &self.import_specs {
98            match spec {
99                ImportSpec::All(module_name) => {
100                    found_sources.push(module_name.clone());
101                }
102                ImportSpec::Selective(module_name, selected) => {
103                    if selected.contains(&name.to_string()) {
104                        found_sources.push(module_name.clone());
105                    }
106                }
107                ImportSpec::Hiding(module_name, hidden) => {
108                    if !hidden.contains(&name.to_string()) {
109                        found_sources.push(module_name.clone());
110                    }
111                }
112                ImportSpec::Renaming(module_name, renamings) => {
113                    for (from, to) in renamings {
114                        if to == name {
115                            return ResolvedName::Imported {
116                                module: module_name.clone(),
117                                name: from.clone(),
118                            };
119                        }
120                    }
121                }
122            }
123        }
124        if !found_sources.is_empty() {
125            if found_sources.len() == 1 {
126                return ResolvedName::Imported {
127                    module: found_sources[0].clone(),
128                    name: name.to_string(),
129                };
130            }
131            return ResolvedName::Ambiguous(found_sources);
132        }
133        if !self.imports.is_empty() {
134            let mut import_sources: Vec<String> = Vec::new();
135            for imp in &self.imports {
136                import_sources.push(imp.clone());
137            }
138            if import_sources.len() == 1 {
139                return ResolvedName::Imported {
140                    module: import_sources[0].clone(),
141                    name: name.to_string(),
142                };
143            }
144            if import_sources.len() > 1 {
145                return ResolvedName::Ambiguous(import_sources);
146            }
147        }
148        ResolvedName::NotFound
149    }
150    /// Get all names declared in this module.
151    fn declared_names(&self) -> Vec<String> {
152        let mut names = Vec::new();
153        for decl in &self.decls {
154            if let Some(name) = Self::decl_name(decl) {
155                names.push(name);
156            }
157        }
158        names
159    }
160    /// Extract the name from a declaration.
161    fn decl_name(decl: &Decl) -> Option<String> {
162        match decl {
163            Decl::Axiom { name, .. } => Some(name.clone()),
164            Decl::Definition { name, .. } => Some(name.clone()),
165            Decl::Theorem { name, .. } => Some(name.clone()),
166            Decl::Inductive { name, .. } => Some(name.clone()),
167            Decl::Namespace { name, .. } => Some(name.clone()),
168            Decl::Structure { name, .. } => Some(name.clone()),
169            Decl::ClassDecl { name, .. } => Some(name.clone()),
170            Decl::InstanceDecl {
171                name, class_name, ..
172            } => name.clone().or_else(|| Some(class_name.clone())),
173            Decl::SectionDecl { name, .. } => Some(name.clone()),
174            Decl::Mutual { .. } => None,
175            Decl::Derive { type_name, .. } => Some(type_name.clone()),
176            Decl::NotationDecl { name, .. } => Some(name.clone()),
177            Decl::Universe { .. } => None,
178            Decl::Import { .. }
179            | Decl::Variable { .. }
180            | Decl::Open { .. }
181            | Decl::Attribute { .. }
182            | Decl::HashCmd { .. } => None,
183        }
184    }
185    /// Get all visible names (declared + imported).
186    #[allow(dead_code)]
187    pub fn visible_names(&self) -> Vec<String> {
188        let mut names = self.declared_names();
189        for ns in &self.namespaces {
190            for alias in ns.aliases.keys() {
191                if !names.contains(alias) {
192                    names.push(alias.clone());
193                }
194            }
195        }
196        names
197    }
198    /// Get names visible to importers of this module.
199    #[allow(dead_code)]
200    pub fn exported_names(&self) -> Vec<String> {
201        match &self.export_spec {
202            Some(ExportSpec::All) => self.declared_names(),
203            Some(ExportSpec::Selective(selected)) => {
204                let declared = self.declared_names();
205                selected
206                    .iter()
207                    .filter(|n| declared.contains(n))
208                    .cloned()
209                    .collect()
210            }
211            None => {
212                if self.exports.is_empty() {
213                    self.declared_names()
214                } else {
215                    self.exports.clone()
216                }
217            }
218        }
219    }
220    /// Add a namespace scope.
221    #[allow(dead_code)]
222    pub fn add_namespace(&mut self, ns: NamespaceScope) {
223        self.namespaces.push(ns);
224    }
225    /// Apply an import specification.
226    #[allow(dead_code)]
227    pub fn with_import_spec(&mut self, spec: ImportSpec) {
228        let module_name = match &spec {
229            ImportSpec::All(m) => m.clone(),
230            ImportSpec::Selective(m, _) => m.clone(),
231            ImportSpec::Hiding(m, _) => m.clone(),
232            ImportSpec::Renaming(m, _) => m.clone(),
233        };
234        if !self.imports.contains(&module_name) {
235            self.imports.push(module_name);
236        }
237        self.import_specs.push(spec);
238    }
239    /// Set visibility for a name.
240    #[allow(dead_code)]
241    pub fn set_visibility(&mut self, name: String, visibility: Visibility) {
242        self.visibility_map.insert(name, visibility);
243    }
244    /// Get visibility of a name.
245    #[allow(dead_code)]
246    pub fn get_visibility(&self, name: &str) -> Visibility {
247        self.visibility_map
248            .get(name)
249            .copied()
250            .unwrap_or(if self.config.private_by_default {
251                Visibility::Private
252            } else {
253                Visibility::Public
254            })
255    }
256    /// Add an open directive.
257    #[allow(dead_code)]
258    pub fn add_open(&mut self, module: String, scoped: bool) {
259        self.opens.push(OpenDirective { module, scoped });
260    }
261    /// Get all open modules.
262    #[allow(dead_code)]
263    pub fn get_opens(&self) -> Vec<String> {
264        self.opens.iter().map(|o| o.module.clone()).collect()
265    }
266    /// Resolve a name considering all open modules and imports.
267    #[allow(dead_code)]
268    pub fn resolve_with_opens(&self, name: &str) -> ResolvedName {
269        if let ResolvedName::Local(n) = self.resolve_name(name) {
270            return ResolvedName::Local(n);
271        }
272        let mut found_sources = Vec::new();
273        for open in &self.opens {
274            found_sources.push(open.module.clone());
275        }
276        if !found_sources.is_empty() {
277            if found_sources.len() == 1 {
278                return ResolvedName::Imported {
279                    module: found_sources[0].clone(),
280                    name: name.to_string(),
281                };
282            }
283            return ResolvedName::Ambiguous(found_sources);
284        }
285        self.resolve_name(name)
286    }
287    /// Get all visible names including from opens.
288    #[allow(dead_code)]
289    pub fn all_visible_names(&self) -> Vec<NameVisibility> {
290        let mut result = Vec::new();
291        let declared = self.declared_names();
292        for name in declared {
293            let visibility = self.get_visibility(&name);
294            result.push(NameVisibility {
295                name,
296                visibility,
297                from_module: None,
298            });
299        }
300        for open in &self.opens {
301            result.push(NameVisibility {
302                name: format!("{}::*", open.module),
303                visibility: Visibility::Public,
304                from_module: Some(open.module.clone()),
305            });
306        }
307        result
308    }
309    /// Check if a name is accessible with given visibility context.
310    #[allow(dead_code)]
311    pub fn is_accessible(&self, name: &str, from_same_module: bool) -> bool {
312        let visibility = self.get_visibility(name);
313        match visibility {
314            Visibility::Public => true,
315            Visibility::Private => from_same_module,
316            Visibility::Protected => true,
317        }
318    }
319    /// Get all direct dependencies (imports and opens).
320    #[allow(dead_code)]
321    pub fn get_dependencies(&self) -> HashSet<String> {
322        let mut deps = HashSet::new();
323        deps.extend(self.imports.clone());
324        for open in &self.opens {
325            deps.insert(open.module.clone());
326        }
327        for spec in &self.import_specs {
328            let mod_name = match spec {
329                ImportSpec::All(m) => m.clone(),
330                ImportSpec::Selective(m, _) => m.clone(),
331                ImportSpec::Hiding(m, _) => m.clone(),
332                ImportSpec::Renaming(m, _) => m.clone(),
333            };
334            deps.insert(mod_name);
335        }
336        deps
337    }
338    /// Check if this module directly imports another.
339    #[allow(dead_code)]
340    pub fn imports_module(&self, other: &str) -> bool {
341        self.get_dependencies().contains(other)
342    }
343    /// Resolve a selective import to actual names.
344    #[allow(dead_code)]
345    pub fn resolve_selective_import(&self, _module: &str, selected: &[String]) -> Vec<String> {
346        selected.to_vec()
347    }
348    /// Get all names hidden by a hiding import.
349    #[allow(dead_code)]
350    pub fn get_hidden_names(&self, module: &str) -> Vec<String> {
351        for spec in &self.import_specs {
352            if let ImportSpec::Hiding(m, hidden) = spec {
353                if m == module {
354                    return hidden.clone();
355                }
356            }
357        }
358        Vec::new()
359    }
360    /// Create a nested namespace scope.
361    #[allow(dead_code)]
362    pub fn create_nested_namespace(&mut self, name: String, parent: NamespaceScope) {
363        let mut nested = NamespaceScope {
364            name,
365            opened: Vec::new(),
366            aliases: HashMap::new(),
367            visibility: HashMap::new(),
368            parent: Some(Box::new(parent)),
369        };
370        if let Some(ref p) = nested.parent {
371            nested.aliases.extend(p.aliases.clone());
372        }
373        self.namespaces.push(nested);
374    }
375    /// Look up a name in namespace hierarchy.
376    #[allow(dead_code)]
377    pub fn lookup_in_namespaces(&self, name: &str) -> Option<String> {
378        for ns in self.namespaces.iter().rev() {
379            if let Some(full) = ns.aliases.get(name) {
380                return Some(full.clone());
381            }
382            let mut current_parent = &ns.parent;
383            while let Some(ref parent) = current_parent {
384                if let Some(full) = parent.aliases.get(name) {
385                    return Some(full.clone());
386                }
387                current_parent = &parent.parent;
388            }
389        }
390        None
391    }
392    /// Get all names in a specific namespace.
393    #[allow(dead_code)]
394    pub fn namespace_names(&self, ns_name: &str) -> Vec<String> {
395        for ns in &self.namespaces {
396            if ns.name == ns_name {
397                return ns.aliases.keys().cloned().collect();
398            }
399        }
400        Vec::new()
401    }
402    /// Set default visibility for all names (for private_by_default config).
403    #[allow(dead_code)]
404    pub fn set_default_visibility(&mut self, visibility: Visibility) {
405        match visibility {
406            Visibility::Private => self.config.private_by_default = true,
407            _ => self.config.private_by_default = false,
408        }
409    }
410}
411/// Resolution result for a name.
412#[derive(Debug, Clone, PartialEq)]
413pub enum ResolvedName {
414    /// Name found in local declarations
415    Local(String),
416    /// Name found in an imported module
417    Imported {
418        /// Module the name comes from
419        module: String,
420        /// The resolved name
421        name: String,
422    },
423    /// Name is ambiguous (found in multiple sources)
424    Ambiguous(Vec<String>),
425    /// Name was not found
426    NotFound,
427}
428/// A module attribute (like #\[inline\], @\[simp\], etc.).
429#[allow(dead_code)]
430#[allow(missing_docs)]
431#[derive(Debug, Clone)]
432pub struct ModuleAttribute {
433    /// Attribute name
434    pub name: String,
435    /// Optional argument
436    pub arg: Option<String>,
437}
438impl ModuleAttribute {
439    /// Create a new attribute.
440    #[allow(dead_code)]
441    pub fn new(name: &str) -> Self {
442        ModuleAttribute {
443            name: name.to_string(),
444            arg: None,
445        }
446    }
447    /// Set an argument.
448    #[allow(dead_code)]
449    pub fn with_arg(mut self, arg: &str) -> Self {
450        self.arg = Some(arg.to_string());
451        self
452    }
453    /// Format the attribute.
454    #[allow(dead_code)]
455    pub fn format(&self) -> String {
456        if let Some(ref arg) = self.arg {
457            format!("@[{} {}]", self.name, arg)
458        } else {
459            format!("@[{}]", self.name)
460        }
461    }
462}
463/// Export specification.
464#[derive(Debug, Clone, PartialEq)]
465pub enum ExportSpec {
466    /// Export all names
467    All,
468    /// Export only selected names
469    Selective(Vec<String>),
470}
471/// Visibility information for a name.
472#[derive(Debug, Clone)]
473pub struct NameVisibility {
474    /// Name itself
475    pub name: String,
476    /// Visibility level
477    pub visibility: Visibility,
478    /// Module it's from
479    pub from_module: Option<String>,
480}
481/// Module dependency graph node.
482#[derive(Debug, Clone)]
483pub struct ModuleDep {
484    /// Module name
485    pub name: String,
486    /// Direct dependencies
487    pub deps: Vec<String>,
488}
489/// A module export entry.
490#[allow(dead_code)]
491#[allow(missing_docs)]
492#[derive(Debug, Clone)]
493pub struct ExportEntry {
494    /// Module being re-exported
495    pub module: String,
496    /// Whether all declarations are re-exported
497    pub all: bool,
498    /// Specific names to export (if not all)
499    pub names: Vec<String>,
500}
501impl ExportEntry {
502    /// Create an "export all" entry.
503    #[allow(dead_code)]
504    pub fn all(module: &str) -> Self {
505        ExportEntry {
506            module: module.to_string(),
507            all: true,
508            names: Vec::new(),
509        }
510    }
511    /// Create an entry for specific names.
512    #[allow(dead_code)]
513    pub fn names(module: &str, names: Vec<&str>) -> Self {
514        ExportEntry {
515            module: module.to_string(),
516            all: false,
517            names: names.into_iter().map(|s| s.to_string()).collect(),
518        }
519    }
520}
521/// A module version record.
522#[allow(dead_code)]
523#[allow(missing_docs)]
524#[derive(Debug, Clone, PartialEq, Eq)]
525pub struct ModuleVersion {
526    /// Major version
527    pub major: u32,
528    /// Minor version
529    pub minor: u32,
530    /// Patch version
531    pub patch: u32,
532}
533impl ModuleVersion {
534    /// Create a new version.
535    #[allow(dead_code)]
536    pub fn new(major: u32, minor: u32, patch: u32) -> Self {
537        ModuleVersion {
538            major,
539            minor,
540            patch,
541        }
542    }
543    /// Format as "major.minor.patch".
544    #[allow(dead_code)]
545    pub fn format(&self) -> String {
546        format!("{}.{}.{}", self.major, self.minor, self.patch)
547    }
548}
549/// Module configuration settings.
550#[derive(Debug, Clone)]
551pub struct ModuleConfig {
552    /// Allow circular imports
553    pub allow_circular: bool,
554    /// Private by default
555    pub private_by_default: bool,
556    /// Enable shadowing
557    pub allow_shadowing: bool,
558}
559/// Import specification.
560#[derive(Debug, Clone, PartialEq)]
561pub enum ImportSpec {
562    /// Import everything: `import Foo`
563    All(String),
564    /// Import specific names: `import Foo (bar, baz)`
565    Selective(String, Vec<String>),
566    /// Import hiding names: `import Foo hiding (bar)`
567    Hiding(String, Vec<String>),
568    /// Import with renaming: `import Foo renaming bar -> baz`
569    Renaming(String, Vec<(String, String)>),
570}
571/// Visibility modifier for declarations.
572#[derive(Debug, Clone, Copy, PartialEq, Eq)]
573pub enum Visibility {
574    /// Public - visible outside module
575    Public,
576    /// Private - only visible within module
577    Private,
578    /// Protected - visible in submodules
579    Protected,
580}
581/// Scoped open with body expression.
582#[derive(Debug, Clone)]
583pub struct ScopedOpen {
584    /// Module to open
585    pub module: String,
586    /// Name of the scope variable
587    pub scope_var: Option<String>,
588}
589/// Open directive with optional scope.
590#[derive(Debug, Clone, PartialEq)]
591pub struct OpenDirective {
592    /// Module to open
593    pub module: String,
594    /// Optional scope: Some(expr) means `open ... in expr`
595    pub scoped: bool,
596}
597/// A module dependency graph.
598#[allow(dead_code)]
599#[allow(missing_docs)]
600pub struct DepGraphExt {
601    /// All edges
602    pub edges: Vec<ModuleDepExt>,
603}
604impl DepGraphExt {
605    /// Create a new empty dependency graph.
606    #[allow(dead_code)]
607    pub fn new() -> Self {
608        DepGraphExt { edges: Vec::new() }
609    }
610    /// Add an edge.
611    #[allow(dead_code)]
612    pub fn add(&mut self, dep: ModuleDepExt) {
613        self.edges.push(dep);
614    }
615    /// Returns all direct dependencies of a module.
616    #[allow(dead_code)]
617    pub fn direct_deps(&self, module: &str) -> Vec<&str> {
618        self.edges
619            .iter()
620            .filter(|e| e.from == module && e.direct)
621            .map(|e| e.to.as_str())
622            .collect()
623    }
624    /// Returns all modules that depend on a given module.
625    #[allow(dead_code)]
626    pub fn dependents(&self, module: &str) -> Vec<&str> {
627        self.edges
628            .iter()
629            .filter(|e| e.to == module)
630            .map(|e| e.from.as_str())
631            .collect()
632    }
633    /// Checks for cycles using DFS (simplified: just checks direct self-import).
634    #[allow(dead_code)]
635    pub fn has_self_import(&self) -> bool {
636        self.edges.iter().any(|e| e.from == e.to)
637    }
638}
639/// A module metadata record.
640#[allow(dead_code)]
641#[allow(missing_docs)]
642#[derive(Debug, Clone)]
643pub struct ModuleMetadata {
644    /// Module name
645    pub name: String,
646    /// Version
647    pub version: Option<ModuleVersion>,
648    /// Author
649    pub author: Option<String>,
650}
651impl ModuleMetadata {
652    /// Create a new metadata record.
653    #[allow(dead_code)]
654    pub fn new(name: &str) -> Self {
655        ModuleMetadata {
656            name: name.to_string(),
657            version: None,
658            author: None,
659        }
660    }
661    /// Set the version.
662    #[allow(dead_code)]
663    pub fn with_version(mut self, v: ModuleVersion) -> Self {
664        self.version = Some(v);
665        self
666    }
667    /// Set the author.
668    #[allow(dead_code)]
669    pub fn with_author(mut self, a: &str) -> Self {
670        self.author = Some(a.to_string());
671        self
672    }
673}
674/// A module dependency edge.
675#[allow(dead_code)]
676#[allow(missing_docs)]
677#[derive(Debug, Clone)]
678pub struct ModuleDepExt {
679    /// The importing module name
680    pub from: String,
681    /// The imported module name
682    pub to: String,
683    /// Whether the import is direct or transitive
684    pub direct: bool,
685}
686impl ModuleDepExt {
687    /// Create a new direct dependency.
688    #[allow(dead_code)]
689    pub fn direct(from: &str, to: &str) -> Self {
690        ModuleDepExt {
691            from: from.to_string(),
692            to: to.to_string(),
693            direct: true,
694        }
695    }
696    /// Create a new transitive dependency.
697    #[allow(dead_code)]
698    pub fn transitive(from: &str, to: &str) -> Self {
699        ModuleDepExt {
700            from: from.to_string(),
701            to: to.to_string(),
702            direct: false,
703        }
704    }
705}
706/// Import cycle detection result.
707#[derive(Debug, Clone, PartialEq)]
708pub enum CycleDetectionResult {
709    /// No cycles found
710    NoCycles,
711    /// Cycle found involving these modules
712    CycleFound(Vec<String>),
713    /// Multiple cycles found
714    MultipleCycles(Vec<Vec<String>>),
715}
716/// Module registry for managing multiple modules.
717pub struct ModuleRegistry {
718    /// Registered modules
719    modules: HashMap<String, Module>,
720}
721impl ModuleRegistry {
722    /// Create a new module registry.
723    pub fn new() -> Self {
724        Self {
725            modules: HashMap::new(),
726        }
727    }
728    /// Register a module.
729    pub fn register(&mut self, module: Module) -> Result<(), String> {
730        let path = module.full_path();
731        match self.modules.entry(path.clone()) {
732            std::collections::hash_map::Entry::Occupied(_) => {
733                Err(format!("Module {} already registered", path))
734            }
735            std::collections::hash_map::Entry::Vacant(entry) => {
736                entry.insert(module);
737                Ok(())
738            }
739        }
740    }
741    /// Get a module by path.
742    pub fn get(&self, path: &str) -> Option<&Module> {
743        self.modules.get(path)
744    }
745    /// Get all registered modules.
746    pub fn all_modules(&self) -> Vec<&Module> {
747        self.modules.values().collect()
748    }
749    /// Check if a module is registered.
750    pub fn contains(&self, path: &str) -> bool {
751        self.modules.contains_key(path)
752    }
753    /// Get a mutable reference to a module by path.
754    #[allow(dead_code)]
755    pub fn get_mut(&mut self, path: &str) -> Option<&mut Module> {
756        self.modules.get_mut(path)
757    }
758    /// Remove and return a module from the registry.
759    #[allow(dead_code)]
760    pub fn unregister(&mut self, path: &str) -> Option<Module> {
761        self.modules.remove(path)
762    }
763    /// Resolve a name from the perspective of a given module.
764    ///
765    /// Checks the module's local declarations first, then searches
766    /// through its imports using import specifications.
767    #[allow(dead_code)]
768    pub fn resolve(&self, from: &str, name: &str) -> ResolvedName {
769        let module = match self.modules.get(from) {
770            Some(m) => m,
771            None => return ResolvedName::NotFound,
772        };
773        let local = module.resolve_name(name);
774        if matches!(local, ResolvedName::Local(_)) {
775            return local;
776        }
777        for spec in &module.import_specs {
778            match spec {
779                ImportSpec::All(mod_name) => {
780                    if let Some(target) = self.modules.get(mod_name) {
781                        let exported = target.exported_names();
782                        if exported.contains(&name.to_string()) {
783                            return ResolvedName::Imported {
784                                module: mod_name.clone(),
785                                name: name.to_string(),
786                            };
787                        }
788                    }
789                }
790                ImportSpec::Selective(mod_name, selected) => {
791                    if selected.contains(&name.to_string()) {
792                        if let Some(target) = self.modules.get(mod_name) {
793                            let exported = target.exported_names();
794                            if exported.contains(&name.to_string()) {
795                                return ResolvedName::Imported {
796                                    module: mod_name.clone(),
797                                    name: name.to_string(),
798                                };
799                            }
800                        }
801                    }
802                }
803                ImportSpec::Hiding(mod_name, hidden) => {
804                    if !hidden.contains(&name.to_string()) {
805                        if let Some(target) = self.modules.get(mod_name) {
806                            let exported = target.exported_names();
807                            if exported.contains(&name.to_string()) {
808                                return ResolvedName::Imported {
809                                    module: mod_name.clone(),
810                                    name: name.to_string(),
811                                };
812                            }
813                        }
814                    }
815                }
816                ImportSpec::Renaming(mod_name, renamings) => {
817                    for (from_name, to_name) in renamings {
818                        if to_name == name {
819                            return ResolvedName::Imported {
820                                module: mod_name.clone(),
821                                name: from_name.clone(),
822                            };
823                        }
824                    }
825                }
826            }
827        }
828        for imp in &module.imports {
829            if let Some(target) = self.modules.get(imp) {
830                let exported = target.exported_names();
831                if exported.contains(&name.to_string()) {
832                    return ResolvedName::Imported {
833                        module: imp.clone(),
834                        name: name.to_string(),
835                    };
836                }
837            }
838        }
839        ResolvedName::NotFound
840    }
841    /// Compute a topological sort of modules based on their dependencies.
842    ///
843    /// Returns `Ok(order)` with module names in dependency order (dependencies first),
844    /// or `Err(cycle)` with the names of modules involved in a cycle.
845    #[allow(dead_code)]
846    pub fn dependency_order(&self) -> Result<Vec<String>, Vec<String>> {
847        let deps = self.build_dep_graph();
848        let mut in_degree: HashMap<String, usize> = HashMap::new();
849        let mut adj: HashMap<String, Vec<String>> = HashMap::new();
850        for dep in &deps {
851            in_degree.entry(dep.name.clone()).or_insert(0);
852            adj.entry(dep.name.clone()).or_default();
853            for d in &dep.deps {
854                adj.entry(d.clone()).or_default();
855                in_degree.entry(d.clone()).or_insert(0);
856                *in_degree.entry(dep.name.clone()).or_insert(0) += 1;
857            }
858        }
859        let mut queue: Vec<String> = in_degree
860            .iter()
861            .filter(|(_, &deg)| deg == 0)
862            .map(|(name, _)| name.clone())
863            .collect();
864        queue.sort();
865        let mut result = Vec::new();
866        while let Some(node) = queue.pop() {
867            result.push(node.clone());
868            if let Some(neighbors) = adj.get(&node) {
869                for _neighbor in neighbors {}
870                let _ = neighbors;
871            }
872        }
873        let mut adj2: HashMap<String, Vec<String>> = HashMap::new();
874        let mut in_deg2: HashMap<String, usize> = HashMap::new();
875        for dep in &deps {
876            in_deg2.entry(dep.name.clone()).or_insert(0);
877            adj2.entry(dep.name.clone()).or_default();
878            for d in &dep.deps {
879                adj2.entry(d.clone()).or_default();
880                in_deg2.entry(d.clone()).or_insert(0);
881                adj2.entry(d.clone()).or_default().push(dep.name.clone());
882                *in_deg2.entry(dep.name.clone()).or_insert(0) += 1;
883            }
884        }
885        let mut queue2: Vec<String> = in_deg2
886            .iter()
887            .filter(|(_, &deg)| deg == 0)
888            .map(|(name, _)| name.clone())
889            .collect();
890        queue2.sort();
891        let mut sorted = Vec::new();
892        while let Some(node) = queue2.pop() {
893            sorted.push(node.clone());
894            if let Some(neighbors) = adj2.get(&node) {
895                for neighbor in neighbors.clone() {
896                    if let Some(deg) = in_deg2.get_mut(&neighbor) {
897                        *deg -= 1;
898                        if *deg == 0 {
899                            queue2.push(neighbor);
900                            queue2.sort();
901                        }
902                    }
903                }
904            }
905        }
906        let total_nodes = in_deg2.len();
907        if sorted.len() == total_nodes {
908            Ok(sorted)
909        } else {
910            let cycle: Vec<String> = in_deg2
911                .iter()
912                .filter(|(_, &deg)| deg > 0)
913                .map(|(name, _)| name.clone())
914                .collect();
915            Err(cycle)
916        }
917    }
918    /// Detect cycles in the module dependency graph.
919    ///
920    /// Returns a list of cycles, where each cycle is a list of module names.
921    #[allow(dead_code)]
922    pub fn detect_cycles(&self) -> Vec<Vec<String>> {
923        let deps = self.build_dep_graph();
924        let mut visited: HashMap<String, u8> = HashMap::new();
925        let mut path: Vec<String> = Vec::new();
926        let mut cycles: Vec<Vec<String>> = Vec::new();
927        let dep_map: HashMap<String, Vec<String>> = deps
928            .iter()
929            .map(|d| (d.name.clone(), d.deps.clone()))
930            .collect();
931        for dep in &deps {
932            if visited.get(&dep.name).copied().unwrap_or(0) == 0 {
933                Self::dfs_cycle(&dep.name, &dep_map, &mut visited, &mut path, &mut cycles);
934            }
935        }
936        cycles
937    }
938    /// DFS helper for cycle detection.
939    fn dfs_cycle(
940        node: &str,
941        adj: &HashMap<String, Vec<String>>,
942        visited: &mut HashMap<String, u8>,
943        path: &mut Vec<String>,
944        cycles: &mut Vec<Vec<String>>,
945    ) {
946        visited.insert(node.to_string(), 1);
947        path.push(node.to_string());
948        if let Some(neighbors) = adj.get(node) {
949            for neighbor in neighbors {
950                let state = visited.get(neighbor).copied().unwrap_or(0);
951                if state == 1 {
952                    if let Some(pos) = path.iter().position(|n| n == neighbor) {
953                        let cycle: Vec<String> = path[pos..].to_vec();
954                        cycles.push(cycle);
955                    }
956                } else if state == 0 {
957                    Self::dfs_cycle(neighbor, adj, visited, path, cycles);
958                }
959            }
960        }
961        path.pop();
962        visited.insert(node.to_string(), 2);
963    }
964    /// Get all transitive dependencies of a module.
965    #[allow(dead_code)]
966    pub fn transitive_deps(&self, module: &str) -> Vec<String> {
967        let dep_map: HashMap<String, Vec<String>> = self
968            .build_dep_graph()
969            .into_iter()
970            .map(|d| (d.name, d.deps))
971            .collect();
972        let mut visited = Vec::new();
973        let mut stack = Vec::new();
974        if let Some(direct) = dep_map.get(module) {
975            stack.extend(direct.clone());
976        }
977        while let Some(dep) = stack.pop() {
978            if visited.contains(&dep) {
979                continue;
980            }
981            visited.push(dep.clone());
982            if let Some(transitive) = dep_map.get(&dep) {
983                for t in transitive {
984                    if !visited.contains(t) {
985                        stack.push(t.clone());
986                    }
987                }
988            }
989        }
990        visited.sort();
991        visited
992    }
993    /// Build the dependency graph from the registered modules.
994    fn build_dep_graph(&self) -> Vec<ModuleDep> {
995        self.modules
996            .values()
997            .map(|m| {
998                let mut deps = m.imports.clone();
999                for spec in &m.import_specs {
1000                    let mod_name = match spec {
1001                        ImportSpec::All(n) => n.clone(),
1002                        ImportSpec::Selective(n, _) => n.clone(),
1003                        ImportSpec::Hiding(n, _) => n.clone(),
1004                        ImportSpec::Renaming(n, _) => n.clone(),
1005                    };
1006                    if !deps.contains(&mod_name) {
1007                        deps.push(mod_name);
1008                    }
1009                }
1010                ModuleDep {
1011                    name: m.full_path(),
1012                    deps,
1013                }
1014            })
1015            .collect()
1016    }
1017    /// Detect mutual (cyclic) imports between modules.
1018    #[allow(dead_code)]
1019    pub fn detect_mutual_imports(&self) -> Vec<(String, String)> {
1020        let mut mutual = Vec::new();
1021        for module in self.modules.values() {
1022            for dep in &module.imports {
1023                if let Some(dep_module) = self.modules.get(dep) {
1024                    if dep_module.imports.contains(&module.full_path()) {
1025                        let pair = (module.full_path(), dep.clone());
1026                        if !mutual.iter().any(|(a, b)| {
1027                            (a == &pair.0 && b == &pair.1) || (a == &pair.1 && b == &pair.0)
1028                        }) {
1029                            mutual.push(pair);
1030                        }
1031                    }
1032                }
1033            }
1034        }
1035        mutual
1036    }
1037    /// Check if two modules import each other.
1038    #[allow(dead_code)]
1039    pub fn are_mutually_dependent(&self, a: &str, b: &str) -> bool {
1040        if let (Some(mod_a), Some(mod_b)) = (self.modules.get(a), self.modules.get(b)) {
1041            (mod_a.imports.contains(&b.to_string()) && mod_b.imports.contains(&a.to_string()))
1042                || (mod_a.imports_module(b) && mod_b.imports_module(a))
1043        } else {
1044            false
1045        }
1046    }
1047    /// Get all modules that depend on a given module.
1048    #[allow(dead_code)]
1049    pub fn get_dependents(&self, module_name: &str) -> Vec<String> {
1050        let mut dependents = Vec::new();
1051        for module in self.modules.values() {
1052            if module.imports_module(module_name) {
1053                dependents.push(module.full_path());
1054            }
1055        }
1056        dependents.sort();
1057        dependents
1058    }
1059    /// Get all modules that a given module depends on (indirect + direct).
1060    #[allow(dead_code)]
1061    pub fn get_all_dependencies(&self, module_name: &str) -> Vec<String> {
1062        let mut all_deps = HashSet::new();
1063        let mut stack = vec![module_name.to_string()];
1064        let mut visited = HashSet::new();
1065        while let Some(current) = stack.pop() {
1066            if visited.contains(&current) {
1067                continue;
1068            }
1069            visited.insert(current.clone());
1070            if let Some(module) = self.modules.get(&current) {
1071                for dep in module.get_dependencies() {
1072                    if !visited.contains(&dep) {
1073                        all_deps.insert(dep.clone());
1074                        stack.push(dep);
1075                    }
1076                }
1077            }
1078        }
1079        let mut result: Vec<_> = all_deps.into_iter().collect();
1080        result.sort();
1081        result
1082    }
1083    /// Verify module consistency (no broken imports).
1084    #[allow(dead_code)]
1085    pub fn verify_consistency(&self) -> Result<(), Vec<String>> {
1086        let mut errors = Vec::new();
1087        for module in self.modules.values() {
1088            for imported in &module.imports {
1089                if !self.modules.contains_key(imported) {
1090                    errors.push(format!(
1091                        "Module {} imports non-existent module {}",
1092                        module.full_path(),
1093                        imported
1094                    ));
1095                }
1096            }
1097        }
1098        if errors.is_empty() {
1099            Ok(())
1100        } else {
1101            Err(errors)
1102        }
1103    }
1104    /// Get all modules that would be transitively affected by changes to a module.
1105    #[allow(dead_code)]
1106    pub fn get_reverse_dependencies(&self, module_name: &str) -> Vec<String> {
1107        let mut affected = HashSet::new();
1108        let mut stack = vec![module_name.to_string()];
1109        let mut visited = HashSet::new();
1110        while let Some(current) = stack.pop() {
1111            if visited.contains(&current) {
1112                continue;
1113            }
1114            visited.insert(current.clone());
1115            for dependent in self.get_dependents(&current) {
1116                if !visited.contains(&dependent) {
1117                    affected.insert(dependent.clone());
1118                    stack.push(dependent);
1119                }
1120            }
1121        }
1122        let mut result: Vec<_> = affected.into_iter().collect();
1123        result.sort();
1124        result
1125    }
1126    /// Reachability analysis: which modules can be reached from a given module.
1127    #[allow(dead_code)]
1128    pub fn reachable_from(&self, module_name: &str) -> Vec<String> {
1129        let mut reachable = Vec::new();
1130        let mut visited = HashSet::new();
1131        let mut stack = vec![module_name.to_string()];
1132        while let Some(current) = stack.pop() {
1133            if visited.contains(&current) {
1134                continue;
1135            }
1136            visited.insert(current.clone());
1137            if let Some(module) = self.modules.get(&current) {
1138                for dep in module.get_dependencies() {
1139                    if !visited.contains(&dep) {
1140                        reachable.push(dep.clone());
1141                        stack.push(dep);
1142                    }
1143                }
1144            }
1145        }
1146        reachable.sort();
1147        reachable
1148    }
1149    /// Get module strongly connected components (for circular dependency analysis).
1150    #[allow(dead_code)]
1151    pub fn get_sccs(&self) -> Vec<Vec<String>> {
1152        let mut sccs = Vec::new();
1153        let deps = self.build_dep_graph();
1154        let mut visited: HashMap<String, bool> = HashMap::new();
1155        let mut rec_stack: HashMap<String, bool> = HashMap::new();
1156        let mut current_scc = Vec::new();
1157        for dep in &deps {
1158            if !visited.contains_key(&dep.name) {
1159                self.tarjan_visit(
1160                    &dep.name,
1161                    &deps,
1162                    &mut visited,
1163                    &mut rec_stack,
1164                    &mut current_scc,
1165                    &mut sccs,
1166                );
1167            }
1168        }
1169        sccs
1170    }
1171    /// Tarjan's algorithm helper for SCC detection.
1172    fn tarjan_visit(
1173        &self,
1174        node: &str,
1175        _graph: &[ModuleDep],
1176        visited: &mut HashMap<String, bool>,
1177        rec_stack: &mut HashMap<String, bool>,
1178        _current_scc: &mut Vec<String>,
1179        sccs: &mut Vec<Vec<String>>,
1180    ) {
1181        visited.insert(node.to_string(), true);
1182        rec_stack.insert(node.to_string(), true);
1183        if let Some(module) = self.modules.get(node) {
1184            for dep in &module.imports {
1185                if !visited.get(dep).copied().unwrap_or(false) {
1186                    self.tarjan_visit(dep, _graph, visited, rec_stack, _current_scc, sccs);
1187                } else if rec_stack.get(dep).copied().unwrap_or(false) {
1188                    sccs.push(vec![node.to_string(), dep.clone()]);
1189                }
1190            }
1191        }
1192        rec_stack.insert(node.to_string(), false);
1193    }
1194    /// Get import statistics for debugging.
1195    #[allow(dead_code)]
1196    pub fn get_statistics(&self) -> HashMap<String, usize> {
1197        let mut stats = HashMap::new();
1198        let mut total_imports = 0;
1199        let mut total_opens = 0;
1200        for module in self.modules.values() {
1201            total_imports += module.imports.len();
1202            total_opens += module.opens.len();
1203        }
1204        stats.insert("modules".to_string(), self.modules.len());
1205        stats.insert("total_imports".to_string(), total_imports);
1206        stats.insert("total_opens".to_string(), total_opens);
1207        stats
1208    }
1209    /// Export a module's public interface.
1210    #[allow(dead_code)]
1211    pub fn get_public_interface(&self, module_name: &str) -> Vec<String> {
1212        if let Some(module) = self.modules.get(module_name) {
1213            module
1214                .exported_names()
1215                .into_iter()
1216                .filter(|name| module.get_visibility(name) == Visibility::Public)
1217                .collect()
1218        } else {
1219            Vec::new()
1220        }
1221    }
1222    /// Check if name is accessible from module A in module B.
1223    #[allow(dead_code)]
1224    pub fn is_name_accessible(&self, name: &str, from_module: &str, to_module: &str) -> bool {
1225        if let Some(target) = self.modules.get(to_module) {
1226            let exported = target.exported_names();
1227            if exported.contains(&name.to_string()) {
1228                return target.is_accessible(name, from_module == to_module);
1229            }
1230        }
1231        false
1232    }
1233}
1234/// A namespace scope.
1235#[derive(Debug, Clone)]
1236pub struct NamespaceScope {
1237    /// Namespace name
1238    pub name: String,
1239    /// Opened namespaces within this scope
1240    pub opened: Vec<String>,
1241    /// Aliases (short name -> full name)
1242    pub aliases: HashMap<String, String>,
1243    /// Visibility map for names in this namespace
1244    pub visibility: HashMap<String, Visibility>,
1245    /// Parent namespace (for nested scopes)
1246    pub parent: Option<Box<NamespaceScope>>,
1247}