diff --git a/evaluate.py b/evaluate.py index 2698ecda..bc8994a7 100644 --- a/evaluate.py +++ b/evaluate.py @@ -139,16 +139,14 @@ class Instance(Executable): # need to execute the __init__ function, because the dynamic param # searching needs it. try: - init_func = self.get_subscope_by_name('__init__') + self.execute_subscope_by_name('__init__', self.var_args) except KeyError: pass - else: - self.get_init_execution(init_func).get_return_types() @memoize_default() def get_init_execution(self, func): - instance_el = InstanceElement(self, Function(func)) - return Execution(instance_el, self.var_args) + func = InstanceElement(self, func) + return Execution(func, self.var_args) def get_func_self_name(self, func): """ @@ -193,19 +191,22 @@ class Instance(Executable): def get_subscope_by_name(self, name): for sub in reversed(self.base.subscopes): if sub.name.get_code() == name: - return sub + return InstanceElement(self, sub) raise KeyError("Couldn't find subscope.") + def execute_subscope_by_name(self, name, args): + method = self.get_subscope_by_name(name) + if args.parent_stmt is None: + args.parent_stmt = method + return Execution(method, args).get_return_types() + def get_descriptor_return(self, obj): """ Throws a KeyError if there's no method. """ - method = self.get_subscope_by_name('__get__') # Arguments in __get__ descriptors are obj, class. # `method` is the new parent of the array, don't know if that's good. v = [[obj], [obj.base]] if isinstance(obj, Instance) else [[], [obj]] - args = parsing.Array('tuple', method, values=v) - method = InstanceElement(self, method) - res = Execution(method, args).get_return_types() - return res + args = parsing.Array(parsing.Array.TUPLE, None, values=v) + return self.execute_subscope_by_name('__get__', args) def get_defined_names(self): """ @@ -219,10 +220,16 @@ class Instance(Executable): names.append(InstanceElement(self, var)) return names + def get_index_types(self, index=None): + v = [[index]] if index is not None else [] + args = parsing.Array(parsing.Array.NOARRAY, None, values=v) + try: + return self.execute_subscope_by_name('__getitem__', args) + except KeyError: + debug.warning('No __getitem__, cannot access the array.') + return [] + def __getattr__(self, name): - if name == 'get_index_types': - # TODO Call __getitem__ in such cases? - return lambda: [] if name not in ['start_pos', 'end_pos', 'name', 'get_imports']: raise AttributeError("Instance %s: Don't touch this (%s)!" % (self, name)) @@ -431,17 +438,14 @@ class Execution(Executable): try: self.base.returns except (AttributeError, DecoratorNotFound): - try: - # If it is an instance, we try to execute the __call__(). - call_method = self.base.get_subscope_by_name('__call__') - except (AttributeError, KeyError): - debug.warning("no execution possible", self.base) + if hasattr(self.base, 'execute_subscope_by_name'): + try: + stmts = self.base.execute_subscope_by_name('__call__', + self.var_args) + except KeyError: + debug.warning("no __call__ func available", self.base) else: - debug.dbg('__call__', call_method, self.base) - base = self.base - call_method = InstanceElement(base, call_method) - exe = Execution(call_method, self.var_args) - stmts = exe.get_return_types() + debug.warning("no execution possible", self.base) else: stmts = self._get_function_returns(evaluate_generator) diff --git a/mixin/builtins.py b/mixin/builtins.py index 38979489..1b8a46c8 100644 --- a/mixin/builtins.py +++ b/mixin/builtins.py @@ -1,4 +1,9 @@ - +""" +Pure Python implementation of some builtins. +This code is not going to be executed anywhere. +These implementations are not always correct, but should work as good as +possible for the auto completion. +""" def next(iterator, default=None): if hasattr("next"): return iterator.next() @@ -6,8 +11,9 @@ def next(iterator, default=None): return iterator.__next__() return default + class property(): - def __init__(self, fget, fset = None, fdel = None, doc = None): + def __init__(self, fget, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel @@ -34,6 +40,7 @@ class property(): self.fdel = func return self + class staticmethod(): def __init__(self, func): self.func = func @@ -41,6 +48,7 @@ class staticmethod(): def __get__(self, obj, cls): return self.func + class classmethod(): def __init__(self, func): self._func = func @@ -49,3 +57,45 @@ class classmethod(): def _method(*args, **kwargs): return self._func(cls, *args, **kwargs) return _method + + +class list(): + def __init__(self, iterable=[]): + self.iterable = [] + for i in iterable: + self.iterable += [i] + + def __iter__(self): + for i in self.iterable: + yield i + + def __getitem__(self, y): + return self.iterable[y] + + def pop(self): + return self.iterable[-1] + + +class set(): + def __init__(self, iterable=[]): + self.iterable = iterable + + def __iter__(self): + for i in self.iterable: + yield i + + def add(self, elem): + self.iterable += [elem] + + def pop(self): + return self.iterable.pop() + + def copy(self): + return self + + +def iter(collection, sentinel=None): + if sentinel: + yield collection() + else: + yield next(collection) diff --git a/test/completion/arrays.py b/test/completion/arrays.py index 5e2b4abc..477f5dfe 100644 --- a/test/completion/arrays.py +++ b/test/completion/arrays.py @@ -138,3 +138,34 @@ dic2[r'asdf'] dic2[r'asdf'] #? int() str() dic2['just_something'] + +# ----------------- +# __getitem__ +# ----------------- + +class GetItem(): + def __getitem__(self, index): + return 1.0 + +#? float() +GetItem()[0] + +class GetItem(): + def __init__(self, el): + self.el = el + + def __getitem__(self, index): + return self.el + +#? str() +GetItem("")[1] + +# ----------------- +# conversions +# ----------------- + +#? str() +list([1,""])[1] + +#? str() +list(set([1,""]))[1]