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