Finish refactoring rules.

This commit is contained in:
Dave Halter
2017-08-17 09:33:46 +02:00
parent e37e2e1ff6
commit 8d20f3d469
3 changed files with 38 additions and 19 deletions
+36 -17
View File
@@ -2,11 +2,23 @@ from contextlib import contextmanager
class Normalizer(object): class Normalizer(object):
_rule_value_classes = {}
_rule_type_classes = {}
def __init__(self, grammar, config): def __init__(self, grammar, config):
self._grammar = grammar self._grammar = grammar
self._config = config self._config = config
self.issues = [] self.issues = []
self._rule_type_instances = self._instantiate_rules(self._rule_type_classes)
self._rule_value_instances = self._instantiate_rules(self._rule_value_classes)
def _instantiate_rules(self, rules_map):
dct = {}
for type_, rule_classes in rules_map.items():
dct[type_] = [rule_cls(self) for rule_cls in rule_classes]
return dct
def walk(self, node): def walk(self, node):
self.initialize(node) self.initialize(node)
value = self.visit(node) value = self.visit(node)
@@ -24,9 +36,18 @@ class Normalizer(object):
@contextmanager @contextmanager
def visit_node(self, node): def visit_node(self, node):
for rule in self._rule_type_instances.get(node.type, []):
rule.feed_node(node)
yield yield
def visit_leaf(self, leaf): def visit_leaf(self, leaf):
for rule in self._rule_type_instances.get(leaf.type, []):
rule.feed_node(leaf)
for rule in self._rule_value_instances.get(leaf.value, []):
rule.feed_node(leaf)
return leaf.prefix + leaf.value return leaf.prefix + leaf.value
def initialize(self, node): def initialize(self, node):
@@ -41,24 +62,12 @@ class Normalizer(object):
self.issues.append(issue) self.issues.append(issue)
return True return True
class NormalizerConfig(object):
normalizer_class = Normalizer
rule_value_map = {}
rule_type_map = {}
def create_normalizer(self, grammar):
if self.normalizer_class is None:
return None
return self.normalizer_class(grammar, self)
@classmethod @classmethod
def register_rule(cls, **kwargs): def register_rule(cls, **kwargs):
""" """
Use it as a class decorator: Use it as a class decorator:
>>> normalizer = NormalizerConfig() >>> normalizer = Normalizer('grammar', 'config')
>>> @normalizer.register_rule(value='foo') >>> @normalizer.register_rule(value='foo')
... class MyRule(Rule): ... class MyRule(Rule):
... error_code = 42 ... error_code = 42
@@ -70,16 +79,26 @@ class NormalizerConfig(object):
if value is None and type is None: if value is None and type is None:
raise ValueError("You must register at least something.") raise ValueError("You must register at least something.")
def decorator(func): def decorator(rule_cls):
if value is not None: if value is not None:
cls.rule_value_map[value] = func cls._rule_value_classes.setdefault(value, []).append(rule_cls)
if type is not None: if type is not None:
cls.rule_type_map[type] = func cls._rule_type_classes.setdefault(type, []).append(rule_cls)
return func return rule_cls
return decorator return decorator
class NormalizerConfig(object):
normalizer_class = Normalizer
def create_normalizer(self, grammar):
if self.normalizer_class is None:
return None
return self.normalizer_class(grammar, self)
class Issue(object): class Issue(object):
def __init__(self, node, code, message): def __init__(self, node, code, message):
self._node = node self._node = node
+1 -1
View File
@@ -793,7 +793,7 @@ class IndentationRule(Rule):
code = 903 code = 903
@ErrorFinderConfig.register_rule(value='await') @ErrorFinder.register_rule(value='await')
class AwaitOutsideAsync(SyntaxRule): class AwaitOutsideAsync(SyntaxRule):
message = "'await' outside async function" message = "'await' outside async function"
+1 -1
View File
@@ -712,7 +712,7 @@ class PEP8NormalizerConfig(ErrorFinderConfig):
self.spaces_before_comment = spaces_before_comment self.spaces_before_comment = spaces_before_comment
@PEP8NormalizerConfig.register_rule(type='endmarker') @PEP8Normalizer.register_rule(type='endmarker')
class BlankLineAtEnd(Rule): class BlankLineAtEnd(Rule):
code = 392 code = 392
message = 'Blank line at end of file' message = 'Blank line at end of file'