17db96d56Sopenharmony_cifrom typing import Optional
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_cifrom pegen import grammar
47db96d56Sopenharmony_cifrom pegen.grammar import Alt, GrammarVisitor, Rhs, Rule
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ci
77db96d56Sopenharmony_ciclass ValidationError(Exception):
87db96d56Sopenharmony_ci    pass
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci
117db96d56Sopenharmony_ciclass GrammarValidator(GrammarVisitor):
127db96d56Sopenharmony_ci    def __init__(self, grammar: grammar.Grammar) -> None:
137db96d56Sopenharmony_ci        self.grammar = grammar
147db96d56Sopenharmony_ci        self.rulename: Optional[str] = None
157db96d56Sopenharmony_ci
167db96d56Sopenharmony_ci    def validate_rule(self, rulename: str, node: Rule) -> None:
177db96d56Sopenharmony_ci        self.rulename = rulename
187db96d56Sopenharmony_ci        self.visit(node)
197db96d56Sopenharmony_ci        self.rulename = None
207db96d56Sopenharmony_ci
217db96d56Sopenharmony_ci
227db96d56Sopenharmony_ciclass SubRuleValidator(GrammarValidator):
237db96d56Sopenharmony_ci    def visit_Rhs(self, node: Rhs) -> None:
247db96d56Sopenharmony_ci        for index, alt in enumerate(node.alts):
257db96d56Sopenharmony_ci            alts_to_consider = node.alts[index + 1 :]
267db96d56Sopenharmony_ci            for other_alt in alts_to_consider:
277db96d56Sopenharmony_ci                self.check_intersection(alt, other_alt)
287db96d56Sopenharmony_ci
297db96d56Sopenharmony_ci    def check_intersection(self, first_alt: Alt, second_alt: Alt) -> None:
307db96d56Sopenharmony_ci        if str(second_alt).startswith(str(first_alt)):
317db96d56Sopenharmony_ci            raise ValidationError(
327db96d56Sopenharmony_ci                f"In {self.rulename} there is an alternative that will "
337db96d56Sopenharmony_ci                f"never be visited:\n{second_alt}"
347db96d56Sopenharmony_ci            )
357db96d56Sopenharmony_ci
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_cidef validate_grammar(the_grammar: grammar.Grammar) -> None:
387db96d56Sopenharmony_ci    for validator_cls in GrammarValidator.__subclasses__():
397db96d56Sopenharmony_ci        validator = validator_cls(the_grammar)
407db96d56Sopenharmony_ci        for rule_name, rule in the_grammar.rules.items():
417db96d56Sopenharmony_ci            validator.validate_rule(rule_name, rule)
42