1
0
forked from VimPlug/jedi

basic refactoring, of function executions super() is not working yet

This commit is contained in:
Dave Halter
2013-12-29 02:05:37 +01:00
parent 870f5da354
commit 4215e7934e
2 changed files with 42 additions and 57 deletions

View File

@@ -664,8 +664,32 @@ class Evaluator(object):
position=position)) position=position))
return self.follow_path(path, set(result), scope, position=position) return self.follow_path(path, set(result), scope, position=position)
def execute(self, scope, params, evaluate_generator=False): def execute(self, obj, params, evaluate_generator=False):
return er.Execution(self, scope, params).get_return_types(evaluate_generator) if obj.isinstance(er.Function):
obj = obj.get_decorated_func()
if obj.isinstance(er.Class):
# There maybe executions of executions.
return [er.Instance(self, obj, params)]
elif isinstance(obj, er.Generator):
return obj.iter_content()
else:
stmts = []
try:
obj.returns # Test if it is a function
except AttributeError:
if hasattr(obj, 'execute_subscope_by_name'):
try:
stmts = obj.execute_subscope_by_name('__call__', params)
except KeyError:
debug.warning("no __call__ func available", obj)
else:
debug.warning("no execution possible", obj)
else:
stmts = er.Execution(self, obj, params).get_return_types(evaluate_generator)
debug.dbg('execute: %s in %s' % (stmts, self))
return imports.strip_imports(self, stmts)
def goto(self, stmt, call_path=None): def goto(self, stmt, call_path=None):
if call_path is None: if call_path is None:

View File

@@ -14,12 +14,11 @@ from __future__ import with_statement
import copy import copy
import itertools import itertools
from jedi._compatibility import use_metaclass, next, hasattr, unicode from jedi._compatibility import use_metaclass, next, unicode
from jedi.parser import representation as pr from jedi.parser import representation as pr
from jedi import helpers from jedi import helpers
from jedi import debug from jedi import debug
from jedi import common from jedi import common
from jedi.evaluate import imports
from jedi.evaluate import builtin from jedi.evaluate import builtin
from jedi.evaluate import recursion from jedi.evaluate import recursion
from jedi.evaluate.cache import memoize_default, CachedMetaClass from jedi.evaluate.cache import memoize_default, CachedMetaClass
@@ -39,18 +38,11 @@ class Executable(pr.IsScope):
self.var_args = var_args self.var_args = var_args
def get_parent_until(self, *args, **kwargs): def get_parent_until(self, *args, **kwargs):
return self._decorated.get_parent_until(*args, **kwargs) return self.base.get_parent_until(*args, **kwargs)
@property @property
def parent(self): def parent(self):
return self._decorated.parent return self.base.parent
@property
def _decorated(self):
"""
Instance doesn't care about decorators and Execution overrides this
"""
return self.base
class Instance(use_metaclass(CachedMetaClass, Executable)): class Instance(use_metaclass(CachedMetaClass, Executable)):
@@ -363,9 +355,9 @@ class Function(use_metaclass(CachedMetaClass, pr.IsScope)):
debug.warning('no wrappers found', self.base_func) debug.warning('no wrappers found', self.base_func)
return None return None
if len(wrappers) > 1: if len(wrappers) > 1:
# TODO resolve issue with multiple wrappers -> multiple types
debug.warning('multiple wrappers found', self.base_func, debug.warning('multiple wrappers found', self.base_func,
wrappers) wrappers)
# This is here, that the wrapper gets executed.
f = wrappers[0] f = wrappers[0]
debug.dbg('decorator end', f) debug.dbg('decorator end', f)
@@ -420,20 +412,11 @@ class Execution(Executable):
else: else:
return [stmt] # just some arbitrary object return [stmt] # just some arbitrary object
@property
@memoize_default(None)
def _decorated(self):
"""Get the decorated version of the input"""
base = self.base
if self.base.isinstance(Function):
base = base.get_decorated_func()
return base
@memoize_default(default=()) @memoize_default(default=())
@recursion.execution_recursion_decorator @recursion.execution_recursion_decorator
def get_return_types(self, evaluate_generator=False): def get_return_types(self, evaluate_generator=False):
""" Get the return types of a function. """ """ Get the return types of a function. """
base = self._decorated base = self.base
stmts = [] stmts = []
if base.parent == builtin.Builtin.scope \ if base.parent == builtin.Builtin.scope \
and not isinstance(base, (Generator, Array)): and not isinstance(base, (Generator, Array)):
@@ -464,7 +447,7 @@ class Execution(Executable):
objects = self._follow_var_arg(0) objects = self._follow_var_arg(0)
return [o.base for o in objects if isinstance(o, Instance)] return [o.base for o in objects if isinstance(o, Instance)]
elif func_name == 'super': elif func_name == 'super':
# TODO make this able to detect multiple inheritance supers # TODO make this able to detect multiple inheritance super
accept = (pr.Function,) accept = (pr.Function,)
func = self.var_args.get_parent_until(accept) func = self.var_args.get_parent_until(accept)
if func.isinstance(*accept): if func.isinstance(*accept):
@@ -477,29 +460,7 @@ class Execution(Executable):
return [Instance(self._evaluator, su[0])] return [Instance(self._evaluator, su[0])]
return [] return []
if base.isinstance(Class): return self._get_function_returns(base, evaluate_generator)
# There maybe executions of executions.
return [Instance(self._evaluator, base, self.var_args)]
elif isinstance(base, Generator):
return base.iter_content()
else:
try:
base.returns # Test if it is a function
except AttributeError:
if hasattr(base, 'execute_subscope_by_name'):
try:
stmts = base.execute_subscope_by_name('__call__',
self.var_args)
except KeyError:
debug.warning("no __call__ func available", base)
else:
debug.warning("no execution possible", base)
else:
stmts = self._get_function_returns(base, evaluate_generator)
debug.dbg('exec result: %s in %s' % (stmts, self))
return imports.strip_imports(self._evaluator, stmts)
def _get_function_returns(self, func, evaluate_generator): def _get_function_returns(self, func, evaluate_generator):
""" A normal Function execution """ """ A normal Function execution """
@@ -531,7 +492,7 @@ class Execution(Executable):
parent = self.var_args.parent parent = self.var_args.parent
start_pos = self.var_args.start_pos start_pos = self.var_args.start_pos
else: else:
parent = self._decorated parent = self.base
start_pos = 0, 0 start_pos = 0, 0
new_param = copy.copy(param) new_param = copy.copy(param)
@@ -558,15 +519,15 @@ class Execution(Executable):
result = [] result = []
start_offset = 0 start_offset = 0
if isinstance(self._decorated, 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._decorated.params[0].get_name()) self_name = copy.copy(self.base.params[0].get_name())
self_name.parent = self._decorated.instance self_name.parent = self.base.instance
result.append(self_name) result.append(self_name)
param_dict = {} param_dict = {}
for param in self._decorated.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.
@@ -575,7 +536,7 @@ class Execution(Executable):
non_matching_keys = [] non_matching_keys = []
keys_used = set() keys_used = set()
keys_only = False keys_only = False
for param in self._decorated.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.
# Wrong value count is just ignored. If you try to test cases that # Wrong value count is just ignored. If you try to test cases that
@@ -719,7 +680,7 @@ class Execution(Executable):
execution. execution.
""" """
# Copy all these lists into this local function. # Copy all these lists into this local function.
attr = getattr(self._decorated, prop) attr = getattr(self.base, prop)
objects = [] objects = []
for element in attr: for element in attr:
if element is None: if element is None:
@@ -735,7 +696,7 @@ class Execution(Executable):
def __getattr__(self, name): def __getattr__(self, name):
if name not in ['start_pos', 'end_pos', 'imports', '_sub_module']: if name not in ['start_pos', 'end_pos', 'imports', '_sub_module']:
raise AttributeError('Tried to access %s: %s. Why?' % (name, self)) raise AttributeError('Tried to access %s: %s. Why?' % (name, self))
return getattr(self._decorated, name) return getattr(self.base, name)
@memoize_default(None) @memoize_default(None)
@common.rethrow_uncaught @common.rethrow_uncaught
@@ -777,7 +738,7 @@ class Execution(Executable):
def __repr__(self): def __repr__(self):
return "<%s of %s>" % \ return "<%s of %s>" % \
(type(self).__name__, self._decorated) (type(self).__name__, self.base)
class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)): class Generator(use_metaclass(CachedMetaClass, pr.Base, Iterable)):