1use 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
73pub 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#[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#[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#[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#[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#[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 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 #[cfg(feature = "grammar-extras")]
230 errors.extend(validate_tag_silent_rules(rules));
231
232 errors.sort_by_key(|error| match error.location {
233 InputLocation::Span(span) => span,
234 _ => unreachable!(),
235 });
236
237 errors
238}
239
240#[cfg(feature = "grammar-extras")]
241fn validate_tag_silent_rules<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
242 use crate::ast::RuleType;
243
244 fn to_type_hash_map<'a, 'i: 'a>(
245 rules: &'a [ParserRule<'i>],
246 ) -> HashMap<String, (&'a ParserNode<'i>, RuleType)> {
247 rules
248 .iter()
249 .map(|r| (r.name.clone(), (&r.node, r.ty)))
250 .collect()
251 }
252 let mut result = vec![];
253
254 fn check_silent_builtin<'a, 'i: 'a>(
255 expr: &ParserExpr<'i>,
256 rules_ref: &HashMap<String, (&'a ParserNode<'i>, RuleType)>,
257 span: Span<'a>,
258 ) -> Option<Error<Rule>> {
259 match &expr {
260 ParserExpr::Ident(rule_name) => {
261 let rule = rules_ref.get(rule_name);
262 if matches!(rule, Some((_, RuleType::Silent))) {
263 return Some(Error::<Rule>::new_from_span(
264 ErrorVariant::CustomError {
265 message: "tags on silent rules will not appear in the output"
266 .to_owned(),
267 },
268 span,
269 ));
270 } else if BUILTINS.contains(rule_name.as_str()) {
271 return Some(Error::new_from_span(
272 ErrorVariant::CustomError {
273 message: "tags on built-in rules will not appear in the output"
274 .to_owned(),
275 },
276 span,
277 ));
278 }
279 }
280 ParserExpr::Rep(node)
281 | ParserExpr::RepMinMax(node, _, _)
282 | ParserExpr::RepMax(node, _)
283 | ParserExpr::RepMin(node, _)
284 | ParserExpr::RepOnce(node)
285 | ParserExpr::RepExact(node, _)
286 | ParserExpr::Opt(node)
287 | ParserExpr::Push(node)
288 | ParserExpr::PosPred(node)
289 | ParserExpr::NegPred(node) => {
290 return check_silent_builtin(&node.expr, rules_ref, span);
291 }
292 _ => {}
293 };
294 None
295 }
296
297 let rules_map = to_type_hash_map(rules);
298 for rule in rules {
299 let rules_ref = &rules_map;
300 let mut errors = rule.node.clone().filter_map_top_down(|node1| {
301 if let ParserExpr::NodeTag(node2, _) = node1.expr {
302 check_silent_builtin(&node2.expr, rules_ref, node1.span)
303 } else {
304 None
305 }
306 });
307 result.append(&mut errors);
308 }
309 result
310}
311
312fn is_non_progressing<'i>(
330 expr: &ParserExpr<'i>,
331 rules: &HashMap<String, &ParserNode<'i>>,
332 trace: &mut Vec<String>,
333) -> bool {
334 match *expr {
335 ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(),
336 ParserExpr::Ident(ref ident) => {
337 if ident == "SOI" || ident == "EOI" {
338 return true;
339 }
340
341 if !trace.contains(ident) {
342 if let Some(node) = rules.get(ident) {
343 trace.push(ident.clone());
344 let result = is_non_progressing(&node.expr, rules, trace);
345 trace.pop().unwrap();
346
347 return result;
348 }
349 }
362 false
369 }
370 ParserExpr::Seq(ref lhs, ref rhs) => {
371 is_non_progressing(&lhs.expr, rules, trace)
372 && is_non_progressing(&rhs.expr, rules, trace)
373 }
374 ParserExpr::Choice(ref lhs, ref rhs) => {
375 is_non_progressing(&lhs.expr, rules, trace)
376 || is_non_progressing(&rhs.expr, rules, trace)
377 }
378 ParserExpr::PosPred(_) | ParserExpr::NegPred(_) => true,
384 ParserExpr::Rep(_) | ParserExpr::Opt(_) | ParserExpr::RepMax(_, _) => true,
385 ParserExpr::Range(_, _) => false,
388 ParserExpr::PeekSlice(_, _) => {
389 false
395 }
396
397 ParserExpr::RepExact(ref inner, min)
398 | ParserExpr::RepMin(ref inner, min)
399 | ParserExpr::RepMinMax(ref inner, min, _) => {
400 min == 0 || is_non_progressing(&inner.expr, rules, trace)
401 }
402 ParserExpr::Push(ref inner) => is_non_progressing(&inner.expr, rules, trace),
403 #[cfg(feature = "grammar-extras")]
404 ParserExpr::PushLiteral(_) => true,
405 ParserExpr::RepOnce(ref inner) => is_non_progressing(&inner.expr, rules, trace),
406 #[cfg(feature = "grammar-extras")]
407 ParserExpr::NodeTag(ref inner, _) => is_non_progressing(&inner.expr, rules, trace),
408 }
409}
410
411fn is_non_failing<'i>(
426 expr: &ParserExpr<'i>,
427 rules: &HashMap<String, &ParserNode<'i>>,
428 trace: &mut Vec<String>,
429) -> bool {
430 match *expr {
431 ParserExpr::Str(ref string) | ParserExpr::Insens(ref string) => string.is_empty(),
432 ParserExpr::Ident(ref ident) => {
433 if !trace.contains(ident) {
434 if let Some(node) = rules.get(ident) {
435 trace.push(ident.clone());
436 let result = is_non_failing(&node.expr, rules, trace);
437 trace.pop().unwrap();
438
439 result
440 } else {
441 false
456 }
457 } else {
458 false
464 }
465 }
466 ParserExpr::Opt(_) => true,
467 ParserExpr::Rep(_) => true,
468 ParserExpr::RepMax(_, _) => true,
469 ParserExpr::Seq(ref lhs, ref rhs) => {
470 is_non_failing(&lhs.expr, rules, trace) && is_non_failing(&rhs.expr, rules, trace)
471 }
472 ParserExpr::Choice(ref lhs, ref rhs) => {
473 is_non_failing(&lhs.expr, rules, trace) || is_non_failing(&rhs.expr, rules, trace)
474 }
475 ParserExpr::Range(_, _) => false,
478 ParserExpr::PeekSlice(_, _) => {
479 false
485 }
486 ParserExpr::RepExact(ref inner, min)
487 | ParserExpr::RepMin(ref inner, min)
488 | ParserExpr::RepMinMax(ref inner, min, _) => {
489 min == 0 || is_non_failing(&inner.expr, rules, trace)
490 }
491 ParserExpr::NegPred(_) => false,
495 ParserExpr::RepOnce(ref inner) => is_non_failing(&inner.expr, rules, trace),
496 ParserExpr::Push(ref inner) | ParserExpr::PosPred(ref inner) => {
497 is_non_failing(&inner.expr, rules, trace)
498 }
499 #[cfg(feature = "grammar-extras")]
500 ParserExpr::PushLiteral(_) => true,
501 #[cfg(feature = "grammar-extras")]
502 ParserExpr::NodeTag(ref inner, _) => is_non_failing(&inner.expr, rules, trace),
503 }
504}
505
506fn validate_repetition<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
507 let mut result = vec![];
508 let map = to_hash_map(rules);
509
510 for rule in rules {
511 let mut errors = rule.node
512 .clone()
513 .filter_map_top_down(|node| match node.expr {
514 ParserExpr::Rep(ref other)
515 | ParserExpr::RepOnce(ref other)
516 | ParserExpr::RepMin(ref other, _) => {
517 if is_non_failing(&other.expr, &map, &mut vec![]) {
518 Some(Error::new_from_span(
519 ErrorVariant::CustomError {
520 message:
521 "expression inside repetition cannot fail and will repeat \
522 infinitely"
523 .to_owned()
524 },
525 node.span
526 ))
527 } else if is_non_progressing(&other.expr, &map, &mut vec![]) {
528 Some(Error::new_from_span(
529 ErrorVariant::CustomError {
530 message:
531 "expression inside repetition is non-progressing and will repeat \
532 infinitely"
533 .to_owned(),
534 },
535 node.span
536 ))
537 } else {
538 None
539 }
540 }
541 _ => None
542 });
543
544 result.append(&mut errors);
545 }
546
547 result
548}
549
550fn validate_choices<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
551 let mut result = vec![];
552 let map = to_hash_map(rules);
553
554 for rule in rules {
555 let mut errors = rule
556 .node
557 .clone()
558 .filter_map_top_down(|node| match node.expr {
559 ParserExpr::Choice(ref lhs, _) => {
560 let node = match lhs.expr {
561 ParserExpr::Choice(_, ref rhs) => rhs,
562 _ => lhs,
563 };
564
565 if is_non_failing(&node.expr, &map, &mut vec![]) {
566 Some(Error::new_from_span(
567 ErrorVariant::CustomError {
568 message:
569 "expression cannot fail; following choices cannot be reached"
570 .to_owned(),
571 },
572 node.span,
573 ))
574 } else {
575 None
576 }
577 }
578 _ => None,
579 });
580
581 result.append(&mut errors);
582 }
583
584 result
585}
586
587fn validate_whitespace_comment<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
588 let map = to_hash_map(rules);
589
590 rules
591 .iter()
592 .filter_map(|rule| {
593 if rule.name == "WHITESPACE" || rule.name == "COMMENT" {
594 if is_non_failing(&rule.node.expr, &map, &mut vec![]) {
595 Some(Error::new_from_span(
596 ErrorVariant::CustomError {
597 message: format!(
598 "{} cannot fail and will repeat infinitely",
599 &rule.name
600 ),
601 },
602 rule.node.span,
603 ))
604 } else if is_non_progressing(&rule.node.expr, &map, &mut vec![]) {
605 Some(Error::new_from_span(
606 ErrorVariant::CustomError {
607 message: format!(
608 "{} is non-progressing and will repeat infinitely",
609 &rule.name
610 ),
611 },
612 rule.node.span,
613 ))
614 } else {
615 None
616 }
617 } else {
618 None
619 }
620 })
621 .collect()
622}
623
624fn validate_left_recursion<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> Vec<Error<Rule>> {
625 left_recursion(to_hash_map(rules))
626}
627
628fn to_hash_map<'a, 'i: 'a>(rules: &'a [ParserRule<'i>]) -> HashMap<String, &'a ParserNode<'i>> {
629 rules.iter().map(|r| (r.name.clone(), &r.node)).collect()
630}
631
632fn left_recursion<'a, 'i: 'a>(rules: HashMap<String, &'a ParserNode<'i>>) -> Vec<Error<Rule>> {
633 fn check_expr<'a, 'i: 'a>(
634 node: &'a ParserNode<'i>,
635 rules: &'a HashMap<String, &ParserNode<'i>>,
636 trace: &mut Vec<String>,
637 ) -> Option<Error<Rule>> {
638 match node.expr.clone() {
639 ParserExpr::Ident(other) => {
640 if trace[0] == other {
641 trace.push(other);
642 let chain = trace
643 .iter()
644 .map(|ident| ident.as_ref())
645 .collect::<Vec<_>>()
646 .join(" -> ");
647
648 return Some(Error::new_from_span(
649 ErrorVariant::CustomError {
650 message: format!(
651 "rule {} is left-recursive ({}); pest::pratt_parser might be useful \
652 in this case",
653 node.span.as_str(),
654 chain
655 )
656 },
657 node.span
658 ));
659 }
660
661 if !trace.contains(&other) {
662 if let Some(node) = rules.get(&other) {
663 trace.push(other);
664 let result = check_expr(node, rules, trace);
665 trace.pop().unwrap();
666
667 return result;
668 }
669 }
670
671 None
672 }
673 ParserExpr::Seq(ref lhs, ref rhs) => {
674 if is_non_failing(&lhs.expr, rules, &mut vec![trace.last().unwrap().clone()])
675 || is_non_progressing(
676 &lhs.expr,
677 rules,
678 &mut vec![trace.last().unwrap().clone()],
679 )
680 {
681 check_expr(rhs, rules, trace)
682 } else {
683 check_expr(lhs, rules, trace)
684 }
685 }
686 ParserExpr::Choice(ref lhs, ref rhs) => {
687 check_expr(lhs, rules, trace).or_else(|| check_expr(rhs, rules, trace))
688 }
689 ParserExpr::Rep(ref node) => check_expr(node, rules, trace),
690 ParserExpr::RepOnce(ref node) => check_expr(node, rules, trace),
691 ParserExpr::Opt(ref node) => check_expr(node, rules, trace),
692 ParserExpr::PosPred(ref node) => check_expr(node, rules, trace),
693 ParserExpr::NegPred(ref node) => check_expr(node, rules, trace),
694 ParserExpr::Push(ref node) => check_expr(node, rules, trace),
695 _ => None,
696 }
697 }
698
699 let mut errors = vec![];
700
701 for (name, node) in &rules {
702 let name = name.clone();
703
704 if let Some(error) = check_expr(node, &rules, &mut vec![name]) {
705 errors.push(error);
706 }
707 }
708
709 errors
710}
711
712#[cfg(test)]
713mod tests {
714 use super::super::parser::{consume_rules, PestParser};
715 use super::super::unwrap_or_report;
716 use super::*;
717 use pest::Parser;
718
719 #[test]
720 #[should_panic(expected = "grammar error
721
722 --> 1:1
723 |
7241 | ANY = { \"a\" }
725 | ^-^
726 |
727 = ANY is a pest keyword")]
728 fn pest_keyword() {
729 let input = "ANY = { \"a\" }";
730 unwrap_or_report(validate_pairs(
731 PestParser::parse(Rule::grammar_rules, input).unwrap(),
732 ));
733 }
734
735 #[test]
736 #[should_panic(expected = "grammar error
737
738 --> 1:13
739 |
7401 | a = { \"a\" } a = { \"a\" }
741 | ^
742 |
743 = rule a already defined")]
744 fn already_defined() {
745 let input = "a = { \"a\" } a = { \"a\" }";
746 unwrap_or_report(validate_pairs(
747 PestParser::parse(Rule::grammar_rules, input).unwrap(),
748 ));
749 }
750
751 #[test]
752 #[should_panic(expected = "grammar error
753
754 --> 1:7
755 |
7561 | a = { b }
757 | ^
758 |
759 = rule b is undefined")]
760 fn undefined() {
761 let input = "a = { b }";
762 unwrap_or_report(validate_pairs(
763 PestParser::parse(Rule::grammar_rules, input).unwrap(),
764 ));
765 }
766
767 #[test]
768 fn valid_recursion() {
769 let input = "a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"b\") ~ a }";
770 unwrap_or_report(consume_rules(
771 PestParser::parse(Rule::grammar_rules, input).unwrap(),
772 ));
773 }
774
775 #[test]
776 #[should_panic(expected = "grammar error
777
778 --> 1:16
779 |
7801 | WHITESPACE = { \"\" }
781 | ^^
782 |
783 = WHITESPACE cannot fail and will repeat infinitely")]
784 fn non_failing_whitespace() {
785 let input = "WHITESPACE = { \"\" }";
786 unwrap_or_report(consume_rules(
787 PestParser::parse(Rule::grammar_rules, input).unwrap(),
788 ));
789 }
790
791 #[test]
792 #[should_panic(expected = "grammar error
793
794 --> 1:13
795 |
7961 | COMMENT = { SOI }
797 | ^-^
798 |
799 = COMMENT is non-progressing and will repeat infinitely")]
800 fn non_progressing_comment() {
801 let input = "COMMENT = { SOI }";
802 unwrap_or_report(consume_rules(
803 PestParser::parse(Rule::grammar_rules, input).unwrap(),
804 ));
805 }
806
807 #[test]
808 fn non_progressing_empty_string() {
809 assert!(is_non_failing(
810 &ParserExpr::Insens("".into()),
811 &HashMap::new(),
812 &mut Vec::new()
813 ));
814 assert!(is_non_progressing(
815 &ParserExpr::Str("".into()),
816 &HashMap::new(),
817 &mut Vec::new()
818 ));
819 }
820
821 #[test]
822 fn progressing_non_empty_string() {
823 assert!(!is_non_progressing(
824 &ParserExpr::Insens("non empty".into()),
825 &HashMap::new(),
826 &mut Vec::new()
827 ));
828 assert!(!is_non_progressing(
829 &ParserExpr::Str("non empty".into()),
830 &HashMap::new(),
831 &mut Vec::new()
832 ));
833 }
834
835 #[test]
836 fn non_progressing_soi_eoi() {
837 assert!(is_non_progressing(
838 &ParserExpr::Ident("SOI".into()),
839 &HashMap::new(),
840 &mut Vec::new()
841 ));
842 assert!(is_non_progressing(
843 &ParserExpr::Ident("EOI".into()),
844 &HashMap::new(),
845 &mut Vec::new()
846 ));
847 }
848
849 #[test]
850 fn non_progressing_predicates() {
851 let progressing = ParserExpr::Str("A".into());
852
853 assert!(is_non_progressing(
854 &ParserExpr::PosPred(Box::new(ParserNode {
855 expr: progressing.clone(),
856 span: Span::new(" ", 0, 1).unwrap(),
857 })),
858 &HashMap::new(),
859 &mut Vec::new()
860 ));
861 assert!(is_non_progressing(
862 &ParserExpr::NegPred(Box::new(ParserNode {
863 expr: progressing,
864 span: Span::new(" ", 0, 1).unwrap(),
865 })),
866 &HashMap::new(),
867 &mut Vec::new()
868 ));
869 }
870
871 #[test]
872 fn non_progressing_0_length_repetitions() {
873 let input_progressing_node = Box::new(ParserNode {
874 expr: ParserExpr::Str("A".into()),
875 span: Span::new(" ", 0, 1).unwrap(),
876 });
877
878 assert!(!is_non_progressing(
879 &input_progressing_node.clone().expr,
880 &HashMap::new(),
881 &mut Vec::new()
882 ));
883
884 assert!(is_non_progressing(
885 &ParserExpr::Rep(input_progressing_node.clone()),
886 &HashMap::new(),
887 &mut Vec::new()
888 ));
889 assert!(is_non_progressing(
890 &ParserExpr::Opt(input_progressing_node.clone()),
891 &HashMap::new(),
892 &mut Vec::new()
893 ));
894 assert!(is_non_progressing(
895 &ParserExpr::RepExact(input_progressing_node.clone(), 0),
896 &HashMap::new(),
897 &mut Vec::new()
898 ));
899 assert!(is_non_progressing(
900 &ParserExpr::RepMin(input_progressing_node.clone(), 0),
901 &HashMap::new(),
902 &mut Vec::new()
903 ));
904 assert!(is_non_progressing(
905 &ParserExpr::RepMax(input_progressing_node.clone(), 0),
906 &HashMap::new(),
907 &mut Vec::new()
908 ));
909 assert!(is_non_progressing(
910 &ParserExpr::RepMax(input_progressing_node.clone(), 17),
911 &HashMap::new(),
912 &mut Vec::new()
913 ));
914
915 assert!(is_non_progressing(
916 &ParserExpr::RepMinMax(input_progressing_node.clone(), 0, 12),
917 &HashMap::new(),
918 &mut Vec::new()
919 ));
920 }
921
922 #[test]
923 fn non_progressing_nonzero_repetitions_with_non_progressing_expr() {
924 let a = "";
925 let non_progressing_node = Box::new(ParserNode {
926 expr: ParserExpr::Str(a.into()),
927 span: Span::new(a, 0, 0).unwrap(),
928 });
929 let exact = ParserExpr::RepExact(non_progressing_node.clone(), 7);
930 let min = ParserExpr::RepMin(non_progressing_node.clone(), 23);
931 let minmax = ParserExpr::RepMinMax(non_progressing_node.clone(), 12, 13);
932 let reponce = ParserExpr::RepOnce(non_progressing_node);
933
934 assert!(is_non_progressing(&exact, &HashMap::new(), &mut Vec::new()));
935 assert!(is_non_progressing(&min, &HashMap::new(), &mut Vec::new()));
936 assert!(is_non_progressing(
937 &minmax,
938 &HashMap::new(),
939 &mut Vec::new()
940 ));
941 assert!(is_non_progressing(
942 &reponce,
943 &HashMap::new(),
944 &mut Vec::new()
945 ));
946 }
947
948 #[test]
949 fn progressing_repetitions() {
950 let a = "A";
951 let input_progressing_node = Box::new(ParserNode {
952 expr: ParserExpr::Str(a.into()),
953 span: Span::new(a, 0, 1).unwrap(),
954 });
955 let exact = ParserExpr::RepExact(input_progressing_node.clone(), 1);
956 let min = ParserExpr::RepMin(input_progressing_node.clone(), 2);
957 let minmax = ParserExpr::RepMinMax(input_progressing_node.clone(), 4, 5);
958 let reponce = ParserExpr::RepOnce(input_progressing_node);
959
960 assert!(!is_non_progressing(
961 &exact,
962 &HashMap::new(),
963 &mut Vec::new()
964 ));
965 assert!(!is_non_progressing(&min, &HashMap::new(), &mut Vec::new()));
966 assert!(!is_non_progressing(
967 &minmax,
968 &HashMap::new(),
969 &mut Vec::new()
970 ));
971 assert!(!is_non_progressing(
972 &reponce,
973 &HashMap::new(),
974 &mut Vec::new()
975 ));
976 }
977
978 #[test]
979 fn non_progressing_push() {
980 let a = "";
981 let non_progressing_node = Box::new(ParserNode {
982 expr: ParserExpr::Str(a.into()),
983 span: Span::new(a, 0, 0).unwrap(),
984 });
985 let push = ParserExpr::Push(non_progressing_node.clone());
986
987 assert!(is_non_progressing(&push, &HashMap::new(), &mut Vec::new()));
988 }
989
990 #[test]
991 fn progressing_push() {
992 let a = "i'm make progress";
993 let progressing_node = Box::new(ParserNode {
994 expr: ParserExpr::Str(a.into()),
995 span: Span::new(a, 0, 1).unwrap(),
996 });
997 let push = ParserExpr::Push(progressing_node.clone());
998
999 assert!(!is_non_progressing(&push, &HashMap::new(), &mut Vec::new()));
1000 }
1001
1002 #[cfg(feature = "grammar-extras")]
1003 #[test]
1004 fn push_literal_is_non_progressing() {
1005 let a = "";
1006 let non_progressing_node = Box::new(ParserNode {
1007 expr: ParserExpr::PushLiteral("a".to_string()),
1008 span: Span::new(a, 0, 0).unwrap(),
1009 });
1010 let push = ParserExpr::Push(non_progressing_node.clone());
1011
1012 assert!(is_non_progressing(&push, &HashMap::new(), &mut Vec::new()));
1013 }
1014
1015 #[test]
1016 fn node_tag_forwards_is_non_progressing() {
1017 let progressing_node = Box::new(ParserNode {
1018 expr: ParserExpr::Str("i'm make progress".into()),
1019 span: Span::new(" ", 0, 1).unwrap(),
1020 });
1021 assert!(!is_non_progressing(
1022 &progressing_node.clone().expr,
1023 &HashMap::new(),
1024 &mut Vec::new()
1025 ));
1026 let non_progressing_node = Box::new(ParserNode {
1027 expr: ParserExpr::Str("".into()),
1028 span: Span::new(" ", 0, 1).unwrap(),
1029 });
1030 assert!(is_non_progressing(
1031 &non_progressing_node.clone().expr,
1032 &HashMap::new(),
1033 &mut Vec::new()
1034 ));
1035 #[cfg(feature = "grammar-extras")]
1036 {
1037 let progressing = ParserExpr::NodeTag(progressing_node.clone(), "TAG".into());
1038 let non_progressing = ParserExpr::NodeTag(non_progressing_node.clone(), "TAG".into());
1039
1040 assert!(!is_non_progressing(
1041 &progressing,
1042 &HashMap::new(),
1043 &mut Vec::new()
1044 ));
1045 assert!(is_non_progressing(
1046 &non_progressing,
1047 &HashMap::new(),
1048 &mut Vec::new()
1049 ));
1050 }
1051 }
1052
1053 #[test]
1054 fn progressing_range() {
1055 let progressing = ParserExpr::Range("A".into(), "Z".into());
1056 let failing_is_progressing = ParserExpr::Range("Z".into(), "A".into());
1057
1058 assert!(!is_non_progressing(
1059 &progressing,
1060 &HashMap::new(),
1061 &mut Vec::new()
1062 ));
1063 assert!(!is_non_progressing(
1064 &failing_is_progressing,
1065 &HashMap::new(),
1066 &mut Vec::new()
1067 ));
1068 }
1069
1070 #[test]
1071 fn progressing_choice() {
1072 let left_progressing_node = Box::new(ParserNode {
1073 expr: ParserExpr::Str("i'm make progress".into()),
1074 span: Span::new(" ", 0, 1).unwrap(),
1075 });
1076 assert!(!is_non_progressing(
1077 &left_progressing_node.clone().expr,
1078 &HashMap::new(),
1079 &mut Vec::new()
1080 ));
1081
1082 let right_progressing_node = Box::new(ParserNode {
1083 expr: ParserExpr::Ident("DROP".into()),
1084 span: Span::new("DROP", 0, 3).unwrap(),
1085 });
1086
1087 assert!(!is_non_progressing(
1088 &ParserExpr::Choice(left_progressing_node, right_progressing_node),
1089 &HashMap::new(),
1090 &mut Vec::new()
1091 ))
1092 }
1093
1094 #[test]
1095 fn non_progressing_choices() {
1096 let left_progressing_node = Box::new(ParserNode {
1097 expr: ParserExpr::Str("i'm make progress".into()),
1098 span: Span::new(" ", 0, 1).unwrap(),
1099 });
1100
1101 assert!(!is_non_progressing(
1102 &left_progressing_node.clone().expr,
1103 &HashMap::new(),
1104 &mut Vec::new()
1105 ));
1106
1107 let left_non_progressing_node = Box::new(ParserNode {
1108 expr: ParserExpr::Str("".into()),
1109 span: Span::new(" ", 0, 1).unwrap(),
1110 });
1111
1112 assert!(is_non_progressing(
1113 &left_non_progressing_node.clone().expr,
1114 &HashMap::new(),
1115 &mut Vec::new()
1116 ));
1117
1118 let right_progressing_node = Box::new(ParserNode {
1119 expr: ParserExpr::Ident("DROP".into()),
1120 span: Span::new("DROP", 0, 3).unwrap(),
1121 });
1122
1123 assert!(!is_non_progressing(
1124 &right_progressing_node.clone().expr,
1125 &HashMap::new(),
1126 &mut Vec::new()
1127 ));
1128
1129 let right_non_progressing_node = Box::new(ParserNode {
1130 expr: ParserExpr::Opt(Box::new(ParserNode {
1131 expr: ParserExpr::Str(" ".into()),
1132 span: Span::new(" ", 0, 1).unwrap(),
1133 })),
1134 span: Span::new(" ", 0, 1).unwrap(),
1135 });
1136
1137 assert!(is_non_progressing(
1138 &right_non_progressing_node.clone().expr,
1139 &HashMap::new(),
1140 &mut Vec::new()
1141 ));
1142
1143 assert!(is_non_progressing(
1144 &ParserExpr::Choice(left_non_progressing_node.clone(), right_progressing_node),
1145 &HashMap::new(),
1146 &mut Vec::new()
1147 ));
1148 assert!(is_non_progressing(
1149 &ParserExpr::Choice(left_progressing_node, right_non_progressing_node.clone()),
1150 &HashMap::new(),
1151 &mut Vec::new()
1152 ));
1153 assert!(is_non_progressing(
1154 &ParserExpr::Choice(left_non_progressing_node, right_non_progressing_node),
1155 &HashMap::new(),
1156 &mut Vec::new()
1157 ))
1158 }
1159
1160 #[test]
1161 fn non_progressing_seq() {
1162 let left_non_progressing_node = Box::new(ParserNode {
1163 expr: ParserExpr::Str("".into()),
1164 span: Span::new(" ", 0, 1).unwrap(),
1165 });
1166
1167 let right_non_progressing_node = Box::new(ParserNode {
1168 expr: ParserExpr::Opt(Box::new(ParserNode {
1169 expr: ParserExpr::Str(" ".into()),
1170 span: Span::new(" ", 0, 1).unwrap(),
1171 })),
1172 span: Span::new(" ", 0, 1).unwrap(),
1173 });
1174
1175 assert!(is_non_progressing(
1176 &ParserExpr::Seq(left_non_progressing_node, right_non_progressing_node),
1177 &HashMap::new(),
1178 &mut Vec::new()
1179 ))
1180 }
1181
1182 #[test]
1183 fn progressing_seqs() {
1184 let left_progressing_node = Box::new(ParserNode {
1185 expr: ParserExpr::Str("i'm make progress".into()),
1186 span: Span::new(" ", 0, 1).unwrap(),
1187 });
1188
1189 assert!(!is_non_progressing(
1190 &left_progressing_node.clone().expr,
1191 &HashMap::new(),
1192 &mut Vec::new()
1193 ));
1194
1195 let left_non_progressing_node = Box::new(ParserNode {
1196 expr: ParserExpr::Str("".into()),
1197 span: Span::new(" ", 0, 1).unwrap(),
1198 });
1199
1200 assert!(is_non_progressing(
1201 &left_non_progressing_node.clone().expr,
1202 &HashMap::new(),
1203 &mut Vec::new()
1204 ));
1205
1206 let right_progressing_node = Box::new(ParserNode {
1207 expr: ParserExpr::Ident("DROP".into()),
1208 span: Span::new("DROP", 0, 3).unwrap(),
1209 });
1210
1211 assert!(!is_non_progressing(
1212 &right_progressing_node.clone().expr,
1213 &HashMap::new(),
1214 &mut Vec::new()
1215 ));
1216
1217 let right_non_progressing_node = Box::new(ParserNode {
1218 expr: ParserExpr::Opt(Box::new(ParserNode {
1219 expr: ParserExpr::Str(" ".into()),
1220 span: Span::new(" ", 0, 1).unwrap(),
1221 })),
1222 span: Span::new(" ", 0, 1).unwrap(),
1223 });
1224
1225 assert!(is_non_progressing(
1226 &right_non_progressing_node.clone().expr,
1227 &HashMap::new(),
1228 &mut Vec::new()
1229 ));
1230
1231 assert!(!is_non_progressing(
1232 &ParserExpr::Seq(left_non_progressing_node, right_progressing_node.clone()),
1233 &HashMap::new(),
1234 &mut Vec::new()
1235 ));
1236 assert!(!is_non_progressing(
1237 &ParserExpr::Seq(left_progressing_node.clone(), right_non_progressing_node),
1238 &HashMap::new(),
1239 &mut Vec::new()
1240 ));
1241 assert!(!is_non_progressing(
1242 &ParserExpr::Seq(left_progressing_node, right_progressing_node),
1243 &HashMap::new(),
1244 &mut Vec::new()
1245 ))
1246 }
1247
1248 #[test]
1249 fn progressing_stack_operations() {
1250 assert!(!is_non_progressing(
1251 &ParserExpr::Ident("DROP".into()),
1252 &HashMap::new(),
1253 &mut Vec::new()
1254 ));
1255 assert!(!is_non_progressing(
1256 &ParserExpr::Ident("PEEK".into()),
1257 &HashMap::new(),
1258 &mut Vec::new()
1259 ));
1260 assert!(!is_non_progressing(
1261 &ParserExpr::Ident("POP".into()),
1262 &HashMap::new(),
1263 &mut Vec::new()
1264 ))
1265 }
1266
1267 #[test]
1268 fn non_failing_string() {
1269 let insens = ParserExpr::Insens("".into());
1270 let string = ParserExpr::Str("".into());
1271
1272 assert!(is_non_failing(&insens, &HashMap::new(), &mut Vec::new()));
1273
1274 assert!(is_non_failing(&string, &HashMap::new(), &mut Vec::new()))
1275 }
1276
1277 #[test]
1278 fn failing_string() {
1279 assert!(!is_non_failing(
1280 &ParserExpr::Insens("i may fail!".into()),
1281 &HashMap::new(),
1282 &mut Vec::new()
1283 ));
1284 assert!(!is_non_failing(
1285 &ParserExpr::Str("failure is not fatal".into()),
1286 &HashMap::new(),
1287 &mut Vec::new()
1288 ))
1289 }
1290
1291 #[test]
1292 fn failing_stack_operations() {
1293 assert!(!is_non_failing(
1294 &ParserExpr::Ident("DROP".into()),
1295 &HashMap::new(),
1296 &mut Vec::new()
1297 ));
1298 assert!(!is_non_failing(
1299 &ParserExpr::Ident("POP".into()),
1300 &HashMap::new(),
1301 &mut Vec::new()
1302 ));
1303 assert!(!is_non_failing(
1304 &ParserExpr::Ident("PEEK".into()),
1305 &HashMap::new(),
1306 &mut Vec::new()
1307 ))
1308 }
1309
1310 #[test]
1311 fn non_failing_zero_length_repetitions() {
1312 let failing = Box::new(ParserNode {
1313 expr: ParserExpr::Range("A".into(), "B".into()),
1314 span: Span::new(" ", 0, 1).unwrap(),
1315 });
1316 assert!(!is_non_failing(
1317 &failing.clone().expr,
1318 &HashMap::new(),
1319 &mut Vec::new()
1320 ));
1321 assert!(is_non_failing(
1322 &ParserExpr::Opt(failing.clone()),
1323 &HashMap::new(),
1324 &mut Vec::new()
1325 ));
1326 assert!(is_non_failing(
1327 &ParserExpr::Rep(failing.clone()),
1328 &HashMap::new(),
1329 &mut Vec::new()
1330 ));
1331 assert!(is_non_failing(
1332 &ParserExpr::RepExact(failing.clone(), 0),
1333 &HashMap::new(),
1334 &mut Vec::new()
1335 ));
1336 assert!(is_non_failing(
1337 &ParserExpr::RepMin(failing.clone(), 0),
1338 &HashMap::new(),
1339 &mut Vec::new()
1340 ));
1341 assert!(is_non_failing(
1342 &ParserExpr::RepMax(failing.clone(), 0),
1343 &HashMap::new(),
1344 &mut Vec::new()
1345 ));
1346 assert!(is_non_failing(
1347 &ParserExpr::RepMax(failing.clone(), 22),
1348 &HashMap::new(),
1349 &mut Vec::new()
1350 ));
1351 assert!(is_non_failing(
1352 &ParserExpr::RepMinMax(failing.clone(), 0, 73),
1353 &HashMap::new(),
1354 &mut Vec::new()
1355 ));
1356 }
1357
1358 #[test]
1359 fn non_failing_non_zero_repetitions_with_non_failing_expr() {
1360 let non_failing = Box::new(ParserNode {
1361 expr: ParserExpr::Opt(Box::new(ParserNode {
1362 expr: ParserExpr::Range("A".into(), "B".into()),
1363 span: Span::new(" ", 0, 1).unwrap(),
1364 })),
1365 span: Span::new(" ", 0, 1).unwrap(),
1366 });
1367 assert!(is_non_failing(
1368 &non_failing.clone().expr,
1369 &HashMap::new(),
1370 &mut Vec::new()
1371 ));
1372 assert!(is_non_failing(
1373 &ParserExpr::RepOnce(non_failing.clone()),
1374 &HashMap::new(),
1375 &mut Vec::new()
1376 ));
1377 assert!(is_non_failing(
1378 &ParserExpr::RepExact(non_failing.clone(), 1),
1379 &HashMap::new(),
1380 &mut Vec::new()
1381 ));
1382 assert!(is_non_failing(
1383 &ParserExpr::RepMin(non_failing.clone(), 6),
1384 &HashMap::new(),
1385 &mut Vec::new()
1386 ));
1387 assert!(is_non_failing(
1388 &ParserExpr::RepMinMax(non_failing.clone(), 32, 73),
1389 &HashMap::new(),
1390 &mut Vec::new()
1391 ));
1392 }
1393
1394 #[test]
1395 #[cfg(feature = "grammar-extras")]
1396 fn failing_non_zero_repetitions() {
1397 let failing = Box::new(ParserNode {
1398 expr: ParserExpr::NodeTag(
1399 Box::new(ParserNode {
1400 expr: ParserExpr::Range("A".into(), "B".into()),
1401 span: Span::new(" ", 0, 1).unwrap(),
1402 }),
1403 "Tag".into(),
1404 ),
1405 span: Span::new(" ", 0, 1).unwrap(),
1406 });
1407 assert!(!is_non_failing(
1408 &failing.clone().expr,
1409 &HashMap::new(),
1410 &mut Vec::new()
1411 ));
1412 assert!(!is_non_failing(
1413 &ParserExpr::RepOnce(failing.clone()),
1414 &HashMap::new(),
1415 &mut Vec::new()
1416 ));
1417 assert!(!is_non_failing(
1418 &ParserExpr::RepExact(failing.clone(), 3),
1419 &HashMap::new(),
1420 &mut Vec::new()
1421 ));
1422 assert!(!is_non_failing(
1423 &ParserExpr::RepMin(failing.clone(), 14),
1424 &HashMap::new(),
1425 &mut Vec::new()
1426 ));
1427 assert!(!is_non_failing(
1428 &ParserExpr::RepMinMax(failing.clone(), 47, 73),
1429 &HashMap::new(),
1430 &mut Vec::new()
1431 ));
1432 }
1433
1434 #[test]
1435 fn failing_choice() {
1436 let left_failing_node = Box::new(ParserNode {
1437 expr: ParserExpr::Str("i'm a failure".into()),
1438 span: Span::new(" ", 0, 1).unwrap(),
1439 });
1440 assert!(!is_non_failing(
1441 &left_failing_node.clone().expr,
1442 &HashMap::new(),
1443 &mut Vec::new()
1444 ));
1445
1446 let right_failing_node = Box::new(ParserNode {
1447 expr: ParserExpr::Ident("DROP".into()),
1448 span: Span::new("DROP", 0, 3).unwrap(),
1449 });
1450
1451 assert!(!is_non_failing(
1452 &ParserExpr::Choice(left_failing_node, right_failing_node),
1453 &HashMap::new(),
1454 &mut Vec::new()
1455 ))
1456 }
1457
1458 #[test]
1459 fn non_failing_choices() {
1460 let left_failing_node = Box::new(ParserNode {
1461 expr: ParserExpr::Str("i'm a failure".into()),
1462 span: Span::new(" ", 0, 1).unwrap(),
1463 });
1464
1465 assert!(!is_non_failing(
1466 &left_failing_node.clone().expr,
1467 &HashMap::new(),
1468 &mut Vec::new()
1469 ));
1470
1471 let left_non_failing_node = Box::new(ParserNode {
1472 expr: ParserExpr::Str("".into()),
1473 span: Span::new(" ", 0, 1).unwrap(),
1474 });
1475
1476 assert!(is_non_failing(
1477 &left_non_failing_node.clone().expr,
1478 &HashMap::new(),
1479 &mut Vec::new()
1480 ));
1481
1482 let right_failing_node = Box::new(ParserNode {
1483 expr: ParserExpr::Ident("DROP".into()),
1484 span: Span::new("DROP", 0, 3).unwrap(),
1485 });
1486
1487 assert!(!is_non_failing(
1488 &right_failing_node.clone().expr,
1489 &HashMap::new(),
1490 &mut Vec::new()
1491 ));
1492
1493 let right_non_failing_node = Box::new(ParserNode {
1494 expr: ParserExpr::Opt(Box::new(ParserNode {
1495 expr: ParserExpr::Str(" ".into()),
1496 span: Span::new(" ", 0, 1).unwrap(),
1497 })),
1498 span: Span::new(" ", 0, 1).unwrap(),
1499 });
1500
1501 assert!(is_non_failing(
1502 &right_non_failing_node.clone().expr,
1503 &HashMap::new(),
1504 &mut Vec::new()
1505 ));
1506
1507 assert!(is_non_failing(
1508 &ParserExpr::Choice(left_non_failing_node.clone(), right_failing_node),
1509 &HashMap::new(),
1510 &mut Vec::new()
1511 ));
1512 assert!(is_non_failing(
1513 &ParserExpr::Choice(left_failing_node, right_non_failing_node.clone()),
1514 &HashMap::new(),
1515 &mut Vec::new()
1516 ));
1517 assert!(is_non_failing(
1518 &ParserExpr::Choice(left_non_failing_node, right_non_failing_node),
1519 &HashMap::new(),
1520 &mut Vec::new()
1521 ))
1522 }
1523
1524 #[test]
1525 fn non_failing_seq() {
1526 let left_non_failing_node = Box::new(ParserNode {
1527 expr: ParserExpr::Str("".into()),
1528 span: Span::new(" ", 0, 1).unwrap(),
1529 });
1530
1531 let right_non_failing_node = Box::new(ParserNode {
1532 expr: ParserExpr::Opt(Box::new(ParserNode {
1533 expr: ParserExpr::Str(" ".into()),
1534 span: Span::new(" ", 0, 1).unwrap(),
1535 })),
1536 span: Span::new(" ", 0, 1).unwrap(),
1537 });
1538
1539 assert!(is_non_failing(
1540 &ParserExpr::Seq(left_non_failing_node, right_non_failing_node),
1541 &HashMap::new(),
1542 &mut Vec::new()
1543 ))
1544 }
1545
1546 #[test]
1547 fn failing_seqs() {
1548 let left_failing_node = Box::new(ParserNode {
1549 expr: ParserExpr::Str("i'm a failure".into()),
1550 span: Span::new(" ", 0, 1).unwrap(),
1551 });
1552
1553 assert!(!is_non_failing(
1554 &left_failing_node.clone().expr,
1555 &HashMap::new(),
1556 &mut Vec::new()
1557 ));
1558
1559 let left_non_failing_node = Box::new(ParserNode {
1560 expr: ParserExpr::Str("".into()),
1561 span: Span::new(" ", 0, 1).unwrap(),
1562 });
1563
1564 assert!(is_non_failing(
1565 &left_non_failing_node.clone().expr,
1566 &HashMap::new(),
1567 &mut Vec::new()
1568 ));
1569
1570 let right_failing_node = Box::new(ParserNode {
1571 expr: ParserExpr::Ident("DROP".into()),
1572 span: Span::new("DROP", 0, 3).unwrap(),
1573 });
1574
1575 assert!(!is_non_failing(
1576 &right_failing_node.clone().expr,
1577 &HashMap::new(),
1578 &mut Vec::new()
1579 ));
1580
1581 let right_non_failing_node = Box::new(ParserNode {
1582 expr: ParserExpr::Opt(Box::new(ParserNode {
1583 expr: ParserExpr::Str(" ".into()),
1584 span: Span::new(" ", 0, 1).unwrap(),
1585 })),
1586 span: Span::new(" ", 0, 1).unwrap(),
1587 });
1588
1589 assert!(is_non_failing(
1590 &right_non_failing_node.clone().expr,
1591 &HashMap::new(),
1592 &mut Vec::new()
1593 ));
1594
1595 assert!(!is_non_failing(
1596 &ParserExpr::Seq(left_non_failing_node, right_failing_node.clone()),
1597 &HashMap::new(),
1598 &mut Vec::new()
1599 ));
1600 assert!(!is_non_failing(
1601 &ParserExpr::Seq(left_failing_node.clone(), right_non_failing_node),
1602 &HashMap::new(),
1603 &mut Vec::new()
1604 ));
1605 assert!(!is_non_failing(
1606 &ParserExpr::Seq(left_failing_node, right_failing_node),
1607 &HashMap::new(),
1608 &mut Vec::new()
1609 ))
1610 }
1611
1612 #[test]
1613 fn failing_range() {
1614 let failing = ParserExpr::Range("A".into(), "Z".into());
1615 let always_failing = ParserExpr::Range("Z".into(), "A".into());
1616
1617 assert!(!is_non_failing(&failing, &HashMap::new(), &mut Vec::new()));
1618 assert!(!is_non_failing(
1619 &always_failing,
1620 &HashMap::new(),
1621 &mut Vec::new()
1622 ));
1623 }
1624
1625 #[test]
1626 fn _push_node_tag_pos_pred_forwarding_is_non_failing() {
1627 let failing_node = Box::new(ParserNode {
1628 expr: ParserExpr::Str("i'm a failure".into()),
1629 span: Span::new(" ", 0, 1).unwrap(),
1630 });
1631 assert!(!is_non_failing(
1632 &failing_node.clone().expr,
1633 &HashMap::new(),
1634 &mut Vec::new()
1635 ));
1636 let non_failing_node = Box::new(ParserNode {
1637 expr: ParserExpr::Str("".into()),
1638 span: Span::new(" ", 0, 1).unwrap(),
1639 });
1640 assert!(is_non_failing(
1641 &non_failing_node.clone().expr,
1642 &HashMap::new(),
1643 &mut Vec::new()
1644 ));
1645
1646 #[cfg(feature = "grammar-extras")]
1647 {
1648 assert!(!is_non_failing(
1649 &ParserExpr::NodeTag(failing_node.clone(), "TAG".into()),
1650 &HashMap::new(),
1651 &mut Vec::new()
1652 ));
1653 assert!(is_non_failing(
1654 &ParserExpr::NodeTag(non_failing_node.clone(), "TAG".into()),
1655 &HashMap::new(),
1656 &mut Vec::new()
1657 ));
1658 }
1659
1660 assert!(!is_non_failing(
1661 &ParserExpr::Push(failing_node.clone()),
1662 &HashMap::new(),
1663 &mut Vec::new()
1664 ));
1665 assert!(is_non_failing(
1666 &ParserExpr::Push(non_failing_node.clone()),
1667 &HashMap::new(),
1668 &mut Vec::new()
1669 ));
1670
1671 assert!(!is_non_failing(
1672 &ParserExpr::PosPred(failing_node.clone()),
1673 &HashMap::new(),
1674 &mut Vec::new()
1675 ));
1676 assert!(is_non_failing(
1677 &ParserExpr::PosPred(non_failing_node.clone()),
1678 &HashMap::new(),
1679 &mut Vec::new()
1680 ));
1681 }
1682
1683 #[cfg(feature = "grammar-extras")]
1684 #[test]
1685 fn push_literal_is_non_failing() {
1686 assert!(is_non_failing(
1687 &ParserExpr::PushLiteral("a".to_string()),
1688 &HashMap::new(),
1689 &mut Vec::new()
1690 ));
1691 }
1692
1693 #[test]
1694 #[should_panic(expected = "grammar error
1695
1696 --> 1:7
1697 |
16981 | a = { (\"\")* }
1699 | ^---^
1700 |
1701 = expression inside repetition cannot fail and will repeat infinitely")]
1702 fn non_failing_repetition() {
1703 let input = "a = { (\"\")* }";
1704 unwrap_or_report(consume_rules(
1705 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1706 ));
1707 }
1708
1709 #[test]
1710 #[should_panic(expected = "grammar error
1711
1712 --> 1:18
1713 |
17141 | a = { \"\" } b = { a* }
1715 | ^^
1716 |
1717 = expression inside repetition cannot fail and will repeat infinitely")]
1718 fn indirect_non_failing_repetition() {
1719 let input = "a = { \"\" } b = { a* }";
1720 unwrap_or_report(consume_rules(
1721 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1722 ));
1723 }
1724
1725 #[test]
1726 #[should_panic(expected = "grammar error
1727
1728 --> 1:20
1729 |
17301 | a = { \"a\" ~ (\"b\" ~ (\"\")*) }
1731 | ^---^
1732 |
1733 = expression inside repetition cannot fail and will repeat infinitely")]
1734 fn deep_non_failing_repetition() {
1735 let input = "a = { \"a\" ~ (\"b\" ~ (\"\")*) }";
1736 unwrap_or_report(consume_rules(
1737 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1738 ));
1739 }
1740
1741 #[test]
1742 #[should_panic(expected = "grammar error
1743
1744 --> 1:7
1745 |
17461 | a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* }
1747 | ^-------------------------------^
1748 |
1749 = expression inside repetition is non-progressing and will repeat infinitely")]
1750 fn non_progressing_repetition() {
1751 let input = "a = { (\"\" ~ &\"a\" ~ !\"a\" ~ (SOI | EOI))* }";
1752 unwrap_or_report(consume_rules(
1753 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1754 ));
1755 }
1756
1757 #[test]
1758 #[should_panic(expected = "grammar error
1759
1760 --> 1:20
1761 |
17621 | a = { !\"a\" } b = { a* }
1763 | ^^
1764 |
1765 = expression inside repetition is non-progressing and will repeat infinitely")]
1766 fn indirect_non_progressing_repetition() {
1767 let input = "a = { !\"a\" } b = { a* }";
1768 unwrap_or_report(consume_rules(
1769 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1770 ));
1771 }
1772
1773 #[test]
1774 #[should_panic(expected = "grammar error
1775
1776 --> 1:7
1777 |
17781 | a = { a }
1779 | ^
1780 |
1781 = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1782 fn simple_left_recursion() {
1783 let input = "a = { a }";
1784 unwrap_or_report(consume_rules(
1785 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1786 ));
1787 }
1788
1789 #[test]
1790 #[should_panic(expected = "grammar error
1791
1792 --> 1:7
1793 |
17941 | a = { b } b = { a }
1795 | ^
1796 |
1797 = rule b is left-recursive (b -> a -> b); pest::pratt_parser might be useful in this case
1798
1799 --> 1:17
1800 |
18011 | a = { b } b = { a }
1802 | ^
1803 |
1804 = rule a is left-recursive (a -> b -> a); pest::pratt_parser might be useful in this case")]
1805 fn indirect_left_recursion() {
1806 let input = "a = { b } b = { a }";
1807 unwrap_or_report(consume_rules(
1808 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1809 ));
1810 }
1811
1812 #[test]
1813 #[should_panic(expected = "grammar error
1814
1815 --> 1:39
1816 |
18171 | a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"\") ~ a }
1818 | ^
1819 |
1820 = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1821 fn non_failing_left_recursion() {
1822 let input = "a = { \"\" ~ \"a\"? ~ \"a\"* ~ (\"a\" | \"\") ~ a }";
1823 unwrap_or_report(consume_rules(
1824 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1825 ));
1826 }
1827
1828 #[test]
1829 #[should_panic(expected = "grammar error
1830
1831 --> 1:13
1832 |
18331 | a = { \"a\" | a }
1834 | ^
1835 |
1836 = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1837 fn non_primary_choice_left_recursion() {
1838 let input = "a = { \"a\" | a }";
1839 unwrap_or_report(consume_rules(
1840 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1841 ));
1842 }
1843
1844 #[test]
1845 #[should_panic(expected = "grammar error
1846
1847 --> 1:14
1848 |
18491 | a = { !\"a\" ~ a }
1850 | ^
1851 |
1852 = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
1853 fn non_progressing_left_recursion() {
1854 let input = "a = { !\"a\" ~ a }";
1855 unwrap_or_report(consume_rules(
1856 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1857 ));
1858 }
1859
1860 #[test]
1861 #[should_panic(expected = "grammar error
1862
1863 --> 1:7
1864 |
18651 | a = { \"a\"* | \"a\" | \"b\" }
1866 | ^--^
1867 |
1868 = expression cannot fail; following choices cannot be reached")]
1869 fn lhs_non_failing_choice() {
1870 let input = "a = { \"a\"* | \"a\" | \"b\" }";
1871 unwrap_or_report(consume_rules(
1872 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1873 ));
1874 }
1875
1876 #[test]
1877 #[should_panic(expected = "grammar error
1878
1879 --> 1:13
1880 |
18811 | a = { \"a\" | \"a\"* | \"b\" }
1882 | ^--^
1883 |
1884 = expression cannot fail; following choices cannot be reached")]
1885 fn lhs_non_failing_choice_middle() {
1886 let input = "a = { \"a\" | \"a\"* | \"b\" }";
1887 unwrap_or_report(consume_rules(
1888 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1889 ));
1890 }
1891
1892 #[test]
1893 #[should_panic(expected = "grammar error
1894
1895 --> 1:7
1896 |
18971 | a = { b | \"a\" } b = { \"b\"* | \"c\" }
1898 | ^
1899 |
1900 = expression cannot fail; following choices cannot be reached
1901
1902 --> 1:23
1903 |
19041 | a = { b | \"a\" } b = { \"b\"* | \"c\" }
1905 | ^--^
1906 |
1907 = expression cannot fail; following choices cannot be reached")]
1908 fn lhs_non_failing_nested_choices() {
1909 let input = "a = { b | \"a\" } b = { \"b\"* | \"c\" }";
1910 unwrap_or_report(consume_rules(
1911 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1912 ));
1913 }
1914
1915 #[test]
1916 fn skip_can_be_defined() {
1917 let input = "skip = { \"\" }";
1918 unwrap_or_report(consume_rules(
1919 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1920 ));
1921 }
1922
1923 #[test]
1924 #[should_panic(expected = "grammar error
1925
1926 --> 1:7
1927 |
19281 | a = { #b = b } b = _{ ASCII_DIGIT+ }
1929 | ^----^
1930 |
1931 = tags on silent rules will not appear in the output")]
1932 #[cfg(feature = "grammar-extras")]
1933 fn tag_on_silent_rule() {
1934 let input = "a = { #b = b } b = _{ ASCII_DIGIT+ }";
1935 unwrap_or_report(consume_rules(
1936 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1937 ));
1938 }
1939
1940 #[test]
1941 #[should_panic(expected = "grammar error
1942
1943 --> 1:7
1944 |
19451 | a = { #b = ASCII_DIGIT+ }
1946 | ^---------------^
1947 |
1948 = tags on built-in rules will not appear in the output")]
1949 #[cfg(feature = "grammar-extras")]
1950 fn tag_on_builtin_rule() {
1951 let input = "a = { #b = ASCII_DIGIT+ }";
1952 unwrap_or_report(consume_rules(
1953 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1954 ));
1955 }
1956
1957 #[test]
1958 #[cfg(feature = "grammar-extras")]
1959 fn tag_on_normal_rule() {
1960 let input = "a = { #b = b } b = { ASCII_DIGIT+ }";
1961 unwrap_or_report(consume_rules(
1962 PestParser::parse(Rule::grammar_rules, input).unwrap(),
1963 ));
1964 }
1965}