Skip to main content

dk_engine/parser/
registry.rs

1use super::LanguageParser;
2use dk_core::{FileAnalysis, Result};
3use std::collections::HashMap;
4use std::path::Path;
5use std::sync::Arc;
6
7/// Central registry that maps file extensions to their language parsers.
8///
9/// Each parser is wrapped in an `Arc` so multiple extensions (e.g. "ts" and
10/// "tsx") can share the same parser instance without cloning.
11pub struct ParserRegistry {
12    parsers: HashMap<String, Arc<dyn LanguageParser>>,
13}
14
15impl ParserRegistry {
16    /// Create a new registry with all built-in language parsers registered.
17    pub fn new() -> Self {
18        let mut parsers: HashMap<String, Arc<dyn LanguageParser>> = HashMap::new();
19
20        // Rust
21        let rust = Arc::new(super::rust_parser::RustParser::new()) as Arc<dyn LanguageParser>;
22        for ext in rust.extensions() {
23            parsers.insert(ext.to_string(), Arc::clone(&rust));
24        }
25
26        // TypeScript / JavaScript
27        let ts = Arc::new(super::typescript_parser::TypeScriptParser::new())
28            as Arc<dyn LanguageParser>;
29        for ext in ts.extensions() {
30            parsers.insert(ext.to_string(), Arc::clone(&ts));
31        }
32
33        // Python
34        let py =
35            Arc::new(super::python_parser::PythonParser::new()) as Arc<dyn LanguageParser>;
36        for ext in py.extensions() {
37            parsers.insert(ext.to_string(), Arc::clone(&py));
38        }
39
40        Self { parsers }
41    }
42
43    /// Return `true` if the file extension is handled by a registered parser.
44    pub fn supports_file(&self, path: &Path) -> bool {
45        path.extension()
46            .and_then(|e| e.to_str())
47            .map(|ext| self.parsers.contains_key(ext))
48            .unwrap_or(false)
49    }
50
51    /// Parse a source file, selecting the parser by file extension.
52    ///
53    /// Returns `Error::UnsupportedLanguage` when no parser is registered for
54    /// the extension (or the path has no extension).
55    pub fn parse_file(&self, path: &Path, source: &[u8]) -> Result<FileAnalysis> {
56        let ext = path
57            .extension()
58            .and_then(|e| e.to_str())
59            .ok_or_else(|| dk_core::Error::UnsupportedLanguage("no extension".into()))?;
60
61        let parser = self
62            .parsers
63            .get(ext)
64            .ok_or_else(|| dk_core::Error::UnsupportedLanguage(ext.into()))?;
65
66        parser.parse_file(source, path)
67    }
68}
69
70impl Default for ParserRegistry {
71    fn default() -> Self {
72        Self::new()
73    }
74}