ast_grep_core/matcher/
kind.rs1use super::Matcher;
2
3use crate::language::Language;
4use crate::meta_var::MetaVarEnv;
5use crate::node::KindId;
6use crate::{Doc, Node};
7
8use std::borrow::Cow;
9
10use bit_set::BitSet;
11use thiserror::Error;
12
13const TS_BUILTIN_SYM_END: KindId = 0;
17const TS_BUILTIN_SYM_ERROR: KindId = 65535;
18
19#[derive(Debug, Error)]
20pub enum KindMatcherError {
21 #[error("Kind `{0}` is invalid.")]
22 InvalidKindName(String),
23}
24
25#[derive(Clone)]
26pub struct KindMatcher {
27 kind: KindId,
28}
29
30impl KindMatcher {
31 pub fn new<L: Language>(node_kind: &str, lang: L) -> Self {
32 Self {
33 kind: lang.kind_to_id(node_kind),
34 }
35 }
36
37 pub fn try_new<L: Language>(node_kind: &str, lang: L) -> Result<Self, KindMatcherError> {
38 println!("KindMatcher created with kind id: {}", node_kind);
39 let s = Self::new(node_kind, lang);
40 if s.is_invalid() {
41 Err(KindMatcherError::InvalidKindName(node_kind.into()))
42 } else {
43 Ok(s)
44 }
45 }
46
47 pub fn from_id(kind: KindId) -> Self {
48 Self { kind }
49 }
50
51 pub fn is_invalid(&self) -> bool {
53 self.kind == TS_BUILTIN_SYM_END
54 }
55
56 pub fn error_matcher() -> Self {
58 Self::from_id(TS_BUILTIN_SYM_ERROR)
59 }
60}
61
62pub mod kind_utils {
63 use super::*;
64
65 pub fn is_error_kind(kind: KindId) -> bool {
70 kind == TS_BUILTIN_SYM_ERROR
71 }
72
73 pub fn are_kinds_matching(goal: KindId, candidate: KindId) -> bool {
74 goal == candidate || is_error_kind(goal)
75 }
76}
77
78impl Matcher for KindMatcher {
79 fn match_node_with_env<'tree, D: Doc>(
80 &self,
81 node: Node<'tree, D>,
82 _env: &mut Cow<MetaVarEnv<'tree, D>>,
83 ) -> Option<Node<'tree, D>> {
84 if node.kind_id() == self.kind {
85 Some(node)
86 } else {
87 None
88 }
89 }
90
91 fn potential_kinds(&self) -> Option<BitSet> {
92 let mut set = BitSet::new();
93 set.insert(self.kind.into());
94 Some(set)
95 }
96}
97
98#[cfg(test)]
99mod test {
100 use super::*;
101 use crate::language::Tsx;
102 use crate::matcher::MatcherExt;
103 use crate::{tree_sitter::StrDoc, Root};
104
105 fn pattern_node(s: &str) -> Root<StrDoc<Tsx>> {
106 Root::str(s, Tsx)
107 }
108 #[test]
109 fn test_kind_match() {
110 let kind = "public_field_definition";
111 let cand = pattern_node("class A { a = 123 }");
112 let cand = cand.root();
113 let pattern = KindMatcher::new(kind, Tsx);
114 assert!(
115 pattern.find_node(cand.clone()).is_some(),
116 "goal: {}, candidate: {}",
117 kind,
118 cand.get_inner_node().to_sexp(),
119 );
120 }
121
122 #[test]
123 fn test_kind_non_match() {
124 let kind = "field_definition";
125 let cand = pattern_node("const a = 123");
126 let cand = cand.root();
127 let pattern = KindMatcher::new(kind, Tsx);
128 assert!(
129 pattern.find_node(cand.clone()).is_none(),
130 "goal: {}, candidate: {}",
131 kind,
132 cand.get_inner_node().to_sexp(),
133 );
134 }
135
136 #[test]
137 fn test_kind_potential_kinds() {
138 let kind = "field_definition";
139 let matcher = KindMatcher::new(kind, Tsx);
140 let potential_kinds = matcher
141 .potential_kinds()
142 .expect("should have potential kinds");
143 assert_eq!(potential_kinds.len(), 1);
145 }
146}