From daa68b66ad6100729f6ad90006ba048e235d475f Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 29 May 2016 19:49:35 +0200 Subject: [PATCH] Fix a few issues caused by the refactoring. --- jedi/api/helpers.py | 50 ++++++++++++++++++++------------------ jedi/evaluate/helpers.py | 3 ++- jedi/evaluate/pep0484.py | 2 +- jedi/parser/__init__.py | 18 +++++++++++--- jedi/parser/pgen2/parse.py | 3 ++- jedi/parser/tree.py | 10 ++++++++ test/completion/classes.py | 5 +++- test/completion/parser.py | 2 +- 8 files changed, 60 insertions(+), 33 deletions(-) diff --git a/jedi/api/helpers.py b/jedi/api/helpers.py index 04317a99..3de7191a 100644 --- a/jedi/api/helpers.py +++ b/jedi/api/helpers.py @@ -50,7 +50,7 @@ def check_error_statements(module, pos): return None, 0, False, False -def get_code(code, start_pos, end_pos): +def _get_code(code, start_pos, end_pos): """ :param code_start_pos: is where the code starts. """ @@ -61,7 +61,7 @@ def get_code(code, start_pos, end_pos): lines[-1] = lines[-1][:end_pos[1]] # Remove first line indentation. lines[0] = lines[0][start_pos[1]:] - return ''.join(lines) + return '\n'.join(lines) def get_user_or_error_stmt(module, position): @@ -82,29 +82,31 @@ def get_stack_at_position(grammar, source, module, pos): """ user_stmt = get_user_or_error_stmt(module, pos) - if user_stmt is None: - user_stmt = module.get_leaf_for_position(pos, include_prefixes=True) - # Only if were in front of the leaf we want to get the stack, - # because after there's probably a newline or whatever that would - # be actually tokenized and is not just prefix. - if pos <= user_stmt.start_pos: - leaf = user_stmt.get_previous_leaf() - for error_stmt in reversed(module.error_statements): - if leaf.start_pos <= error_stmt.start_pos <= user_stmt.start_pos: - # The leaf appears not to be the last leaf. It's actually an - # error statement. - user_stmt = error_stmt - break - else: - user_stmt = get_user_or_error_stmt(module, leaf.start_pos) + if user_stmt is not None and user_stmt.type in ('indent', 'dedent'): + code = '' + else: + if user_stmt is None: + user_stmt = module.get_leaf_for_position(pos, include_prefixes=True) + # Only if were in front of the leaf we want to get the stack, + # because after there's probably a newline or whatever that would + # be actually tokenized and is not just prefix. + if pos <= user_stmt.start_pos: + leaf = user_stmt.get_previous_leaf() + for error_stmt in reversed(module.error_statements): + if leaf.start_pos <= error_stmt.start_pos <= user_stmt.start_pos: + # The leaf appears not to be the last leaf. It's actually an + # error statement. + user_stmt = error_stmt + break + else: + user_stmt = get_user_or_error_stmt(module, leaf.start_pos) - - print(user_stmt.start_pos, pos) - code = get_code(source, user_stmt.start_pos, pos) - # Remove whitespace at the end. Necessary, because the tokenizer will parse - # an error token (there's no new line at the end in our case). This doesn't - # alter any truth about the valid tokens at that position. - code = code.strip() + print(user_stmt.start_pos, pos) + code = _get_code(source, user_stmt.start_pos, pos) + # Remove whitespace at the end. Necessary, because the tokenizer will parse + # an error token (there's no new line at the end in our case). This doesn't + # alter any truth about the valid tokens at that position. + code = code.strip() class EndMarkerReached(Exception): pass diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index 49edadbf..af79ac46 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -26,7 +26,8 @@ def deep_ast_copy(obj, parent=None, new_elements=None): new_children = [] for child in obj.children: typ = child.type - if typ in ('whitespace', 'operator', 'keyword', 'number', 'string'): + if typ in ('whitespace', 'operator', 'keyword', 'number', 'string', + 'indent', 'dedent'): # At the moment we're not actually copying those primitive # elements, because there's really no need to. The parents are # obviously wrong, but that's not an issue. diff --git a/jedi/evaluate/pep0484.py b/jedi/evaluate/pep0484.py index 4eec2fed..8dd74190 100644 --- a/jedi/evaluate/pep0484.py +++ b/jedi/evaluate/pep0484.py @@ -33,7 +33,7 @@ def _evaluate_for_annotation(evaluator, annotation): if (isinstance(definition, CompiledObject) and isinstance(definition.obj, str)): try: - p = Parser(load_grammar(), definition.obj, start='eval_input') + p = Parser(load_grammar(), definition.obj, start_symbol='eval_input') element = p.get_parsed_node() except ParseError: debug.warning('Annotation not parsed: %s' % definition.obj) diff --git a/jedi/parser/__init__.py b/jedi/parser/__init__.py index 78ee047e..b1b5deb1 100644 --- a/jedi/parser/__init__.py +++ b/jedi/parser/__init__.py @@ -113,11 +113,17 @@ class ErrorStatement(object): of the stack at which time its parents don't yet exist.. """ start_pos = self.start_pos - for c in root_node.children: - if c.start_pos < start_pos <= c.end_pos: - return self.set_parent(c) + try: + children = root_node.children + except AttributeError: + self.parent = root_node + else: + for c in children: + if c.start_pos < start_pos <= c.end_pos: + self.set_parent(c) + return - self.parent = root_node + self.parent = root_node class ErrorToken(tree.LeafWithNewLines): @@ -288,6 +294,10 @@ class Parser(object): return pt.Number(self.position_modifier, value, start_pos, prefix) elif type in (NEWLINE, ENDMARKER): return pt.Whitespace(self.position_modifier, value, start_pos, prefix) + elif type == INDENT: + return pt.Indent(self.position_modifier, value, start_pos, prefix) + elif type == DEDENT: + return pt.Dedent(self.position_modifier, value, start_pos, prefix) else: return pt.Operator(self.position_modifier, value, start_pos, prefix) diff --git a/jedi/parser/pgen2/parse.py b/jedi/parser/pgen2/parse.py index dcd0fe0b..072b8075 100644 --- a/jedi/parser/pgen2/parse.py +++ b/jedi/parser/pgen2/parse.py @@ -121,7 +121,8 @@ class PgenParser(object): break else: # We never broke out -- EOF is too soon -- Unfinished statement. - self.error_recovery(self.grammar, self.stack, type_, value, + # TODO the arcs argument [] is not correctly defined. + self.error_recovery(self.grammar, self.stack, [], type_, value, start_pos, prefix, self.addtoken) # Add the ENDMARKER again. if not self.addtoken(type_, value, prefix, start_pos): diff --git a/jedi/parser/tree.py b/jedi/parser/tree.py index c4ab6b78..616e03d1 100644 --- a/jedi/parser/tree.py +++ b/jedi/parser/tree.py @@ -433,6 +433,16 @@ class String(Literal): __slots__ = () +class Indent(Leaf): + type = 'indent' + __slots__ = () + + +class Dedent(Leaf): + type = 'indent' + __slots__ = () + + class Operator(Leaf): type = 'operator' __slots__ = () diff --git a/test/completion/classes.py b/test/completion/classes.py index 1481c6a9..9bb5d99d 100644 --- a/test/completion/classes.py +++ b/test/completion/classes.py @@ -238,7 +238,10 @@ class V: V(1).b() #? int() V(1).c() -#? [] +#? +V(1).d() +# Only keywords should be possible to complete. +#? ['is', 'in', 'not', 'and', 'or', 'if'] V(1).d() diff --git a/test/completion/parser.py b/test/completion/parser.py index 2f6fbb3f..2cfdd06a 100644 --- a/test/completion/parser.py +++ b/test/completion/parser.py @@ -32,5 +32,5 @@ Just because there's a def keyword, doesn't mean it should not be able to complete to definition. """ definition = 0 -#? ['definition', 'def'] +#? ['definition'] str(def