pest_meta/
validator.rs

1// pest. The Elegant Parser
2// Copyright (c) 2018 Dragoș Tiselice
3//
4// Licensed under the Apache License, Version 2.0
5// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. All files in the project carrying such notice may not be copied,
8// modified, or distributed except according to those terms.
9
10//! Helpers for validating pest grammars that could help with debugging
11//! and provide a more user-friendly error message.
12
13use once_cell::sync::Lazy;
14use std::collections::{HashMap, HashSet};
15
16use pest::error::{Error, ErrorVariant, InputLocation};
17use pest::iterators::Pairs;
18use pest::unicode::unicode_property_names;
19use pest::Span;
20
21use crate::parser::{ParserExpr, ParserNode, ParserRule, Rule};
22
23static RUST_KEYWORDS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
24    [
25        "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
26        "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
27        "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pure",
28        "pub", "ref", "return", "Self", "self", "sizeof", "static", "struct", "super", "trait",
29        "true", "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
30    ]
31    .iter()
32    .cloned()
33    .collect()
34});
35
36static PEST_KEYWORDS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
37    [
38        "_", "ANY", "DROP", "EOI", "PEEK", "PEEK_ALL", "POP", "POP_ALL", "PUSH", "SOI",
39    ]
40    .iter()
41    .cloned()
42    .collect()
43});
44
45static BUILTINS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
46    [
47        "ANY",
48        "DROP",
49        "EOI",
50        "PEEK",
51        "PEEK_ALL",
52        "POP",
53        "POP_ALL",
54        "SOI",
55        "ASCII_DIGIT",
56        "ASCII_NONZERO_DIGIT",
57        "ASCII_BIN_DIGIT",
58        "ASCII_OCT_DIGIT",
59        "ASCII_HEX_DIGIT",
60        "ASCII_ALPHA_LOWER",
61        "ASCII_ALPHA_UPPER",
62        "ASCII_ALPHA",
63        "ASCII_ALPHANUMERIC",
64        "ASCII",
65        "NEWLINE",
66    ]
67    .iter()
68    .cloned()
69    .chain(unicode_property_names())
70    .collect::<HashSet<&str>>()
71});
72
73/// It checks the parsed grammar for common mistakes:
74/// - using Pest keywords
75/// - duplicate rules
76/// - undefined rules
77///
78/// It returns a `Result` with a `Vec` of `Error`s if any of the above is found.
79/// If no errors are found, it returns the vector of names of used builtin rules.
80pub fn validate_pairs(pairs: Pairs<'_, Rule>) -> Result<Vec<&str>, Vec<Error<Rule>>> {
81    let definitions: Vec<_> = pairs
82        .clone()
83        .filter(|pair| pair.as_rule() == Rule::grammar_rule)
84        .map(|pair| pair.into_inner().next().unwrap())
85        .filter(|pair| pair.as_rule() != Rule::line_doc)
86        .map(|pair| pair.as_span())
87        .collect();
88
89    let called_rules: Vec<_> = pairs
90        .clone()
91        .filter(|pair| pair.as_rule() == Rule::grammar_rule)
92        .flat_map(|pair| {
93            pair.into_inner()
94                .flatten()
95                .skip(1)
96                .filter(|pair| pair.as_rule() == Rule::identifier)
97                .map(|pair| pair.as_span())
98        })
99        .collect();
100
101    let mut errors = vec![];
102
103    errors.extend(validate_pest_keywords(&definitions));
104    errors.extend(validate_already_defined(&definitions));
105    errors.extend(validate_undefined(&definitions, &called_rules));
106
107    if !errors.is_empty() {
108        return Err(errors);
109    }
110
111    let definitions: HashSet<_> = definitions.iter().map(|span| span.as_str()).collect();
112    let called_rules: HashSet<_> = called_rules.iter().map(|span| span.as_str()).collect();
113
114    let defaults = called_rules.difference(&definitions);
115
116    Ok(defaults.cloned().collect())
117}
118
119/// Validates that the given `definitions` do not contain any Rust keywords.
120#[allow(clippy::ptr_arg)]
121#[deprecated = "Rust keywords are no longer restricted from the pest grammar"]
122pub fn validate_rust_keywords(definitions: &Vec<Span<'_>>) -> Vec<Error<Rule>> {
123    let mut errors = vec![];
124
125    for definition in definitions {
126        let name = definition.as_str();
127
128        if RUST_KEYWORDS.contains(name) {
129            errors.push(Error::new_from_span(
130                ErrorVariant::CustomError {
131                    message: format!("{} is a rust keyword", name),
132                },
133                *definition,
134            ))
135        }
136    }
137
138    errors
139}
140
141/// Validates that the given `definitions` do not contain any Pest keywords.
142#[allow(clippy::ptr_arg)]
143pub fn validate_pest_keywords(definitions: &Vec<Span<'_>>) -> Vec<Error<Rule>> {
144    let mut errors = vec![];
145
146    for definition in definitions {
147        let name = definition.as_str();
148
149        if PEST_KEYWORDS.contains(name) {
150            errors.push(Error::new_from_span(
151                ErrorVariant::CustomError {
152                    message: format!("{} is a pest keyword", name),
153                },
154                *definition,
155            ))
156        }
157    }
158
159    errors
160}
161
162/// Validates that the given `definitions` do not contain any duplicate rules.
163#[allow(clippy::ptr_arg)]
164pub fn validate_already_defined(definitions: &Vec<Span<'_>>) -> Vec<Error<Rule>> {
165    let mut errors = vec![];
166    let mut defined = HashSet::new();
167
168    for definition in definitions {
169        let name = definition.as_str();
170
171        if defined.contains(&name) {
172            errors.push(Error::new_from_span(
173                ErrorVariant::CustomError {
174                    message: format!("rule {} already defined", name),
175                },
176                *definition,
177            ))
178        } else {
179            defined.insert(name);
180        }
181    }
182
183    errors
184}
185
186/// Validates that the given `definitions` do not contain any undefined rules.
187#[allow(clippy::ptr_arg)]
188pub fn validate_undefined<'i>(
189    definitions: &Vec<Span<'i>>,
190    called_rules: &Vec<Span<'i>>,
191) -> Vec<Error<Rule>> {
192    let mut errors = vec![];
193    let definitions: HashSet<_> = definitions.iter().map(|span| span.as_str()).collect();
194
195    for rule in called_rules {
196        let name = rule.as_str();
197
198        if !definitions.contains(name) && !BUILTINS.contains(name) {
199            errors.push(Error::new_from_span(
200                ErrorVariant::CustomError {
201                    message: format!("rule {} is undefined", name),
202                },
203                *rule,
204            ))
205        }
206    }
207
208    errors
209}
210
211/// Validates the abstract syntax tree for common mistakes:
212/// - infinite repetitions
213/// - choices that cannot be reached
214/// - left recursion
215#[allow(clippy::ptr_arg)]
216pub fn validate_ast<'a, 'i: 'a>(rules: &'a Vec<ParserRule<'i>>) -> Vec<Error<Rule>> {
217    let mut errors = vec![];
218
219    // WARNING: validate_{repetition,choice,whitespace_comment}
220    // use is_non_failing and is_non_progressing breaking assumptions:
221    // - for every `ParserExpr::RepMinMax(inner,min,max)`,
222    //   `min<=max` was not checked
223    // - left recursion was not checked
224    // - Every expression might not be checked
225    errors.extend(validate_repetition(rules));
226    errors.extend(validate_choices(rules));
227    errors.extend(validate_whitespace_comment(rules));
228    errors.extend(validate_left_recursion(rules));
229
230    errors.sort_by_key(|error| match error.location {
231        InputLocation::Span(span) => span,
232        _ => unreachable!(),
233    });
234
235    errors
236}
237
238/// Checks if `expr` is non-progressing, that is the expression does not
239/// consume any input or any stack. This includes expressions matching the empty input,
240/// `SOI` and ̀ `EOI`, predicates and repetitions.
241///
242/// # Example
243///
244/// ```pest
245/// not_progressing_1 = { "" }
246/// not_progressing_2 = { "a"? }
247/// not_progressing_3 = { !"a" }
248/// ```
249///
250/// # Assumptions
251/// - In `ParserExpr::RepMinMax(inner,min,max)`, `min<=max`
252/// - All rules identiers have a matching definition
253/// - There is no left-recursion (if only this one is broken returns false)
254/// - Every expression is being checked
255fn is_non_progressing<'i>(
256    expr: &ParserExpr<'i>,
257    rules: &HashMap<String, &ParserNode<'i>>,
258    trace: &mut Vec<String>,
259) -> bool {
260    match *expr {
261        ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(),
262        ParserExpr::Ident(ref ident) => {
263            if ident == "SOI" || ident == "EOI" {
264                return true;
265            }
266
267            if !trace.contains(ident) {
268                if let Some(node) = rules.get(ident) {
269                    trace.push(ident.clone());
270                    let result = is_non_progressing(&node.expr, rules, trace);
271                    trace.pop().unwrap();
272
273                    return result;
274                }
275                // else
276                // the ident is
277                // - "POP","PEEK" => false
278                //      the slice being checked is not non_progressing since every
279                //      PUSH is being checked (assumption 4) and the expr
280                //      of a PUSH has to be non_progressing.
281                // - "POPALL", "PEEKALL" => false
282                //      same as "POP", "PEEK" unless the following:
283                //      BUG: if the stack is empty they are non_progressing
284                // - "DROP" => false doesn't consume the input but consumes the stack,
285                // - "ANY", "ASCII_*", UNICODE categories, "NEWLINE" => false
286                // - referring to another rule that is undefined (breaks assumption)
287            }
288            // else referring to another rule that was already seen.
289            //    this happens only if there is a left-recursion
290            //    that is only if an assumption is broken,
291            //    WARNING: we can choose to return false, but that might
292            //    cause bugs into the left_recursion check
293
294            false
295        }
296        ParserExpr::Seq(ref lhs, ref rhs) => {
297            is_non_progressing(&lhs.expr, rules, trace)
298                && is_non_progressing(&rhs.expr, rules, trace)
299        }
300        ParserExpr::Choice(ref lhs, ref rhs) => {
301            is_non_progressing(&lhs.expr, rules, trace)
302                || is_non_progressing(&rhs.expr, rules, trace)
303        }
304        // WARNING: the predicate indeed won't make progress on input but  it
305        // might progress on the stack
306        // ex: @{ PUSH(ANY) ~ (&(DROP))* ~ ANY }, input="AA"
307        //     Notice that this is ex not working as of now, the debugger seems
308        //     to run into an infinite loop on it
309        ParserExpr::PosPred(_) | ParserExpr::NegPred(_) => true,
310        ParserExpr::Rep(_) | ParserExpr::Opt(_) | ParserExpr::RepMax(_, _) => true,
311        // it either always fail (failing is progressing)
312        // or always match at least a character
313        ParserExpr::Range(_, _) => false,
314        ParserExpr::PeekSlice(_, _) => {
315            // the slice being checked is not non_progressing since every
316            // PUSH is being checked (assumption 4) and the expr
317            // of a PUSH has to be non_progressing.
318            // BUG: if the slice is of size 0, or the stack is not large
319            // enough it might be non-progressing
320            false
321        }
322
323        ParserExpr::RepExact(ref inner, min)
324        | ParserExpr::RepMin(ref inner, min)
325        | ParserExpr::RepMinMax(ref inner, min, _) => {
326            min == 0 || is_non_progressing(&inner.expr, rules, trace)
327        }
328        ParserExpr::Push(ref inner) => is_non_progressing(&inner.expr, rules, trace),
329        ParserExpr::RepOnce(ref inner) => is_non_progressing(&inner.expr, rules, trace),
330        #[cfg(feature = "grammar-extras")]
331        ParserExpr::NodeTag(ref inner, _) => is_non_progressing(&inner.expr, rules, trace),
332    }
333}
334
335/// Checks if `expr` is non-failing, that is it matches any input.
336///
337/// # Example
338///
339/// ```pest
340/// non_failing_1 = { "" }
341/// ```
342///
343/// # Assumptions
344/// - In `ParserExpr::RepMinMax(inner,min,max)`, `min<=max`
345/// - In `ParserExpr::PeekSlice(max,Some(min))`, `max>=min`
346/// - All rules identiers have a matching definition
347/// - There is no left-recursion
348/// - All rules are being checked
349fn is_non_failing<'i>(
350    expr: &ParserExpr<'i>,
351    rules: &HashMap<String, &ParserNode<'i>>,
352    trace: &mut Vec<String>,
353) -> bool {
354    match *expr {
355        ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(),
356        ParserExpr::Ident(ref ident) => {
357            if !trace.contains(ident) {
358                if let Some(node) = rules.get(ident) {
359                    trace.push(ident.clone());
360                    let result = is_non_failing(&node.expr, rules, trace);
361                    trace.pop().unwrap();
362
363                    result
364                } else {
365                    // else
366                    // the ident is
367                    // - "POP","PEEK" => false
368                    //      the slice being checked is not non_failing since every
369                    //      PUSH is being checked (assumption 4) and the expr
370                    //      of a PUSH has to be non_failing.
371                    // - "POP_ALL", "PEEK_ALL" => false
372                    //      same as "POP", "PEEK" unless the following:
373                    //      BUG: if the stack is empty they are non_failing
374                    // - "DROP" => false
375                    // - "ANY", "ASCII_*", UNICODE categories, "NEWLINE",
376                    //      "SOI", "EOI" => false
377                    // - referring to another rule that is undefined (breaks assumption)
378                    //      WARNING: might want to introduce a panic or report the error
379                    false
380                }
381            } else {
382                // referring to another rule R that was already seen
383                // WARNING: this might mean there is a circular non-failing path
384                //   it's not obvious wether this can happen without left-recursion
385                //   and thus breaking the assumption. Until there is answer to
386                //   this, to avoid changing behaviour we return:
387                false
388            }
389        }
390        ParserExpr::Opt(_) => true,
391        ParserExpr::Rep(_) => true,
392        ParserExpr::RepMax(_, _) => true,
393        ParserExpr::Seq(ref lhs, ref rhs) => {
394            is_non_failing(&lhs.expr, rules, trace) && is_non_failing(&rhs.expr, rules, trace)
395        }
396        ParserExpr::Choice(ref lhs, ref rhs) => {
397            is_non_failing(&lhs.expr, rules, trace) || is_non_failing(&rhs.expr, rules, trace)
398        }
399        // it either always fail
400        // or always match at least a character
401        ParserExpr::Range(_, _) => false,
402        ParserExpr::PeekSlice(_, _) => {
403            // the slice being checked is not non_failing since every
404            // PUSH is being checked (assumption 4) and the expr
405            // of a PUSH has to be non_failing.
406            // BUG: if the slice is of size 0, or the stack is not large
407            // enough it might be non-failing
408            false
409        }
410        ParserExpr::RepExact(ref inner, min)
411        | ParserExpr::RepMin(ref inner, min)
412        | ParserExpr::RepMinMax(ref inner, min, _) => {
413            min == 0 || is_non_failing(&inner.expr, rules, trace)
414        }
415        // BUG: the predicate may always fail, resulting in this expr non_failing
416        // ex of always failing predicates :
417        //     @{EOI ~ ANY | ANY ~ SOI | &("A") ~ &("B") | 'z'..'a'}
418        ParserExpr::NegPred(_) => false,
419        ParserExpr::RepOnce(ref inner) => is_non_failing(&inner.expr, rules, trace),
420        ParserExpr::Push(ref inner) | ParserExpr::PosPred(ref inner) => {
421            is_non_failing(&inner.expr, rules, trace)
422        }
423        #[cfg(feature = "grammar-extras")]
424        ParserExpr::NodeTag(ref inner, _) => is_non_failing(&inner.expr, rules, trace),
425    }
426}
427
428fn validate_repetition<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
429    let mut result = vec![];
430    let map = to_hash_map(rules);
431
432    for rule in rules {
433        let mut errors = rule.node
434            .clone()
435            .filter_map_top_down(|node| match node.expr {
436                ParserExpr::Rep(ref other)
437                | ParserExpr::RepOnce(ref other)
438                | ParserExpr::RepMin(ref other, _) => {
439                    if is_non_failing(&other.expr, &map, &mut vec![]) {
440                        Some(Error::new_from_span(
441                            ErrorVariant::CustomError {
442                                message:
443                                    "expression inside repetition cannot fail and will repeat \
444                                     infinitely"
445                                        .to_owned()
446                            },
447                            node.span
448                        ))
449                    } else if is_non_progressing(&other.expr, &map, &mut vec![]) {
450                        Some(Error::new_from_span(
451                            ErrorVariant::CustomError {
452                                message:
453                                    "expression inside repetition is non-progressing and will repeat \
454                                     infinitely"
455                                        .to_owned(),
456                            },
457                            node.span
458                        ))
459                    } else {
460                        None
461                    }
462                }
463                _ => None
464            });
465
466        result.append(&mut errors);
467    }
468
469    result
470}
471
472fn validate_choices<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
473    let mut result = vec![];
474    let map = to_hash_map(rules);
475
476    for rule in rules {
477        let mut errors = rule
478            .node
479            .clone()
480            .filter_map_top_down(|node| match node.expr {
481                ParserExpr::Choice(ref lhs, _) => {
482                    let node = match lhs.expr {
483                        ParserExpr::Choice(_, ref rhs) => rhs,
484                        _ => lhs,
485                    };
486
487                    if is_non_failing(&node.expr, &map, &mut vec![]) {
488                        Some(Error::new_from_span(
489                            ErrorVariant::CustomError {
490                                message:
491                                    "expression cannot fail; following choices cannot be reached"
492                                        .to_owned(),
493                            },
494                            node.span,
495                        ))
496                    } else {
497                        None
498                    }
499                }
500                _ => None,
501            });
502
503        result.append(&mut errors);
504    }
505
506    result
507}
508
509fn validate_whitespace_comment<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
510    let map = to_hash_map(rules);
511
512    rules
513        .iter()
514        .filter_map(|rule| {
515            if rule.name == "WHITESPACE" || rule.name == "COMMENT" {
516                if is_non_failing(&rule.node.expr, &map, &mut vec![]) {
517                    Some(Error::new_from_span(
518                        ErrorVariant::CustomError {
519                            message: format!(
520                                "{} cannot fail and will repeat infinitely",
521                                &rule.name
522                            ),
523                        },
524                        rule.node.span,
525                    ))
526                } else if is_non_progressing(&rule.node.expr, &map, &mut vec![]) {
527                    Some(Error::new_from_span(
528                        ErrorVariant::CustomError {
529                            message: format!(
530                                "{} is non-progressing and will repeat infinitely",
531                                &rule.name
532                            ),
533                        },
534                        rule.node.span,
535                    ))
536                } else {
537                    None
538                }
539            } else {
540                None
541            }
542        })
543        .collect()
544}
545
546fn validate_left_recursion<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
547    left_recursion(to_hash_map(rules))
548}
549
550fn to_hash_map<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> HashMap<String, &'a ParserNode<'i>> {
551    rules.iter().map(|r| (r.name.clone(), &r.node)).collect()
552}
553
554fn left_recursion<'a, 'i: 'a>(rules: HashMap<String, &'a ParserNode<'i>>) -> Vec<Error<Rule>> {
555    fn check_expr<'a, 'i: 'a>(
556        node: &'a ParserNode<'i>,
557        rules: &'a HashMap<String, &ParserNode<'i>>,
558        trace: &mut Vec<String>,
559    ) -> Option<Error<Rule>> {
560        match node.expr.clone() {
561            ParserExpr::Ident(other) => {
562                if trace[0] == other {
563                    trace.push(other);
564                    let chain = trace
565                        .iter()
566                        .map(|ident| ident.as_ref())
567                        .collect::<Vec<_>>()
568                        .join(" -> ");
569
570                    return Some(Error::new_from_span(
571                        ErrorVariant::CustomError {
572                            message: format!(
573                                "rule {} is left-recursive ({}); pest::pratt_parser might be useful \
574                                 in this case",
575                                node.span.as_str(),
576                                chain
577                            )
578                        },
579                        node.span
580                    ));
581                }
582
583                if !trace.contains(&other) {
584                    if let Some(node) = rules.get(&other) {
585                        trace.push(other);
586                        let result = check_expr(node, rules, trace);
587                        trace.pop().unwrap();
588
589                        return result;
590                    }
591                }
592
593                None
594            }
595            ParserExpr::Seq(ref lhs, ref rhs) => {
596                if is_non_failing(&lhs.expr, rules, &mut vec![trace.last().unwrap().clone()]) {
597                    check_expr(rhs, rules, trace)
598                } else {
599                    check_expr(lhs, rules, trace)
600                }
601            }
602            ParserExpr::Choice(ref lhs, ref rhs) => {
603                check_expr(lhs, rules, trace).or_else(|| check_expr(rhs, rules, trace))
604            }
605            ParserExpr::Rep(ref node) => check_expr(node, rules, trace),
606            ParserExpr::RepOnce(ref node) => check_expr(node, rules, trace),
607            ParserExpr::Opt(ref node) => check_expr(node, rules, trace),
608            ParserExpr::PosPred(ref node) => check_expr(node, rules, trace),
609            ParserExpr::NegPred(ref node) => check_expr(node, rules, trace),
610            ParserExpr::Push(ref node) => check_expr(node, rules, trace),
611            _ => None,
612        }
613    }
614
615    let mut errors = vec![];
616
617    for (name, node) in &rules {
618        let name = name.clone();
619
620        if let Some(error) = check_expr(node, &rules, &mut vec![name]) {
621            errors.push(error);
622        }
623    }
624
625    errors
626}
627
628#[cfg(test)]
629mod tests {
630    use super::super::parser::{consume_rules, PestParser};
631    use super::super::unwrap_or_report;
632    use super::*;
633    use pest::Parser;
634
635    #[test]
636    #[should_panic(expected = "grammar error
637
638 --> 1:1
639  |
6401 | ANY = { \"a\" }
641  | ^-^
642  |
643  = ANY is a pest keyword")]
644    fn pest_keyword() {
645        let input = "ANY = { \"a\" }";
646        unwrap_or_report(validate_pairs(
647            PestParser::parse(Rule::grammar_rules, input).unwrap(),
648        ));
649    }
650
651    #[test]
652    #[should_panic(expected = "grammar error
653
654 --> 1:13
655  |
6561 | a = { \"a\" } a = { \"a\" }
657  |             ^
658  |
659  = rule a already defined")]
660    fn already_defined() {
661        let input = "a = { \"a\" } a = { \"a\" }";
662        unwrap_or_report(validate_pairs(
663            PestParser::parse(Rule::grammar_rules, input).unwrap(),
664        ));
665    }
666
667    #[test]
668    #[should_panic(expected = "grammar error
669
670 --> 1:7
671  |
6721 | a = { b }
673  |       ^
674  |
675  = rule b is undefined")]
676    fn undefined() {
677        let input = "a = { b }";
678        unwrap_or_report(validate_pairs(
679            PestParser::parse(Rule::grammar_rules, input).unwrap(),
680        ));
681    }
682
683    #[test]
684    fn valid_recursion() {
685        let input = "a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"b\") ~ a }";
686        unwrap_or_report(consume_rules(
687            PestParser::parse(Rule::grammar_rules, input).unwrap(),
688        ));
689    }
690
691    #[test]
692    #[should_panic(expected = "grammar error
693
694 --> 1:16
695  |
6961 | WHITESPACE = { \"\" }
697  |                ^^
698  |
699  = WHITESPACE cannot fail and will repeat infinitely")]
700    fn non_failing_whitespace() {
701        let input = "WHITESPACE = { \"\" }";
702        unwrap_or_report(consume_rules(
703            PestParser::parse(Rule::grammar_rules, input).unwrap(),
704        ));
705    }
706
707    #[test]
708    #[should_panic(expected = "grammar error
709
710 --> 1:13
711  |
7121 | COMMENT = { SOI }
713  |             ^-^
714  |
715  = COMMENT is non-progressing and will repeat infinitely")]
716    fn non_progressing_comment() {
717        let input = "COMMENT = { SOI }";
718        unwrap_or_report(consume_rules(
719            PestParser::parse(Rule::grammar_rules, input).unwrap(),
720        ));
721    }
722
723    #[test]
724    fn non_progressing_empty_string() {
725        assert!(is_non_failing(
726            &ParserExpr::Insens("".into()),
727            &HashMap::new(),
728            &mut Vec::new()
729        ));
730        assert!(is_non_progressing(
731            &ParserExpr::Str("".into()),
732            &HashMap::new(),
733            &mut Vec::new()
734        ));
735    }
736
737    #[test]
738    fn progressing_non_empty_string() {
739        assert!(!is_non_progressing(
740            &ParserExpr::Insens("non empty".into()),
741            &HashMap::new(),
742            &mut Vec::new()
743        ));
744        assert!(!is_non_progressing(
745            &ParserExpr::Str("non empty".into()),
746            &HashMap::new(),
747            &mut Vec::new()
748        ));
749    }
750
751    #[test]
752    fn non_progressing_soi_eoi() {
753        assert!(is_non_progressing(
754            &ParserExpr::Ident("SOI".into()),
755            &HashMap::new(),
756            &mut Vec::new()
757        ));
758        assert!(is_non_progressing(
759            &ParserExpr::Ident("EOI".into()),
760            &HashMap::new(),
761            &mut Vec::new()
762        ));
763    }
764
765    #[test]
766    fn non_progressing_predicates() {
767        let progressing = ParserExpr::Str("A".into());
768
769        assert!(is_non_progressing(
770            &ParserExpr::PosPred(Box::new(ParserNode {
771                expr: progressing.clone(),
772                span: Span::new(" ", 0, 1).unwrap(),
773            })),
774            &HashMap::new(),
775            &mut Vec::new()
776        ));
777        assert!(is_non_progressing(
778            &ParserExpr::NegPred(Box::new(ParserNode {
779                expr: progressing,
780                span: Span::new(" ", 0, 1).unwrap(),
781            })),
782            &HashMap::new(),
783            &mut Vec::new()
784        ));
785    }
786
787    #[test]
788    fn non_progressing_0_length_repetitions() {
789        let input_progressing_node = Box::new(ParserNode {
790            expr: ParserExpr::Str("A".into()),
791            span: Span::new(" ", 0, 1).unwrap(),
792        });
793
794        assert!(!is_non_progressing(
795            &input_progressing_node.clone().expr,
796            &HashMap::new(),
797            &mut Vec::new()
798        ));
799
800        assert!(is_non_progressing(
801            &ParserExpr::Rep(input_progressing_node.clone()),
802            &HashMap::new(),
803            &mut Vec::new()
804        ));
805        assert!(is_non_progressing(
806            &ParserExpr::Opt(input_progressing_node.clone()),
807            &HashMap::new(),
808            &mut Vec::new()
809        ));
810        assert!(is_non_progressing(
811            &ParserExpr::RepExact(input_progressing_node.clone(), 0),
812            &HashMap::new(),
813            &mut Vec::new()
814        ));
815        assert!(is_non_progressing(
816            &ParserExpr::RepMin(input_progressing_node.clone(), 0),
817            &HashMap::new(),
818            &mut Vec::new()
819        ));
820        assert!(is_non_progressing(
821            &ParserExpr::RepMax(input_progressing_node.clone(), 0),
822            &HashMap::new(),
823            &mut Vec::new()
824        ));
825        assert!(is_non_progressing(
826            &ParserExpr::RepMax(input_progressing_node.clone(), 17),
827            &HashMap::new(),
828            &mut Vec::new()
829        ));
830
831        assert!(is_non_progressing(
832            &ParserExpr::RepMinMax(input_progressing_node.clone(), 0, 12),
833            &HashMap::new(),
834            &mut Vec::new()
835        ));
836    }
837
838    #[test]
839    fn non_progressing_nonzero_repetitions_with_non_progressing_expr() {
840        let a = "";
841        let non_progressing_node = Box::new(ParserNode {
842            expr: ParserExpr::Str(a.into()),
843            span: Span::new(a, 0, 0).unwrap(),
844        });
845        let exact = ParserExpr::RepExact(non_progressing_node.clone(), 7);
846        let min = ParserExpr::RepMin(non_progressing_node.clone(), 23);
847        let minmax = ParserExpr::RepMinMax(non_progressing_node.clone(), 12, 13);
848        let reponce = ParserExpr::RepOnce(non_progressing_node);
849
850        assert!(is_non_progressing(&exact, &HashMap::new(), &mut Vec::new()));
851        assert!(is_non_progressing(&min, &HashMap::new(), &mut Vec::new()));
852        assert!(is_non_progressing(
853            &minmax,
854            &HashMap::new(),
855            &mut Vec::new()
856        ));
857        assert!(is_non_progressing(
858            &reponce,
859            &HashMap::new(),
860            &mut Vec::new()
861        ));
862    }
863
864    #[test]
865    fn progressing_repetitions() {
866        let a = "A";
867        let input_progressing_node = Box::new(ParserNode {
868            expr: ParserExpr::Str(a.into()),
869            span: Span::new(a, 0, 1).unwrap(),
870        });
871        let exact = ParserExpr::RepExact(input_progressing_node.clone(), 1);
872        let min = ParserExpr::RepMin(input_progressing_node.clone(), 2);
873        let minmax = ParserExpr::RepMinMax(input_progressing_node.clone(), 4, 5);
874        let reponce = ParserExpr::RepOnce(input_progressing_node);
875
876        assert!(!is_non_progressing(
877            &exact,
878            &HashMap::new(),
879            &mut Vec::new()
880        ));
881        assert!(!is_non_progressing(&min, &HashMap::new(), &mut Vec::new()));
882        assert!(!is_non_progressing(
883            &minmax,
884            &HashMap::new(),
885            &mut Vec::new()
886        ));
887        assert!(!is_non_progressing(
888            &reponce,
889            &HashMap::new(),
890            &mut Vec::new()
891        ));
892    }
893
894    #[test]
895    fn non_progressing_push() {
896        let a = "";
897        let non_progressing_node = Box::new(ParserNode {
898            expr: ParserExpr::Str(a.into()),
899            span: Span::new(a, 0, 0).unwrap(),
900        });
901        let push = ParserExpr::Push(non_progressing_node.clone());
902
903        assert!(is_non_progressing(&push, &HashMap::new(), &mut Vec::new()));
904    }
905
906    #[test]
907    fn progressing_push() {
908        let a = "i'm make progress";
909        let progressing_node = Box::new(ParserNode {
910            expr: ParserExpr::Str(a.into()),
911            span: Span::new(a, 0, 1).unwrap(),
912        });
913        let push = ParserExpr::Push(progressing_node.clone());
914
915        assert!(!is_non_progressing(&push, &HashMap::new(), &mut Vec::new()));
916    }
917
918    #[test]
919    fn node_tag_forwards_is_non_progressing() {
920        let progressing_node = Box::new(ParserNode {
921            expr: ParserExpr::Str("i'm make progress".into()),
922            span: Span::new(" ", 0, 1).unwrap(),
923        });
924        assert!(!is_non_progressing(
925            &progressing_node.clone().expr,
926            &HashMap::new(),
927            &mut Vec::new()
928        ));
929        let non_progressing_node = Box::new(ParserNode {
930            expr: ParserExpr::Str("".into()),
931            span: Span::new(" ", 0, 1).unwrap(),
932        });
933        assert!(is_non_progressing(
934            &non_progressing_node.clone().expr,
935            &HashMap::new(),
936            &mut Vec::new()
937        ));
938        #[cfg(feature = "grammar-extras")]
939        {
940            let progressing = ParserExpr::NodeTag(progressing_node.clone(), "TAG".into());
941            let non_progressing = ParserExpr::NodeTag(non_progressing_node.clone(), "TAG".into());
942
943            assert!(!is_non_progressing(
944                &progressing,
945                &HashMap::new(),
946                &mut Vec::new()
947            ));
948            assert!(is_non_progressing(
949                &non_progressing,
950                &HashMap::new(),
951                &mut Vec::new()
952            ));
953        }
954    }
955
956    #[test]
957    fn progressing_range() {
958        let progressing = ParserExpr::Range("A".into(), "Z".into());
959        let failing_is_progressing = ParserExpr::Range("Z".into(), "A".into());
960
961        assert!(!is_non_progressing(
962            &progressing,
963            &HashMap::new(),
964            &mut Vec::new()
965        ));
966        assert!(!is_non_progressing(
967            &failing_is_progressing,
968            &HashMap::new(),
969            &mut Vec::new()
970        ));
971    }
972
973    #[test]
974    fn progressing_choice() {
975        let left_progressing_node = Box::new(ParserNode {
976            expr: ParserExpr::Str("i'm make progress".into()),
977            span: Span::new(" ", 0, 1).unwrap(),
978        });
979        assert!(!is_non_progressing(
980            &left_progressing_node.clone().expr,
981            &HashMap::new(),
982            &mut Vec::new()
983        ));
984
985        let right_progressing_node = Box::new(ParserNode {
986            expr: ParserExpr::Ident("DROP".into()),
987            span: Span::new("DROP", 0, 3).unwrap(),
988        });
989
990        assert!(!is_non_progressing(
991            &ParserExpr::Choice(left_progressing_node, right_progressing_node),
992            &HashMap::new(),
993            &mut Vec::new()
994        ))
995    }
996
997    #[test]
998    fn non_progressing_choices() {
999        let left_progressing_node = Box::new(ParserNode {
1000            expr: ParserExpr::Str("i'm make progress".into()),
1001            span: Span::new(" ", 0, 1).unwrap(),
1002        });
1003
1004        assert!(!is_non_progressing(
1005            &left_progressing_node.clone().expr,
1006            &HashMap::new(),
1007            &mut Vec::new()
1008        ));
1009
1010        let left_non_progressing_node = Box::new(ParserNode {
1011            expr: ParserExpr::Str("".into()),
1012            span: Span::new(" ", 0, 1).unwrap(),
1013        });
1014
1015        assert!(is_non_progressing(
1016            &left_non_progressing_node.clone().expr,
1017            &HashMap::new(),
1018            &mut Vec::new()
1019        ));
1020
1021        let right_progressing_node = Box::new(ParserNode {
1022            expr: ParserExpr::Ident("DROP".into()),
1023            span: Span::new("DROP", 0, 3).unwrap(),
1024        });
1025
1026        assert!(!is_non_progressing(
1027            &right_progressing_node.clone().expr,
1028            &HashMap::new(),
1029            &mut Vec::new()
1030        ));
1031
1032        let right_non_progressing_node = Box::new(ParserNode {
1033            expr: ParserExpr::Opt(Box::new(ParserNode {
1034                expr: ParserExpr::Str("   ".into()),
1035                span: Span::new(" ", 0, 1).unwrap(),
1036            })),
1037            span: Span::new(" ", 0, 1).unwrap(),
1038        });
1039
1040        assert!(is_non_progressing(
1041            &right_non_progressing_node.clone().expr,
1042            &HashMap::new(),
1043            &mut Vec::new()
1044        ));
1045
1046        assert!(is_non_progressing(
1047            &ParserExpr::Choice(left_non_progressing_node.clone(), right_progressing_node),
1048            &HashMap::new(),
1049            &mut Vec::new()
1050        ));
1051        assert!(is_non_progressing(
1052            &ParserExpr::Choice(left_progressing_node, right_non_progressing_node.clone()),
1053            &HashMap::new(),
1054            &mut Vec::new()
1055        ));
1056        assert!(is_non_progressing(
1057            &ParserExpr::Choice(left_non_progressing_node, right_non_progressing_node),
1058            &HashMap::new(),
1059            &mut Vec::new()
1060        ))
1061    }
1062
1063    #[test]
1064    fn non_progressing_seq() {
1065        let left_non_progressing_node = Box::new(ParserNode {
1066            expr: ParserExpr::Str("".into()),
1067            span: Span::new(" ", 0, 1).unwrap(),
1068        });
1069
1070        let right_non_progressing_node = Box::new(ParserNode {
1071            expr: ParserExpr::Opt(Box::new(ParserNode {
1072                expr: ParserExpr::Str("   ".into()),
1073                span: Span::new(" ", 0, 1).unwrap(),
1074            })),
1075            span: Span::new(" ", 0, 1).unwrap(),
1076        });
1077
1078        assert!(is_non_progressing(
1079            &ParserExpr::Seq(left_non_progressing_node, right_non_progressing_node),
1080            &HashMap::new(),
1081            &mut Vec::new()
1082        ))
1083    }
1084
1085    #[test]
1086    fn progressing_seqs() {
1087        let left_progressing_node = Box::new(ParserNode {
1088            expr: ParserExpr::Str("i'm make progress".into()),
1089            span: Span::new(" ", 0, 1).unwrap(),
1090        });
1091
1092        assert!(!is_non_progressing(
1093            &left_progressing_node.clone().expr,
1094            &HashMap::new(),
1095            &mut Vec::new()
1096        ));
1097
1098        let left_non_progressing_node = Box::new(ParserNode {
1099            expr: ParserExpr::Str("".into()),
1100            span: Span::new(" ", 0, 1).unwrap(),
1101        });
1102
1103        assert!(is_non_progressing(
1104            &left_non_progressing_node.clone().expr,
1105            &HashMap::new(),
1106            &mut Vec::new()
1107        ));
1108
1109        let right_progressing_node = Box::new(ParserNode {
1110            expr: ParserExpr::Ident("DROP".into()),
1111            span: Span::new("DROP", 0, 3).unwrap(),
1112        });
1113
1114        assert!(!is_non_progressing(
1115            &right_progressing_node.clone().expr,
1116            &HashMap::new(),
1117            &mut Vec::new()
1118        ));
1119
1120        let right_non_progressing_node = Box::new(ParserNode {
1121            expr: ParserExpr::Opt(Box::new(ParserNode {
1122                expr: ParserExpr::Str("   ".into()),
1123                span: Span::new(" ", 0, 1).unwrap(),
1124            })),
1125            span: Span::new(" ", 0, 1).unwrap(),
1126        });
1127
1128        assert!(is_non_progressing(
1129            &right_non_progressing_node.clone().expr,
1130            &HashMap::new(),
1131            &mut Vec::new()
1132        ));
1133
1134        assert!(!is_non_progressing(
1135            &ParserExpr::Seq(left_non_progressing_node, right_progressing_node.clone()),
1136            &HashMap::new(),
1137            &mut Vec::new()
1138        ));
1139        assert!(!is_non_progressing(
1140            &ParserExpr::Seq(left_progressing_node.clone(), right_non_progressing_node),
1141            &HashMap::new(),
1142            &mut Vec::new()
1143        ));
1144        assert!(!is_non_progressing(
1145            &ParserExpr::Seq(left_progressing_node, right_progressing_node),
1146            &HashMap::new(),
1147            &mut Vec::new()
1148        ))
1149    }
1150
1151    #[test]
1152    fn progressing_stack_operations() {
1153        assert!(!is_non_progressing(
1154            &ParserExpr::Ident("DROP".into()),
1155            &HashMap::new(),
1156            &mut Vec::new()
1157        ));
1158        assert!(!is_non_progressing(
1159            &ParserExpr::Ident("PEEK".into()),
1160            &HashMap::new(),
1161            &mut Vec::new()
1162        ));
1163        assert!(!is_non_progressing(
1164            &ParserExpr::Ident("POP".into()),
1165            &HashMap::new(),
1166            &mut Vec::new()
1167        ))
1168    }
1169
1170    #[test]
1171    fn non_failing_string() {
1172        let insens = ParserExpr::Insens("".into());
1173        let string = ParserExpr::Str("".into());
1174
1175        assert!(is_non_failing(&insens, &HashMap::new(), &mut Vec::new()));
1176
1177        assert!(is_non_failing(&string, &HashMap::new(), &mut Vec::new()))
1178    }
1179
1180    #[test]
1181    fn failing_string() {
1182        assert!(!is_non_failing(
1183            &ParserExpr::Insens("i may fail!".into()),
1184            &HashMap::new(),
1185            &mut Vec::new()
1186        ));
1187        assert!(!is_non_failing(
1188            &ParserExpr::Str("failure is not fatal".into()),
1189            &HashMap::new(),
1190            &mut Vec::new()
1191        ))
1192    }
1193
1194    #[test]
1195    fn failing_stack_operations() {
1196        assert!(!is_non_failing(
1197            &ParserExpr::Ident("DROP".into()),
1198            &HashMap::new(),
1199            &mut Vec::new()
1200        ));
1201        assert!(!is_non_failing(
1202            &ParserExpr::Ident("POP".into()),
1203            &HashMap::new(),
1204            &mut Vec::new()
1205        ));
1206        assert!(!is_non_failing(
1207            &ParserExpr::Ident("PEEK".into()),
1208            &HashMap::new(),
1209            &mut Vec::new()
1210        ))
1211    }
1212
1213    #[test]
1214    fn non_failing_zero_length_repetitions() {
1215        let failing = Box::new(ParserNode {
1216            expr: ParserExpr::Range("A".into(), "B".into()),
1217            span: Span::new(" ", 0, 1).unwrap(),
1218        });
1219        assert!(!is_non_failing(
1220            &failing.clone().expr,
1221            &HashMap::new(),
1222            &mut Vec::new()
1223        ));
1224        assert!(is_non_failing(
1225            &ParserExpr::Opt(failing.clone()),
1226            &HashMap::new(),
1227            &mut Vec::new()
1228        ));
1229        assert!(is_non_failing(
1230            &ParserExpr::Rep(failing.clone()),
1231            &HashMap::new(),
1232            &mut Vec::new()
1233        ));
1234        assert!(is_non_failing(
1235            &ParserExpr::RepExact(failing.clone(), 0),
1236            &HashMap::new(),
1237            &mut Vec::new()
1238        ));
1239        assert!(is_non_failing(
1240            &ParserExpr::RepMin(failing.clone(), 0),
1241            &HashMap::new(),
1242            &mut Vec::new()
1243        ));
1244        assert!(is_non_failing(
1245            &ParserExpr::RepMax(failing.clone(), 0),
1246            &HashMap::new(),
1247            &mut Vec::new()
1248        ));
1249        assert!(is_non_failing(
1250            &ParserExpr::RepMax(failing.clone(), 22),
1251            &HashMap::new(),
1252            &mut Vec::new()
1253        ));
1254        assert!(is_non_failing(
1255            &ParserExpr::RepMinMax(failing.clone(), 0, 73),
1256            &HashMap::new(),
1257            &mut Vec::new()
1258        ));
1259    }
1260
1261    #[test]
1262    fn non_failing_non_zero_repetitions_with_non_failing_expr() {
1263        let non_failing = Box::new(ParserNode {
1264            expr: ParserExpr::Opt(Box::new(ParserNode {
1265                expr: ParserExpr::Range("A".into(), "B".into()),
1266                span: Span::new(" ", 0, 1).unwrap(),
1267            })),
1268            span: Span::new(" ", 0, 1).unwrap(),
1269        });
1270        assert!(is_non_failing(
1271            &non_failing.clone().expr,
1272            &HashMap::new(),
1273            &mut Vec::new()
1274        ));
1275        assert!(is_non_failing(
1276            &ParserExpr::RepOnce(non_failing.clone()),
1277            &HashMap::new(),
1278            &mut Vec::new()
1279        ));
1280        assert!(is_non_failing(
1281            &ParserExpr::RepExact(non_failing.clone(), 1),
1282            &HashMap::new(),
1283            &mut Vec::new()
1284        ));
1285        assert!(is_non_failing(
1286            &ParserExpr::RepMin(non_failing.clone(), 6),
1287            &HashMap::new(),
1288            &mut Vec::new()
1289        ));
1290        assert!(is_non_failing(
1291            &ParserExpr::RepMinMax(non_failing.clone(), 32, 73),
1292            &HashMap::new(),
1293            &mut Vec::new()
1294        ));
1295    }
1296
1297    #[test]
1298    #[cfg(feature = "grammar-extras")]
1299    fn failing_non_zero_repetitions() {
1300        let failing = Box::new(ParserNode {
1301            expr: ParserExpr::NodeTag(
1302                Box::new(ParserNode {
1303                    expr: ParserExpr::Range("A".into(), "B".into()),
1304                    span: Span::new(" ", 0, 1).unwrap(),
1305                }),
1306                "Tag".into(),
1307            ),
1308            span: Span::new(" ", 0, 1).unwrap(),
1309        });
1310        assert!(!is_non_failing(
1311            &failing.clone().expr,
1312            &HashMap::new(),
1313            &mut Vec::new()
1314        ));
1315        assert!(!is_non_failing(
1316            &ParserExpr::RepOnce(failing.clone()),
1317            &HashMap::new(),
1318            &mut Vec::new()
1319        ));
1320        assert!(!is_non_failing(
1321            &ParserExpr::RepExact(failing.clone(), 3),
1322            &HashMap::new(),
1323            &mut Vec::new()
1324        ));
1325        assert!(!is_non_failing(
1326            &ParserExpr::RepMin(failing.clone(), 14),
1327            &HashMap::new(),
1328            &mut Vec::new()
1329        ));
1330        assert!(!is_non_failing(
1331            &ParserExpr::RepMinMax(failing.clone(), 47, 73),
1332            &HashMap::new(),
1333            &mut Vec::new()
1334        ));
1335    }
1336
1337    #[test]
1338    fn failing_choice() {
1339        let left_failing_node = Box::new(ParserNode {
1340            expr: ParserExpr::Str("i'm a failure".into()),
1341            span: Span::new(" ", 0, 1).unwrap(),
1342        });
1343        assert!(!is_non_failing(
1344            &left_failing_node.clone().expr,
1345            &HashMap::new(),
1346            &mut Vec::new()
1347        ));
1348
1349        let right_failing_node = Box::new(ParserNode {
1350            expr: ParserExpr::Ident("DROP".into()),
1351            span: Span::new("DROP", 0, 3).unwrap(),
1352        });
1353
1354        assert!(!is_non_failing(
1355            &ParserExpr::Choice(left_failing_node, right_failing_node),
1356            &HashMap::new(),
1357            &mut Vec::new()
1358        ))
1359    }
1360
1361    #[test]
1362    fn non_failing_choices() {
1363        let left_failing_node = Box::new(ParserNode {
1364            expr: ParserExpr::Str("i'm a failure".into()),
1365            span: Span::new(" ", 0, 1).unwrap(),
1366        });
1367
1368        assert!(!is_non_failing(
1369            &left_failing_node.clone().expr,
1370            &HashMap::new(),
1371            &mut Vec::new()
1372        ));
1373
1374        let left_non_failing_node = Box::new(ParserNode {
1375            expr: ParserExpr::Str("".into()),
1376            span: Span::new(" ", 0, 1).unwrap(),
1377        });
1378
1379        assert!(is_non_failing(
1380            &left_non_failing_node.clone().expr,
1381            &HashMap::new(),
1382            &mut Vec::new()
1383        ));
1384
1385        let right_failing_node = Box::new(ParserNode {
1386            expr: ParserExpr::Ident("DROP".into()),
1387            span: Span::new("DROP", 0, 3).unwrap(),
1388        });
1389
1390        assert!(!is_non_failing(
1391            &right_failing_node.clone().expr,
1392            &HashMap::new(),
1393            &mut Vec::new()
1394        ));
1395
1396        let right_non_failing_node = Box::new(ParserNode {
1397            expr: ParserExpr::Opt(Box::new(ParserNode {
1398                expr: ParserExpr::Str("   ".into()),
1399                span: Span::new(" ", 0, 1).unwrap(),
1400            })),
1401            span: Span::new(" ", 0, 1).unwrap(),
1402        });
1403
1404        assert!(is_non_failing(
1405            &right_non_failing_node.clone().expr,
1406            &HashMap::new(),
1407            &mut Vec::new()
1408        ));
1409
1410        assert!(is_non_failing(
1411            &ParserExpr::Choice(left_non_failing_node.clone(), right_failing_node),
1412            &HashMap::new(),
1413            &mut Vec::new()
1414        ));
1415        assert!(is_non_failing(
1416            &ParserExpr::Choice(left_failing_node, right_non_failing_node.clone()),
1417            &HashMap::new(),
1418            &mut Vec::new()
1419        ));
1420        assert!(is_non_failing(
1421            &ParserExpr::Choice(left_non_failing_node, right_non_failing_node),
1422            &HashMap::new(),
1423            &mut Vec::new()
1424        ))
1425    }
1426
1427    #[test]
1428    fn non_failing_seq() {
1429        let left_non_failing_node = Box::new(ParserNode {
1430            expr: ParserExpr::Str("".into()),
1431            span: Span::new(" ", 0, 1).unwrap(),
1432        });
1433
1434        let right_non_failing_node = Box::new(ParserNode {
1435            expr: ParserExpr::Opt(Box::new(ParserNode {
1436                expr: ParserExpr::Str("   ".into()),
1437                span: Span::new(" ", 0, 1).unwrap(),
1438            })),
1439            span: Span::new(" ", 0, 1).unwrap(),
1440        });
1441
1442        assert!(is_non_failing(
1443            &ParserExpr::Seq(left_non_failing_node, right_non_failing_node),
1444            &HashMap::new(),
1445            &mut Vec::new()
1446        ))
1447    }
1448
1449    #[test]
1450    fn failing_seqs() {
1451        let left_failing_node = Box::new(ParserNode {
1452            expr: ParserExpr::Str("i'm a failure".into()),
1453            span: Span::new(" ", 0, 1).unwrap(),
1454        });
1455
1456        assert!(!is_non_failing(
1457            &left_failing_node.clone().expr,
1458            &HashMap::new(),
1459            &mut Vec::new()
1460        ));
1461
1462        let left_non_failing_node = Box::new(ParserNode {
1463            expr: ParserExpr::Str("".into()),
1464            span: Span::new(" ", 0, 1).unwrap(),
1465        });
1466
1467        assert!(is_non_failing(
1468            &left_non_failing_node.clone().expr,
1469            &HashMap::new(),
1470            &mut Vec::new()
1471        ));
1472
1473        let right_failing_node = Box::new(ParserNode {
1474            expr: ParserExpr::Ident("DROP".into()),
1475            span: Span::new("DROP", 0, 3).unwrap(),
1476        });
1477
1478        assert!(!is_non_failing(
1479            &right_failing_node.clone().expr,
1480            &HashMap::new(),
1481            &mut Vec::new()
1482        ));
1483
1484        let right_non_failing_node = Box::new(ParserNode {
1485            expr: ParserExpr::Opt(Box::new(ParserNode {
1486                expr: ParserExpr::Str("   ".into()),
1487                span: Span::new(" ", 0, 1).unwrap(),
1488            })),
1489            span: Span::new(" ", 0, 1).unwrap(),
1490        });
1491
1492        assert!(is_non_failing(
1493            &right_non_failing_node.clone().expr,
1494            &HashMap::new(),
1495            &mut Vec::new()
1496        ));
1497
1498        assert!(!is_non_failing(
1499            &ParserExpr::Seq(left_non_failing_node, right_failing_node.clone()),
1500            &HashMap::new(),
1501            &mut Vec::new()
1502        ));
1503        assert!(!is_non_failing(
1504            &ParserExpr::Seq(left_failing_node.clone(), right_non_failing_node),
1505            &HashMap::new(),
1506            &mut Vec::new()
1507        ));
1508        assert!(!is_non_failing(
1509            &ParserExpr::Seq(left_failing_node, right_failing_node),
1510            &HashMap::new(),
1511            &mut Vec::new()
1512        ))
1513    }
1514
1515    #[test]
1516    fn failing_range() {
1517        let failing = ParserExpr::Range("A".into(), "Z".into());
1518        let always_failing = ParserExpr::Range("Z".into(), "A".into());
1519
1520        assert!(!is_non_failing(&failing, &HashMap::new(), &mut Vec::new()));
1521        assert!(!is_non_failing(
1522            &always_failing,
1523            &HashMap::new(),
1524            &mut Vec::new()
1525        ));
1526    }
1527
1528    #[test]
1529    fn _push_node_tag_pos_pred_forwarding_is_non_failing() {
1530        let failing_node = Box::new(ParserNode {
1531            expr: ParserExpr::Str("i'm a failure".into()),
1532            span: Span::new(" ", 0, 1).unwrap(),
1533        });
1534        assert!(!is_non_failing(
1535            &failing_node.clone().expr,
1536            &HashMap::new(),
1537            &mut Vec::new()
1538        ));
1539        let non_failing_node = Box::new(ParserNode {
1540            expr: ParserExpr::Str("".into()),
1541            span: Span::new(" ", 0, 1).unwrap(),
1542        });
1543        assert!(is_non_failing(
1544            &non_failing_node.clone().expr,
1545            &HashMap::new(),
1546            &mut Vec::new()
1547        ));
1548
1549        #[cfg(feature = "grammar-extras")]
1550        {
1551            assert!(!is_non_failing(
1552                &ParserExpr::NodeTag(failing_node.clone(), "TAG".into()),
1553                &HashMap::new(),
1554                &mut Vec::new()
1555            ));
1556            assert!(is_non_failing(
1557                &ParserExpr::NodeTag(non_failing_node.clone(), "TAG".into()),
1558                &HashMap::new(),
1559                &mut Vec::new()
1560            ));
1561        }
1562
1563        assert!(!is_non_failing(
1564            &ParserExpr::Push(failing_node.clone()),
1565            &HashMap::new(),
1566            &mut Vec::new()
1567        ));
1568        assert!(is_non_failing(
1569            &ParserExpr::Push(non_failing_node.clone()),
1570            &HashMap::new(),
1571            &mut Vec::new()
1572        ));
1573
1574        assert!(!is_non_failing(
1575            &ParserExpr::PosPred(failing_node.clone()),
1576            &HashMap::new(),
1577            &mut Vec::new()
1578        ));
1579        assert!(is_non_failing(
1580            &ParserExpr::PosPred(non_failing_node.clone()),
1581            &HashMap::new(),
1582            &mut Vec::new()
1583        ));
1584    }
1585
1586    #[test]
1587    #[should_panic(expected = "grammar error
1588
1589 --> 1:7
1590  |
15911 | a = { (\"\")* }
1592  |       ^---^
1593  |
1594  = expression inside repetition cannot fail and will repeat infinitely")]
1595    fn non_failing_repetition() {
1596        let input = "a = { (\"\")* }";
1597        unwrap_or_report(consume_rules(
1598            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1599        ));
1600    }
1601
1602    #[test]
1603    #[should_panic(expected = "grammar error
1604
1605 --> 1:18
1606  |
16071 | a = { \"\" } b = { a* }
1608  |                  ^^
1609  |
1610  = expression inside repetition cannot fail and will repeat infinitely")]
1611    fn indirect_non_failing_repetition() {
1612        let input = "a = { \"\" } b = { a* }";
1613        unwrap_or_report(consume_rules(
1614            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1615        ));
1616    }
1617
1618    #[test]
1619    #[should_panic(expected = "grammar error
1620
1621 --> 1:20
1622  |
16231 | a = { \"a\" ~ (\"b\" ~ (\"\")*) }
1624  |                    ^---^
1625  |
1626  = expression inside repetition cannot fail and will repeat infinitely")]
1627    fn deep_non_failing_repetition() {
1628        let input = "a = { \"a\" ~ (\"b\" ~ (\"\")*) }";
1629        unwrap_or_report(consume_rules(
1630            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1631        ));
1632    }
1633
1634    #[test]
1635    #[should_panic(expected = "grammar error
1636
1637 --> 1:7
1638  |
16391 | a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* }
1640  |       ^-------------------------------^
1641  |
1642  = expression inside repetition is non-progressing and will repeat infinitely")]
1643    fn non_progressing_repetition() {
1644        let input = "a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* }";
1645        unwrap_or_report(consume_rules(
1646            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1647        ));
1648    }
1649
1650    #[test]
1651    #[should_panic(expected = "grammar error
1652
1653 --> 1:20
1654  |
16551 | a = { !\"a\" } b = { a* }
1656  |                    ^^
1657  |
1658  = expression inside repetition is non-progressing and will repeat infinitely")]
1659    fn indirect_non_progressing_repetition() {
1660        let input = "a = { !\"a\" } b = { a* }";
1661        unwrap_or_report(consume_rules(
1662            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1663        ));
1664    }
1665
1666    #[test]
1667    #[should_panic(expected = "grammar error
1668
1669 --> 1:7
1670  |
16711 | a = { a }
1672  |       ^
1673  |
1674  = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1675    fn simple_left_recursion() {
1676        let input = "a = { a }";
1677        unwrap_or_report(consume_rules(
1678            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1679        ));
1680    }
1681
1682    #[test]
1683    #[should_panic(expected = "grammar error
1684
1685 --> 1:7
1686  |
16871 | a = { b } b = { a }
1688  |       ^
1689  |
1690  = rule b is left-recursive (b -> a -> b); pest::pratt_parser might be useful in this case
1691
1692 --> 1:17
1693  |
16941 | a = { b } b = { a }
1695  |                 ^
1696  |
1697  = rule a is left-recursive (a -> b -> a); pest::pratt_parser might be useful in this case")]
1698    fn indirect_left_recursion() {
1699        let input = "a = { b } b = { a }";
1700        unwrap_or_report(consume_rules(
1701            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1702        ));
1703    }
1704
1705    #[test]
1706    #[should_panic(expected = "grammar error
1707
1708 --> 1:39
1709  |
17101 | a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"\") ~ a }
1711  |                                       ^
1712  |
1713  = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1714    fn non_failing_left_recursion() {
1715        let input = "a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"\") ~ a }";
1716        unwrap_or_report(consume_rules(
1717            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1718        ));
1719    }
1720
1721    #[test]
1722    #[should_panic(expected = "grammar error
1723
1724 --> 1:13
1725  |
17261 | a = { \"a\" | a }
1727  |             ^
1728  |
1729  = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1730    fn non_primary_choice_left_recursion() {
1731        let input = "a = { \"a\" | a }";
1732        unwrap_or_report(consume_rules(
1733            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1734        ));
1735    }
1736
1737    #[test]
1738    #[should_panic(expected = "grammar error
1739
1740 --> 1:7
1741  |
17421 | a = { \"a\"* | \"a\" | \"b\" }
1743  |       ^--^
1744  |
1745  = expression cannot fail; following choices cannot be reached")]
1746    fn lhs_non_failing_choice() {
1747        let input = "a = { \"a\"* | \"a\" | \"b\" }";
1748        unwrap_or_report(consume_rules(
1749            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1750        ));
1751    }
1752
1753    #[test]
1754    #[should_panic(expected = "grammar error
1755
1756 --> 1:13
1757  |
17581 | a = { \"a\" | \"a\"* | \"b\" }
1759  |             ^--^
1760  |
1761  = expression cannot fail; following choices cannot be reached")]
1762    fn lhs_non_failing_choice_middle() {
1763        let input = "a = { \"a\" | \"a\"* | \"b\" }";
1764        unwrap_or_report(consume_rules(
1765            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1766        ));
1767    }
1768
1769    #[test]
1770    #[should_panic(expected = "grammar error
1771
1772 --> 1:7
1773  |
17741 | a = { b | \"a\" } b = { \"b\"* | \"c\" }
1775  |       ^
1776  |
1777  = expression cannot fail; following choices cannot be reached
1778
1779 --> 1:23
1780  |
17811 | a = { b | \"a\" } b = { \"b\"* | \"c\" }
1782  |                       ^--^
1783  |
1784  = expression cannot fail; following choices cannot be reached")]
1785    fn lhs_non_failing_nested_choices() {
1786        let input = "a = { b | \"a\" } b = { \"b\"* | \"c\" }";
1787        unwrap_or_report(consume_rules(
1788            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1789        ));
1790    }
1791
1792    #[test]
1793    fn skip_can_be_defined() {
1794        let input = "skip = { \"\" }";
1795        unwrap_or_report(consume_rules(
1796            PestParser::parse(Rule::grammar_rules, input).unwrap(),
1797        ));
1798    }
1799}