Skip to main content

dk_engine/parser/
lang_config.rs

1//! Per-language configuration for the query-driven parser engine.
2//!
3//! Each supported language implements [`LanguageConfig`] to provide its
4//! tree-sitter grammar, S-expression queries, comment style, and any
5//! language-specific fixups.
6
7use dk_core::{Symbol, SymbolKind, Visibility};
8
9// ── Comment style ──
10
11/// How doc-comments are written in a given language.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum CommentStyle {
14    /// Rust-style `///` doc comments.
15    TripleSlash,
16    /// Python / Ruby / shell `#` comments.
17    Hash,
18    /// Go / Java / TypeScript / C `//` comments.
19    SlashSlash,
20    /// Haskell `--` comments.
21    DashDash,
22}
23
24// ── Language configuration trait ──
25
26/// Configuration a language must supply so the generic
27/// [`QueryDrivenParser`](super) can extract symbols, calls, and imports.
28pub trait LanguageConfig: Send + Sync {
29    /// The tree-sitter [`Language`] grammar.
30    fn language(&self) -> tree_sitter::Language;
31
32    /// File extensions this language handles (without leading dot).
33    fn extensions(&self) -> &'static [&'static str];
34
35    /// Tree-sitter S-expression query that captures symbols.
36    ///
37    /// Capture names must end with a kind suffix that
38    /// [`default_kind_mapping`] (or an override of
39    /// [`map_capture_to_kind`](Self::map_capture_to_kind)) understands,
40    /// e.g. `@definition.function`, `@definition.class`.
41    fn symbols_query(&self) -> &'static str;
42
43    /// Tree-sitter S-expression query that captures call-sites.
44    fn calls_query(&self) -> &'static str;
45
46    /// Tree-sitter S-expression query that captures import statements.
47    fn imports_query(&self) -> &'static str;
48
49    /// The comment style used for doc-comments.
50    fn comment_style(&self) -> CommentStyle;
51
52    /// Resolve the visibility of a symbol from its modifier keywords and name.
53    fn resolve_visibility(&self, modifiers: Option<&str>, name: &str) -> Visibility;
54
55    // ── Default implementations ──
56
57    /// Map a tree-sitter capture suffix (e.g. `"function"`) to a
58    /// [`SymbolKind`].  The default delegates to [`default_kind_mapping`].
59    fn map_capture_to_kind(&self, capture_suffix: &str) -> Option<SymbolKind> {
60        default_kind_mapping(capture_suffix)
61    }
62
63    /// Post-process hook that can mutate a [`Symbol`] after extraction.
64    ///
65    /// Override this when the generic engine cannot capture all details
66    /// through queries alone (e.g. Rust `pub(crate)` modifiers).
67    #[allow(unused_variables)]
68    fn adjust_symbol(&self, sym: &mut Symbol, node: &tree_sitter::Node, source: &[u8]) {
69        // no-op by default
70    }
71
72    /// Return `true` if `module_path` refers to an external dependency.
73    ///
74    /// Paths starting with `.`, `crate`, `self`, or `super` are considered
75    /// internal by default.
76    fn is_external_import(&self, module_path: &str) -> bool {
77        !module_path.starts_with('.')
78            && !module_path.starts_with("crate")
79            && !module_path.starts_with("self")
80            && !module_path.starts_with("super")
81    }
82}
83
84// ── Shared helpers ──
85
86/// Map a capture-name suffix to a [`SymbolKind`].
87///
88/// This is the default implementation used by
89/// [`LanguageConfig::map_capture_to_kind`].  Language configs can call it
90/// directly or override the method entirely.
91pub fn default_kind_mapping(capture_suffix: &str) -> Option<SymbolKind> {
92    match capture_suffix {
93        "function" | "method" => Some(SymbolKind::Function),
94        "class" => Some(SymbolKind::Class),
95        "struct" => Some(SymbolKind::Struct),
96        "enum" => Some(SymbolKind::Enum),
97        "trait" => Some(SymbolKind::Trait),
98        "impl" => Some(SymbolKind::Impl),
99        "interface" => Some(SymbolKind::Interface),
100        "type_alias" | "type" => Some(SymbolKind::TypeAlias),
101        "const" | "expression" => Some(SymbolKind::Const),
102        "static" => Some(SymbolKind::Static),
103        "module" => Some(SymbolKind::Module),
104        "variable" => Some(SymbolKind::Variable),
105        _ => None,
106    }
107}