Skip to main content

rma_parser/
languages.rs

1//! Language support module - provides tree-sitter grammars for each language
2
3use anyhow::Result;
4use rma_common::{Language, RmaError};
5use tree_sitter::Language as TsLanguage;
6
7/// Get the tree-sitter language for a given language enum
8pub fn get_language(lang: Language) -> Result<TsLanguage> {
9    match lang {
10        Language::Rust => Ok(tree_sitter_rust::LANGUAGE.into()),
11        Language::JavaScript => Ok(tree_sitter_javascript::LANGUAGE.into()),
12        Language::TypeScript => Ok(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
13        Language::Python => Ok(tree_sitter_python::LANGUAGE.into()),
14        Language::Go => Ok(tree_sitter_go::LANGUAGE.into()),
15        Language::Java => Ok(tree_sitter_java::LANGUAGE.into()),
16        Language::Unknown => Err(RmaError::UnsupportedLanguage("unknown".into()).into()),
17    }
18}
19
20/// Get query patterns for common constructs in each language
21pub mod queries {
22    use rma_common::Language;
23
24    /// Function definition query for each language
25    pub fn function_query(lang: Language) -> Option<&'static str> {
26        match lang {
27            Language::Rust => Some(
28                r#"
29                (function_item name: (identifier) @name) @function
30                (impl_item (function_item name: (identifier) @name)) @method
31                "#,
32            ),
33            Language::JavaScript | Language::TypeScript => Some(
34                r#"
35                (function_declaration name: (identifier) @name) @function
36                (method_definition name: (property_identifier) @name) @method
37                (arrow_function) @arrow
38                "#,
39            ),
40            Language::Python => Some(
41                r#"
42                (function_definition name: (identifier) @name) @function
43                (class_definition body: (block (function_definition name: (identifier) @name))) @method
44                "#,
45            ),
46            Language::Go => Some(
47                r#"
48                (function_declaration name: (identifier) @name) @function
49                (method_declaration name: (field_identifier) @name) @method
50                "#,
51            ),
52            Language::Java => Some(
53                r#"
54                (method_declaration name: (identifier) @name) @method
55                (constructor_declaration name: (identifier) @name) @constructor
56                "#,
57            ),
58            Language::Unknown => None,
59        }
60    }
61
62    /// Class/struct definition query for each language
63    pub fn class_query(lang: Language) -> Option<&'static str> {
64        match lang {
65            Language::Rust => Some(
66                r#"
67                (struct_item name: (type_identifier) @name) @struct
68                (enum_item name: (type_identifier) @name) @enum
69                (impl_item type: (type_identifier) @name) @impl
70                "#,
71            ),
72            Language::JavaScript | Language::TypeScript => Some(
73                r#"
74                (class_declaration name: (identifier) @name) @class
75                "#,
76            ),
77            Language::Python => Some(
78                r#"
79                (class_definition name: (identifier) @name) @class
80                "#,
81            ),
82            Language::Go => Some(
83                r#"
84                (type_declaration (type_spec name: (type_identifier) @name)) @type
85                "#,
86            ),
87            Language::Java => Some(
88                r#"
89                (class_declaration name: (identifier) @name) @class
90                (interface_declaration name: (identifier) @name) @interface
91                "#,
92            ),
93            Language::Unknown => None,
94        }
95    }
96
97    /// Import/use statement query for each language
98    pub fn import_query(lang: Language) -> Option<&'static str> {
99        match lang {
100            Language::Rust => Some(
101                r#"
102                (use_declaration) @import
103                (extern_crate_declaration) @import
104                "#,
105            ),
106            Language::JavaScript | Language::TypeScript => Some(
107                r#"
108                (import_statement) @import
109                (import_clause) @import
110                "#,
111            ),
112            Language::Python => Some(
113                r#"
114                (import_statement) @import
115                (import_from_statement) @import
116                "#,
117            ),
118            Language::Go => Some(
119                r#"
120                (import_declaration) @import
121                "#,
122            ),
123            Language::Java => Some(
124                r#"
125                (import_declaration) @import
126                "#,
127            ),
128            Language::Unknown => None,
129        }
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136
137    #[test]
138    fn test_get_language() {
139        assert!(get_language(Language::Rust).is_ok());
140        assert!(get_language(Language::JavaScript).is_ok());
141        assert!(get_language(Language::Python).is_ok());
142        assert!(get_language(Language::Go).is_ok());
143        assert!(get_language(Language::Java).is_ok());
144        assert!(get_language(Language::Unknown).is_err());
145    }
146
147    #[test]
148    fn test_function_queries_exist() {
149        assert!(queries::function_query(Language::Rust).is_some());
150        assert!(queries::function_query(Language::JavaScript).is_some());
151        assert!(queries::function_query(Language::Python).is_some());
152        assert!(queries::function_query(Language::Unknown).is_none());
153    }
154}