From db10b4fa725a1fb9448f22cda7e227e2e8c9a06c Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 5 Apr 2020 14:39:56 +0200 Subject: [PATCH] Diff parser: Need to care for eror dedents in some open parentheses/always break contexts --- parso/python/diff.py | 16 ++++++++++++++-- test/test_diff_parser.py | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/parso/python/diff.py b/parso/python/diff.py index cc403e8..c7c1ba4 100644 --- a/parso/python/diff.py +++ b/parso/python/diff.py @@ -24,6 +24,7 @@ _INDENTATION_TOKENS = 'INDENT', 'ERROR_DEDENT', 'DEDENT' NEWLINE = PythonTokenTypes.NEWLINE DEDENT = PythonTokenTypes.DEDENT +ERROR_DEDENT = PythonTokenTypes.ERROR_DEDENT ENDMARKER = PythonTokenTypes.ENDMARKER @@ -381,6 +382,9 @@ class DiffParser(object): nodes = node.children self._nodes_tree.add_parsed_nodes(nodes) + if self._replace_tos_indent is not None: + self._nodes_tree.indents[-1] = self._replace_tos_indent + LOG.debug( 'parse_part from %s to %s (to %s in part parser)', nodes[0].get_start_pos_of_prefix()[0], @@ -426,6 +430,7 @@ class DiffParser(object): indents=indents ) stack = self._active_parser.stack + self._replace_tos_indent = None #print('start', line_offset + 1, indents) for token in tokens: #print(token, indents) @@ -435,8 +440,15 @@ class DiffParser(object): # We are done here, only thing that can come now is an # endmarker or another dedented code block. while True: - typ, string, start_pos, prefix = next(tokens) - if typ != DEDENT: + typ, string, start_pos, prefix = token = next(tokens) + if typ in (DEDENT, ERROR_DEDENT): + if typ == ERROR_DEDENT: + # We want to force an error dedent in the next + # parser/pass. To make this possible we just + # increase the location by one. + self._replace_tos_indent = start_pos[1] + 1 + pass + else: break if '\n' in prefix or '\r' in prefix: diff --git a/test/test_diff_parser.py b/test/test_diff_parser.py index 26fd4ae..994af10 100644 --- a/test/test_diff_parser.py +++ b/test/test_diff_parser.py @@ -1541,3 +1541,27 @@ def c(): ''') differ.initialize(code1) differ.parse(code2, parsers=1, copies=1, expect_error_leaves=True) + + +def test_class_with_paren_breaker(differ): + code1 = dedent('''\ +class Grammar: + x + def parse(): + y + parser( + ) + z + ''') + code2 = dedent('''\ +class Grammar: + x + def parse(): + y + parser( + finally ; + ) + z + ''') + differ.initialize(code1) + differ.parse(code2, parsers=3, copies=1, expect_error_leaves=True)