diff --git a/parso/pgen2/parse.py b/parso/pgen2/parse.py index b3673a0..8669634 100644 --- a/parso/pgen2/parse.py +++ b/parso/pgen2/parse.py @@ -40,8 +40,8 @@ class Stack(list): def get_tos_first_tokens(self, grammar): tos = self[-1] - inv_tokens = {v: k for k, v in grammar.tokens.items()} - inv_keywords = {v: k for k, v in grammar.keywords.items()} + inv_tokens = dict((v, k) for k, v in grammar.tokens.items()) + inv_keywords = dict((v, k) for k, v in grammar.keywords.items()) dfa, state, nodes = tos def check(): @@ -51,7 +51,7 @@ class Stack(list): except KeyError: yield tokenize.tok_name[inv_tokens[first]] - return list(check()) + return sorted(check()) def token_to_ilabel(grammar, type_, value): diff --git a/parso/python/parser.py b/parso/python/parser.py index 7cdf987..5298212 100644 --- a/parso/python/parser.py +++ b/parso/python/parser.py @@ -160,7 +160,6 @@ class Parser(BaseParser): dfa, state, (type_, nodes) = stack[-1] states, first = dfa - # In Python statements need to end with a newline. But since it's # possible (and valid in Python ) that there's no newline at the # end of a file, we have to recover even if the user doesn't want @@ -198,12 +197,22 @@ class Parser(BaseParser): def current_suite(stack): # For now just discard everything that is not a suite or # file_input, if we detect an error. + suite_with_newline = False for index, (symbol, nodes) in reversed(list(enumerate(get_symbol_and_nodes(stack)))): # `suite` can sometimes be only simple_stmt, not stmt. if symbol == 'file_input': break - elif symbol == 'suite' and len(nodes) > 1: - # suites without an indent in them get discarded. + elif symbol == 'suite': + if len(nodes) > 1: + break + elif nodes: + suite_with_newline = True + # `suite` without an indent are error nodes. + continue + elif symbol in ('with_stmt', 'if_stmt', 'while_stmt', + # 'funcdef', 'classdef', + 'try_stmt') \ + and nodes[-1] == ':' and not suite_with_newline: break return index, symbol, nodes diff --git a/test/test_error_recovery.py b/test/test_error_recovery.py new file mode 100644 index 0000000..ae72383 --- /dev/null +++ b/test/test_error_recovery.py @@ -0,0 +1,21 @@ +from parso import parse + + +def test_with_stmt(): + module = parse('with x: f.\na') + assert module.children[0].type == 'with_stmt' + w, with_item, colon, f = module.children[0].children + assert f.type == 'error_node' + assert f.get_code(include_prefix=False) == 'f.' + + assert module.children[2].type == 'name' + + +def test_if_stmt(): + module = parse('if x: f.')# \nelse: g( + if_stmt = module.children[0] + assert if_stmt.type == 'if_stmt' + if_, test, colon, f = if_stmt.children + assert f.type == 'error_node' + assert f.children[0].value == 'f' + assert f.children[1].value == '.'