ast_grep_core/
matcher.rs

1//! This module defines the core `Matcher` trait in ast-grep.
2//!
3//! `Matcher` has three notable implementations in this module:
4//! * Pattern: matches against a tree-sitter node based on its tree structure.
5//! * KindMatcher: matches a node based on its `kind`
6//! * RegexMatcher: matches a node based on its textual content using regex.
7
8mod kind;
9mod node_match;
10mod pattern;
11mod text;
12
13use crate::Doc;
14use crate::{meta_var::MetaVarEnv, Node};
15
16use bit_set::BitSet;
17use std::borrow::Cow;
18
19pub use kind::{kind_utils, KindMatcher, KindMatcherError};
20pub use node_match::NodeMatch;
21pub use pattern::{Pattern, PatternBuilder, PatternError, PatternNode};
22pub use text::{RegexMatcher, RegexMatcherError};
23
24/// `Matcher` defines whether a tree-sitter node matches certain pattern,
25/// and update the matched meta-variable values in `MetaVarEnv`.
26/// N.B. At least one positive term is required for matching
27pub trait Matcher {
28  /// Returns the node why the input is matched or None if not matched.
29  /// The return value is usually input node itself, but it can be different node.
30  /// For example `Has` matcher can return the child or descendant node.
31  fn match_node_with_env<'tree, D: Doc>(
32    &self,
33    _node: Node<'tree, D>,
34    _env: &mut Cow<MetaVarEnv<'tree, D>>,
35  ) -> Option<Node<'tree, D>>;
36
37  /// Returns a bitset for all possible target node kind ids.
38  /// Returns None if the matcher needs to try against all node kind.
39  fn potential_kinds(&self) -> Option<BitSet> {
40    None
41  }
42
43  /// get_match_len will skip trailing anonymous child node to exclude punctuation.
44  // This is not included in NodeMatch since it is only used in replace
45  fn get_match_len<D: Doc>(&self, _node: Node<'_, D>) -> Option<usize> {
46    None
47  }
48}
49
50/// MatcherExt provides additional utility methods for `Matcher`.
51/// It is implemented for all types that implement `Matcher`.
52/// N.B. This trait is not intended to be implemented by users.
53pub trait MatcherExt: Matcher {
54  fn match_node<'tree, D: Doc>(&self, node: Node<'tree, D>) -> Option<NodeMatch<'tree, D>> {
55    // in future we might need to customize initial MetaVarEnv
56    let mut env = Cow::Owned(MetaVarEnv::new());
57    let node = self.match_node_with_env(node, &mut env)?;
58    Some(NodeMatch::new(node, env.into_owned()))
59  }
60
61  fn find_node<'tree, D: Doc>(&self, node: Node<'tree, D>) -> Option<NodeMatch<'tree, D>> {
62    for n in node.dfs() {
63      if let Some(ret) = self.match_node(n.clone()) {
64        return Some(ret);
65      }
66    }
67    None
68  }
69}
70
71impl<T> MatcherExt for T where T: Matcher {}
72
73impl Matcher for str {
74  fn match_node_with_env<'tree, D: Doc>(
75    &self,
76    node: Node<'tree, D>,
77    env: &mut Cow<MetaVarEnv<'tree, D>>,
78  ) -> Option<Node<'tree, D>> {
79    let pattern = Pattern::new(self, node.lang().clone());
80    pattern.match_node_with_env(node, env)
81  }
82
83  fn get_match_len<D: Doc>(&self, node: Node<'_, D>) -> Option<usize> {
84    let pattern = Pattern::new(self, node.lang().clone());
85    pattern.get_match_len(node)
86  }
87}
88
89impl<T> Matcher for &T
90where
91  T: Matcher + ?Sized,
92{
93  fn match_node_with_env<'tree, D: Doc>(
94    &self,
95    node: Node<'tree, D>,
96    env: &mut Cow<MetaVarEnv<'tree, D>>,
97  ) -> Option<Node<'tree, D>> {
98    (**self).match_node_with_env(node, env)
99  }
100
101  fn potential_kinds(&self) -> Option<BitSet> {
102    (**self).potential_kinds()
103  }
104
105  fn get_match_len<D: Doc>(&self, node: Node<'_, D>) -> Option<usize> {
106    (**self).get_match_len(node)
107  }
108}
109
110pub struct MatchAll;
111impl Matcher for MatchAll {
112  fn match_node_with_env<'tree, D: Doc>(
113    &self,
114    node: Node<'tree, D>,
115    _env: &mut Cow<MetaVarEnv<'tree, D>>,
116  ) -> Option<Node<'tree, D>> {
117    Some(node)
118  }
119
120  fn potential_kinds(&self) -> Option<BitSet> {
121    // return None to match anything
122    None
123  }
124}
125
126pub struct MatchNone;
127impl Matcher for MatchNone {
128  fn match_node_with_env<'tree, D: Doc>(
129    &self,
130    _node: Node<'tree, D>,
131    _env: &mut Cow<MetaVarEnv<'tree, D>>,
132  ) -> Option<Node<'tree, D>> {
133    None
134  }
135
136  fn potential_kinds(&self) -> Option<BitSet> {
137    // matches nothing
138    Some(BitSet::new())
139  }
140}