5 from typing import Callable
6 from lib.utils import Schema, ConfigASTVisitor, SourceLogger
7 from .common import Schema, ConfigNodeError
10 def __init__(self, t, v, name, fn):
15 self.__help_msg = inspect.getdoc(fn)
16 self.__help_msg = textwrap.dedent(self.__help_msg.strip())
18 def match_variant(self, astn):
21 return self.__var.match(astn)
23 def invoke(self, reducer, node):
24 if self.__fn(reducer._rules, reducer, node):
27 SourceLogger.warn(reducer._cfgn, node,
28 f"rule violation: {self.__name}: {self.__help_msg}")
29 # raise ConfigNodeError(reducer._cfgn,
30 # f"rule failed: {self.__name}: {self.__help_msg}")
33 def rule(ast_type: type, variant: Schema, name: str):
34 def __rule(fn: Callable):
35 return Rule(ast_type, variant, name, fn)
42 members = inspect.getmembers(self, lambda p: isinstance(p, Rule))
43 for _, rule in members:
45 if rule.type not in self.__rules:
46 self.__rules[t] = [rule]
48 self.__rules[t].append(rule)
50 def execute(self, reducer, node):
51 rules = self.__rules.get(type(node))
56 if not rule.match_variant(node):
58 rule.invoke(reducer, node)
60 class NodeValidator(ast.NodeTransformer):
61 def __init__(self, all_rules):
63 self._rules = all_rules
65 def validate(self, cfgn, astn):
69 def visit(self, node):
70 self._rules.execute(self, node)
71 return super().visit(node)