normalize_languages/
ast_grep.rs1use ast_grep_core::matcher::PatternBuilder;
7use ast_grep_core::tree_sitter::{LanguageExt, StrDoc, TSLanguage};
8use ast_grep_core::{Language as AstGrepLanguage, Pattern, PatternError};
9
10pub use ast_grep_core::tree_sitter::LanguageExt as AstGrepLanguageExt;
12
13#[derive(Clone)]
18pub struct DynLang(pub tree_sitter::Language);
19
20impl DynLang {
21 pub fn new(lang: tree_sitter::Language) -> Self {
23 Self(lang)
24 }
25
26 pub fn pattern(&self, pattern: &str) -> Result<Pattern, PatternError> {
28 Pattern::try_new(pattern, self.clone())
29 }
30}
31
32impl AstGrepLanguage for DynLang {
33 fn kind_to_id(&self, kind: &str) -> u16 {
34 self.0.id_for_node_kind(kind, true)
35 }
36
37 fn field_to_id(&self, field: &str) -> Option<u16> {
38 self.0.field_id_for_name(field).map(|nz| nz.get())
39 }
40
41 fn build_pattern(&self, builder: &PatternBuilder) -> Result<Pattern, PatternError> {
42 builder.build(|src| StrDoc::try_new(src, self.clone()))
43 }
44}
45
46impl LanguageExt for DynLang {
47 fn get_ts_language(&self) -> TSLanguage {
48 self.0.clone()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 #[test]
56 fn test_pattern_matching() {
57 use ast_grep_core::tree_sitter::LanguageExt;
58
59 let loader = crate::parsers::grammar_loader();
60 let Some(ts_lang) = loader.get("rust").ok() else {
61 eprintln!("Skipping test: rust grammar not available");
62 return;
63 };
64
65 let lang = DynLang::new(ts_lang);
66 let source = "fn foo() { let x = 1; }";
67
68 let grep = lang.ast_grep(source);
69 let root = grep.root();
70
71 let pattern = lang.pattern("foo").expect("pattern failed");
73 let matches: Vec<_> = root.find_all(&pattern).collect();
74 assert_eq!(matches.len(), 1);
75 assert_eq!(matches[0].text(), "foo");
76
77 let pattern = lang.pattern("let $X = $Y").expect("pattern failed");
79 let matches: Vec<_> = root.find_all(&pattern).collect();
80 assert_eq!(matches.len(), 1);
81 assert!(matches[0].text().contains("let x = 1"));
82 }
83}