macros_utils/
pattern.rs

1use std::borrow::Cow;
2
3use crate::{
4    call_site, Delimiter, MacroStream, MacrosError, Match, Parse, ParseError, ParseErrorKind,
5    ParserOutput, Spacing, Token,
6};
7use proc_macro_error::{abort, abort_call_site};
8
9#[doc(hidden)]
10pub struct ParserInput<T>
11where
12    T: ToOwned<Owned = T> + ParserOutput,
13{
14    pub patterns: Vec<Pattern<T>>,
15}
16
17/// A pattern to match against a `MacroStream` in a parser from the `parser!` macro.
18///
19/// The following are the various patterns that can be used:
20/// {...}? indicates that the pattern is optional
21/// {... :name}@ indicates that the match should be bound to the parameter `name`
22/// {...}* indicates zero or more (non-greedy), meaning it will consume the stream until the next pattern matches
23/// {...}** indicates zero or more (greedy), meaning it will consume the remainder of the stream
24/// {...}+ indicates one or more (non-greedy), meaning it will consume the stream until the next pattern matches
25/// {...}++ indicates one or more (greedy), meaning it will consume the remainder of the stream
26/// {... | ... | ...}& indicates a choice
27/// ... indicates a token to match exactly
28/// {}$ indicates an arbitrary token, if used in a zero or more or one or more then it will consume the stream until the next pattern matches
29/// {...}= indicates a validation function, should be anything of type type `for<'a> fn(Cow<'a, T>, &Match) -> (Result<(), String>, Cow<'a, T>)` as it will be interpolated directly into the code expecting that type
30/// {{...}} escapes the {} grouping
31/// To escape any of the special endings, use ~whatever before the ending, to escape the tilde use ~~
32pub enum Pattern<T>
33where
34    T: ToOwned<Owned = T> + ParserOutput,
35{
36    Optional(Vec<Pattern<T>>),
37    Parameter(Vec<Pattern<T>>, String),
38    ZeroOrMore(Vec<Pattern<T>>, bool),
39    OneOrMore(Vec<Pattern<T>>, bool),
40    Choice(Vec<Vec<Pattern<T>>>),
41    Token(Token),
42    Group(Delimiter, Vec<Pattern<T>>),
43    Any,
44    #[allow(clippy::type_complexity)]
45    Validator(
46        Option<MacroStream>,
47        Option<for<'a> fn(Cow<'a, T>, &Match) -> (Result<(), String>, Cow<'a, T>)>,
48    ),
49}
50
51impl<T> ParserInput<T>
52where
53    T: ToOwned<Owned = T> + ParserOutput,
54{
55    pub fn params(&self) -> Vec<(String, bool)> {
56        let mut params = vec![];
57        for pattern in &self.patterns {
58            params.extend(pattern.params());
59        }
60        params
61    }
62}
63
64impl<T> Parse for ParserInput<T>
65where
66    T: ToOwned<Owned = T> + ParserOutput,
67{
68    fn parse(stream: &mut MacroStream) -> Result<Self, MacrosError> {
69        Ok(Self {
70            patterns: stream_to_patterns(stream)?,
71        })
72    }
73}
74
75fn stream_to_patterns<T>(stream: &mut MacroStream) -> Result<Vec<Pattern<T>>, MacrosError>
76where
77    T: ToOwned<Owned = T> + ParserOutput,
78{
79    let mut patterns = Vec::new();
80    let mut prev = None;
81    while !stream.is_empty() {
82        let current = Pattern::parse(stream)?;
83        if let (Some(&Pattern::Validator(_, _)) | None, Pattern::Validator(_, _)) = (prev, &current)
84        {
85            return Err(ParseError::new(
86                stream.peek().map(|t| t.span()).unwrap_or_else(call_site),
87                ParseErrorKind::InvalidValidatorPosition,
88            )
89            .into());
90        }
91        patterns.push(current);
92        prev = Some(patterns.last().unwrap());
93    }
94    Ok(patterns)
95}
96
97impl<T> Parse for Pattern<T>
98where
99    T: ToOwned<Owned = T> + ParserOutput,
100{
101    fn parse(input: &mut MacroStream) -> Result<Self, MacrosError> {
102        let token = input.pop_or_err().map_err(|mut e| {
103            e.unexpected_end_of_input("started parsing a pattern and found no start");
104            e
105        })?;
106        Ok(match token {
107            Token::Group {
108                delimiter: Delimiter::Brace,
109                mut stream,
110                ..
111            } => {
112                let token = stream.pop_or_err();
113                let ending = input.peek();
114                match token {
115                    Ok(Token::Group {
116                        delimiter: Delimiter::Brace,
117                        stream: mut inner_stream,
118                        ..
119                    }) if stream.is_empty() => {
120                        Self::Group(Delimiter::Brace, stream_to_patterns(&mut inner_stream)?)
121                    },
122                    Ok(token) => {
123                        let t = match ending {
124                            Some(Token::Punctuation { value: '?', spacing: Spacing::Alone, .. }) => {
125                                stream.push_front(token);
126                                Self::Optional(stream_to_patterns(&mut stream)?)
127                            },
128                            Some(Token::Punctuation { value: '*', spacing: Spacing::Alone, .. }) => {
129                                stream.push_front(token);
130                                Self::ZeroOrMore(stream_to_patterns(&mut stream)?, false)
131                            },
132                            Some(Token::Punctuation { value: '*', spacing: Spacing::Joint, .. }) => {
133                                stream.push_front(token);
134                                Self::ZeroOrMore(stream_to_patterns(&mut stream)?, match input.peek_at(1) {
135                                    Some(Token::Punctuation { value: '*', spacing: Spacing::Alone, .. }) => {
136                                        input.pop(); // pops the previous token off so that this one is popped off at the end of the match
137                                        true
138                                    },
139                                    _ => false
140                                })
141
142                            }
143                            Some(Token::Punctuation { value: '+', spacing: Spacing::Alone, .. }) => {
144                                stream.push_front(token);
145                                Self::OneOrMore(stream_to_patterns(&mut stream)?, false)
146                            },
147                            Some(Token::Punctuation { value: '+', spacing: Spacing::Joint, .. }) => {
148                                stream.push_front(token);
149                                Self::OneOrMore(stream_to_patterns(&mut stream)?, match input.peek_at(1) {
150                                    Some(Token::Punctuation { value: '+', spacing: Spacing::Alone, .. }) => {
151                                        input.pop(); // pops the previous token off so that this one is popped off at the end of the match
152                                        true
153                                    },
154                                    _ => false
155                                })
156                            }
157                            Some(Token::Punctuation { value: '@', spacing: Spacing::Alone, .. }) => {
158                                let mut span = token.span();
159                                stream.push_front(token);
160                                let mut patterns = vec![];
161                                while !stream.is_empty() {
162                                    let token = stream.peek();
163                                    if let Some(token) = token.as_ref() {
164                                        span = token.span();
165                                    }
166                                    match token {
167                                        Some(Token::Punctuation { value: ':', spacing: Spacing::Alone, .. }) => {
168                                            stream.pop();
169                                            break;
170                                        },
171                                        _ => patterns.push(Pattern::parse(&mut stream)?),
172                                    }
173                                }
174                                if stream.is_empty() {
175                                    abort!(span, "expected a pattern, a colon, then an ident, (like some_pattern_here:name), found end of input");
176                                }
177                                if patterns.is_empty() {
178                                    abort!(span, "expected a pattern, a colon, then an ident, (like some_pattern_here:name), found no pattern");
179                                }
180                                let token = stream.pop_or_err()?;
181                                match token {
182                                    Token::Ident { name, .. } => Self::Parameter(patterns, name),
183                                    _ => abort!(token.span(), "expected an identifier"),
184                                }
185                            },
186                            Some(Token::Punctuation { value: '&', spacing: Spacing::Alone, .. }) => {
187                                stream.push_front(token);
188                                let mut patterns = vec![];
189                                let mut current = vec![];
190                                while !stream.is_empty() {
191                                    let token = stream.peek();
192                                    match token {
193                                        Some(Token::Punctuation { value: '|', spacing: Spacing::Alone, .. }) => {
194                                            if !current.is_empty() {
195                                                patterns.push(current);
196                                                current = vec![];
197                                            }
198                                            stream.pop();
199                                            continue;
200                                        },
201                                        _ => current.push(Pattern::parse(&mut stream)?),
202                                    }
203                                }
204                                if !current.is_empty() {
205                                    patterns.push(current);
206                                }
207                                Self::Choice(patterns)
208                            },
209                            Some(Token::Punctuation { value: '$', spacing: Spacing::Alone, .. }) => {
210                                Self::Any
211                            },
212                            Some(Token::Punctuation { value: '=', spacing: Spacing::Alone, .. }) => {
213                                stream.push_front(token);
214                                Self::Validator(Some(stream), None)
215                            },
216                            _ => {
217                                abort!(token.span(), "expected one of ?*+=~@&$ after single braces")
218                            },
219                        };
220                        input.pop();
221                        t
222                    },
223                    Err(_) => match ending {
224                        Some(Token::Punctuation { value: '$', spacing: Spacing::Alone, .. }) => {
225                            input.pop();
226                            Self::Any
227                        },
228                        _ => abort_call_site!("found empty group, expected either an any pattern (like {}$) after the braces or something in the braces"),
229                    },
230                }
231            },
232            Token::Punctuation { value: '~', .. } => {
233                let next = input.pop_or_err().map_err(|mut e| {
234                    e.unexpected_end_of_input("started parsing a pattern and found no start");
235                    e
236                })?;
237                match next {
238                    next @ Token::Punctuation {
239                        value: '?' | '*' | '+' | '=' | '~' | '@' | '&' | '$',
240                        ..
241                    } => Self::Token(next),
242                    _ => abort!(next.span(), "expected one of ?*+=~@&$ after tilde"),
243                }
244            },
245            Token::Group {
246                delimiter,
247                mut stream,
248                ..
249            } => Self::Group(delimiter, stream_to_patterns(&mut stream)?),
250            token => Self::Token(token),
251        })
252    }
253}
254
255impl<T> Pattern<T>
256where
257    T: ToOwned<Owned = T> + ParserOutput,
258{
259    pub fn params(&self) -> Vec<(String, bool)> {
260        let mut params = vec![];
261        match self {
262            Self::Group(_, patterns) => {
263                for i in patterns {
264                    params.extend(i.params());
265                }
266            },
267            Self::Optional(patterns) => {
268                for i in patterns {
269                    params.extend(i.params().into_iter().map(|(name, _)| (name, true)));
270                }
271            },
272            Self::ZeroOrMore(patterns, _) => {
273                for i in patterns {
274                    params.extend(i.params());
275                }
276            },
277            Self::OneOrMore(patterns, _) => {
278                for i in patterns {
279                    params.extend(i.params());
280                }
281            },
282            Self::Choice(patterns) => {
283                for i in patterns {
284                    for j in i {
285                        params.extend(j.params());
286                    }
287                }
288            },
289            Self::Parameter(patterns, name) => {
290                for i in patterns {
291                    params.extend(i.params());
292                }
293                params.push((name.clone(), false));
294            },
295            _ => {},
296        };
297        params
298    }
299
300    pub fn match_pattern<'a>(
301        &self,
302        mut output: Cow<'a, T>,
303        next: Option<&Pattern<T>>,
304        next2: Option<&Pattern<T>>,
305        stream: &mut MacroStream,
306    ) -> (Result<Match, MacrosError>, Cow<'a, T>) {
307        let match_next = match next {
308            Some(Pattern::Validator(_, _)) => next2,
309            _ => next,
310        };
311        let res = match self {
312            Self::Any => (
313                stream
314                    .pop_or_err()
315                    .map(Match::One)
316                    .map_err(MacrosError::Parse),
317                output,
318            ),
319            Self::Choice(choices) => {
320                'choice: for choice in choices {
321                    let mut fork = stream.fork();
322                    let (res, o) = Self::match_patterns(output, choice, &mut fork);
323                    if res.is_err() {
324                        output = o;
325                        continue 'choice;
326                    }
327                    stream.pop_many(fork.popped());
328                    return (res, o);
329                }
330                (
331                    Err(MacrosError::Parse(ParseError::new(
332                        stream.peek().map(|t| t.span()).unwrap_or_else(call_site),
333                        ParseErrorKind::NoMatchingChoice,
334                    ))),
335                    output,
336                )
337            },
338            Self::Group(delimiter, patterns) => {
339                let token = match stream.pop_or_err().map_err(MacrosError::Parse) {
340                    Ok(token) => token,
341                    Err(e) => return (Err(e), output),
342                };
343                if let Token::Group {
344                    delimiter: d,
345                    stream: s,
346                    ..
347                } = &token
348                {
349                    if d == delimiter {
350                        let mut fork = s.fork();
351                        let (res, o) = Self::match_patterns(output, patterns, &mut fork);
352                        if !fork.is_empty() {
353                            return (
354                                Err(MacrosError::Parse(ParseError::new(
355                                    stream.peek().map(|t| t.span()).unwrap_or_else(call_site),
356                                    ParseErrorKind::InputTooLong,
357                                ))),
358                                o,
359                            );
360                        }
361                        stream.pop_many(fork.popped());
362                        return (res, o);
363                    }
364                }
365                (
366                    Err(MacrosError::Parse(ParseError::new(
367                        token.span(),
368                        ParseErrorKind::ExpectedGroup(*delimiter),
369                    ))),
370                    output,
371                )
372            },
373            Self::OneOrMore(patterns, greedy) => {
374                let mut matches = vec![];
375                loop {
376                    let mut fork = stream.fork();
377                    match Self::match_patterns(output, patterns, &mut fork) {
378                        (Ok(m), o) => {
379                            stream.pop_many(fork.popped());
380                            matches.push(m);
381                            output = o;
382                        },
383                        (Err(_), o) => {
384                            output = o;
385                            break;
386                        },
387                    }
388                    match match_next {
389                        Some(next) if !greedy && !matches.is_empty() => {
390                            match next.match_pattern(output, None, None, &mut fork) {
391                                (Ok(_), o) => {
392                                    output = o;
393                                    break;
394                                },
395                                (_, o) => output = o,
396                            }
397                        },
398                        _ => {},
399                    }
400                }
401                (
402                    if matches.is_empty() {
403                        Err(MacrosError::Parse(ParseError::new(
404                            stream.peek().map(|t| t.span()).unwrap_or_else(call_site),
405                            ParseErrorKind::ExpectedRepetition,
406                        )))
407                    } else {
408                        Ok(Match::Many(matches))
409                    },
410                    output,
411                )
412            },
413            Self::ZeroOrMore(patterns, greedy) => {
414                let mut matches = vec![];
415                loop {
416                    let mut fork = stream.fork();
417                    match Self::match_patterns(output, patterns, &mut fork) {
418                        (Ok(m), o) => {
419                            stream.pop_many(fork.popped());
420                            matches.push(m);
421                            output = o;
422                        },
423                        (_, o) => {
424                            output = o;
425                            break;
426                        },
427                    }
428                    match match_next {
429                        Some(next) if !greedy => {
430                            match next.match_pattern(output.clone(), None, None, &mut fork) {
431                                (Ok(_), o) => {
432                                    output = o;
433                                    break;
434                                },
435                                (_, o) => output = o,
436                            }
437                        },
438                        _ => {},
439                    }
440                }
441                (
442                    if matches.is_empty() {
443                        Ok(Match::None)
444                    } else {
445                        Ok(Match::Many(matches))
446                    },
447                    output,
448                )
449            },
450            Self::Optional(patterns) => {
451                let mut fork = stream.fork();
452                match Self::match_patterns(output.clone(), patterns, &mut fork) {
453                    r @ (Ok(_), _) => {
454                        stream.pop_many(fork.popped());
455                        r
456                    },
457                    (_, o) => (Ok(Match::None), o),
458                }
459            },
460            Self::Token(token) => (
461                match stream.pop_or_err().map_err(MacrosError::Parse) {
462                    Ok(t) if t == *token => Ok(Match::One(t)),
463                    Ok(t) => Err(MacrosError::Parse(ParseError::new(
464                        t.span(),
465                        ParseErrorKind::Expected(token.clone(), t),
466                    ))),
467                    Err(e) => Err(e),
468                },
469                output,
470            ),
471            Self::Parameter(patterns, name) => {
472                let mut fork = stream.fork();
473                let (res, mut o) = Self::match_patterns(output, patterns, &mut fork);
474                match res {
475                    Ok(m) => {
476                        stream.pop_many(fork.popped());
477                        o.to_mut().set_match(name, m.clone());
478                        (Ok(m), o)
479                    },
480                    Err(e) => (Err(e), o),
481                }
482            },
483            Self::Validator(_, _) => panic!(
484                "Validator pattern should not have been passed into `Pattern::match_pattern`"
485            ),
486        };
487        match (next, res) {
488            (Some(Pattern::Validator(_, Some(f))), (Ok(m), output)) => match f(output, &m) {
489                (Ok(_), o) => (Ok(m), o),
490                (Err(e), o) => (
491                    Err(MacrosError::Parse(ParseError::new(
492                        stream.peek().map(|t| t.span()).unwrap_or_else(call_site),
493                        ParseErrorKind::ValidatorFailed(e),
494                    ))),
495                    o,
496                ),
497            },
498            (_, m) => m,
499        }
500    }
501
502    pub fn match_patterns<'b, 'a: 'b>(
503        mut output: Cow<'a, T>,
504        patterns: &'b [Pattern<T>],
505        stream: &mut MacroStream,
506    ) -> (Result<Match, MacrosError>, Cow<'a, T>) {
507        let mut matches = vec![];
508        let mut fork = stream.fork();
509        for (i, pattern) in patterns.iter().enumerate() {
510            if let Pattern::Validator(_, _) = pattern {
511                continue;
512            }
513            match pattern.match_pattern(output, patterns.get(i + 1), patterns.get(i + 2), &mut fork)
514            {
515                (Ok(m @ Match::One(_)), o) => {
516                    matches.push(m);
517                    output = o;
518                },
519                (Ok(Match::None), o) => output = o,
520                (Ok(Match::Many(m)), o) => {
521                    matches.extend(m);
522                    output = o;
523                },
524                e => return e,
525            }
526        }
527        stream.pop_many(fork.popped());
528        (Ok(Match::Many(matches)), output)
529    }
530}
531
532unsafe impl<T> Sync for Pattern<T> where T: ToOwned<Owned = T> + ParserOutput {}