parser decorators

This commit is contained in:
David Halter
2012-03-05 23:04:11 +01:00
parent 057731916f
commit 8d85154fe9
3 changed files with 47 additions and 25 deletions

View File

@@ -249,6 +249,10 @@ for s in cmpl.parser.top.subscopes[2].subscopes:
names = s.get_set_vars() names = s.get_set_vars()
handle_names(names) handle_names(names)
print
print 'start/end'
for s in cmpl.parser.top.subscopes:
print repr(s)
p = cmpl.parser p = cmpl.parser
s = p.top s = p.top

View File

@@ -30,6 +30,8 @@ Ignored statements:
TODO take special care for future imports TODO take special care for future imports
TODO check meta classes TODO check meta classes
TODO evaluate options to either replace tokenize or change its behavior for
multiline parentheses (if they don't close, there must be a break somewhere)
""" """
import tokenize import tokenize
@@ -71,10 +73,12 @@ class Scope(object):
self.parent = None self.parent = None
self.indent = indent self.indent = indent
self.line_nr = line_nr self.line_nr = line_nr
self.line_end = None
def add_scope(self, sub): def add_scope(self, sub, decorators):
# print 'push scope: [%s@%s]' % (sub.line_nr, sub.indent) # print 'push scope: [%s@%s]' % (sub.line_nr, sub.indent)
sub.parent = self sub.parent = self
sub.decorators = decorators
self.subscopes.append(sub) self.subscopes.append(sub)
return sub return sub
@@ -181,6 +185,15 @@ class Scope(object):
""" """
return not (self.imports or self.subscopes or self.statements) return not (self.imports or self.subscopes or self.statements)
def __repr__(self):
try:
name = self.name
except:
name = self.command
return "<%s: %s@%s-%s>" % \
(self.__class__.__name__, name, self.line_nr, self.line_end)
class Class(Scope): class Class(Scope):
""" """
@@ -201,12 +214,11 @@ class Class(Scope):
super(Class, self).__init__(indent, line_nr, docstr) super(Class, self).__init__(indent, line_nr, docstr)
self.name = name self.name = name
self.supers = supers self.supers = supers
self.decorators = []
def __repr__(self):
return "<Class instance: %s@%s>" % (self.name, self.line_nr)
def get_code(self, first_indent=False, indention=" "): def get_code(self, first_indent=False, indention=" "):
str = 'class %s' % (self.name) str = "\n".join('@' + stmt.get_code() for stmt in self.decorators)
str += 'class %s' % (self.name)
if len(self.supers) > 0: if len(self.supers) > 0:
sup = ','.join(stmt.code for stmt in self.supers) sup = ','.join(stmt.code for stmt in self.supers)
str += '(%s)' % sup str += '(%s)' % sup
@@ -254,13 +266,12 @@ class Function(Scope):
Scope.__init__(self, indent, line_nr, docstr) Scope.__init__(self, indent, line_nr, docstr)
self.name = name self.name = name
self.params = params self.params = params
self.decorators = []
def __repr__(self):
return "<Function instance: %s@%s>" % (self.name, self.line_nr)
def get_code(self, first_indent=False, indention=" "): def get_code(self, first_indent=False, indention=" "):
str = "\n".join('@' + stmt.get_code() for stmt in self.decorators)
params = ','.join([stmt.code for stmt in self.params]) params = ','.join([stmt.code for stmt in self.params])
str = "def %s(%s):\n" % (self.name, params) str += "def %s(%s):\n" % (self.name, params)
str += super(Function, self).get_code(True, indention) str += super(Function, self).get_code(True, indention)
if self.is_empty(): if self.is_empty():
str += "pass\n" str += "pass\n"
@@ -300,7 +311,6 @@ class Flow(Scope):
:type set_vars: list :type set_vars: list
""" """
def __init__(self, command, statement, indent, line_nr, set_vars=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, '') super(Flow, self).__init__(indent, line_nr, '')
self.command = command self.command = command
self.statement = statement self.statement = statement
@@ -310,9 +320,6 @@ class Flow(Scope):
self.set_vars = set_vars self.set_vars = set_vars
self.next = None self.next = None
def __repr__(self):
return "<Flow instance: %s@%s>" % (self.command, self.line_nr)
def get_code(self, first_indent=False, indention=" "): def get_code(self, first_indent=False, indention=" "):
if self.set_vars: if self.set_vars:
vars = ",".join(map(lambda x: x.get_code(), self.set_vars)) vars = ",".join(map(lambda x: x.get_code(), self.set_vars))
@@ -785,12 +792,13 @@ class PyFuzzyParser(object):
self.gen = tokenize.generate_tokens(buf.readline) self.gen = tokenize.generate_tokens(buf.readline)
self.currentscope = self.scope self.currentscope = self.scope
try:
extended_flow = ['else', 'except', 'finally'] extended_flow = ['else', 'except', 'finally']
statement_toks = ['{', '[', '(', '`'] statement_toks = ['{', '[', '(', '`']
decorators = []
freshscope = True freshscope = True
while True: while True:
try:
token_type, tok, indent = self.next() token_type, tok, indent = self.next()
dbg('main: tok=[%s] type=[%s] indent=[%s]'\ dbg('main: tok=[%s] type=[%s] indent=[%s]'\
% (tok, token_type, indent)) % (tok, token_type, indent))
@@ -799,16 +807,18 @@ class PyFuzzyParser(object):
print 'dedent', self.scope print 'dedent', self.scope
token_type, tok, indent = self.next() token_type, tok, indent = self.next()
if indent <= self.scope.indent: if indent <= self.scope.indent:
self.scope.line_end = self.line_nr
self.scope = self.scope.parent self.scope = self.scope.parent
# check again for unindented stuff. this is true for syntax # check again for unindented stuff. this is true for syntax
# errors. only check for names, because thats relevant here. If # errors. only check for names, because thats relevant here. If
# some docstrings are not indented, I don't care. # some docstrings are not indented, I don't care.
if indent <= self.scope.indent \ while indent <= self.scope.indent \
and token_type in [tokenize.NAME] \ and token_type in [tokenize.NAME] \
and self.scope != self.top: and self.scope != self.top:
print 'syntax_err, dedent @%s - %s<=%s', \ print 'syntax_err, dedent @%s - %s<=%s', \
(self.line_nr, indent, self.scope.indent) (self.line_nr, indent, self.scope.indent)
self.scope.line_end = self.line_nr
self.scope = self.scope.parent self.scope = self.scope.parent
if tok == 'def': if tok == 'def':
@@ -818,14 +828,16 @@ class PyFuzzyParser(object):
continue continue
dbg("new scope: function %s" % (func.name)) dbg("new scope: function %s" % (func.name))
freshscope = True freshscope = True
self.scope = self.scope.add_scope(func) self.scope = self.scope.add_scope(func, decorators)
decorators = []
elif tok == 'class': elif tok == 'class':
cls = self._parseclass(indent) cls = self._parseclass(indent)
if cls is None: if cls is None:
continue continue
freshscope = True freshscope = True
dbg("new scope: class %s" % (cls.name)) dbg("new scope: class %s" % (cls.name))
self.scope = self.scope.add_scope(cls) self.scope = self.scope.add_scope(cls, decorators)
decorators = []
# import stuff # import stuff
elif tok == 'import': elif tok == 'import':
imports = self._parseimportlist() imports = self._parseimportlist()
@@ -891,6 +903,10 @@ class PyFuzzyParser(object):
# add the global to the top, because there it is # add the global to the top, because there it is
# important. # important.
self.top.add_global(name) self.top.add_global(name)
# decorator
elif tok == '@':
stmt, tok = self._parse_statement()
decorators.append(stmt)
elif tok == 'pass': elif tok == 'pass':
continue continue
# check for docstrings # check for docstrings
@@ -908,7 +924,7 @@ class PyFuzzyParser(object):
#else: #else:
#print "_not_implemented_", tok, self.parserline #print "_not_implemented_", tok, self.parserline
except StopIteration: # thrown on EOF except StopIteration: # thrown on EOF
pass break
#except StopIteration: #except StopIteration:
# dbg("parse error: %s, %s @ %s" % # dbg("parse error: %s, %s @ %s" %
# (sys.exc_info()[0], sys.exc_info()[1], self.parserline)) # (sys.exc_info()[0], sys.exc_info()[1], self.parserline))

View File

@@ -56,11 +56,12 @@ c = a or c
class Empty(): class Empty():
pass pass
#def blub(): def blub():
cdef = 5 cdef = 5
cdef cdef cdef cdef
for i in range(3): for i in range(3):
if 1:if 2:for a in range(3): exec a
asdf = aaa asdf = aaa
print 'blub' print 'blub'
else: else:
@@ -81,6 +82,7 @@ def ass_test(a):
return result return result
matrix = [[1,2,3], [4,5,6], [7,8,9]] matrix = [[1,2,3], [4,5,6], [7,8,9]]
@property
def flow_test(a): def flow_test(a):
global matrix global matrix
for i in matrix: for i in matrix: