1from pegen import grammar 2from pegen.grammar import ( 3 Alt, 4 Cut, 5 Gather, 6 GrammarVisitor, 7 Group, 8 Lookahead, 9 NamedItem, 10 NameLeaf, 11 NegativeLookahead, 12 Opt, 13 PositiveLookahead, 14 Repeat0, 15 Repeat1, 16 Rhs, 17 Rule, 18 StringLeaf, 19) 20 21class ValidationError(Exception): 22 pass 23 24class GrammarValidator(GrammarVisitor): 25 def __init__(self, grammar: grammar.Grammar): 26 self.grammar = grammar 27 self.rulename = None 28 29 def validate_rule(self, rulename: str, node: Rule): 30 self.rulename = rulename 31 self.visit(node) 32 self.rulename = None 33 34 35class SubRuleValidator(GrammarValidator): 36 def visit_Rhs(self, node: Rule): 37 for index, alt in enumerate(node.alts): 38 alts_to_consider = node.alts[index+1:] 39 for other_alt in alts_to_consider: 40 self.check_intersection(alt, other_alt) 41 42 def check_intersection(self, first_alt: Alt, second_alt: Alt) -> bool: 43 if str(second_alt).startswith(str(first_alt)): 44 raise ValidationError( 45 f"In {self.rulename} there is an alternative that will " 46 f"never be visited:\n{second_alt}") 47 48def validate_grammar(the_grammar: grammar.Grammar): 49 for validator_cls in GrammarValidator.__subclasses__(): 50 validator = validator_cls(the_grammar) 51 for rule_name, rule in the_grammar.rules.items(): 52 validator.validate_rule(rule_name, rule) 53