mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 23:04:48 +08:00
*args / **kwargs done - untested
This commit is contained in:
146
evaluate.py
146
evaluate.py
@@ -60,12 +60,24 @@ class Executable(object):
|
||||
""" An instance is also an executable - because __init__ is called """
|
||||
def __init__(self, base, var_args=[]):
|
||||
self.base = base
|
||||
# the param input array
|
||||
self.var_args = var_args
|
||||
self.func = None
|
||||
|
||||
def get_parent_until(self, *args):
|
||||
return self.base.get_parent_until(*args)
|
||||
|
||||
@property
|
||||
def scope(self):
|
||||
""" Just try through the whole param array to find the own scope """
|
||||
for param in self.var_args:
|
||||
for call in param:
|
||||
try:
|
||||
return call.parent_stmt.parent
|
||||
except AttributeError: # if operators are there
|
||||
pass
|
||||
raise IndexError('No params available')
|
||||
|
||||
@memoize(default=[])
|
||||
def get_params(self):
|
||||
"""
|
||||
@@ -84,35 +96,55 @@ class Executable(object):
|
||||
self_name = copy.copy(self.func.params[0].get_name())
|
||||
self_name.parent = self.func.instance
|
||||
result.append(self_name)
|
||||
|
||||
param_dict = {}
|
||||
for param in self.func.params:
|
||||
# print 'para', param.get_name()
|
||||
param_dict[str(param.get_name())] = param
|
||||
# There may be calls, which don't fit all the params, this just ignores
|
||||
# it.
|
||||
param_iterator = iter(self.var_args)
|
||||
for i, value in enumerate(param_iterator, start_offset):
|
||||
var_arg_iterator = self.get_var_args_iterator()
|
||||
for i, (key, value) in enumerate(var_arg_iterator, start_offset):
|
||||
param = None
|
||||
try:
|
||||
param = self.func.params[i]
|
||||
except IndexError:
|
||||
debug.warning('Too many arguments given.', value)
|
||||
else:
|
||||
param = param_dict[key]
|
||||
except:
|
||||
try:
|
||||
param = self.func.params[i]
|
||||
except IndexError:
|
||||
debug.warning('Too many arguments given.', value)
|
||||
|
||||
if param:
|
||||
calls = parsing.Array(parsing.Array.NOARRAY,
|
||||
self.var_args.parent_stmt)
|
||||
|
||||
assignment = param.get_assignment_calls().values[0]
|
||||
calls.values = [value]
|
||||
|
||||
if assignment[0] == '*':
|
||||
# it is a *args param
|
||||
print '\n\n*', assignment
|
||||
for value in param_iterator:
|
||||
print value
|
||||
calls.values.append(value)
|
||||
# *args param
|
||||
print '\n\n3*', value, assignment
|
||||
calls.type = parsing.Array.TUPLE
|
||||
if key:
|
||||
var_arg_iterator.push_back(key, value)
|
||||
else:
|
||||
calls.values = [value]
|
||||
for key, value in var_arg_iterator:
|
||||
if key:
|
||||
var_arg_iterator.push_back(key, value)
|
||||
break
|
||||
calls.values.append(value)
|
||||
elif assignment[0] == '**':
|
||||
for value in param_iterator:
|
||||
print value
|
||||
calls.values.append(value)
|
||||
# **kwargs param
|
||||
calls.type = parsing.Array.DICT
|
||||
calls.values = [value]
|
||||
calls.keys = [key]
|
||||
for value in var_arg_iterator:
|
||||
calls.values.append(value)
|
||||
calls.keys.append(key)
|
||||
# it is a **args param
|
||||
print '\n\n**', assignment
|
||||
print '\n\n**', key, value, assignment
|
||||
else:
|
||||
# normal param
|
||||
calls.values = [value]
|
||||
|
||||
new_param = copy.copy(param)
|
||||
new_param._assignment_calls = calls
|
||||
@@ -122,8 +154,64 @@ class Executable(object):
|
||||
result.append(name)
|
||||
return result
|
||||
|
||||
def var_args_iterator(self):
|
||||
yield
|
||||
def get_var_args_iterator(self):
|
||||
"""
|
||||
Yields a key/value pair, the key is None, if its not a named arg.
|
||||
"""
|
||||
def iterate():
|
||||
# var_args is typically an Array, and not a list
|
||||
for var_arg in self.var_args:
|
||||
print '\nv', var_arg
|
||||
# *args
|
||||
if var_arg[0] == '*':
|
||||
arrays = follow_call_list(self.scope, [var_arg[1:]])
|
||||
for array in arrays:
|
||||
for field in array.get_contents():
|
||||
yield None, field
|
||||
# **kwargs
|
||||
elif var_arg[0] == '**':
|
||||
arrays = follow_call_list(self.scope, [var_arg[1:]])
|
||||
for array in arrays:
|
||||
for key, field in array.get_contents():
|
||||
yield key[0].name, field
|
||||
print '**', var_arg
|
||||
yield var_arg
|
||||
# normal arguments (including key arguments)
|
||||
else:
|
||||
if len(var_arg) > 1 and var_arg[1] == '=':
|
||||
# this is a named parameter
|
||||
print '\nnix', var_arg[0].name, '\n'
|
||||
yield var_arg[0].name, var_arg[2:]
|
||||
else:
|
||||
yield None, var_arg
|
||||
|
||||
class PushBackIterator(object):
|
||||
def __init__(self, iterator):
|
||||
self.pushes = []
|
||||
self.iterator = iterator
|
||||
|
||||
def push_back(self, key, value):
|
||||
self.pushes.append((key,value))
|
||||
print 'pushed back', self.pushes
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
""" Python 2 Compatibility """
|
||||
return self.__next__()
|
||||
|
||||
def __next__(self):
|
||||
try:
|
||||
return self.pushes.pop()
|
||||
except IndexError:
|
||||
return next(self.iterator)
|
||||
|
||||
print 'va', self.var_args
|
||||
#print 'va2', self.var_args[0]
|
||||
|
||||
return iter(PushBackIterator(iterate()))
|
||||
|
||||
|
||||
def set_param_cb(self, func):
|
||||
self.func = func
|
||||
@@ -149,7 +237,7 @@ class Instance(Executable):
|
||||
normally self
|
||||
"""
|
||||
try:
|
||||
return func.var_args[0].used_vars[0].names[0]
|
||||
return func.params[0].used_vars[0].names[0]
|
||||
except:
|
||||
return None
|
||||
|
||||
@@ -280,7 +368,8 @@ class Execution(Executable):
|
||||
#s.parent = temp
|
||||
|
||||
# reset the callback function on exit
|
||||
self.base.param_cb = None
|
||||
# TODO how can we deactivate this again?
|
||||
#self.base.param_cb = None
|
||||
else:
|
||||
debug.warning("no execution possible", self.base)
|
||||
|
||||
@@ -326,6 +415,9 @@ class Array(object):
|
||||
names = scope.get_defined_names()
|
||||
return [ArrayElement(n) for n in names]
|
||||
|
||||
def get_contents(self):
|
||||
return self._array
|
||||
|
||||
def __repr__(self):
|
||||
return "<p%s of %s>" % (self.__class__.__name__, self._array)
|
||||
|
||||
@@ -560,11 +652,13 @@ def follow_statement(stmt, scope=None, seek_name=None):
|
||||
|
||||
call_list = stmt.get_assignment_calls()
|
||||
debug.dbg('calls', call_list, call_list.values)
|
||||
result = set(follow_call_list(scope, call_list))
|
||||
result = follow_call_list(scope, call_list)
|
||||
|
||||
# assignment checking is only important if the statement defines multiple
|
||||
# variables
|
||||
if len(stmt.get_set_vars()) > 1 and seek_name and stmt.assignment_details:
|
||||
# TODO this should have its own call_list, because call_list can also
|
||||
# return 3 results for 2 variables.
|
||||
new_result = []
|
||||
for op, set_vars in stmt.assignment_details:
|
||||
new_result += assign_tuples(set_vars, result, seek_name)
|
||||
@@ -574,8 +668,10 @@ def follow_statement(stmt, scope=None, seek_name=None):
|
||||
|
||||
def follow_call_list(scope, call_list):
|
||||
"""
|
||||
The call list has a special structure.
|
||||
This can be either `parsing.Array` or `list`.
|
||||
The call_list has a special structure.
|
||||
This can be either `parsing.Array` or `list of list`.
|
||||
It is used to evaluate a two dimensional object, that has calls, arrays and
|
||||
operators in it.
|
||||
"""
|
||||
if parsing.Array.is_type(call_list, parsing.Array.TUPLE):
|
||||
# Tuples can stand just alone without any braces. These would be
|
||||
@@ -591,7 +687,7 @@ def follow_call_list(scope, call_list):
|
||||
if not isinstance(call, str):
|
||||
# The string tokens are just operations (+, -, etc.)
|
||||
result += follow_call(scope, call)
|
||||
return result
|
||||
return set(result)
|
||||
|
||||
|
||||
def follow_call(scope, call):
|
||||
|
||||
@@ -845,7 +845,7 @@ class Array(Call):
|
||||
|
||||
def __iter__(self):
|
||||
if self.type == self.DICT:
|
||||
return iter(self.values.items())
|
||||
return iter(zip(self.keys, self.values))
|
||||
else:
|
||||
return iter(self.values)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user