tree_sitter_utils/predicates.rs
1//! [`NodePredicate`] trait and built-in predicate constructors.
2
3use crate::input::Input;
4
5/// A predicate over an [`Input`] — returns `true` when the node matches.
6///
7/// Any `F: Fn(Input<'_, Ctx>) -> bool + Send + Sync` implements this trait
8/// automatically via the blanket implementation, so plain closures work too.
9///
10/// Use the free-function constructors ([`kind_is`], [`kind_is_not`], …) to
11/// obtain named predicate values, or supply any compatible closure directly.
12///
13/// # Example
14///
15/// ```rust
16/// use tree_sitter_utils::{NodePredicate, kind_is};
17///
18/// fn accepts_pred<Ctx: Copy, P: NodePredicate<Ctx>>(_: P) {}
19/// accepts_pred::<(), _>(kind_is(&["identifier"]));
20/// accepts_pred::<(), _>(|input: tree_sitter_utils::Input<()>| input.node.kind() == "identifier");
21/// ```
22pub trait NodePredicate<Ctx>: Send + Sync {
23 /// Test whether the predicate holds for the given input.
24 fn test(&self, input: Input<'_, Ctx>) -> bool;
25}
26
27/// Blanket impl: every `Fn(Input<'_, Ctx>) -> bool + Send + Sync` is a predicate.
28impl<Ctx, F> NodePredicate<Ctx> for F
29where
30 F: Fn(Input<'_, Ctx>) -> bool + Send + Sync,
31{
32 #[inline]
33 fn test(&self, input: Input<'_, Ctx>) -> bool {
34 self(input)
35 }
36}
37
38// ---------------------------------------------------------------------------
39// Built-in predicate structs
40// ---------------------------------------------------------------------------
41
42/// Predicate: `true` when `node.kind()` is one of the given static `kinds`.
43///
44/// # Example
45///
46/// ```rust
47/// use tree_sitter_utils::kind_is;
48/// let pred = kind_is(&["identifier", "type_identifier"]);
49/// let _ = pred;
50/// ```
51#[derive(Clone, Copy, Debug)]
52pub struct KindIs(pub &'static [&'static str]);
53
54impl<Ctx> NodePredicate<Ctx> for KindIs {
55 #[inline]
56 fn test(&self, input: Input<'_, Ctx>) -> bool {
57 self.0.contains(&input.node.kind())
58 }
59}
60
61/// Predicate: `true` when `node.kind()` is **not** in the given `kinds`.
62///
63/// # Example
64///
65/// ```rust
66/// use tree_sitter_utils::kind_is_not;
67/// let pred = kind_is_not(&["comment", "ERROR"]);
68/// let _ = pred;
69/// ```
70#[derive(Clone, Copy, Debug)]
71pub struct KindIsNot(pub &'static [&'static str]);
72
73impl<Ctx> NodePredicate<Ctx> for KindIsNot {
74 #[inline]
75 fn test(&self, input: Input<'_, Ctx>) -> bool {
76 !self.0.contains(&input.node.kind())
77 }
78}
79
80/// Predicate: `true` when `node.parent()` has the given `kind`.
81///
82/// # Example
83///
84/// ```rust
85/// use tree_sitter_utils::has_parent_kind;
86/// let pred = has_parent_kind("function_definition");
87/// let _ = pred;
88/// ```
89#[derive(Clone, Copy, Debug)]
90pub struct HasParentKind(pub &'static str);
91
92impl<Ctx> NodePredicate<Ctx> for HasParentKind {
93 #[inline]
94 fn test(&self, input: Input<'_, Ctx>) -> bool {
95 input.node.parent().is_some_and(|p| p.kind() == self.0)
96 }
97}
98
99/// Predicate: `true` when the node depth (root = 0) is at most `max`.
100///
101/// # Example
102///
103/// ```rust
104/// use tree_sitter_utils::node_depth_lte;
105/// let pred = node_depth_lte(3);
106/// let _ = pred;
107/// ```
108#[derive(Clone, Copy, Debug)]
109pub struct NodeDepthLte(pub usize);
110
111impl<Ctx> NodePredicate<Ctx> for NodeDepthLte {
112 #[inline]
113 fn test(&self, input: Input<'_, Ctx>) -> bool {
114 let mut depth = 0usize;
115 let mut current = input.node;
116 while let Some(parent) = current.parent() {
117 depth += 1;
118 if depth > self.0 {
119 return false;
120 }
121 current = parent;
122 }
123 depth <= self.0
124 }
125}
126
127// ---------------------------------------------------------------------------
128// Public constructor functions
129// ---------------------------------------------------------------------------
130
131/// Returns a predicate that is `true` when `node.kind()` is in `kinds`.
132///
133/// # Example
134///
135/// ```rust
136/// use tree_sitter_utils::kind_is;
137/// let _ = kind_is(&["identifier"]);
138/// ```
139#[inline]
140pub fn kind_is(kinds: &'static [&'static str]) -> KindIs {
141 KindIs(kinds)
142}
143
144/// Returns a predicate that is `true` when `node.kind()` is **not** in `kinds`.
145///
146/// # Example
147///
148/// ```rust
149/// use tree_sitter_utils::kind_is_not;
150/// let _ = kind_is_not(&["comment", "ERROR"]);
151/// ```
152#[inline]
153pub fn kind_is_not(kinds: &'static [&'static str]) -> KindIsNot {
154 KindIsNot(kinds)
155}
156
157/// Returns a predicate that is `true` when the node's parent has `kind`.
158///
159/// # Example
160///
161/// ```rust
162/// use tree_sitter_utils::has_parent_kind;
163/// let _ = has_parent_kind("call_expression");
164/// ```
165#[inline]
166pub fn has_parent_kind(kind: &'static str) -> HasParentKind {
167 HasParentKind(kind)
168}
169
170/// Returns a predicate that is `true` when the node's tree-depth ≤ `max`.
171///
172/// # Example
173///
174/// ```rust
175/// use tree_sitter_utils::node_depth_lte;
176/// let _ = node_depth_lte(5);
177/// ```
178#[inline]
179pub fn node_depth_lte(max: usize) -> NodeDepthLte {
180 NodeDepthLte(max)
181}
182
183/// Predicate: `true` when **any strict ancestor** of the node has the given
184/// `kind`.
185///
186/// Unlike [`HasParentKind`], which only inspects the immediate parent, this
187/// predicate walks the full ancestry chain from the node up to the root and
188/// returns `true` as soon as it finds a node whose kind matches.
189///
190/// The node itself is **not** tested — only its strict ancestors.
191///
192/// This is the predicate counterpart of the java parser's `find_ancestor`
193/// utility. Use it to write guards such as:
194///
195/// ```rust
196/// use tree_sitter_utils::{handler_fn, HandlerExt, has_ancestor_kind, Input};
197///
198/// // Only fire when the node lives somewhere inside an `argument_list`.
199/// let h = handler_fn(|_: Input<()>| "inside arg list".to_owned())
200/// .when(has_ancestor_kind("argument_list"));
201/// let _ = h;
202/// ```
203#[derive(Clone, Copy, Debug)]
204pub struct HasAncestorKind(pub &'static str);
205
206impl<Ctx> NodePredicate<Ctx> for HasAncestorKind {
207 #[inline]
208 fn test(&self, input: Input<'_, Ctx>) -> bool {
209 let mut current = input.node.parent();
210 while let Some(ancestor) = current {
211 if ancestor.kind() == self.0 {
212 return true;
213 }
214 current = ancestor.parent();
215 }
216 false
217 }
218}
219
220/// Returns a predicate that is `true` when **any strict ancestor** of the
221/// node has the given `kind`.
222///
223/// See [`HasAncestorKind`] for the full semantics.
224///
225/// # Example
226///
227/// ```rust
228/// use tree_sitter_utils::has_ancestor_kind;
229/// let _ = has_ancestor_kind("lambda_expression");
230/// ```
231#[inline]
232pub fn has_ancestor_kind(kind: &'static str) -> HasAncestorKind {
233 HasAncestorKind(kind)
234}
235
236/// Predicate: `true` when **any strict ancestor** of the node has a kind that
237/// is one of the given `kinds`.
238///
239/// This is the multi-kind variant of [`HasAncestorKind`]. It walks the full
240/// ancestry chain from the node up to the root and returns `true` as soon as
241/// it finds a node whose kind appears in `kinds`.
242///
243/// The node itself is **not** tested — only its strict ancestors.
244///
245/// # Example
246///
247/// ```rust
248/// use tree_sitter_utils::{handler_fn, HandlerExt, has_ancestor_kinds, Input};
249///
250/// // Only fire when the node is nested inside a method or constructor.
251/// let h = handler_fn(|_: Input<()>| "in method or ctor".to_owned())
252/// .when(has_ancestor_kinds(&["method_declaration", "constructor_declaration"]));
253/// let _ = h;
254/// ```
255#[derive(Clone, Copy, Debug)]
256pub struct HasAncestorKinds(pub &'static [&'static str]);
257
258impl<Ctx> NodePredicate<Ctx> for HasAncestorKinds {
259 #[inline]
260 fn test(&self, input: Input<'_, Ctx>) -> bool {
261 let mut current = input.node.parent();
262 while let Some(ancestor) = current {
263 if self.0.contains(&ancestor.kind()) {
264 return true;
265 }
266 current = ancestor.parent();
267 }
268 false
269 }
270}
271
272/// Returns a predicate that is `true` when **any strict ancestor** of the
273/// node has a kind that is one of `kinds`.
274///
275/// See [`HasAncestorKinds`] for the full semantics.
276///
277/// # Example
278///
279/// ```rust
280/// use tree_sitter_utils::has_ancestor_kinds;
281/// let _ = has_ancestor_kinds(&["method_declaration", "constructor_declaration"]);
282/// ```
283#[inline]
284pub fn has_ancestor_kinds(kinds: &'static [&'static str]) -> HasAncestorKinds {
285 HasAncestorKinds(kinds)
286}