Skip to main content

tree_sitter_utils/
combinators.rs

1//! Combinator extension trait and sub-modules.
2//!
3//! Import [`HandlerExt`] to unlock all combinator methods on any [`Handler`].
4
5pub mod and_then;
6pub mod boxed;
7pub mod climb;
8pub mod find_ancestor;
9pub mod for_children;
10pub mod map;
11pub mod or;
12pub mod when;
13
14use std::marker::PhantomData;
15
16use crate::handler::Handler;
17use crate::input::Input;
18use crate::predicates::{kind_is, KindIs, NodePredicate};
19
20use self::and_then::AndThen;
21use self::boxed::BoxedHandler;
22use self::climb::{Climb, OrElseClimb};
23use self::find_ancestor::FindAncestor;
24use self::for_children::{ForChildren, ScanChildren};
25use self::map::Map;
26use self::or::Or;
27use self::when::When;
28
29/// Extension trait that adds combinator methods to every [`Handler`].
30///
31/// Blanket-implemented for all `T: Handler<Ctx, R>`; not intended as a trait
32/// object.
33///
34/// # Example
35///
36/// ```rust
37/// use tree_sitter_utils::{handler_fn, HandlerExt, Input, never};
38///
39/// let h = never::<(), u32>()
40///     .or(handler_fn(|_: Input<()>| 42u32))
41///     .map(|n| n.to_string());
42/// let _ = h;
43/// ```
44pub trait HandlerExt<Ctx, R>: Handler<Ctx, R> + Sized {
45    /// Try `self`; if it returns `None`, try `other`.
46    ///
47    /// # Example
48    ///
49    /// ```rust
50    /// use tree_sitter_utils::{never, handler_fn, HandlerExt, Input};
51    ///
52    /// let h = never::<(), String>()
53    ///     .or(handler_fn(|_: Input<()>| "fallback".to_owned()));
54    /// let _ = h;
55    /// ```
56    fn or<H: Handler<Ctx, R>>(self, other: H) -> Or<Self, H> {
57        Or { first: self, second: other }
58    }
59
60    /// Run `self` only when `pred` returns `true`; otherwise return `None`.
61    ///
62    /// # Example
63    ///
64    /// ```rust
65    /// use tree_sitter_utils::{handler_fn, HandlerExt, kind_is, Input};
66    ///
67    /// let h = handler_fn(|_: Input<()>| "hit".to_owned())
68    ///     .when(kind_is(&["identifier"]));
69    /// let _ = h;
70    /// ```
71    fn when<P: NodePredicate<Ctx>>(self, pred: P) -> When<Self, P> {
72        When { inner: self, pred }
73    }
74
75    /// Sugar for `.when(kind_is(kinds))` - only handle specific node kinds.
76    ///
77    /// # Example
78    ///
79    /// ```rust
80    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
81    ///
82    /// let h = handler_fn(|_: Input<()>| "ident".to_owned())
83    ///     .for_kinds(&["identifier", "type_identifier"]);
84    /// let _ = h;
85    /// ```
86    fn for_kinds(self, kinds: &'static [&'static str]) -> When<Self, KindIs> {
87        self.when(kind_is(kinds))
88    }
89
90    /// Apply `f` to the output value when `self` succeeds.
91    ///
92    /// # Example
93    ///
94    /// ```rust
95    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
96    ///
97    /// let h = handler_fn(|_: Input<()>| 1u32).map(|n| n.to_string());
98    /// let _ = h;
99    /// ```
100    fn map<F, R2>(self, f: F) -> Map<Self, F, R>
101    where
102        F: Fn(R) -> R2 + Send + Sync,
103    {
104        Map { inner: self, f, _marker: PhantomData }
105    }
106
107    /// Transform the [`Input`] before passing it to `self`.
108    ///
109    /// # Example
110    ///
111    /// ```rust
112    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
113    ///
114    /// let h = handler_fn(|input: Input<()>| input.node.kind().to_owned())
115    ///     .map_input(|mut i: Input<()>| { i.trigger_char = Some('.'); i });
116    /// let _ = h;
117    /// ```
118    fn map_input<F>(self, f: F) -> MapInput<Self, F>
119    where
120        F: for<'tree> Fn(Input<'tree, Ctx>) -> Input<'tree, Ctx> + Send + Sync,
121    {
122        MapInput { inner: self, f }
123    }
124
125    /// On success, pass `(input, out)` to `f`, which may itself return `None`.
126    ///
127    /// # Example
128    ///
129    /// ```rust
130    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
131    ///
132    /// let h = handler_fn(|_: Input<()>| 1u32)
133    ///     .and_then(|_: Input<()>, n: u32| Some(n + 1));
134    /// let _ = h;
135    /// ```
136    fn and_then<F, R2>(self, f: F) -> AndThen<Self, F, R>
137    where
138        F: Fn(Input<'_, Ctx>, R) -> Option<R2> + Send + Sync,
139    {
140        AndThen { inner: self, f, _marker: PhantomData }
141    }
142
143    /// Retry `self` on each ancestor until it succeeds, stopping at any kind
144    /// in `stop_kinds` or at the root.
145    ///
146    /// # Example
147    ///
148    /// ```rust
149    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
150    ///
151    /// let h = handler_fn(|input: Input<()>| {
152    ///     (input.node.kind() == "module").then(|| "module".to_owned())
153    /// })
154    /// .climb(&["source_file"]);
155    /// let _ = h;
156    /// ```
157    fn climb(self, stop_kinds: &'static [&'static str]) -> Climb<Self> {
158        Climb { inner: self, stop_kinds }
159    }
160
161    /// Try `self` on the original node; on `None`, try `other` on each ancestor.
162    ///
163    /// # Example
164    ///
165    /// ```rust
166    /// use tree_sitter_utils::{never, HandlerExt, Input};
167    ///
168    /// let h = never::<(), String>()
169    ///     .or_else_climb(
170    ///         |input: tree_sitter_utils::Input<()>| -> Option<String> {
171    ///             Some(input.node.kind().to_owned())
172    ///         },
173    ///         &["source_file"],
174    ///     );
175    /// let _ = h;
176    /// ```
177    fn or_else_climb<O: Handler<Ctx, R>>(self, other: O, stop_kinds: &'static [&'static str]) -> OrElseClimb<Self, O> {
178        OrElseClimb { inner: self, other, stop_kinds }
179    }
180
181    /// Walk up to the nearest strict ancestor in `target_kinds`, then run
182    /// `self` on **that ancestor node** once.
183    ///
184    /// Unlike [`HandlerExt::climb`], which retries `self` on every ancestor,
185    /// `find_ancestor` locates a specific kind first and invokes `self` once.
186    ///
187    /// Stops (`None`) when a `stop_kinds` node or the root is reached.
188    ///
189    /// # Example
190    ///
191    /// ```rust
192    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
193    ///
194    /// let h = handler_fn(|inp: Input<()>| inp.node.kind().to_owned())
195    ///     .find_ancestor(&["argument_list"], &["program"]);
196    /// let _ = h;
197    /// ```
198    fn find_ancestor(self, target_kinds: &'static [&'static str], stop_kinds: &'static [&'static str]) -> FindAncestor<Self> {
199        FindAncestor { inner: self, target_kinds, stop_kinds }
200    }
201
202    /// Apply `self` to every **named child**, collect all `Some(r)` into a
203    /// `Vec<R>`, and return `Some(vec)` (never `None`).
204    ///
205    /// # Example
206    ///
207    /// ```rust
208    /// use tree_sitter_utils::{handler_fn, HandlerExt, Input};
209    ///
210    /// let h = handler_fn(|inp: Input<()>| inp.node.kind().to_owned())
211    ///     .for_children();
212    /// let _ = h;
213    /// ```
214    fn for_children(self) -> ForChildren<Self> {
215        ForChildren { inner: self }
216    }
217
218    /// Apply `self` to each **named child** in order; return the first
219    /// `Some(r)`, or `None` if no child matches.
220    ///
221    /// # Example
222    ///
223    /// ```rust
224    /// use tree_sitter_utils::{Input, HandlerExt};
225    ///
226    /// let h = (|inp: Input<()>| -> Option<String> {
227    ///     (inp.node.kind() == "identifier").then(|| inp.node.kind().to_owned())
228    /// })
229    /// .scan_children();
230    /// let _ = h;
231    /// ```
232    fn scan_children(self) -> ScanChildren<Self> {
233        ScanChildren { inner: self }
234    }
235
236    /// Erase the concrete type into a [`BoxedHandler`] for dynamic dispatch.
237    ///
238    /// # Example
239    ///
240    /// ```rust
241    /// use tree_sitter_utils::{handler_fn, HandlerExt, BoxedHandler, Input};
242    ///
243    /// let h: BoxedHandler<(), String> =
244    ///     handler_fn(|_: Input<()>| "hi".to_owned()).boxed();
245    /// let _ = h;
246    /// ```
247    fn boxed(self) -> BoxedHandler<Ctx, R>
248    where
249        Self: 'static,
250        Ctx: Copy,
251    {
252        BoxedHandler::new(move |input| self.handle(input))
253    }
254}
255
256impl<Ctx, R, T: Handler<Ctx, R>> HandlerExt<Ctx, R> for T {}
257
258pub struct MapInput<H, F> {
259    pub inner: H,
260    pub f: F,
261}
262
263impl<Ctx, R, H, F> Handler<Ctx, R> for MapInput<H, F>
264where
265    H: Handler<Ctx, R>,
266    F: for<'tree> Fn(Input<'tree, Ctx>) -> Input<'tree, Ctx> + Send + Sync,
267    Ctx: Copy,
268{
269    #[inline]
270    fn handle<'tree>(&self, input: Input<'tree, Ctx>) -> Option<R> {
271        self.inner.handle((self.f)(input))
272    }
273}