mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-16 02:27:06 +08:00
first more or less atempt of functions, that are copied. therefore it is possible to make more complicated function calls (recursion, use function multiple times differently, etc)
This commit is contained in:
94
evaluate.py
94
evaluate.py
@@ -68,7 +68,6 @@ class Executable(object):
|
|||||||
self.base = base
|
self.base = base
|
||||||
# the param input array
|
# the param input array
|
||||||
self.var_args = var_args
|
self.var_args = var_args
|
||||||
self.func = None
|
|
||||||
|
|
||||||
def get_parent_until(self, *args):
|
def get_parent_until(self, *args):
|
||||||
return self.base.get_parent_until(*args)
|
return self.base.get_parent_until(*args)
|
||||||
@@ -160,14 +159,6 @@ class InstanceElement(object):
|
|||||||
def parent(self):
|
def parent(self):
|
||||||
return InstanceElement(self.instance, self.var.parent)
|
return InstanceElement(self.instance, self.var.parent)
|
||||||
|
|
||||||
@property
|
|
||||||
def param_cb(self):
|
|
||||||
return self.var.param_cb
|
|
||||||
|
|
||||||
@param_cb.setter
|
|
||||||
def param_cb(self, value):
|
|
||||||
self.var.param_cb = value
|
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
return getattr(self.var, name)
|
return getattr(self.var, name)
|
||||||
|
|
||||||
@@ -247,7 +238,7 @@ class Function(object):
|
|||||||
# create param array
|
# create param array
|
||||||
old_func = Function.create(func, is_decorated=True)
|
old_func = Function.create(func, is_decorated=True)
|
||||||
params = parsing.Array(parsing.Array.NOARRAY, old_func)
|
params = parsing.Array(parsing.Array.NOARRAY, old_func)
|
||||||
params.values = [[func]]
|
params.values = [[old_func]]
|
||||||
wrappers = Execution(decorator, params).get_return_types()
|
wrappers = Execution(decorator, params).get_return_types()
|
||||||
if not len(wrappers):
|
if not len(wrappers):
|
||||||
debug.warning('no wrappers found', self.base_func)
|
debug.warning('no wrappers found', self.base_func)
|
||||||
@@ -259,8 +250,10 @@ class Function(object):
|
|||||||
func = wrappers[0]
|
func = wrappers[0]
|
||||||
|
|
||||||
debug.dbg('decorator end')
|
debug.dbg('decorator end')
|
||||||
#print dec.parent
|
if func != self.base_func:
|
||||||
return func
|
return Function.create(func)
|
||||||
|
else:
|
||||||
|
return func
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<e%s of %s>" % (self.__class__.__name__, self.func)
|
return "<e%s of %s>" % (self.__class__.__name__, self.func)
|
||||||
@@ -273,6 +266,8 @@ class Execution(Executable):
|
|||||||
This is the most complicated class, because it contains the logic to
|
This is the most complicated class, because it contains the logic to
|
||||||
transfer parameters. This is even more complicated, because there may be
|
transfer parameters. This is even more complicated, because there may be
|
||||||
multiple call to functions and recursion has to be avoided.
|
multiple call to functions and recursion has to be avoided.
|
||||||
|
|
||||||
|
TODO InstantElements ?
|
||||||
"""
|
"""
|
||||||
cache = {}
|
cache = {}
|
||||||
|
|
||||||
@@ -302,27 +297,14 @@ class Execution(Executable):
|
|||||||
return strip_imports(stmts)
|
return strip_imports(stmts)
|
||||||
|
|
||||||
def _get_function_returns(self, evaluate_generator):
|
def _get_function_returns(self, evaluate_generator):
|
||||||
stmts = []
|
|
||||||
func = self.base
|
func = self.base
|
||||||
if func.is_generator and not evaluate_generator:
|
if func.is_generator and not evaluate_generator:
|
||||||
return [Generator(func)]
|
return [Generator(func)]
|
||||||
else:
|
else:
|
||||||
self.set_param_cb(func)
|
stmts = []
|
||||||
func.is_decorated = True
|
for r in self.returns:
|
||||||
ret = self.returns
|
stmts += follow_statement(r)
|
||||||
for s in ret:
|
return stmts
|
||||||
#temp, s.parent = s.parent, self
|
|
||||||
stmts += follow_statement(s)
|
|
||||||
#s.parent = temp
|
|
||||||
|
|
||||||
# reset the callback function on exit
|
|
||||||
# TODO how can we deactivate this again?
|
|
||||||
#func.param_cb = None
|
|
||||||
|
|
||||||
# func could have changed because of decorators, so clear
|
|
||||||
# them again
|
|
||||||
func.is_decorated = False
|
|
||||||
return stmts
|
|
||||||
|
|
||||||
@memoize_default(default=[])
|
@memoize_default(default=[])
|
||||||
def get_params(self):
|
def get_params(self):
|
||||||
@@ -330,42 +312,42 @@ class Execution(Executable):
|
|||||||
This returns the params for an Execution/Instance and is injected as a
|
This returns the params for an Execution/Instance and is injected as a
|
||||||
'hack' into the parsing.Function class.
|
'hack' into the parsing.Function class.
|
||||||
This needs to be here, because Instance can have __init__ functions,
|
This needs to be here, because Instance can have __init__ functions,
|
||||||
which act the same way as normal functions
|
which act the same way as normal functions.
|
||||||
"""
|
"""
|
||||||
def gen_param_name_copy(param, keys=[], values=[], array_type=None):
|
def gen_param_name_copy(param, keys=[], values=[], array_type=None):
|
||||||
calls = parsing.Array(parsing.Array.NOARRAY,
|
""" Create a param with self as parent. """
|
||||||
self.var_args.parent_stmt)
|
calls = parsing.Array(parsing.Array.NOARRAY, parent_stmt=self)
|
||||||
calls.values = values
|
calls.values = values
|
||||||
calls.keys = keys
|
calls.keys = keys
|
||||||
calls.type = array_type
|
calls.type = array_type
|
||||||
new_param = copy.copy(param)
|
new_param = copy.copy(param)
|
||||||
new_param.parent = self.var_args.parent_stmt
|
new_param.parent = self
|
||||||
new_param._assignment_calls_calculated = True
|
new_param._assignment_calls_calculated = True
|
||||||
new_param._assignment_calls = calls
|
new_param._assignment_calls = calls
|
||||||
name = copy.copy(param.get_name())
|
name = copy.copy(param.get_name())
|
||||||
name.parent = new_param
|
name.parent = new_param
|
||||||
#print 'insert', i, name, calls.values, value, self.func.params
|
#print 'insert', i, name, calls.values, value, self.base.params
|
||||||
return name
|
return name
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
start_offset = 0
|
start_offset = 0
|
||||||
#print '\n\nfunc_params', self.func, self.func.parent, self.func
|
#print '\n\nfunc_params', self.base, self.base.parent, self.base
|
||||||
if isinstance(self.func, InstanceElement):
|
if isinstance(self.base, InstanceElement):
|
||||||
# care for self -> just exclude it and add the instance
|
# care for self -> just exclude it and add the instance
|
||||||
start_offset = 1
|
start_offset = 1
|
||||||
self_name = copy.copy(self.func.params[0].get_name())
|
self_name = copy.copy(self.base.params[0].get_name())
|
||||||
self_name.parent = self.func.instance
|
self_name.parent = self.base.instance
|
||||||
result.append(self_name)
|
result.append(self_name)
|
||||||
|
|
||||||
param_dict = {}
|
param_dict = {}
|
||||||
for param in self.func.params:
|
for param in self.base.params:
|
||||||
param_dict[str(param.get_name())] = param
|
param_dict[str(param.get_name())] = param
|
||||||
# There may be calls, which don't fit all the params, this just ignores
|
# There may be calls, which don't fit all the params, this just ignores
|
||||||
# it.
|
# it.
|
||||||
var_arg_iterator = self.get_var_args_iterator()
|
var_arg_iterator = self.get_var_args_iterator()
|
||||||
|
|
||||||
non_matching_keys = []
|
non_matching_keys = []
|
||||||
for param in self.func.params[start_offset:]:
|
for param in self.base.params[start_offset:]:
|
||||||
# The value and key can both be null. There, the defaults apply.
|
# The value and key can both be null. There, the defaults apply.
|
||||||
# args / kwargs will just be empty arrays / dicts, respectively.
|
# args / kwargs will just be empty arrays / dicts, respectively.
|
||||||
key, value = next(var_arg_iterator, (None, None))
|
key, value = next(var_arg_iterator, (None, None))
|
||||||
@@ -466,8 +448,21 @@ class Execution(Executable):
|
|||||||
|
|
||||||
return iter(PushBackIterator(iterate()))
|
return iter(PushBackIterator(iterate()))
|
||||||
|
|
||||||
|
def get_set_vars(self):
|
||||||
|
raise NotImplementedError("This should never be called")
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
return []
|
"""
|
||||||
|
Call the default method with the own instance (self implements all
|
||||||
|
the necessary functions). Add also the params.
|
||||||
|
"""
|
||||||
|
# result = self.get_params() + parsing.Scope._get_set_vars(self)
|
||||||
|
# print '\n\ndef', result, 'par', self, self.parent
|
||||||
|
# print 'set', parsing.Scope._get_set_vars(self)
|
||||||
|
# print 'set', [r.parent for r in parsing.Scope._get_set_vars(self)]
|
||||||
|
# print 'para', [r.parent.parent for r in self.get_params()]
|
||||||
|
# return result
|
||||||
|
return self.get_params() + parsing.Scope._get_set_vars(self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def scope(self):
|
def scope(self):
|
||||||
@@ -482,21 +477,20 @@ class Execution(Executable):
|
|||||||
|
|
||||||
def copy_properties(self, prop):
|
def copy_properties(self, prop):
|
||||||
# copy all these lists into this local function.
|
# copy all these lists into this local function.
|
||||||
attr = getattr(self.func, prop)
|
attr = getattr(self.base, prop)
|
||||||
objects = []
|
objects = []
|
||||||
for element in attr:
|
for element in attr:
|
||||||
copied = copy.copy(element)
|
temp, element.parent = element.parent, None
|
||||||
|
copied = copy.deepcopy(element)
|
||||||
|
element.parent = temp
|
||||||
copied.parent = self
|
copied.parent = self
|
||||||
|
if isinstance(copied, parsing.Function):
|
||||||
|
copied = Function.create(copied)
|
||||||
objects.append(copied)
|
objects.append(copied)
|
||||||
return objects
|
return objects
|
||||||
|
|
||||||
@property
|
def __getattr__(self, name):
|
||||||
def param_cb(self):
|
return getattr(self.base, name)
|
||||||
return self.func.param_cb
|
|
||||||
|
|
||||||
@param_cb.setter
|
|
||||||
def param_cb(self, value):
|
|
||||||
self.func.param_cb = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
|
|||||||
30
parsetest.py
30
parsetest.py
@@ -158,23 +158,23 @@ a = 3; b = ""
|
|||||||
b,a=a,b
|
b,a=a,b
|
||||||
a.
|
a.
|
||||||
|
|
||||||
|
def decorator2(func):
|
||||||
|
def wrapper(*args):
|
||||||
|
return func(*args)
|
||||||
|
return wrapper
|
||||||
|
def decorator1(func):
|
||||||
|
|
||||||
|
|
||||||
def decorator(func):
|
|
||||||
def wrapper(*args):
|
def wrapper(*args):
|
||||||
return func(1, *args)
|
return func(1, *args)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
@decorator2
|
||||||
@decorator
|
@decorator1
|
||||||
def decorated(a,b):
|
def decorated(a,b):
|
||||||
return a,b
|
return a,b
|
||||||
|
exe = decorated(frozenset, '')
|
||||||
exe = decorated(set, '')
|
exe[1].
|
||||||
|
def gen():
|
||||||
#? []
|
yield 1
|
||||||
exe[0].union
|
yield ""
|
||||||
|
gen_exe = gen()
|
||||||
|
#? ['upper']
|
||||||
|
next(gen_exe).
|
||||||
|
|||||||
28
parsing.py
28
parsing.py
@@ -183,6 +183,15 @@ class Scope(Simple):
|
|||||||
:return: list of Name
|
:return: list of Name
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
|
return self._get_set_vars(self)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_set_vars(self):
|
||||||
|
"""
|
||||||
|
This is a hack, because Python 2 has another understanding of methods,
|
||||||
|
than Python 3. In Python 2 it is not possible to use a method without
|
||||||
|
the `self` being an instance of the class.
|
||||||
|
"""
|
||||||
n = []
|
n = []
|
||||||
for stmt in self.statements:
|
for stmt in self.statements:
|
||||||
try:
|
try:
|
||||||
@@ -196,7 +205,6 @@ class Scope(Simple):
|
|||||||
for i in self.imports:
|
for i in self.imports:
|
||||||
if not i.star:
|
if not i.star:
|
||||||
n += i.get_defined_names()
|
n += i.get_defined_names()
|
||||||
|
|
||||||
return n
|
return n
|
||||||
|
|
||||||
def get_defined_names(self):
|
def get_defined_names(self):
|
||||||
@@ -310,14 +318,9 @@ class Function(Scope):
|
|||||||
for p in params:
|
for p in params:
|
||||||
p.parent = self
|
p.parent = self
|
||||||
self.decorators = []
|
self.decorators = []
|
||||||
# helper variable for the evaluator, maybe remove this, when
|
|
||||||
# evaluate.py is rewritten, fully functional.
|
|
||||||
self.returns = []
|
self.returns = []
|
||||||
self.is_generator = False
|
self.is_generator = False
|
||||||
|
|
||||||
# callback to set the function
|
|
||||||
self.param_cb = None
|
|
||||||
|
|
||||||
def get_code(self, first_indent=False, indention=" "):
|
def get_code(self, first_indent=False, indention=" "):
|
||||||
str = "\n".join('@' + stmt.get_code() for stmt in self.decorators)
|
str = "\n".join('@' + stmt.get_code() for stmt in self.decorators)
|
||||||
params = ','.join([stmt.code for stmt in self.params])
|
params = ','.join([stmt.code for stmt in self.params])
|
||||||
@@ -329,18 +332,19 @@ class Function(Scope):
|
|||||||
|
|
||||||
def get_set_vars(self):
|
def get_set_vars(self):
|
||||||
n = super(Function, self).get_set_vars()
|
n = super(Function, self).get_set_vars()
|
||||||
|
"""
|
||||||
if self.param_cb:
|
if self.param_cb:
|
||||||
# This is the really ugly part, where the functional style of this
|
# This is the really ugly part, where the functional style of this
|
||||||
# get methods is broken, it executes a callback.
|
# get methods is broken, it executes a callback.
|
||||||
# This is important, because something has to inject the params
|
# This is important, because something has to inject the params
|
||||||
# into the functions, with the right values.
|
# into the functions, with the right values.
|
||||||
n += self.param_cb()
|
n += self.param_cb()
|
||||||
else:
|
"""
|
||||||
for p in self.params:
|
for p in self.params:
|
||||||
try:
|
try:
|
||||||
n.append(p.get_name())
|
n.append(p.get_name())
|
||||||
except IndexError:
|
except IndexError:
|
||||||
debug.warning("multiple names in param %s" % n)
|
debug.warning("multiple names in param %s" % n)
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def recursion(a, b):
|
|||||||
else:
|
else:
|
||||||
return recursion(a+".", b+1)
|
return recursion(a+".", b+1)
|
||||||
|
|
||||||
#? int() float()
|
##? int() float()
|
||||||
recursion("a", 1.0)
|
recursion("a", 1.0)
|
||||||
|
|
||||||
# -----------------
|
# -----------------
|
||||||
|
|||||||
Reference in New Issue
Block a user