_A=None
from contextlib import contextmanager
from typing import Dict,List
class _NormalizerMeta(type):
	def __new__(B,name,bases,dct):A=type.__new__(B,name,bases,dct);A.rule_value_classes={};A.rule_type_classes={};return A
class Normalizer(metaclass=_NormalizerMeta):
	_rule_type_instances:Dict[str,List[type]]={};_rule_value_instances:Dict[str,List[type]]={}
	def __init__(A,grammar,config):A.grammar=grammar;A._config=config;A.issues=[];A._rule_type_instances=A._instantiate_rules('rule_type_classes');A._rule_value_instances=A._instantiate_rules('rule_value_classes')
	def _instantiate_rules(A,attr):
		B={}
		for C in type(A).mro():
			D=getattr(C,attr,{})
			for(E,F)in D.items():G=[B(A)for B in F];B.setdefault(E,[]).extend(G)
		return B
	def walk(A,node):A.initialize(node);B=A.visit(node);A.finalize();return B
	def visit(A,node):
		B=node
		try:C=B.children
		except AttributeError:return A.visit_leaf(B)
		else:
			with A.visit_node(B):return''.join(A.visit(B)for B in C)
	@contextmanager
	def visit_node(self,node):self._check_type_rules(node);yield
	def _check_type_rules(A,node):
		for B in A._rule_type_instances.get(node.type,[]):B.feed_node(node)
	def visit_leaf(B,leaf):
		A=leaf;B._check_type_rules(A)
		for C in B._rule_value_instances.get(A.value,[]):C.feed_node(A)
		return A.prefix+A.value
	def initialize(A,node):0
	def finalize(A):0
	def add_issue(A,node,code,message):
		B=Issue(node,code,message)
		if B not in A.issues:A.issues.append(B)
		return True
	@classmethod
	def register_rule(D,*,value=_A,values=(),type=_A,types=()):
		"\n        Use it as a class decorator::\n\n            normalizer = Normalizer('grammar', 'config')\n            @normalizer.register_rule(value='foo')\n            class MyRule(Rule):\n                error_code = 42\n        ";C=value;A=types;B=values;B=list(B);A=list(A)
		if C is not _A:B.append(C)
		if type is not _A:A.append(type)
		if not B and not A:raise ValueError('You must register at least something.')
		def E(rule_cls):
			C=rule_cls
			for E in B:D.rule_value_classes.setdefault(E,[]).append(C)
			for F in A:D.rule_type_classes.setdefault(F,[]).append(C)
			return C
		return E
class NormalizerConfig:
	normalizer_class=Normalizer
	def create_normalizer(A,grammar):
		if A.normalizer_class is _A:return
		return A.normalizer_class(grammar,A)
class Issue:
	def __init__(A,node,code,message):A.code=code;'\n        An integer code that stands for the type of error.\n        ';A.message=message;'\n        A message (string) for the issue.\n        ';A.start_pos=node.start_pos;'\n        The start position position of the error as a tuple (line, column). As\n        always in |parso| the first line is 1 and the first column 0.\n        ';A.end_pos=node.end_pos
	def __eq__(A,other):B=other;return A.start_pos==B.start_pos and A.code==B.code
	def __ne__(A,other):return not A.__eq__(other)
	def __hash__(A):return hash((A.code,A.start_pos))
	def __repr__(A):return'<%s: %s>'%(A.__class__.__name__,A.code)
class Rule:
	code:int;message:str
	def __init__(A,normalizer):A._normalizer=normalizer
	def is_issue(A,node):raise NotImplementedError
	def get_node(A,node):return node
	def _get_message(B,message,node):
		A=message
		if A is _A:
			A=B.message
			if A is _A:raise ValueError('The message on the class is not set.')
		return A
	def add_issue(B,node,code=_A,message=_A):
		C=message;A=code
		if A is _A:
			A=B.code
			if A is _A:raise ValueError('The error code on the class is not set.')
		C=B._get_message(C,node);B._normalizer.add_issue(node,A,C)
	def feed_node(A,node):
		if A.is_issue(node):B=A.get_node(node);A.add_issue(B)
class RefactoringNormalizer(Normalizer):
	def __init__(A,node_to_str_map):A._node_to_str_map=node_to_str_map
	def visit(A,node):
		try:return A._node_to_str_map[node]
		except KeyError:return super().visit(node)
	def visit_leaf(A,leaf):
		try:return A._node_to_str_map[leaf]
		except KeyError:return super().visit_leaf(leaf)