refactor search_call_signatures. Now we don't need to set Call.next.parent in a strange way anymore and the whole thing seems to be more logical.

This commit is contained in:
Dave Halter
2014-08-18 14:51:38 +02:00
parent 542648f5a0
commit 00d15da143
3 changed files with 44 additions and 42 deletions

View File

@@ -379,7 +379,7 @@ class Script(object):
else: else:
# Fetch definition of callee, if there's no path otherwise. # Fetch definition of callee, if there's no path otherwise.
if not goto_path: if not goto_path:
(call, _) = search_call_signatures(user_stmt, self._pos) (call, _, _) = search_call_signatures(user_stmt, self._pos)
if call is not None: if call is not None:
while call.next is not None: while call.next is not None:
call = call.next call = call.next
@@ -559,22 +559,12 @@ class Script(object):
:rtype: list of :class:`classes.CallSignature` :rtype: list of :class:`classes.CallSignature`
""" """
user_stmt = self._parser.user_stmt_with_whitespace() user_stmt = self._parser.user_stmt_with_whitespace()
call, index = search_call_signatures(user_stmt, self._pos) call, execution_arr, index = search_call_signatures(user_stmt, self._pos)
if call is None: if call is None:
return [] return []
stmt_el = call
while isinstance(stmt_el.parent, pr.StatementElement):
# Go to parent literal/variable until not possible anymore. This
# makes it possible to return the whole expression.
stmt_el = stmt_el.parent
# We can change the execution since it's a new object
# (fast_parent_copy).
execution_arr, call.execution = call.execution, None
call.next = None
with common.scale_speed_settings(settings.scale_call_signatures): with common.scale_speed_settings(settings.scale_call_signatures):
_callable = lambda: self._evaluator.eval_call(stmt_el) _callable = lambda: self._evaluator.eval_call(call)
origins = cache.cache_call_signatures(_callable, self.source, origins = cache.cache_call_signatures(_callable, self.source,
self._pos, user_stmt) self._pos, user_stmt)
debug.speed('func_call followed') debug.speed('func_call followed')

View File

@@ -78,50 +78,53 @@ def fast_parent_copy(obj):
def call_signature_array_for_pos(stmt, pos): def call_signature_array_for_pos(stmt, pos):
""" """
Searches for the array and position of a tuple. Searches for the array and position of a tuple.
Returns a tuple of (array, index-in-the-array, call).
""" """
def search_array(arr, pos, origin_call=None): def search_array(arr, pos, origin_call=None):
accepted_types = pr.Array.TUPLE, pr.Array.NOARRAY accepted_types = pr.Array.TUPLE, pr.Array.NOARRAY
if arr.type == 'dict': if arr.type == 'dict':
for stmt in arr.values + arr.keys: for stmt in arr.values + arr.keys:
new_arr, index = call_signature_array_for_pos(stmt, pos) tup = call_signature_array_for_pos(stmt, pos)
if new_arr is not None: if tup[0] is not None:
return new_arr, index return tup
else: else:
for i, stmt in enumerate(arr): for i, stmt in enumerate(arr):
new_arr, index = call_signature_array_for_pos(stmt, pos) tup = call_signature_array_for_pos(stmt, pos)
if new_arr is not None: if tup[0] is not None:
return new_arr, index return tup
# TODO couldn't we merge with the len(arr) == 0 check? # Since we need the index, we duplicate efforts (with empty
# arrays).
if arr.start_pos < pos <= stmt.end_pos: if arr.start_pos < pos <= stmt.end_pos:
if arr.type in accepted_types and isinstance(origin_call, pr.Call): if arr.type in accepted_types and isinstance(origin_call, pr.Call):
return arr, i return arr, i, origin_call
if len(arr) == 0 and arr.start_pos < pos < arr.end_pos: if len(arr) == 0 and arr.start_pos < pos < arr.end_pos:
if arr.type in accepted_types and isinstance(origin_call, pr.Call): if arr.type in accepted_types and isinstance(origin_call, pr.Call):
return arr, 0 return arr, 0, origin_call
return None, 0 return None, 0, None
def search_call(call, pos, origin_call=None): def search_call(call, pos, origin_call=None):
arr, index = None, 0 tup = None, 0, None
if call.next is not None: if call.next is not None:
method = search_array if isinstance(call.next, pr.Array) else search_call method = search_array if isinstance(call.next, pr.Array) else search_call
arr, index = method(call.next, pos, origin_call or call) tup = method(call.next, pos, origin_call or call)
if not arr and call.execution is not None: if not tup[0] and call.execution is not None:
arr, index = search_array(call.execution, pos, origin_call) tup = search_array(call.execution, pos, origin_call)
return arr, index return tup
if stmt.start_pos >= pos >= stmt.end_pos: if stmt.start_pos >= pos >= stmt.end_pos:
return None, 0 return None, 0, None
tup = None, 0, None
for command in stmt.expression_list(): for command in stmt.expression_list():
arr = None
if isinstance(command, pr.Array): if isinstance(command, pr.Array):
arr, index = search_array(command, pos) tup = search_array(command, pos)
elif isinstance(command, pr.StatementElement): elif isinstance(command, pr.StatementElement):
arr, index = search_call(command, pos, command) tup = search_call(command, pos, command)
if arr is not None: if tup[0] is not None:
return arr, index break
return None, 0 return tup
def search_call_signatures(user_stmt, position): def search_call_signatures(user_stmt, position):
@@ -129,16 +132,25 @@ def search_call_signatures(user_stmt, position):
Returns the function Call that matches the position before. Returns the function Call that matches the position before.
""" """
debug.speed('func_call start') debug.speed('func_call start')
call, index = None, 0 call, arr, index = None, None, 0
if user_stmt is not None and isinstance(user_stmt, pr.Statement): if user_stmt is not None and isinstance(user_stmt, pr.Statement):
# some parts will of the statement will be removed # some parts will of the statement will be removed
user_stmt = fast_parent_copy(user_stmt) user_stmt = fast_parent_copy(user_stmt)
arr, index = call_signature_array_for_pos(user_stmt, position) arr, index, call = call_signature_array_for_pos(user_stmt, position)
if arr is not None:
call = arr.parent # Now remove the part after the call. Including the array from the
# statement.
stmt_el = call
while isinstance(stmt_el, pr.StatementElement):
if stmt_el.execution == arr:
stmt_el.execution = None
stmt_el.next = None
break
stmt_el = stmt_el.next
debug.speed('func_call parsed') debug.speed('func_call parsed')
return call, index return call, arr, index
def scan_statement_for_calls(stmt, search_name, assignment_details=False): def scan_statement_for_calls(stmt, search_name, assignment_details=False):

View File

@@ -1277,7 +1277,7 @@ class StatementElement(Simple):
def set_next(self, call): def set_next(self, call):
""" Adds another part of the statement""" """ Adds another part of the statement"""
call.parent = self call.parent = self.parent
if self.next is not None: if self.next is not None:
self.next.set_next(call) self.next.set_next(call)
else: else:
@@ -1288,7 +1288,7 @@ class StatementElement(Simple):
An execution is nothing else than brackets, with params in them, which An execution is nothing else than brackets, with params in them, which
shows access on the internals of this name. shows access on the internals of this name.
""" """
call.parent = self call.parent = self.parent
if self.next is not None: if self.next is not None:
self.next.set_execution(call) self.next.set_execution(call)
elif self.execution is not None: elif self.execution is not None: