litcheck_filecheck/pattern/matcher/matchers/
any.rs

1use crate::common::*;
2
3use super::{MatchAll, RegexSetMatcher, SubstringSetMatcher};
4
5#[derive(Debug)]
6pub enum MatchAny<'a> {
7    /// Match a set of literal strings
8    Literal(SubstringSetMatcher<'a>),
9    /// Match a set of static regex patterns
10    Regex(RegexSetMatcher<'a>),
11    /// A highly dynamic pattern matcher, but less efficient, as
12    /// it is forced to perform some number of redundant searches
13    /// of the input in order to check for all patterns. This is
14    /// the only searcher which can match multiple patterns with
15    /// match/blocks substitutions in at least one of the pattern
16    /// prefixes
17    AnyPrefix {
18        /// The prefix patterns to search for
19        prefixes: Vec<Pattern<'a>>,
20        /// The suffix patterns corresponding to each prefix
21        suffixes: Vec<Vec<Pattern<'a>>>,
22    },
23    /// An optimized form of `AnyPrefix` when all of the prefixes
24    /// can be evaluated as a set of regular expressions.
25    RegexPrefix {
26        prefixes: RegexSetMatcher<'a>,
27        suffixes: Vec<Vec<Pattern<'a>>>,
28    },
29    /// An optimized form of `AnyPrefix` when all of the prefixes
30    /// can be evaluated as a set of substring literals.
31    SubstringPrefix {
32        prefixes: SubstringSetMatcher<'a>,
33        suffixes: Vec<Vec<Pattern<'a>>>,
34    },
35}
36impl<'a> From<MatchAll<'a>> for MatchAny<'a> {
37    fn from(match_all: MatchAll<'a>) -> Self {
38        match match_all {
39            MatchAll::Literal(lit) => Self::Literal(lit),
40            MatchAll::Regex(re) => Self::Regex(re),
41            MatchAll::AnyPrefix { prefixes, suffixes } => Self::AnyPrefix { prefixes, suffixes },
42            MatchAll::SubstringPrefix { prefixes, suffixes } => {
43                Self::SubstringPrefix { prefixes, suffixes }
44            }
45            MatchAll::RegexPrefix { prefixes, suffixes } => {
46                Self::RegexPrefix { prefixes, suffixes }
47            }
48        }
49    }
50}
51impl<'a> MatchAny<'a> {
52    pub fn pattern_len(&self) -> usize {
53        match self {
54            Self::Literal(ref matcher) => matcher.pattern_len(),
55            Self::Regex(ref matcher) => matcher.patterns_len(),
56            Self::AnyPrefix { suffixes, .. }
57            | Self::RegexPrefix { suffixes, .. }
58            | Self::SubstringPrefix { suffixes, .. } => suffixes.iter().map(|ps| ps.len()).sum(),
59        }
60    }
61
62    pub fn first_pattern(&self) -> Span<usize> {
63        match self {
64            Self::Literal(matcher) => matcher.first_pattern(),
65            Self::Regex(matcher) => matcher.first_pattern(),
66            Self::AnyPrefix {
67                ref prefixes,
68                ref suffixes,
69            } => {
70                let (prefix_id, start) = prefixes
71                    .iter()
72                    .enumerate()
73                    .map(|(i, p)| (i, p.span().start()))
74                    .min_by_key(|&(_, s)| s)
75                    .unwrap();
76                let (offset, end) = suffixes[prefix_id]
77                    .iter()
78                    .enumerate()
79                    .map(|(offset, p)| (offset, p.span().end()))
80                    .min_by_key(|&(_, e)| e)
81                    .unwrap();
82                Span::new(SourceSpan::from(start..end), prefix_id + offset)
83            }
84            Self::RegexPrefix {
85                ref prefixes,
86                ref suffixes,
87            } => {
88                let (first_prefix_span, first_prefix) = prefixes.first_pattern().into_parts();
89                let start = first_prefix_span.start();
90                let (offset, end) = suffixes[first_prefix]
91                    .iter()
92                    .enumerate()
93                    .map(|(offset, p)| (offset, p.span().end()))
94                    .min_by_key(|&(_, end)| end)
95                    .unwrap();
96                Span::new(SourceSpan::from(start..end), first_prefix + offset)
97            }
98            Self::SubstringPrefix {
99                ref prefixes,
100                ref suffixes,
101            } => {
102                let (first_prefix_span, first_prefix) = prefixes.first_pattern().into_parts();
103                let start = first_prefix_span.start();
104                let (offset, end) = suffixes[first_prefix]
105                    .iter()
106                    .enumerate()
107                    .map(|(offset, p)| (offset, p.span().end()))
108                    .min_by_key(|&(_, end)| end)
109                    .unwrap();
110                Span::new(SourceSpan::from(start..end), first_prefix + offset)
111            }
112        }
113    }
114
115    pub fn first_pattern_span(&self) -> SourceSpan {
116        self.first_pattern().span()
117    }
118}
119impl<'a> Spanned for MatchAny<'a> {
120    fn span(&self) -> SourceSpan {
121        match self {
122            Self::Literal(ref matcher) => matcher.span(),
123            Self::Regex(ref matcher) => matcher.span(),
124            Self::AnyPrefix {
125                ref prefixes,
126                ref suffixes,
127            } => {
128                let start = prefixes
129                    .iter()
130                    .map(|prefix| prefix.span().start())
131                    .min()
132                    .unwrap();
133                let end = prefixes
134                    .iter()
135                    .zip(suffixes.iter())
136                    .map(|(prefix, suffixes)| {
137                        suffixes
138                            .iter()
139                            .map(|p| p.span().end())
140                            .max()
141                            .unwrap_or(prefix.span().end())
142                    })
143                    .max()
144                    .unwrap();
145                SourceSpan::from(start..end)
146            }
147            Self::RegexPrefix {
148                ref prefixes,
149                ref suffixes,
150            } => {
151                let prefix_span = prefixes.span();
152                let start = prefix_span.start();
153                let prefix_end = prefix_span.end();
154                let end = core::cmp::max(
155                    prefix_end,
156                    suffixes
157                        .iter()
158                        .map(|suffixes| {
159                            suffixes
160                                .iter()
161                                .map(|p| p.span().end())
162                                .max()
163                                .unwrap_or(prefix_end)
164                        })
165                        .max()
166                        .unwrap(),
167                );
168                SourceSpan::from(start..end)
169            }
170            Self::SubstringPrefix {
171                ref prefixes,
172                ref suffixes,
173            } => {
174                let prefix_span = prefixes.span();
175                let start = prefix_span.start();
176                let prefix_end = prefix_span.end();
177                let end = core::cmp::max(
178                    prefix_end,
179                    suffixes
180                        .iter()
181                        .map(|suffixes| {
182                            suffixes
183                                .iter()
184                                .map(|p| p.span().end())
185                                .max()
186                                .unwrap_or(prefix_end)
187                        })
188                        .max()
189                        .unwrap(),
190                );
191                SourceSpan::from(start..end)
192            }
193        }
194    }
195}
196impl<'a> MatcherMut for MatchAny<'a> {
197    fn try_match_mut<'input, 'context, C>(
198        &self,
199        input: Input<'input>,
200        context: &mut C,
201    ) -> DiagResult<MatchResult<'input>>
202    where
203        C: Context<'input, 'context> + ?Sized,
204    {
205        use crate::pattern::search::PatternSetSearcher;
206
207        match self {
208            Self::Literal(ref matcher) => matcher.try_match_mut(input, context),
209            Self::Regex(ref matcher) => matcher.try_match_mut(input, context),
210            Self::AnyPrefix {
211                ref prefixes,
212                ref suffixes,
213            } => {
214                let searcher = PatternSetSearcher::new(input, prefixes)?;
215                try_match_searcher(searcher, suffixes, input, context)
216            }
217            Self::RegexPrefix {
218                ref prefixes,
219                ref suffixes,
220            } => try_match_searcher(prefixes.search(input), suffixes, input, context),
221            Self::SubstringPrefix {
222                ref prefixes,
223                ref suffixes,
224            } => try_match_searcher(prefixes.search(input)?, suffixes, input, context),
225        }
226    }
227}
228
229fn try_match_searcher<'input, 'context, 'a, S, C>(
230    mut searcher: S,
231    suffixes: &[Vec<Pattern<'a>>],
232    input: Input<'input>,
233    context: &mut C,
234) -> DiagResult<MatchResult<'input>>
235where
236    S: PatternSearcher<'input>,
237    C: Context<'input, 'context> + ?Sized,
238{
239    loop {
240        match searcher.try_match_next(context)? {
241            MatchResult {
242                info: Some(ref mut info),
243                ty: MatchType::MatchFoundAndExpected,
244            } => {
245                let mut suffix_input = input;
246                suffix_input.set_start(searcher.last_match_end().unwrap());
247                suffix_input.set_anchored(true);
248                let suffixes = &suffixes[info.pattern_id];
249                if let Some(found) =
250                    try_match_suffix(info, suffixes, info.pattern_id, suffix_input, context)?
251                {
252                    break Ok(found);
253                }
254            }
255            result @ MatchResult { info: None, .. } => break Ok(result),
256            _ => continue,
257        }
258    }
259}
260
261fn try_match_suffix<'input, 'context, 'a, C>(
262    prefix_info: &mut MatchInfo<'input>,
263    suffixes: &[Pattern<'a>],
264    mut pattern_id: usize,
265    input: Input<'input>,
266    context: &mut C,
267) -> DiagResult<Option<MatchResult<'input>>>
268where
269    C: Context<'input, 'context> + ?Sized,
270{
271    for suffix in suffixes.iter() {
272        match suffix.try_match_mut(input, context)? {
273            MatchResult {
274                info: Some(mut suffix_info),
275                ty: MatchType::MatchFoundAndExpected,
276            } => {
277                // Match found, we're done
278                let mut captures = core::mem::take(&mut prefix_info.captures);
279                captures.append(&mut suffix_info.captures);
280                return Ok(Some(MatchResult::ok(MatchInfo {
281                    pattern_id,
282                    span: SourceSpan::from(prefix_info.span.start()..suffix_info.span.end()),
283                    captures,
284                    ..suffix_info
285                })));
286            }
287            MatchResult {
288                info: Some(mut info),
289                ty,
290            } => {
291                // We found a match, but then some error occurred, so let's propagate the error
292                info.pattern_id = pattern_id;
293                return Ok(Some(MatchResult {
294                    info: Some(info),
295                    ty,
296                }));
297            }
298            _ => {
299                // No match for this suffix
300                pattern_id += 1;
301            }
302        }
303    }
304
305    Ok(None)
306}