mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
Copying an if (and other flows) is now working.
This commit is contained in:
@@ -41,10 +41,19 @@ def _merge_names_dicts(base_dict, other_dict):
|
|||||||
base_dict.setdefault(key, []).extend(names)
|
base_dict.setdefault(key, []).extend(names)
|
||||||
|
|
||||||
|
|
||||||
def suite_or_file_input_is_valid(parser):
|
def _flows_finished(grammar, stack):
|
||||||
stack = parser.pgen_parser.stack
|
|
||||||
for dfa, newstate, (symbol_number, nodes) in reversed(stack):
|
for dfa, newstate, (symbol_number, nodes) in reversed(stack):
|
||||||
if symbol_number == parser._grammar.symbol2number['suite']:
|
print('symbol', grammar.number2symbol[symbol_number], nodes)
|
||||||
|
#if symbol_number == symbol2number['suite']:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def suite_or_file_input_is_valid(grammar, stack):
|
||||||
|
if not _flows_finished(grammar, stack):
|
||||||
|
return False
|
||||||
|
|
||||||
|
for dfa, newstate, (symbol_number, nodes) in reversed(stack):
|
||||||
|
if symbol_number == grammar.symbol2number['suite']:
|
||||||
# If we don't have nodes already, the suite is not valid.
|
# If we don't have nodes already, the suite is not valid.
|
||||||
return bool(nodes)
|
return bool(nodes)
|
||||||
# Not reaching a suite means that we're dealing with file_input levels
|
# Not reaching a suite means that we're dealing with file_input levels
|
||||||
@@ -52,11 +61,20 @@ def suite_or_file_input_is_valid(parser):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _is_flow_node(node):
|
||||||
|
try:
|
||||||
|
value = node.children[0].value
|
||||||
|
except AttributeError:
|
||||||
|
return False
|
||||||
|
return value in ('if', 'for', 'while', 'try')
|
||||||
|
|
||||||
|
|
||||||
class DiffParser(object):
|
class DiffParser(object):
|
||||||
endmarker_type = 'endmarker'
|
endmarker_type = 'endmarker'
|
||||||
|
|
||||||
def __init__(self, parser):
|
def __init__(self, parser):
|
||||||
self._parser = parser
|
self._parser = parser
|
||||||
|
self._grammar = self._parser._grammar
|
||||||
self._old_module = parser.get_root_node()
|
self._old_module = parser.get_root_node()
|
||||||
|
|
||||||
def _reset(self):
|
def _reset(self):
|
||||||
@@ -152,6 +170,7 @@ class DiffParser(object):
|
|||||||
p_children = line_stmt.parent.children
|
p_children = line_stmt.parent.children
|
||||||
index = p_children.index(line_stmt)
|
index = p_children.index(line_stmt)
|
||||||
nodes = []
|
nodes = []
|
||||||
|
print(p_children)
|
||||||
for node in p_children[index:]:
|
for node in p_children[index:]:
|
||||||
last_leaf = node.last_leaf()
|
last_leaf = node.last_leaf()
|
||||||
if last_leaf.type == 'newline':
|
if last_leaf.type == 'newline':
|
||||||
@@ -169,12 +188,16 @@ class DiffParser(object):
|
|||||||
else:
|
else:
|
||||||
nodes.append(node)
|
nodes.append(node)
|
||||||
|
|
||||||
|
if nodes and _is_flow_node(nodes[-1]):
|
||||||
|
# If we just copy flows at the end, they might be continued
|
||||||
|
# after the copy limit (in the new parser).
|
||||||
|
nodes.pop()
|
||||||
|
|
||||||
if nodes:
|
if nodes:
|
||||||
print('COPY', until_line_new)
|
print('COPY', until_line_new)
|
||||||
self._copy_count += 1
|
self._copy_count += 1
|
||||||
parent = self._insert_nodes(nodes)
|
parent = self._insert_nodes(nodes)
|
||||||
self._update_names_dict(parent, nodes)
|
self._update_names_dict(parent, nodes)
|
||||||
# TODO remove dedent at end
|
|
||||||
self._update_positions(nodes, line_offset)
|
self._update_positions(nodes, line_offset)
|
||||||
# We have copied as much as possible (but definitely not too
|
# We have copied as much as possible (but definitely not too
|
||||||
# much). Therefore we escape, even if we're not at the end. The
|
# much). Therefore we escape, even if we're not at the end. The
|
||||||
@@ -211,22 +234,19 @@ class DiffParser(object):
|
|||||||
is_endmarker = last_leaf.type == self.endmarker_type
|
is_endmarker = last_leaf.type == self.endmarker_type
|
||||||
last_non_endmarker = last_leaf
|
last_non_endmarker = last_leaf
|
||||||
if is_endmarker:
|
if is_endmarker:
|
||||||
try:
|
self._parsed_until_line = last_leaf.start_pos[0]
|
||||||
last_non_endmarker = last_leaf.get_previous_leaf()
|
if last_leaf.prefix.endswith('\n') or \
|
||||||
except IndexError:
|
not last_leaf.prefix and last_leaf.get_previous_leaf().type == 'newline':
|
||||||
# If the parsed part is empty, nevermind and continue with the
|
self._parsed_until_line -= 1
|
||||||
# endmarker.
|
else:
|
||||||
pass
|
|
||||||
|
|
||||||
while last_non_endmarker.type == 'dedent':
|
|
||||||
last_non_endmarker = last_non_endmarker.get_previous_leaf()
|
|
||||||
if last_non_endmarker.type == 'newline':
|
if last_non_endmarker.type == 'newline':
|
||||||
# Newlines end on the next line, which means that they would cover
|
# Newlines end on the next line, which means that they would cover
|
||||||
# the next line. That line is not fully parsed at this point.
|
# the next line. That line is not fully parsed at this point.
|
||||||
self._parsed_until_line = last_leaf.start_pos[0]
|
self._parsed_until_line = last_leaf.start_pos[0]
|
||||||
else:
|
else:
|
||||||
self._parsed_until_line = last_leaf.end_pos[0]
|
self._parsed_until_line = last_leaf.end_pos[0]
|
||||||
print('parsed_until', last_leaf.end_pos, self._parsed_until_line)
|
debug.dbg('set parsed_until %s', self._parsed_until_line)
|
||||||
|
|
||||||
first_leaf = nodes[0].first_leaf()
|
first_leaf = nodes[0].first_leaf()
|
||||||
first_leaf.prefix = self._prefix + first_leaf.prefix
|
first_leaf.prefix = self._prefix + first_leaf.prefix
|
||||||
@@ -250,8 +270,8 @@ class DiffParser(object):
|
|||||||
while True:
|
while True:
|
||||||
p_children = new_parent.children
|
p_children = new_parent.children
|
||||||
if new_parent.type == 'suite':
|
if new_parent.type == 'suite':
|
||||||
# A suite starts with NEWLINE, INDENT, ...
|
# A suite starts with NEWLINE, ...
|
||||||
indentation = p_children[2].start_pos[1]
|
indentation = p_children[1].start_pos[1]
|
||||||
else:
|
else:
|
||||||
indentation = p_children[0].start_pos[1]
|
indentation = p_children[0].start_pos[1]
|
||||||
|
|
||||||
@@ -260,7 +280,6 @@ class DiffParser(object):
|
|||||||
# don't want to depend on the first statement
|
# don't want to depend on the first statement
|
||||||
# having the right indentation.
|
# having the right indentation.
|
||||||
if new_parent.parent is not None:
|
if new_parent.parent is not None:
|
||||||
# TODO add dedent
|
|
||||||
new_parent = search_ancestor(
|
new_parent = search_ancestor(
|
||||||
new_parent,
|
new_parent,
|
||||||
('suite', 'file_input')
|
('suite', 'file_input')
|
||||||
@@ -288,10 +307,7 @@ class DiffParser(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
line = self._parsed_until_line + 1
|
line = self._parsed_until_line + 1
|
||||||
leaf = self._new_module.last_leaf()
|
node = self._new_module.last_leaf()
|
||||||
while leaf.type == 'dedent':
|
|
||||||
leaf = leaf.get_previous_leaf()
|
|
||||||
node = leaf
|
|
||||||
while True:
|
while True:
|
||||||
parent = node.parent
|
parent = node.parent
|
||||||
print('get_ins', parent)
|
print('get_ins', parent)
|
||||||
@@ -360,8 +376,6 @@ class DiffParser(object):
|
|||||||
leaf = self._old_module.get_leaf_for_position((old_line, 0), include_prefixes=True)
|
leaf = self._old_module.get_leaf_for_position((old_line, 0), include_prefixes=True)
|
||||||
if leaf.type == 'newline':
|
if leaf.type == 'newline':
|
||||||
leaf = leaf.get_next_leaf()
|
leaf = leaf.get_next_leaf()
|
||||||
while leaf.type == 'dedent':
|
|
||||||
leaf = leaf.get_next_leaf()
|
|
||||||
if leaf.get_start_pos_of_prefix()[0] == old_line:
|
if leaf.get_start_pos_of_prefix()[0] == old_line:
|
||||||
node = leaf
|
node = leaf
|
||||||
# TODO use leaf.get_definition one day when that one is working
|
# TODO use leaf.get_definition one day when that one is working
|
||||||
@@ -410,7 +424,7 @@ class DiffParser(object):
|
|||||||
line_offset=self._parsed_until_line
|
line_offset=self._parsed_until_line
|
||||||
)
|
)
|
||||||
self._active_parser = ParserWithRecovery(
|
self._active_parser = ParserWithRecovery(
|
||||||
self._parser._grammar,
|
self._grammar,
|
||||||
source='\n',
|
source='\n',
|
||||||
start_parsing=False
|
start_parsing=False
|
||||||
)
|
)
|
||||||
@@ -430,9 +444,6 @@ class DiffParser(object):
|
|||||||
|
|
||||||
# Add an endmarker.
|
# Add an endmarker.
|
||||||
last_leaf = self._new_module.last_leaf()
|
last_leaf = self._new_module.last_leaf()
|
||||||
while last_leaf.type == 'dedent':
|
|
||||||
last_leaf = last_leaf.get_previous_leaf()
|
|
||||||
|
|
||||||
end_pos = list(last_leaf.end_pos)
|
end_pos = list(last_leaf.end_pos)
|
||||||
lines = splitlines(self._prefix)
|
lines = splitlines(self._prefix)
|
||||||
assert len(lines) > 0
|
assert len(lines) > 0
|
||||||
@@ -452,6 +463,7 @@ class DiffParser(object):
|
|||||||
indents = []
|
indents = []
|
||||||
l = iter(lines)
|
l = iter(lines)
|
||||||
tokens = generate_tokens(lambda: next(l, ''), use_exact_op_types=True)
|
tokens = generate_tokens(lambda: next(l, ''), use_exact_op_types=True)
|
||||||
|
stack = self._active_parser.pgen_parser.stack
|
||||||
for typ, string, start_pos, prefix in tokens:
|
for typ, string, start_pos, prefix in tokens:
|
||||||
start_pos = start_pos[0] + line_offset, start_pos[1]
|
start_pos = start_pos[0] + line_offset, start_pos[1]
|
||||||
if typ == INDENT:
|
if typ == INDENT:
|
||||||
@@ -467,7 +479,8 @@ class DiffParser(object):
|
|||||||
|
|
||||||
if typ == tokenize.DEDENT:
|
if typ == tokenize.DEDENT:
|
||||||
indents.pop()
|
indents.pop()
|
||||||
if omitted_first_indent and not indents:
|
if omitted_first_indent and not indents and \
|
||||||
|
_flows_finished(self._grammar, stack):
|
||||||
# We are done here, only thing that can come now is an
|
# We are done here, only thing that can come now is an
|
||||||
# endmarker or another dedented code block.
|
# endmarker or another dedented code block.
|
||||||
yield tokenize.TokenInfo(tokenize.ENDMARKER, '', start_pos, '')
|
yield tokenize.TokenInfo(tokenize.ENDMARKER, '', start_pos, '')
|
||||||
@@ -475,7 +488,7 @@ class DiffParser(object):
|
|||||||
elif typ == NEWLINE and start_pos[0] >= until_line:
|
elif typ == NEWLINE and start_pos[0] >= until_line:
|
||||||
yield tokenize.TokenInfo(typ, string, start_pos, prefix)
|
yield tokenize.TokenInfo(typ, string, start_pos, prefix)
|
||||||
# Check if the parser is actually in a valid suite state.
|
# Check if the parser is actually in a valid suite state.
|
||||||
if suite_or_file_input_is_valid(self._active_parser):
|
if suite_or_file_input_is_valid(self._grammar, stack):
|
||||||
start_pos = start_pos[0] + 1, 0
|
start_pos = start_pos[0] + 1, 0
|
||||||
while len(indents) > int(omitted_first_indent):
|
while len(indents) > int(omitted_first_indent):
|
||||||
indents.pop()
|
indents.pop()
|
||||||
|
|||||||
@@ -38,6 +38,19 @@ def test_add_to_end():
|
|||||||
assert jedi.Script(a + b, path='example.py').completions()
|
assert jedi.Script(a + b, path='example.py').completions()
|
||||||
|
|
||||||
|
|
||||||
|
def _check_error_leafs(node):
|
||||||
|
try:
|
||||||
|
children = node.children
|
||||||
|
except AttributeError:
|
||||||
|
if node.type == 'error_leaf':
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
for child in children:
|
||||||
|
if _check_error_leafs(child):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class Differ(object):
|
class Differ(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._first_use = True
|
self._first_use = True
|
||||||
@@ -56,6 +69,7 @@ class Differ(object):
|
|||||||
assert diff_parser._parser_count == parsers
|
assert diff_parser._parser_count == parsers
|
||||||
self.parser.module = new_module
|
self.parser.module = new_module
|
||||||
self.parser._parsed = new_module
|
self.parser._parsed = new_module
|
||||||
|
assert not _check_error_leafs(new_module)
|
||||||
return new_module
|
return new_module
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user