1
0
forked from VimPlug/jedi

Implement binary search for get_leaf_for_position. This makes it a lot faster.

This commit is contained in:
Dave Halter
2017-01-25 22:27:36 +01:00
parent f2db0dceb4
commit 4918fb49f5
3 changed files with 27 additions and 24 deletions

View File

@@ -223,20 +223,11 @@ class Parser(object):
newline = endmarker.get_previous_leaf() newline = endmarker.get_previous_leaf()
except IndexError: except IndexError:
return # This means that the parser is empty. return # This means that the parser is empty.
while True:
if newline.value == '': assert newline.value.endswith('\n')
# Must be a DEDENT, just continue. newline.value = newline.value[:-1]
try: endmarker.start_pos = \
newline = newline.get_previous_leaf() newline.start_pos[0], newline.start_pos[1] + len(newline.value)
except IndexError:
# If there's a statement that fails to be parsed, there
# will be no previous leaf. So just ignore it.
break
else:
assert newline.value.endswith('\n')
newline.value = newline.value[:-1]
endmarker.start_pos = newline.start_pos
break
class ParserWithRecovery(Parser): class ParserWithRecovery(Parser):

View File

@@ -258,6 +258,8 @@ def generate_tokens(readline, use_exact_op_types=False):
# If a literal starts but doesn't end the whole rest of the # If a literal starts but doesn't end the whole rest of the
# line is an error token. # line is an error token.
txt = line[pos:] txt = line[pos:]
if txt.endswith('\n'):
new_line = True
yield TokenInfo(ERRORTOKEN, txt, (lnum, pos), prefix) yield TokenInfo(ERRORTOKEN, txt, (lnum, pos), prefix)
break break

View File

@@ -543,19 +543,29 @@ class BaseNode(Base):
return None return None
def get_leaf_for_position(self, position, include_prefixes=False): def get_leaf_for_position(self, position, include_prefixes=False):
for c in self.children: def binary_search(lower, upper):
if include_prefixes: if lower == upper:
start_pos = c.get_start_pos_of_prefix() element = self.children[lower]
else: if not include_prefixes and position < element.start_pos:
start_pos = c.start_pos # We're on a prefix.
return None
if start_pos <= position <= c.end_pos: # In case we have prefixes, a leaf always matches
try: try:
return c.get_leaf_for_position(position, include_prefixes) return element.get_leaf_for_position(position, include_prefixes)
except AttributeError: except AttributeError:
return c return element
return None
index = int((lower + upper) / 2)
element = self.children[index]
if position <= element.end_pos:
return binary_search(lower, index)
else:
return binary_search(index + 1, upper)
if not ((1, 0) <= position <= self.children[-1].end_pos):
raise ValueError('Please provide a position that exists within this node.')
return binary_search(0, len(self.children) - 1)
@Python3Method @Python3Method
def get_statement_for_position(self, pos): def get_statement_for_position(self, pos):