acp/ast/languages/
mod.rs

1//! @acp:module "Language Extractors"
2//! @acp:summary "Language-specific symbol extraction implementations"
3//! @acp:domain cli
4//! @acp:layer parsing
5
6pub mod go;
7pub mod java;
8pub mod javascript;
9pub mod python;
10pub mod rust;
11pub mod typescript;
12
13use super::{ExtractedSymbol, FunctionCall, Import};
14use crate::error::Result;
15use tree_sitter::{Language, Node, Tree};
16
17/// Trait for language-specific symbol extraction
18pub trait LanguageExtractor: Send + Sync {
19    /// Get the tree-sitter language
20    fn language(&self) -> Language;
21
22    /// Get the language name
23    fn name(&self) -> &'static str;
24
25    /// Get file extensions for this language
26    fn extensions(&self) -> &'static [&'static str];
27
28    /// Extract symbols from a parsed AST
29    fn extract_symbols(&self, tree: &Tree, source: &str) -> Result<Vec<ExtractedSymbol>>;
30
31    /// Extract import statements from a parsed AST
32    fn extract_imports(&self, tree: &Tree, source: &str) -> Result<Vec<Import>>;
33
34    /// Extract function calls from a parsed AST
35    fn extract_calls(
36        &self,
37        tree: &Tree,
38        source: &str,
39        current_function: Option<&str>,
40    ) -> Result<Vec<FunctionCall>>;
41
42    /// Extract doc comment for a node (language-specific comment syntax)
43    fn extract_doc_comment(&self, node: &Node, source: &str) -> Option<String>;
44}
45
46/// Get text for a node from source
47pub fn node_text<'a>(node: &Node, source: &'a str) -> &'a str {
48    &source[node.byte_range()]
49}
50
51/// Get an extractor for a language name
52pub fn get_extractor(language: &str) -> Option<Box<dyn LanguageExtractor>> {
53    match language.to_lowercase().as_str() {
54        "typescript" | "ts" => Some(Box::new(typescript::TypeScriptExtractor)),
55        "javascript" | "js" => Some(Box::new(javascript::JavaScriptExtractor)),
56        "rust" | "rs" => Some(Box::new(rust::RustExtractor)),
57        "python" | "py" => Some(Box::new(python::PythonExtractor)),
58        "go" => Some(Box::new(go::GoExtractor)),
59        "java" => Some(Box::new(java::JavaExtractor)),
60        _ => None,
61    }
62}
63
64/// Get an extractor by file extension
65pub fn extractor_for_extension(ext: &str) -> Option<Box<dyn LanguageExtractor>> {
66    match ext.to_lowercase().as_str() {
67        "ts" | "tsx" => Some(Box::new(typescript::TypeScriptExtractor)),
68        "js" | "jsx" | "mjs" | "cjs" => Some(Box::new(javascript::JavaScriptExtractor)),
69        "rs" => Some(Box::new(rust::RustExtractor)),
70        "py" | "pyi" => Some(Box::new(python::PythonExtractor)),
71        "go" => Some(Box::new(go::GoExtractor)),
72        "java" => Some(Box::new(java::JavaExtractor)),
73        _ => None,
74    }
75}