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().into()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::GrammarLoader;
56
57 #[test]
58 fn test_pattern_matching() {
59 use ast_grep_core::tree_sitter::LanguageExt;
60
61 let loader = GrammarLoader::new();
62 let Some(ts_lang) = loader.get("rust") else {
63 eprintln!("Skipping test: rust grammar not available");
64 return;
65 };
66
67 let lang = DynLang::new(ts_lang);
68 let source = "fn foo() { let x = 1; }";
69
70 let grep = lang.ast_grep(source);
71 let root = grep.root();
72
73 let pattern = lang.pattern("foo").expect("pattern failed");
75 let matches: Vec<_> = root.find_all(&pattern).collect();
76 assert_eq!(matches.len(), 1);
77 assert_eq!(matches[0].text(), "foo");
78
79 let pattern = lang.pattern("let $X = $Y").expect("pattern failed");
81 let matches: Vec<_> = root.find_all(&pattern).collect();
82 assert_eq!(matches.len(), 1);
83 assert!(matches[0].text().contains("let x = 1"));
84 }
85}