Skip to main content

ts_gen/
context.rs

1//! Global context: owns all arenas and provides the central data store
2//! for the entire parse → codegen pipeline.
3//!
4//! The `GlobalContext` is created once, mutated during parsing (Phase 1+2),
5//! then borrowed immutably for codegen.
6
7use crate::external_map::ExternalMap;
8use crate::ir::{TypeDeclaration, TypeKind};
9use crate::parse::scope::{PendingImport, ScopeArena, ScopeId};
10use crate::util::diagnostics::DiagnosticCollector;
11
12/// Well-typed index into the type arena.
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub struct TypeId(u32);
15
16impl TypeId {
17    /// Convert to a `usize` for indexing into slices.
18    pub fn index(self) -> usize {
19        self.0 as usize
20    }
21}
22
23/// Well-typed index into the module registry.
24#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
25pub struct ModuleId(u32);
26
27/// A parsed source file / module.
28#[derive(Clone, Debug)]
29pub struct ParsedModule {
30    /// The module specifier (e.g. `"node:buffer"`, `"es-module-lexer"`).
31    pub specifier: String,
32    /// The file scope in the arena.
33    pub scope: ScopeId,
34    /// Type ids owned by this module.
35    pub types: Vec<TypeId>,
36}
37
38/// The global data store shared across parsing and codegen.
39///
40/// Owns:
41/// - `ScopeArena`: type scopes (file, namespace, module, builtin)
42/// - Type arena: type definitions
43/// - Module registry: parsed source files
44/// - `ExternalMap`: external type mappings
45/// - `DiagnosticCollector`: warnings and info messages
46///
47/// Arenas are append-only during parsing and read-only during codegen.
48#[derive(Clone, Debug)]
49pub struct GlobalContext {
50    pub scopes: ScopeArena,
51    pub diagnostics: DiagnosticCollector,
52    pub external_map: ExternalMap,
53    /// Pending imports that need to be resolved during import resolution.
54    pub pending_imports: Vec<PendingImport>,
55    types: Vec<TypeDeclaration>,
56    modules: Vec<ParsedModule>,
57    /// Map from module specifier to ModuleId for fast lookup.
58    module_index: std::collections::HashMap<String, ModuleId>,
59}
60
61impl GlobalContext {
62    pub fn new() -> Self {
63        Self {
64            scopes: ScopeArena::new(),
65            diagnostics: DiagnosticCollector::new(),
66            external_map: ExternalMap::new(),
67            pending_imports: Vec::new(),
68            types: Vec::new(),
69            modules: Vec::new(),
70            module_index: std::collections::HashMap::new(),
71        }
72    }
73
74    /// Emit a warning diagnostic.
75    pub fn warn(&mut self, message: impl Into<String>) {
76        self.diagnostics.warn(message);
77    }
78
79    /// Emit an info diagnostic.
80    pub fn info(&mut self, message: impl Into<String>) {
81        self.diagnostics.info(message);
82    }
83
84    // ─── Scope operations (delegate to ScopeArena) ───────────────────
85
86    /// Create the root (builtin) scope.
87    pub fn create_root_scope(&mut self) -> ScopeId {
88        self.scopes.create_root()
89    }
90
91    /// Create a child scope.
92    pub fn create_child_scope(&mut self, parent: ScopeId) -> ScopeId {
93        self.scopes.create_child(parent)
94    }
95
96    // ─── Module registry operations ────────────────────────────────
97
98    /// Register a parsed module, returning its `ModuleId`.
99    pub fn register_module(&mut self, specifier: String, scope: ScopeId) -> ModuleId {
100        let id = ModuleId(self.modules.len() as u32);
101        self.module_index.insert(specifier.clone(), id);
102        self.modules.push(ParsedModule {
103            specifier,
104            scope,
105            types: Vec::new(),
106        });
107        id
108    }
109
110    /// Look up a module by specifier.
111    pub fn find_module(&self, specifier: &str) -> Option<ModuleId> {
112        self.module_index.get(specifier).copied()
113    }
114
115    /// Get a reference to a parsed module by `ModuleId`.
116    pub fn get_module(&self, id: ModuleId) -> &ParsedModule {
117        &self.modules[id.0 as usize]
118    }
119
120    /// Get a mutable reference to a parsed module by `ModuleId`.
121    pub fn get_module_mut(&mut self, id: ModuleId) -> &mut ParsedModule {
122        &mut self.modules[id.0 as usize]
123    }
124
125    // ─── Type arena operations ───────────────────────────────────────
126
127    /// Insert a declaration into the type arena, returning its `TypeId`.
128    pub fn insert_type(&mut self, decl: TypeDeclaration) -> TypeId {
129        let id = TypeId(self.types.len() as u32);
130        self.types.push(decl);
131        id
132    }
133
134    /// Get a reference to a declaration by `TypeId`.
135    pub fn get_type(&self, id: TypeId) -> &TypeDeclaration {
136        &self.types[id.index()]
137    }
138
139    /// Read-only access to the full type arena slice.
140    pub fn type_arena(&self) -> &[TypeDeclaration] {
141        &self.types
142    }
143
144    /// Resolve a dotted type path like `"NodeJS.TypedArray"` through namespace scopes.
145    ///
146    /// Splits on `.`, resolves the first segment in the starting scope, then
147    /// follows `Namespace` declarations for subsequent segments.
148    pub fn resolve_path(&self, scope: ScopeId, path: &str) -> Option<TypeId> {
149        let mut segments = path.split('.');
150        let first = segments.next()?;
151
152        let mut current_id = self.scopes.resolve(scope, first)?;
153
154        for segment in segments {
155            let decl = self.get_type(current_id);
156            match &decl.kind {
157                TypeKind::Namespace(ns) => {
158                    current_id = self.scopes.resolve(ns.child_scope, segment)?;
159                }
160                _ => return None, // Non-namespace in the middle of a path
161            }
162        }
163
164        Some(current_id)
165    }
166
167    /// Iterate all types in the arena.
168    pub fn iter_types(&self) -> impl Iterator<Item = (TypeId, &TypeDeclaration)> {
169        self.types
170            .iter()
171            .enumerate()
172            .map(|(i, d)| (TypeId(i as u32), d))
173    }
174}
175
176impl Default for GlobalContext {
177    fn default() -> Self {
178        Self::new()
179    }
180}