From 6cdfecb541d47e3860b7e297c9d21a4b3e7cec64 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Mon, 2 Feb 2015 15:03:57 +0100 Subject: [PATCH] Fix a number of issues in the fast parser around functions with only one statement (no suite) and wrong indentations). --- jedi/parser/fast.py | 21 ++++++++++++++++++--- test/test_parser/test_fast_parser.py | 21 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/jedi/parser/fast.py b/jedi/parser/fast.py index fd60b8a6..3ab1bce8 100644 --- a/jedi/parser/fast.py +++ b/jedi/parser/fast.py @@ -541,6 +541,7 @@ class FastTokenizer(object): self._indent_counter = 0 self._flow_indent_counter = 0 self._returned_endmarker = False + self._expect_indent = False def __iter__(self): return self @@ -562,8 +563,14 @@ class FastTokenizer(object): self.previous = self.current self.current = current + print(self.current, self._expect_indent, self.previous) if typ == INDENT: self._indent_counter += 1 + if not self._expect_indent and not self._first_stmt: + # This does not mean that there is an actual flow, but it means + # that the INDENT is either syntactically wrong or a flow. + self._in_flow = True + self._expect_indent = False elif typ == DEDENT: self._indent_counter -= 1 if self._in_flow and self._indent_counter == self._flow_indent_counter: @@ -575,9 +582,9 @@ class FastTokenizer(object): # Parentheses ignore the indentation rules. The other three stand for # new lines. if self.previous[0] in (NEWLINE, INDENT, DEDENT) \ - and not self._parentheses_level: + and not self._parentheses_level and typ != INDENT: # Check for NEWLINE, which symbolizes the indent. - #print('X', repr(value), tokenize.tok_name[typ]) + print('X', repr(value), tokenize.tok_name[typ]) if not self._in_flow: self._in_flow = value in FLOWS if self._in_flow: @@ -586,10 +593,18 @@ class FastTokenizer(object): # The values here are exactly the same check as in # _split_parts, but this time with tokenize and therefore # precise. - if not self._is_decorator: + if not self._first_stmt and not self._is_decorator: return self._close() self._is_decorator = '@' == value + if not self._is_decorator: + self._first_stmt = False + self._expect_indent = True + elif self._expect_indent: + print('EXP', self._first_stmt) + return self._close() + else: + self._first_stmt = False if value in '([{' and value: self._parentheses_level += 1 diff --git a/test/test_parser/test_fast_parser.py b/test/test_parser/test_fast_parser.py index 11a09d67..84036900 100644 --- a/test/test_parser/test_fast_parser.py +++ b/test/test_parser/test_fast_parser.py @@ -213,6 +213,27 @@ def test_func_with_for_and_comment(): check_fp('a\n' + src, 1, 3) +def test_one_statement_func(): + src = dedent("""\ + first + def func(): a + """) + check_fp(src + 'second', 3) + # Empty the parser cache, because we're not interested in modifications + # here. + cache.parser_cache.pop(None, None) + check_fp(src + 'def second():\n a', 3) + +def test_wrong_indentation(): + src = dedent("""\ + def func(): + a + b + a + """) + check_fp(src, 1) + + def test_incomplete_function(): source = '''return ImportErr'''