PEP-0318, @decorator-style. In Guido's words:

"@ seems the syntax that everybody can hate equally"
Implementation by Mark Russell, from SF #979728.
This commit is contained in:
Anthony Baxter 2004-08-02 06:10:11 +00:00
parent fd7dc5169c
commit c2a5a63654
28 changed files with 2965 additions and 2335 deletions

File diff suppressed because it is too large Load diff

View file

@ -366,6 +366,13 @@ class CodeGenerator:
self._visitFuncOrLambda(node, isLambda=1)
def _visitFuncOrLambda(self, node, isLambda=0):
if not isLambda and node.decorators:
for decorator in reversed(node.decorators.nodes):
self.visit(decorator)
ndecorators = len(node.decorators.nodes)
else:
ndecorators = 0
gen = self.FunctionGen(node, self.scopes, isLambda,
self.class_name, self.get_module())
walk(node.code, gen)
@ -382,6 +389,9 @@ class CodeGenerator:
else:
self.emit('LOAD_CONST', gen)
self.emit('MAKE_FUNCTION', len(node.defaults))
for i in range(ndecorators):
self.emit('CALL_FUNCTION', 1)
def visitClass(self, node):
gen = self.ClassGen(node, self.scopes,

View file

@ -224,6 +224,8 @@ class SymbolVisitor:
visitExpression = visitModule
def visitFunction(self, node, parent):
if node.decorators:
self.visit(node.decorators, parent)
parent.add_def(node.name)
for n in node.defaults:
self.visit(n, parent)

View file

@ -185,29 +185,81 @@ class Transformer:
### is this sufficient?
return Expression(self.com_node(nodelist[0]))
def decorator_name(self, nodelist):
listlen = len(nodelist)
assert listlen >= 1 and listlen % 2 == 1
item = self.atom_name(nodelist)
i = 1
while i < listlen:
assert nodelist[i][0] == token.DOT
assert nodelist[i + 1][0] == token.NAME
item = Getattr(item, nodelist[i + 1][1])
i += 2
return item
def decorator(self, nodelist):
# '@' dotted_name [ '(' [arglist] ')' ]
assert len(nodelist) in (2, 4, 5)
assert nodelist[0][0] == token.AT
assert nodelist[1][0] == symbol.dotted_name
funcname = self.decorator_name(nodelist[1][1:])
if len(nodelist) > 2:
assert nodelist[2][0] == token.LPAR
expr = self.com_call_function(funcname, nodelist[3])
else:
expr = funcname
return expr
def decorators(self, nodelist):
# decorators: decorator ([NEWLINE] decorator)* NEWLINE
listlen = len(nodelist)
i = 0
items = []
while i < listlen:
assert nodelist[i][0] == symbol.decorator
items.append(self.decorator(nodelist[i][1:]))
i += 1
if i < listlen and nodelist[i][0] == token.NEWLINE:
i += 1
return Decorators(items)
def funcdef(self, nodelist):
# funcdef: 'def' NAME parameters ':' suite
# -6 -5 -4 -3 -2 -1
# funcdef: [decorators] 'def' NAME parameters ':' suite
# parameters: '(' [varargslist] ')'
lineno = nodelist[1][2]
name = nodelist[1][1]
args = nodelist[2][2]
if len(nodelist) == 6:
assert nodelist[0][0] == symbol.decorators
decorators = self.decorators(nodelist[0][1:])
else:
assert len(nodelist) == 5
decorators = None
lineno = nodelist[-4][2]
name = nodelist[-4][1]
args = nodelist[-3][2]
if args[0] == symbol.varargslist:
names, defaults, flags = self.com_arglist(args[1:])
else:
names = defaults = ()
flags = 0
doc = self.get_docstring(nodelist[4])
doc = self.get_docstring(nodelist[-1])
# code for function
code = self.com_node(nodelist[4])
code = self.com_node(nodelist[-1])
if doc is not None:
assert isinstance(code, Stmt)
assert isinstance(code.nodes[0], Discard)
del code.nodes[0]
n = Function(name, names, defaults, flags, doc, code)
n = Function(decorators, name, names, defaults, flags, doc, code)
n.lineno = lineno
return n