diff --git a/pycomplete.py b/pycomplete.py index 40f51597..13915901 100755 --- a/pycomplete.py +++ b/pycomplete.py @@ -5,7 +5,6 @@ import cStringIO import sys import types -from pyfuzzyparser import PyFuzzyParser import pyfuzzyparser @@ -49,7 +48,7 @@ def _sanitize(str): class Completer(object): def __init__(self): self.compldict = {} - self.parser = PyFuzzyParser() + self.parser = pyfuzzyparser.PyFuzzyParser() def evalsource(self, text, line=0): sc = self.parser.parse(text) @@ -207,6 +206,7 @@ def showdbg(): print "DBG: %s " % d +pyfuzzyparser.debug_function = pyfuzzyparser.dbg() text = cStringIO.StringIO(open('test.py').read()) cmpl = Completer() cmpl.evalsource(text, 51) @@ -223,13 +223,32 @@ showdbg() print cmpl.parser.top.get_code() #print cmpl.parser.top.subscopes[1].subscopes[0].get_code() +def handle_names(names): + #print names + for n in names: + try: + print n.names + except AttributeError: + print 'star!', n.from_ns + print 'global names:' names = cmpl.parser.top.get_names() -print [n.names for n in names] +handle_names(names) +print print 'func names:' names = cmpl.parser.top.subscopes[0].get_names() -print [n.names for n in names] +handle_names(names) + +print +print 'class names:' +names = cmpl.parser.top.subscopes[2].get_names() +handle_names(names) +for s in cmpl.parser.top.subscopes[2].subscopes: + print 'method names:' + names = s.get_names() + handle_names(names) + p = cmpl.parser s = p.top diff --git a/pyfuzzyparser.py b/pyfuzzyparser.py index aa210c74..5a2864c4 100644 --- a/pyfuzzyparser.py +++ b/pyfuzzyparser.py @@ -29,8 +29,8 @@ Ignored statements: - exec (dangerous - not controllable) TODO be tolerant with indents -TODO dictionaries not working with statement parser TODO take special care for future imports +TODO check meta classes """ import sys @@ -65,7 +65,7 @@ class Scope(object): :param docstr: The docstring for the current Scope. :type docstr: str """ - def __init__(self, name, indent, line_nr, docstr=''): + def __init__(self, indent, line_nr, docstr=''): self.subscopes = [] self.imports = [] self.statements = [] @@ -162,6 +162,10 @@ class Scope(object): # function and class names n += [s.name for s in self.subscopes] n += self.global_vars + + for i in self.imports: + n += i.get_names() + return n def is_empty(self): @@ -192,10 +196,14 @@ class Class(Scope): self.name = name self.supers = supers + def __repr__(self): + return "" % (self.name, self.line_nr) + def get_code(self, first_indent=False, indention=" "): str = 'class %s' % (self.name) if len(self.supers) > 0: - str += '(%s)' % ','.join(self.supers) + sup = ','.join([stmt.code for stmt in self.supers]) + str += '(%s)' % sup str += ':\n' str += super(Class, self).get_code(True, indention) if self.is_empty(): @@ -209,7 +217,7 @@ class Function(Scope): :param name: The Function name. :type name: string - :param params: The parameters (Name) of a Function. + :param params: The parameters (Statement) of a Function. :type name: list :param indent: The indent level of the flow statement. :type indent: int @@ -223,15 +231,22 @@ class Function(Scope): self.name = name self.params = params + def __repr__(self): + return "" % (self.name, self.line_nr) + def get_code(self, first_indent=False, indention=" "): - str = "def %s(%s):\n" % (self.name, ','.join(self.params)) + params = ','.join([stmt.code for stmt in self.params]) + str = "def %s(%s):\n" % (self.name, params) str += super(Function, self).get_code(True, indention) if self.is_empty(): str += "pass\n" return str def get_names(self): - n = self.params + #n = self.params + n = [] + for p in self.params: + n += p.set_vars or p.used_vars n += super(Function, self).get_names() return n @@ -258,32 +273,35 @@ class Flow(Scope): :type indent: int :param line_nr: Line number of the flow statement. :type line_nr: int - :param set_args: Local variables used in the for loop (only there). - :type set_args: list + :param set_vars: Local variables used in the for loop (only there). + :type set_vars: list """ - def __init__(self, command, statement, indent, line_nr, set_args=None): + def __init__(self, command, statement, indent, line_nr, set_vars=None): name = "%s@%s" % (command, line_nr) super(Flow, self).__init__(indent, line_nr, '') self.command = command self.statement = statement - if set_args == None: - self.set_args = [] + if set_vars == None: + self.set_vars = [] else: - self.set_args = set_args + self.set_vars = set_vars self.next = None + def __repr__(self): + return "" % (self.command, self.line_nr) + def get_code(self, first_indent=False, indention=" "): - if self.set_args: - args = ",".join(map(lambda x: x.get_code(), self.set_args)) - args += ' in ' + if self.set_vars: + vars = ",".join(map(lambda x: x.get_code(), self.set_vars)) + vars += ' in ' else: - args = '' + vars = '' if self.statement: stmt = self.statement.get_code(new_line=False) else: stmt = '' - str = "%s %s%s:\n" % (self.command, args, stmt) + str = "%s %s%s:\n" % (self.command, vars, stmt) str += super(Flow, self).get_code(True, indention) if self.next: str += self.next.get_code() @@ -294,7 +312,7 @@ class Flow(Scope): Get the names for the flow. This includes also a call to the super class. """ - n = self.set_args + n = self.set_vars if self.next: n += self.next.get_names() n += super(Flow, self).get_names() @@ -350,6 +368,11 @@ class Import(object): else: return "import " + ns_str + '\n' + def get_names(self): + if self.star: + return [self] + return [self.alias] if self.alias else [self.namespace] + class Statement(object): """ @@ -431,7 +454,8 @@ class PyFuzzyParser(object): class structure of different scopes. """ def __init__(self): - self.top = Scope('global', 0, 0) + # initialize global Scope + self.top = Scope(0, 0) self.scope = self.top self.current = (None, None, None) @@ -521,43 +545,18 @@ class PyFuzzyParser(object): def _parseparen(self): """ Functions and Classes have params (which means for classes - super-classes). They are parsed here and returned as Names. + super-classes). They are parsed here and returned as Statements. - TODO change behaviour, at the moment it's acting pretty weird and - doesn't return list(Name) - :return: List of Names + :return: List of Statements :rtype: list """ - name = '' names = [] - level = 1 + tok = None + while tok not in [')', '\n', ':']: + stmt, tok = self._parse_statement(add_break=',') + if stmt: + names.append(stmt) - while True: - self._parse_statement() - - while True: - break - token_type, tok, indent = self.next() - if tok in (')', ',') and level == 1: - if '=' in name: - pass - else: - name = name.replace(' ', '') - names.append(name.strip()) - name = '' - if tok == '(': - level += 1 - name += "(" - elif tok == ')': - level -= 1 - if level == 0: - break - else: - name += ")" - elif tok == ',' and level == 1: - pass - else: - name += "%s " % str(tok) return names def _parsefunction(self, indent): @@ -666,18 +665,20 @@ class PyFuzzyParser(object): set_vars = [] used_funcs = [] used_vars = [] + level = 0 # The level of parentheses if pre_used_token: token_type, tok, indent = pre_used_token else: token_type, tok, indent = self.next() - breaks = ['\n', ':', ';'] + breaks = ['\n', ':', ';', ')'] if add_break: breaks += add_break + is_break_token = lambda tok: tok in breaks - while not is_break_token(tok): + while not (is_break_token(tok) and level <= 0): set_string = '' #print 'parse_stmt', tok, token.tok_name[token_type] if token_type == tokenize.NAME: @@ -707,10 +708,14 @@ class PyFuzzyParser(object): string += ".".join(path) #print 'parse_stmt', tok, token.tok_name[token_type] continue - elif ('=' in tok and not tok in ['>=', '<=', '==', '!=']): + elif '=' in tok and not tok in ['>=', '<=', '==', '!=']: # there has been an assignement -> change vars set_vars = used_vars used_vars = [] + elif tok in ['{', '(', '[']: + level += 1 + elif tok in ['}', ')', ']']: + level -= 1 if set_string: string = set_string @@ -758,7 +763,7 @@ class PyFuzzyParser(object): % (tok, token_type, indent)) if token_type == tokenize.DEDENT: - print 'dedent' + print 'dedent', self.scope self.scope = self.scope.parent elif tok == 'def': func = self._parsefunction(indent) diff --git a/test.py b/test.py index 034006ca..ea349d09 100644 --- a/test.py +++ b/test.py @@ -10,7 +10,7 @@ from token import OP as OP_TEST, INDENT as INDENT_TEST aaa = 6; bbb = 13 ccc = bbb; d = open("test.py"); -def func(): +def func(a,b,c=3): #def test: # return 2 cdef = A() @@ -27,10 +27,16 @@ class Supi(A, datetime.datetime): static_var = 0 def __init__(): - pass + self.b = A() def test(self): import time print 1 + self.a = 1 + self.b = (1, + 2,[3,2 + ]) + self.c = {1:3, + 4:2,5:9} return A() class A(): @@ -38,7 +44,7 @@ class A(): def test(self): return A() class init: - def __init__(self, a, b=3, c = A()): + def __init__(self, a, b=3, c = A): self.a = a a = A()