1
0
forked from VimPlug/jedi

started better dynamic support for list/set conversions including appends after conversions

This commit is contained in:
David Halter
2012-08-10 16:39:56 +02:00
parent b57cf57af6
commit e0ebc0e3ac
4 changed files with 75 additions and 24 deletions

View File

@@ -1,10 +1,14 @@
""" """
For dynamic completion. For dynamic completion.
Sorry to everyone who is reading this code. Especially the array parts are
really cryptic and not understandable. It's just a hack, that turned out to be
working quite good.
""" """
import copy
import parsing import parsing
import evaluate import evaluate
import helpers
# This is something like the sys.path, but only for searching params. It means # This is something like the sys.path, but only for searching params. It means
# that this is the order in which Jedi searches params. # that this is the order in which Jedi searches params.
@@ -83,8 +87,14 @@ def search_params(param):
return result return result
@evaluate.memoize_default([])
def check_array_additions(array): def check_array_additions(array):
""" Just a mapper function for the internal _check_array_additions """
is_list = array._array.type == 'list'
current_module = array._array.parent_stmt.get_parent_until()
return _check_array_additions(array, current_module, is_list)
@evaluate.memoize_default([])
def _check_array_additions(compare_array, module, is_list):
""" """
Checks if a `parsing.Array` has "add" statements: Checks if a `parsing.Array` has "add" statements:
>>> a = [""] >>> a = [""]
@@ -116,7 +126,7 @@ def check_array_additions(array):
position = c.parent_stmt.start_pos position = c.parent_stmt.start_pos
scope = c.parent_stmt.parent scope = c.parent_stmt.parent
e = evaluate.follow_call_path(backtrack_path, scope, position) e = evaluate.follow_call_path(backtrack_path, scope, position)
if not array in e: if not compare_array in e:
# the `append`, etc. belong to other arrays # the `append`, etc. belong to other arrays
continue continue
@@ -137,19 +147,48 @@ def check_array_additions(array):
result += evaluate.follow_call_list(params) result += evaluate.follow_call_list(params)
return result return result
is_list = array._array.type == 'list'
stmt = array._array.parent_stmt
current_module = stmt.get_parent_until()
search_names = ['append', 'extend', 'insert'] if is_list else \ search_names = ['append', 'extend', 'insert'] if is_list else \
['add', 'update'] ['add', 'update']
possible_stmts = [] possible_stmts = []
result = [] result = []
for n in search_names: for n in search_names:
try: try:
possible_stmts += current_module.used_names[n] possible_stmts += module.used_names[n]
except KeyError: except KeyError:
continue continue
for stmt in possible_stmts: for stmt in possible_stmts:
result += check_calls(scan_array(stmt.get_assignment_calls(), n), n) result += check_calls(scan_array(stmt.get_assignment_calls(), n), n)
return result return result
def check_array_instances(instance):
ai = ArrayInstance(instance)
return helpers.generate_param_array([ai])
class ArrayInstance(parsing.Base):
"""
Used for the usage of set() and list().
At the moment this is not done lazy, maybe do that later on?
"""
def __init__(self, instance):
self.instance = instance
self.var_args = instance.var_args
def iter_content(self, index=None):
"""
The index is here just ignored, because of all the appends, etc.
lists/sets are too complicated too handle that.
"""
items = []
for array in evaluate.follow_call_list(self.var_args):
items += array.get_index_types()
module = self.var_args.parent_stmt.get_parent_until()
items += _check_array_additions(self.instance, module, str(self.instance.name) == 'list')
return items
@property
def parent(self):
return None

View File

@@ -136,13 +136,17 @@ class Instance(Executable):
""" This class is used to evaluate instances. """ """ This class is used to evaluate instances. """
def __init__(self, base, var_args=parsing.Array(None, None)): def __init__(self, base, var_args=parsing.Array(None, None)):
super(Instance, self).__init__(base, var_args) super(Instance, self).__init__(base, var_args)
if str(base.name) in ['list', 'set'] \
# need to execute the __init__ function, because the dynamic param and builtin.Builtin.name == base.get_parent_until().path:
# searching needs it. # compare the module path with the builtin name.
try: self.var_args = dynamic.check_array_instances(self)
self.execute_subscope_by_name('__init__', self.var_args) else:
except KeyError: # need to execute the __init__ function, because the dynamic param
pass # searching needs it.
try:
self.execute_subscope_by_name('__init__', self.var_args)
except KeyError:
pass
@memoize_default() @memoize_default()
def get_init_execution(self, func): def get_init_execution(self, func):
@@ -339,7 +343,7 @@ class Class(parsing.Base):
def __getattr__(self, name): def __getattr__(self, name):
if name not in ['start_pos', 'end_pos', 'parent', 'subscopes', if name not in ['start_pos', 'end_pos', 'parent', 'subscopes',
'get_imports']: 'get_imports', 'get_parent_until']:
raise AttributeError("Don't touch this (%s)!" % name) raise AttributeError("Don't touch this (%s)!" % name)
return getattr(self.base, name) return getattr(self.base, name)
@@ -707,7 +711,8 @@ class Generator(parsing.Base):
debug.dbg('generator names', names) debug.dbg('generator names', names)
return names return names
def get_content(self): def iter_content(self):
""" returns the content of __iter__ """
return Execution(self.func, self.var_args).get_return_types(True) return Execution(self.func, self.var_args).get_return_types(True)
def get_index_types(self, index=None): def get_index_types(self, index=None):
@@ -936,7 +941,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
# Take the first statement (for has always only # Take the first statement (for has always only
# one, remember `in`). And follow it. # one, remember `in`). And follow it.
for it in follow_statement(par.inits[0]): for it in follow_statement(par.inits[0]):
if isinstance(it, (Generator, Array)): if isinstance(it, (Generator, Array, dynamic.ArrayInstance)):
generators.append(it) generators.append(it)
else: else:
if not hasattr(it, 'execute_subscope_by_name'): if not hasattr(it, 'execute_subscope_by_name'):
@@ -963,7 +968,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
debug.warning('Instance has no __next__ function', gen) debug.warning('Instance has no __next__ function', gen)
else: else:
# is a generator # is a generator
in_vars = gen.get_content() in_vars = gen.iter_content()
if len(par.set_vars) > 1: if len(par.set_vars) > 1:
var_arr = par.set_stmt.get_assignment_calls() var_arr = par.set_stmt.get_assignment_calls()
result += assign_tuples(var_arr, in_vars, name_str) result += assign_tuples(var_arr, in_vars, name_str)
@@ -983,6 +988,7 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False):
else: else:
debug.warning('Flow: Why are you here? %s' % par.command) debug.warning('Flow: Why are you here? %s' % par.command)
elif isinstance(par, parsing.Param) \ elif isinstance(par, parsing.Param) \
and par.parent is not None \
and isinstance(par.parent.parent, parsing.Class) \ and isinstance(par.parent.parent, parsing.Class) \
and par.position == 0: and par.position == 0:
# This is where self gets added - this happens at another # This is where self gets added - this happens at another
@@ -1151,7 +1157,8 @@ def follow_call_list(call_list):
result += follow_call_list(call) result += follow_call_list(call)
else: else:
# With things like params, these can also be functions... # With things like params, these can also be functions...
if isinstance(call, (Function, Class, Instance)): if isinstance(call, (Function, Class, Instance,
dynamic.ArrayInstance)):
result.append(call) result.append(call)
# The string tokens are just operations (+, -, etc.) # The string tokens are just operations (+, -, etc.)
elif not isinstance(call, str): elif not isinstance(call, str):

View File

@@ -124,9 +124,6 @@ class set():
for i in self.__iterable: for i in self.__iterable:
yield i yield i
def add(self, elem):
self.__iterable += [elem]
def pop(self): def pop(self):
return self.__iterable.pop() return self.__iterable.pop()

View File

@@ -88,7 +88,7 @@ A(3).test(2.0)
A(3).test2() A(3).test2()
# ----------------- # -----------------
# list.append/insert # list.append
# ----------------- # -----------------
arr = [] arr = []
for a in [1,2]: for a in [1,2]:
@@ -109,6 +109,14 @@ arr[10]
#? int() #? int()
arr[10].index() arr[10].index()
arr = list([])
arr.append(1)
#? int()
arr[0]
# -----------------
# list.insert
# -----------------
arr = [""] arr = [""]
arr.insert(0, 1.0) arr.insert(0, 1.0)
@@ -166,5 +174,5 @@ lst = list(st)
lst.append('') lst.append('')
#? int() str() ##? int() str()
lst[0] lst[0]