X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/0f7cf9187f9c9644565570a67a66f690f8f2bfbb..e9f520c16abc8a864b61ae658bc3c91fda46fdd0:/src/black/parsing.py diff --git a/src/black/parsing.py b/src/black/parsing.py index e384056..c101643 100644 --- a/src/black/parsing.py +++ b/src/black/parsing.py @@ -17,6 +17,7 @@ from blib2to3 import pygram from blib2to3.pgen2 import driver from blib2to3.pgen2.grammar import Grammar from blib2to3.pgen2.parse import ParseError +from blib2to3.pgen2.tokenize import TokenError from black.mode import TargetVersion, Feature, supports_feature from black.nodes import syms @@ -42,6 +43,11 @@ except ImportError: ast3 = ast27 = ast +PY310_HINT: Final[ + str +] = "Consider using --target-version py310 to parse Python 3.10 code." + + class InvalidInput(ValueError): """Raised when input source code fails all parse attempts.""" @@ -95,7 +101,8 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) - if not src_txt.endswith("\n"): src_txt += "\n" - for grammar in get_grammars(set(target_versions)): + grammars = get_grammars(set(target_versions)) + for grammar in grammars: drv = driver.Driver(grammar) try: result = drv.parse_string(src_txt, True) @@ -109,7 +116,19 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) - except IndexError: faulty_line = "" exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {faulty_line}") + + except TokenError as te: + # In edge cases these are raised; and typically don't have a "faulty_line". + lineno, column = te.args[1] + exc = InvalidInput(f"Cannot parse: {lineno}:{column}: {te.args[0]}") + else: + if pygram.python_grammar_soft_keywords not in grammars and matches_grammar( + src_txt, pygram.python_grammar_soft_keywords + ): + original_msg = exc.args[0] + msg = f"{original_msg}\n{PY310_HINT}" + raise InvalidInput(msg) from None raise exc from None if isinstance(result, Leaf): @@ -117,6 +136,16 @@ def lib2to3_parse(src_txt: str, target_versions: Iterable[TargetVersion] = ()) - return result +def matches_grammar(src_txt: str, grammar: Grammar) -> bool: + drv = driver.Driver(grammar) + try: + drv.parse_string(src_txt, True) + except (ParseError, TokenError, IndentationError): + return False + else: + return True + + def lib2to3_unparse(node: Node) -> str: """Given a lib2to3 node, return its string representation.""" code = str(node)