oxilean_parse/module_system/types.rs
1//! Module system types for import resolution and dependency tracking.
2
3use std::collections::HashMap;
4use std::fmt;
5use std::path::PathBuf;
6
7// ─────────────────────────────────────────────────────────────────────────────
8// ModulePath
9// ─────────────────────────────────────────────────────────────────────────────
10
11/// A dot-separated module path, e.g. `Mathlib.Algebra.Ring` →
12/// `["Mathlib", "Algebra", "Ring"]`.
13#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
14pub struct ModulePath {
15 /// Ordered components of the path (no empty strings).
16 pub components: Vec<String>,
17}
18
19impl fmt::Display for ModulePath {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "{}", self.components.join("."))
22 }
23}
24
25// ─────────────────────────────────────────────────────────────────────────────
26// ImportDecl
27// ─────────────────────────────────────────────────────────────────────────────
28
29/// A parsed `import` declaration.
30///
31/// Supports three forms:
32/// - `import Foo.Bar` — bare import
33/// - `import Foo.Bar as FB` — aliased import
34/// - `import Foo.Bar (f, g)` — selective import
35#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct ImportDecl {
37 /// The module being imported.
38 pub module: ModulePath,
39 /// Optional alias (`import X as Y`).
40 pub alias: Option<String>,
41 /// Selective names (`import X (f, g)`). Empty means "import all".
42 pub selective: Vec<String>,
43}
44
45// ─────────────────────────────────────────────────────────────────────────────
46// ModuleInfo
47// ─────────────────────────────────────────────────────────────────────────────
48
49/// Metadata about a resolved module.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct ModuleInfo {
52 /// Canonical file-system path of the module file.
53 pub path: PathBuf,
54 /// Names exported by the module.
55 pub exports: Vec<String>,
56 /// Direct module dependencies (as declared by `import` statements inside
57 /// the module).
58 pub dependencies: Vec<ModulePath>,
59}
60
61// ─────────────────────────────────────────────────────────────────────────────
62// ModuleRegistry
63// ─────────────────────────────────────────────────────────────────────────────
64
65/// Registry that maps [`ModulePath`]s to [`ModuleInfo`]s, with file-system
66/// root search and a resolution cache.
67#[derive(Debug, Clone)]
68pub struct ModuleRegistry {
69 /// Root directories searched when resolving a module path to a file.
70 pub roots: Vec<PathBuf>,
71 /// Cache: module path → resolved info. Populated on first successful
72 /// [`ModuleRegistry::resolve`] or explicit [`ModuleRegistry::register`].
73 pub cache: HashMap<ModulePath, ModuleInfo>,
74}
75
76// ─────────────────────────────────────────────────────────────────────────────
77// ModuleGraph
78// ─────────────────────────────────────────────────────────────────────────────
79
80/// A directed graph of module dependencies.
81///
82/// - `nodes`: module → its info
83/// - `edges`: `(from, to)` — `from` imports `to`
84#[derive(Debug, Clone, Default)]
85pub struct ModuleGraph {
86 /// All known modules, keyed by path.
87 pub nodes: HashMap<ModulePath, ModuleInfo>,
88 /// Directed dependency edges `(importer, importee)`.
89 pub edges: Vec<(ModulePath, ModulePath)>,
90}
91
92// ─────────────────────────────────────────────────────────────────────────────
93// CycleError
94// ─────────────────────────────────────────────────────────────────────────────
95
96/// A detected import cycle.
97///
98/// `cycle` contains the sequence of modules that form the cycle, in order.
99/// The last element imports the first element.
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct CycleError {
102 /// Ordered list of modules forming the cycle.
103 pub cycle: Vec<ModulePath>,
104}
105
106impl fmt::Display for CycleError {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let names: Vec<String> = self.cycle.iter().map(|p| p.to_string()).collect();
109 write!(f, "import cycle detected: {}", names.join(" → "))
110 }
111}
112
113// ─────────────────────────────────────────────────────────────────────────────
114// ModuleResolutionResult
115// ─────────────────────────────────────────────────────────────────────────────
116
117/// The outcome of attempting to resolve a [`ModulePath`] in a
118/// [`ModuleRegistry`].
119#[derive(Debug, Clone, PartialEq, Eq)]
120pub enum ModuleResolutionResult {
121 /// The module was found and its info is returned.
122 Found(ModuleInfo),
123 /// No file could be located for the given path.
124 NotFound(ModulePath),
125 /// Resolving the module would create an import cycle.
126 Cycle(CycleError),
127}