Skip to main content

ct_regex_internal/matcher/
interface.rs

1use std::fmt::Debug;
2
3use crate::expr::IndexedCaptures;
4use crate::haystack::{HaystackItem, HaystackOf};
5use crate::sealed::Sealed;
6
7pub trait Matcher<I: HaystackItem>: Sealed + Debug + Default + Clone + Copy {
8    type AllMatches<'a, H: HaystackOf<'a, I>>: Iterator<Item = usize>;
9    type AllCaptures<'a, H: HaystackOf<'a, I>>: Iterator<Item = (usize, IndexedCaptures)>;
10
11    /// Checks if the start of the haystack contains a match for this [`Matcher`]. If this method
12    /// successfully matches the start of the haystack, `hay` is progressed so that `hay.item()`
13    /// hasn't been matched yet. On a fail, the state of hay is undefined.
14    fn matches<'a, H: HaystackOf<'a, I>>(hay: &mut H) -> bool;
15
16    /// Produces a Vec of all valid haystack states produced as the result of a valid match at the
17    /// start of `hay`, used to implement backtracking. The Vec is produced in reverse priority
18    /// order, so the last match has the highest priority. After calling all_matches, the state of
19    /// `hay` itself is undefined.
20    ///
21    /// # Required
22    /// This method needs to be implemented by all [`Matcher`]s that can match more than one string
23    /// of characters from a haystack.
24    fn all_matches<'a, H: HaystackOf<'a, I>>(hay: &mut H) -> Self::AllMatches<'a, H>;
25
26    /// Checks if the start of the haystack contains a match for this Matcher, writing any groups
27    /// to `caps`. Similar to [`matches`], this method progresses `hay` and `caps` on a success. On
28    /// a fail, they have undefined states.
29    ///
30    /// # Required
31    /// This method needs to be implemented for capturing groups or any type that holds other
32    /// [`Matcher`]s, so that it can redirect to the relevant `capture` methods.
33    fn captures<'a, H: HaystackOf<'a, I>>(hay: &mut H, caps: &mut IndexedCaptures) -> bool {
34        let _ = caps;
35        Self::matches(hay)
36    }
37
38    /// Produces a Vec of all valid captures (and accompanying haystack states) present at the start
39    /// of `hay`. Used to implement backtracking for capturing methods. As with
40    /// [`all_matches`](Matcher::all_matches), the resulting Vec is produced in reverse priority
41    /// order. After calling all_captures, the state of `hay` and `caps` are undefined.
42    ///
43    /// # Required
44    /// This method needs to be implemented for any type that also implements
45    /// [`captures`](Matcher::captures) and [`all_matches`](Matcher::all_matches).
46    fn all_captures<'a, H: HaystackOf<'a, I>>(
47        hay: &mut H,
48        caps: &mut IndexedCaptures,
49    ) -> Self::AllCaptures<'a, H>;
50}
51
52// I'm just going to write this down cause I seem to keep forgetting. For alternations, either
53// branch may match a longer sequence in the haystack, but the first branch should be the priority.
54// This would complicate lazy semantics beyond just reversing the order of return values if it
55// wasn't for the simple fact that *alternations can't be lazy*. Laziness only applies to
56// quantifiers, even if that quantifiers is a 0-1 ("??" in the expression). Because there is always
57// a type between Lazy and Or in the type expression, it doesn't matter.
58// - Or<Lazy<..>, Lazy<..>> is valid and has clear semantics. No need for any special logic.
59// - Lazy<QuantifierNOrMore<Or<..>, N>> is also valid and matches Or eagerly during every
60//   repetition, rolling back if necessary.
61// - Lazy<Or<..>> is where things would get complicated, but there is no way to express it in an
62//   expression.
63
64pub trait LazyMatcher<I: HaystackItem>: Matcher<I> {
65    type LazyAllMatches<'a, H: HaystackOf<'a, I>>: Iterator<Item = usize>;
66    type LazyAllCaptures<'a, H: HaystackOf<'a, I>>: Iterator<Item = (usize, IndexedCaptures)>;
67
68    /// Functions exactly the same as [`Matcher::matches`], except that the haystack's index is left
69    /// at the first location where the match is considered successful.
70    fn lazy_matches<'a, H: HaystackOf<'a, I>>(hay: &mut H) -> bool;
71
72    /// Functions exactly the same as [`Matcher::all_matches`], except that the indices are produced
73    /// in the opposite order. The first value returned by the iterator is the one first encountered
74    /// in the haystack, not the one that produces the longest match.
75    fn lazy_all_matches<'a, H: HaystackOf<'a, I>>(hay: &mut H) -> Self::LazyAllMatches<'a, H>;
76
77    /// Functions exactly the same as [`Matcher::captures`], except that the haystack's index and
78    /// captures represent the first location where the match is considered successful.
79    fn lazy_captures<'a, H: HaystackOf<'a, I>>(hay: &mut H, caps: &mut IndexedCaptures) -> bool;
80
81    /// Functions exactly the same as [`Matcher::all_captures`], except that the indices and
82    /// captures are produced in the opposite order. The first value returned by the iterator is the
83    /// one first encountered in the haystack, not the one that produces the longest match.
84    fn lazy_all_captures<'a, H: HaystackOf<'a, I>>(
85        hay: &mut H,
86        caps: &mut IndexedCaptures,
87    ) -> Self::LazyAllCaptures<'a, H>;
88}