litcheck_filecheck/pattern/matcher/
mod.rs

1mod matchers;
2mod result;
3
4pub use self::matchers::*;
5pub use self::result::{CaptureInfo, MatchInfo, MatchResult, MatchType};
6
7use crate::common::*;
8
9pub type AnyMatcher<'a> = Box<dyn DynMatcher + 'a>;
10
11pub type AnyMatcherMut<'a> = Box<dyn DynMatcherMut + 'a>;
12
13/// This trait is used for match patterns which are pure, i.e. they have
14/// no effect on the current [MatchContext].
15pub trait Matcher: MatcherMut {
16    /// Search for a match in the given input buffer
17    ///
18    /// The first match found is returned.
19    fn try_match<'input, 'context, C>(
20        &self,
21        input: Input<'input>,
22        context: &C,
23    ) -> DiagResult<MatchResult<'input>>
24    where
25        C: Context<'input, 'context> + ?Sized;
26}
27impl<'a, M> Matcher for &'a M
28where
29    M: ?Sized + Matcher,
30{
31    fn try_match<'input, 'context, C>(
32        &self,
33        input: Input<'input>,
34        context: &C,
35    ) -> DiagResult<MatchResult<'input>>
36    where
37        C: Context<'input, 'context> + ?Sized,
38    {
39        <M as Matcher>::try_match(self, input, context)
40    }
41}
42
43pub trait DynMatcher: DynMatcherMut {
44    fn try_match_dyn<'input>(
45        &self,
46        input: Input<'input>,
47        context: &dyn Context<'input, '_>,
48    ) -> DiagResult<MatchResult<'input>>;
49}
50impl<M> DynMatcher for M
51where
52    M: Matcher,
53{
54    fn try_match_dyn<'input>(
55        &self,
56        input: Input<'input>,
57        context: &dyn Context<'input, '_>,
58    ) -> DiagResult<MatchResult<'input>> {
59        self.try_match(input, context)
60    }
61}
62
63/// This trait is used for match patterns which have side effects on the
64/// current [MatchContext] when successful.
65///
66/// These matchers may bind new variables, push operands or otherwise modify the match context.
67/// Implementors should ensure that such effects are only applied if a match succeeds however,
68/// to avoid polluting the match context.
69pub trait MatcherMut: fmt::Debug + Spanned {
70    /// Search for a match in the given input buffer
71    ///
72    /// The first match found is returned.
73    fn try_match_mut<'input, 'context, C>(
74        &self,
75        input: Input<'input>,
76        context: &mut C,
77    ) -> DiagResult<MatchResult<'input>>
78    where
79        C: Context<'input, 'context> + ?Sized;
80}
81impl<'a, M> MatcherMut for &'a M
82where
83    M: ?Sized + MatcherMut,
84{
85    fn try_match_mut<'input, 'context, C>(
86        &self,
87        input: Input<'input>,
88        context: &mut C,
89    ) -> DiagResult<MatchResult<'input>>
90    where
91        C: Context<'input, 'context> + ?Sized,
92    {
93        <M as MatcherMut>::try_match_mut(self, input, context)
94    }
95}
96impl<'a> MatcherMut for (dyn DynMatcher + 'a) {
97    #[inline]
98    fn try_match_mut<'input, 'context, C>(
99        &self,
100        input: Input<'input>,
101        context: &mut C,
102    ) -> DiagResult<MatchResult<'input>>
103    where
104        C: Context<'input, 'context> + ?Sized,
105    {
106        let passthrough = context.protect();
107        self.try_match_dyn(input, &passthrough)
108    }
109}
110impl<'a> MatcherMut for Box<dyn DynMatcher + 'a> {
111    #[inline]
112    fn try_match_mut<'input, 'context, C>(
113        &self,
114        input: Input<'input>,
115        context: &mut C,
116    ) -> DiagResult<MatchResult<'input>>
117    where
118        C: Context<'input, 'context> + ?Sized,
119    {
120        (**self).try_match_mut(input, context)
121    }
122}
123
124pub trait DynMatcherMut: fmt::Debug + Spanned {
125    fn try_match_mut_dyn<'input>(
126        &self,
127        input: Input<'input>,
128        context: &mut dyn Context<'input, '_>,
129    ) -> DiagResult<MatchResult<'input>>;
130}
131impl<M> DynMatcherMut for M
132where
133    M: MatcherMut,
134{
135    fn try_match_mut_dyn<'input>(
136        &self,
137        input: Input<'input>,
138        context: &mut dyn Context<'input, '_>,
139    ) -> DiagResult<MatchResult<'input>> {
140        self.try_match_mut(input, context)
141    }
142}
143impl<'a> MatcherMut for (dyn DynMatcherMut + 'a) {
144    #[inline]
145    fn try_match_mut<'input, 'context, C>(
146        &self,
147        input: Input<'input>,
148        context: &mut C,
149    ) -> DiagResult<MatchResult<'input>>
150    where
151        C: Context<'input, 'context> + ?Sized,
152    {
153        let mut passthrough = context.protect();
154        let result = self.try_match_mut_dyn(input, &mut passthrough)?;
155        if result.is_ok() {
156            passthrough.save();
157        }
158        Ok(result)
159    }
160}
161impl<'a> MatcherMut for Box<dyn DynMatcherMut + 'a> {
162    #[inline]
163    fn try_match_mut<'input, 'context, C>(
164        &self,
165        input: Input<'input>,
166        context: &mut C,
167    ) -> DiagResult<MatchResult<'input>>
168    where
169        C: Context<'input, 'context> + ?Sized,
170    {
171        (**self).try_match_mut(input, context)
172    }
173}