From 5332a87d3944a37a540b6c0ade90c159120880ad Mon Sep 17 00:00:00 2001 From: David Halter Date: Sat, 10 Mar 2012 15:34:07 +0100 Subject: [PATCH] split parsing functions file, the path following is now in evaluate.py --- evaluate.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ functions.py | 51 ++++++++------------------------------------- parsing.py | 50 +++++++++++++++++++++++++------------------- test.py | 4 ++-- 4 files changed, 97 insertions(+), 66 deletions(-) create mode 100644 evaluate.py diff --git a/evaluate.py b/evaluate.py new file mode 100644 index 00000000..6ee4763c --- /dev/null +++ b/evaluate.py @@ -0,0 +1,58 @@ +import parsing + +def Statement(object): + """ The statement object of functions, to """ + pass + +def get_names_for_scope(scope): + """ Get all completions possible for the current scope. """ + comp = [] + start_scope = scope + while scope: + # class variables/functions are only availabe + if not isinstance(scope, parsing.Class) or scope == start_scope: + comp += scope.get_set_vars() + scope = scope.parent + return comp + + +def follow_path(scope, path): + """ + Follow a path of python names. + recursive! + :returns: list(Scope) + """ + comp = get_names_for_scope(scope) + print path, comp + + path = list(path) + name = path.pop(0) + scopes = [] + + # make the full comparison, because the names have to match exactly + comp = [c for c in comp if [name] == list(c.names)] + # TODO differentiate between the different comp input (some are overridden) + for c in comp: + p_class = c.parent.__class__ + if p_class == parsing.Class or p_class == parsing.Scope: + scopes.append(c.parent) + #elif p_class == parsing.Function: + elif p_class == parsing.Statement: + pass + else: + print 'error follow_path:', p_class, repr(c.parent) + + if path: + new_scopes = [] + for s in tuple(scopes): + new_scopes += follow_path(s, tuple(path)) + scopes = new_scopes + return set(scopes) + + +def dbg(*args): + if debug_function: + debug_function(*args) + + +debug_function = None diff --git a/functions.py b/functions.py index 41a746ac..6572e6d4 100644 --- a/functions.py +++ b/functions.py @@ -1,5 +1,6 @@ import parsing +import evaluate import re __all__ = ['complete', 'set_debug_function'] @@ -181,8 +182,11 @@ def complete(source, row, column, file_callback=None): f = File(source=source, row=row) scope = f.parser.user_scope - print - print + # print a dbg title + dbg() + dbg('-' * 70) + dbg(' ' * 62 + 'complete') + dbg('-' * 70) print scope print f.parser.user_scope.get_simple_for_line(row) @@ -197,7 +201,7 @@ def complete(source, row, column, file_callback=None): name = path.pop() if path: - scopes = follow_path(scope, tuple(path)) + scopes = evaluate.follow_path(scope, tuple(path)) dbg('possible scopes', scopes) compl = [] @@ -213,46 +217,6 @@ def complete(source, row, column, file_callback=None): return result -def get_names_for_scope(scope): - """ Get all completions possible for the current scope. """ - comp = [] - start_scope = scope - while scope: - # class variables/functions are only availabe - if not isinstance(scope, parsing.Class) or scope == start_scope: - comp += scope.get_set_vars() - scope = scope.parent - return comp - -def follow_path(scope, path): - """ - Follow a path of python names. - recursive! - :returns: list(Scope) - """ - comp = get_names_for_scope(scope) - print path, comp - - path = list(path) - name = path.pop() - scopes = [] - - # make the full comparison, because the names have to match exactly - comp = [c for c in comp if [name] == list(c.names)] - # TODO differentiate between the different comp input (some are overridden) - for c in comp: - p_class = c.parent.__class__ - if p_class == parsing.Class or p_class == parsing.Scope: - scopes.append(c.parent) - #elif p_class == parsing.Function: - else: - print 'error follow_path:', p_class - if path: - for s in tuple(scopes): - scopes += follow_path(s, tuple(path)) - return set(scopes) - - def dbg(*args): if debug_function: debug_function(*args) @@ -262,6 +226,7 @@ def set_debug_function(func): global debug_function debug_function = func parsing.debug_function = func + evaluate.debug_function = func debug_function = None diff --git a/parsing.py b/parsing.py index 0328e549..6890a8c5 100644 --- a/parsing.py +++ b/parsing.py @@ -60,6 +60,11 @@ class Simple(object): self.line_end = line_end self.parent = None + def __repr__(self): + code = self.get_code().replace('\n', ' ') + return "<%s: %s@%s>" % \ + (self.__class__.__name__, code, self.line_nr) + class Scope(Simple): """ @@ -126,6 +131,7 @@ class Scope(Simple): def add_import(self, imp): self.imports.append(imp) + imp.parent = self def add_global(self, name): """ @@ -137,14 +143,7 @@ class Scope(Simple): :type name: Name """ self.global_vars.append(name) - - def _checkexisting(self, test): - "Convienance function... keep out duplicates" - if test.find('=') > -1: - var = test.split('=')[0].strip() - for l in self.locals: - if l.find('=') > -1 and var == l.split('=')[0].strip(): - self.locals.remove(l) + # set no parent here, because globals are not defined in this scope. def get_code(self, first_indent=False, indention=" "): """ @@ -291,7 +290,10 @@ class Function(Scope): def __init__(self, name, params, indent, line_nr, docstr=''): Scope.__init__(self, indent, line_nr, docstr) self.name = name + name.parent = self self.params = params + for p in params: + p.parent = self self.decorators = [] def get_code(self, first_indent=False, indention=" "): @@ -340,10 +342,14 @@ class Flow(Scope): super(Flow, self).__init__(indent, line_nr, '') self.command = command self.statement = statement + if statement: + statement.parent = self if set_vars == None: self.set_vars = [] else: self.set_vars = set_vars + for s in self.set_vars: + s.parent = self self.next = None def get_code(self, first_indent=False, indention=" "): @@ -395,22 +401,30 @@ class Import(Simple): :param line_nr: Line number. :type line_nr: int - :param namespace: The import, as an array list of Name, \ - e.g. ['datetime', 'time']. - :type namespace: list + :param namespace: The import, can be empty if a star is given + :type namespace: Name :param alias: The alias of a namespace(valid in the current namespace). - :type alias: str + :type alias: Name :param from_ns: Like the namespace, can be equally used. - :type from_ns: list + :type from_ns: Name :param star: If a star is used -> from time import *. :type star: bool """ def __init__(self, indent, line_nr, line_end, namespace, alias='', \ from_ns='', star=False): super(Import, self).__init__(indent, line_nr, line_end) + self.namespace = namespace + namespace.parent = self + self.alias = alias + if alias: + alias.parent = self + self.from_ns = from_ns + if from_ns: + from_ns.parent = self + self.star = star def get_code(self): @@ -430,10 +444,6 @@ class Import(Simple): return [self] return [self.alias] if self.alias else [self.namespace] - def __repr__(self): - return "<%s: %s@%s>" % \ - (self.__class__.__name__, self.get_code(), self.line_nr) - class Statement(Simple): """ @@ -462,6 +472,8 @@ class Statement(Simple): self.set_vars = set_vars self.used_funcs = used_funcs self.used_vars = used_vars + for s in set_vars + used_funcs + used_vars: + s.parent = self def get_code(self, new_line=True): if new_line: @@ -503,10 +515,6 @@ class Name(Simple): def __hash__(self): return hash(self.names) + hash(self.indent) + hash(self.line_nr) - def __repr__(self): - return "<%s: %s@%s>" % \ - (self.__class__.__name__, self.get_code(), self.line_nr) - def __len__(self): return len(self.names) diff --git a/test.py b/test.py index 619cf65f..83158166 100644 --- a/test.py +++ b/test.py @@ -128,7 +128,7 @@ if True or a: # completion import time class c1(): - c2 = 1 + c2 = c1() def c3(self): import time as c4 c5 = 3 @@ -136,5 +136,5 @@ class c1(): -c1.\ +c1.c2.\ c