Skip to main content

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}