_B='file_input'
_A=None
import hashlib,os
from typing import Generic,TypeVar,Union,Dict,Optional,Any
from pathlib import Path
from parso._compatibility import is_pypy
from parso.pgen2 import generate_grammar
from parso.utils import split_lines,python_bytes_to_unicode,PythonVersionInfo,parse_version_string
from parso.python.diff import DiffParser
from parso.python.tokenize import tokenize_lines,tokenize
from parso.python.token import PythonTokenTypes
from parso.cache import parser_cache,load_module,try_to_save_module
from parso.parser import BaseParser
from parso.python.parser import Parser as PythonParser
from parso.python.errors import ErrorFinderConfig
from parso.python import pep8
from parso.file_io import FileIO,KnownContentFileIO
from parso.normalizer import RefactoringNormalizer,NormalizerConfig
_loaded_grammars={}
_NodeT=TypeVar('_NodeT')
class Grammar(Generic[_NodeT]):
	'\n    :py:func:`parso.load_grammar` returns instances of this class.\n\n    Creating custom none-python grammars by calling this is not supported, yet.\n\n    :param text: A BNF representation of your grammar.\n    ';_start_nonterminal:str;_error_normalizer_config:Optional[ErrorFinderConfig]=_A;_token_namespace:Any=_A;_default_normalizer_config:NormalizerConfig=pep8.PEP8NormalizerConfig()
	def __init__(A,text,*,tokenizer,parser=BaseParser,diff_parser=_A):A._pgen_grammar=generate_grammar(text,token_namespace=A._get_token_namespace());A._parser=parser;A._tokenizer=tokenizer;A._diff_parser=diff_parser;A._hashed=hashlib.sha256(text.encode('utf-8')).hexdigest()
	def parse(A,code=_A,*,error_recovery=True,path=_A,start_symbol=_A,cache=False,diff_cache=False,cache_path=_A,file_io=_A):
		"\n        If you want to parse a Python file you want to start here, most likely.\n\n        If you need finer grained control over the parsed instance, there will be\n        other ways to access it.\n\n        :param str code: A unicode or bytes string. When it's not possible to\n            decode bytes to a string, returns a\n            :py:class:`UnicodeDecodeError`.\n        :param bool error_recovery: If enabled, any code will be returned. If\n            it is invalid, it will be returned as an error node. If disabled,\n            you will get a ParseError when encountering syntax errors in your\n            code.\n        :param str start_symbol: The grammar rule (nonterminal) that you want\n            to parse. Only allowed to be used when error_recovery is False.\n        :param str path: The path to the file you want to open. Only needed for caching.\n        :param bool cache: Keeps a copy of the parser tree in RAM and on disk\n            if a path is given. Returns the cached trees if the corresponding\n            files on disk have not changed. Note that this stores pickle files\n            on your file system (e.g. for Linux in ``~/.cache/parso/``).\n        :param bool diff_cache: Diffs the cached python module against the new\n            code and tries to parse only the parts that have changed. Returns\n            the same (changed) module that is found in cache. Using this option\n            requires you to not do anything anymore with the cached modules\n            under that path, because the contents of it might change. This\n            option is still somewhat experimental. If you want stability,\n            please don't use it.\n        :param bool cache_path: If given saves the parso cache in this\n            directory. If not given, defaults to the default cache places on\n            each platform.\n\n        :return: A subclass of :py:class:`parso.tree.NodeOrLeaf`. Typically a\n            :py:class:`parso.python.tree.Module`.\n        ";J=diff_cache;K=error_recovery;H=cache;I=start_symbol;D=cache_path;E=path;C=code;B=file_io
		if C is _A and E is _A and B is _A:raise TypeError('Please provide either code or a path.')
		if isinstance(E,str):E=Path(E)
		if isinstance(D,str):D=Path(D)
		if I is _A:I=A._start_nonterminal
		if K and I!=_B:raise NotImplementedError('This is currently not implemented.')
		if B is _A:
			if C is _A:B=FileIO(E)
			else:B=KnownContentFileIO(E,C)
		if H and B.path is not _A:
			F=load_module(A._hashed,B,cache_path=D)
			if F is not _A:return F
		if C is _A:C=B.read()
		C=python_bytes_to_unicode(C);G=split_lines(C,keepends=True)
		if J:
			if A._diff_parser is _A:raise TypeError('You have to define a diff parser to be able to use this option.')
			try:L=parser_cache[A._hashed][B.path]
			except KeyError:pass
			else:
				F=L.node;M=L.lines
				if M==G:return F
				N=A._diff_parser(A._pgen_grammar,A._tokenizer,F).update(old_lines=M,new_lines=G);try_to_save_module(A._hashed,B,N,G,pickling=H and not is_pypy,cache_path=D);return N
		P=A._tokenizer(G);Q=A._parser(A._pgen_grammar,error_recovery=K,start_nonterminal=I);O=Q.parse(tokens=P)
		if H or J:try_to_save_module(A._hashed,B,O,G,pickling=H and not is_pypy,cache_path=D)
		return O
	def _get_token_namespace(B):
		A=B._token_namespace
		if A is _A:raise ValueError('The token namespace should be set.')
		return A
	def iter_errors(A,node):
		'\n        Given a :py:class:`parso.tree.NodeOrLeaf` returns a generator of\n        :py:class:`parso.normalizer.Issue` objects. For Python this is\n        a list of syntax/indentation errors.\n        '
		if A._error_normalizer_config is _A:raise ValueError('No error normalizer specified for this grammar.')
		return A._get_normalizer_issues(node,A._error_normalizer_config)
	def refactor(A,base_node,node_to_str_map):return RefactoringNormalizer(node_to_str_map).walk(base_node)
	def _get_normalizer(B,normalizer_config):
		A=normalizer_config
		if A is _A:
			A=B._default_normalizer_config
			if A is _A:raise ValueError("You need to specify a normalizer, because there's no default normalizer for this tree.")
		return A.create_normalizer(B)
	def _normalize(A,node,normalizer_config=_A):'\n        TODO this is not public, yet.\n        The returned code will be normalized, e.g. PEP8 for Python.\n        ';B=A._get_normalizer(normalizer_config);return B.walk(node)
	def _get_normalizer_issues(B,node,normalizer_config=_A):A=B._get_normalizer(normalizer_config);A.walk(node);return A.issues
	def __repr__(A):B=A._pgen_grammar.nonterminal_to_dfas.keys();C=' '.join(list(B)[:3])+' ...';return'<%s:%s>'%(A.__class__.__name__,C)
class PythonGrammar(Grammar):
	_error_normalizer_config=ErrorFinderConfig();_token_namespace=PythonTokenTypes;_start_nonterminal=_B
	def __init__(A,version_info,bnf_text):super().__init__(bnf_text,tokenizer=A._tokenize_lines,parser=PythonParser,diff_parser=DiffParser);A.version_info=version_info
	def _tokenize_lines(A,lines,**B):return tokenize_lines(lines,version_info=A.version_info,**B)
	def _tokenize(A,code):return tokenize(code,version_info=A.version_info)
def load_grammar(*,version=_A,path=_A):
	"\n    Loads a :py:class:`parso.Grammar`. The default version is the current Python\n    version.\n\n    :param str version: A python version string, e.g. ``version='3.8'``.\n    :param str path: A path to a grammar file\n    ";A=path;B=parse_version_string(version);C=A or os.path.join('python','grammar%s%s.txt'%(B.major,B.minor));global _loaded_grammars;A=os.path.join(os.path.dirname(__file__),C)
	try:return _loaded_grammars[A]
	except KeyError:
		try:
			with open(A)as D:E=D.read()
			F=PythonGrammar(B,E);return _loaded_grammars.setdefault(A,F)
		except FileNotFoundError:G='Python version %s.%s is currently not supported.'%(B.major,B.minor);raise NotImplementedError(G)