diff --git a/debug.py b/debug.py index 113037b8..c0bbdedf 100644 --- a/debug.py +++ b/debug.py @@ -23,5 +23,6 @@ def print_to_stdout(level, *args): """ The default debug function """ print 'dbg:' if level == NOTICE else 'warning:', args -debug_function = print_to_stdout +debug_function = None +#debug_function = print_to_stdout ignored_modules = [] diff --git a/evaluate.py b/evaluate.py index a62c6f99..b5f6cb03 100644 --- a/evaluate.py +++ b/evaluate.py @@ -21,10 +21,10 @@ def memoize(default=None): don't think, that there is a big speed difference, but there are many cases where recursion could happen (think about a = b; b = a). """ - memo = {} def func(function): + memo = {} + def wrapper(*args): - print function, args if args in memo: return memo[args] else: @@ -166,7 +166,20 @@ def get_scopes_for_name(scope, name, search_global=False): # result += filter_name(i) #else: if [name] == list(scope.names): - result.append(scope.parent) + par = scope.parent + if isinstance(par, parsing.Flow): + # TODO get Flow data, which is defined by the loop (or + # with) + pass + elif isinstance(par, parsing.Param): + if isinstance(par.parent.parent, parsing.Class) \ + and par.position == 0: + result.append(Instance(par.parent.parent)) + else: + # TODO get function data + pass + else: + result.append(scope.parent) debug.dbg('sfn filter', result) return result @@ -188,12 +201,12 @@ def strip_imports(scopes): if isinstance(s, parsing.Import): print 'dini mueter, steile griech!' try: - scope = follow_import(s) + new = follow_import(s) except modules.ModuleNotFound: debug.dbg('Module not found: ' + str(s)) else: - result.append(scope) - result += strip_imports(i for i in scope.get_imports() if i.star) + result.append(new) + result += strip_imports(i for i in new.get_imports() if i.star) else: result.append(s) return result @@ -223,7 +236,6 @@ def follow_call(scope, call): path = call.generate_call_list() current = next(path) - print 'call', scope, call, current if isinstance(current, parsing.Array): result = [current] else: diff --git a/ftest.py b/ftest.py index 974f3328..25f9523c 100755 --- a/ftest.py +++ b/ftest.py @@ -9,6 +9,6 @@ functions.modules.module_find_path.insert(0, '.') with open('test.py') as f: code = f.read() for i in range(1): - completions = functions.complete(code, 50, 20) + completions = functions.complete(code, 50, 200) -print '\n', [c.names for c in completions] +print '\n', [c.names[-1] for c in completions] diff --git a/functions.py b/functions.py index 1e8e1623..b622d286 100644 --- a/functions.py +++ b/functions.py @@ -8,11 +8,6 @@ import debug __all__ = ['complete', 'complete_test', 'set_debug_function'] -class ParserError(LookupError): - """ The exception that is thrown if some handmade parser fails. """ - pass - - class FileWithCursor(modules.File): """ Manages all files, that are parsed and caches them. @@ -118,44 +113,27 @@ def complete(source, row, column, file_callback=None): """ f = FileWithCursor('__main__', source=source, row=row) scope = f.parser.user_scope + path = f.get_row_path(column) + debug.dbg('completion_start: %s in %s' % (path, scope)) - # print a debug.dbg title - debug.dbg('complete_scope', scope) + # just parse one statement, take it and evaluate it + r = parsing.PyFuzzyParser(path) + scopes = evaluate.follow_statement(r.top.statements[0], scope) - try: - path = f.get_row_path(column) - print path - debug.dbg('completion_path', path) - except ParserError as e: - path = [] - debug.dbg(e) + #name = path.pop() # use this later + completions = [] + debug.dbg('possible scopes', scopes) + for s in scopes: + completions += s.get_defined_names() - result = [] - if path and path[0]: - # just parse one statement - #debug.ignored_modules = ['builtin'] - r = parsing.PyFuzzyParser(path) - #debug.ignored_modules = ['parsing', 'builtin'] - #print 'p', r.top.get_code().replace('\n', r'\n'), r.top.statements[0] - scopes = evaluate.follow_statement(r.top.statements[0], scope) + #else: + # compl = evaluate.get_names_for_scope(scope) - #name = path.pop() # use this later - compl = [] - debug.dbg('possible scopes') - for s in scopes: - compl += s.get_defined_names() + debug.dbg('possible-compl', completions) - #else: - # compl = evaluate.get_names_for_scope(scope) + #result = [c for c in compl if name in c.names[-1]] - debug.dbg('possible-compl', compl) - - # make a partial comparison, because the other options have to - # be returned as well. - result = compl - #result = [c for c in compl if name in c.names[-1]] - - return result + return completions def complete_test(source, row, column, file_callback=None): diff --git a/parsing.py b/parsing.py index 07fed9f1..3b36cdd9 100644 --- a/parsing.py +++ b/parsing.py @@ -151,8 +151,8 @@ class Scope(Simple): i = self.imports for s in self.statements: if isinstance(s, Scope): - i += s.get_imports() - return i + i += s.get_imports() + return i def add_global(self, name): """ @@ -212,7 +212,8 @@ class Scope(Simple): return n def get_defined_names(self): - return [n for n in self.get_set_vars() if isinstance(n, Import) or len(n) == 1] + return [n for n in self.get_set_vars() \ + if isinstance(n, Import) or len(n) == 1] def is_empty(self): """ @@ -515,7 +516,6 @@ class Statement(Simple): close_brackets = False debug.dbg('tok_list', self.token_list) - print 'tok_list', self.token_list for i, tok_temp in enumerate(self.token_list): #print 'tok', tok_temp, result try: @@ -608,10 +608,23 @@ class Statement(Simple): "behaviour. Please submit a bug" % level) self.assignment_calls = top - print 'top', top.values, top.values[0][0].name, repr(top.values[0][0].name) return top +class Param(Statement): + """ + The class which shows definitions of params of classes and functions. + But this is not to define function calls. + """ + def __init__(self, code, set_vars, used_funcs, used_vars, token_list, + indent, line_nr, line_end): + super(Param, self).__init__(code, set_vars, used_funcs, + used_vars, token_list, indent, line_nr, line_end) + + # this is defined by the parser later on, not at the initialization + self.position = None + + class Call(object): NAME = object() NUMBER = object() @@ -910,10 +923,14 @@ class PyFuzzyParser(object): """ names = [] tok = None + pos = 0 while tok not in [')', ':']: - stmt, tok = self._parse_statement(added_breaks=',') + stmt, tok = self._parse_statement(added_breaks=',', + stmt_class=Param) if stmt: + stmt.position = pos names.append(stmt) + pos += 1 return names @@ -972,7 +989,8 @@ class PyFuzzyParser(object): return Class(cname, super, indent, start_line) - def _parse_statement(self, pre_used_token=None, added_breaks=None): + def _parse_statement(self, pre_used_token=None, added_breaks=None, + stmt_class=Statement): """ Parses statements like: @@ -1075,7 +1093,7 @@ class PyFuzzyParser(object): and self.last_token[1] == tokenize.STRING: self.scope.add_docstr(self.last_token[1]) else: - stmt = Statement(string, set_vars, used_funcs, used_vars,\ + stmt = stmt_class(string, set_vars, used_funcs, used_vars,\ tok_list, indent, line_start, self.line_nr) if is_return: # add returns to the scope diff --git a/test.py b/test.py index d9a54b7c..55394c8d 100644 --- a/test.py +++ b/test.py @@ -47,7 +47,7 @@ class A(): return 8 + a.test() class init: def __init__(self, a, b=3, c = A): - self.a = a + a=0;self.a = a;self aclass = A()