From: <th...@us...> - 2008-10-20 17:20:08
|
Revision: 5482 http://jython.svn.sourceforge.net/jython/?rev=5482&view=rev Author: thobes Date: 2008-10-20 17:19:57 +0000 (Mon, 20 Oct 2008) Log Message: ----------- Added support for class decorators. The test file added for this (test_classdecorators) should be removed when we import test_decorators from CPython 3.x, because that is where the caes come from. This is also documented in that file. Modified Paths: -------------- trunk/jython/Lib/test/test_ast.py trunk/jython/ast/Python.asdl trunk/jython/grammar/Python.g trunk/jython/grammar/PythonPartial.g trunk/jython/src/org/python/antlr/GrammarActions.java trunk/jython/src/org/python/antlr/ast/ClassDef.java trunk/jython/src/org/python/compiler/CodeCompiler.java Added Paths: ----------- trunk/jython/Lib/test/test_classdecorators.py Modified: trunk/jython/Lib/test/test_ast.py =================================================================== --- trunk/jython/Lib/test/test_ast.py 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/Lib/test/test_ast.py 2008-10-20 17:19:57 UTC (rev 5482) @@ -168,14 +168,15 @@ (eval_tests, eval_results, "eval")): for i, o in itertools.izip(input, output): ast_tree = compile(i, "?", kind, 0x400) - assert to_tuple(ast_tree) == o + assert to_tuple(ast_tree) == o, "expected %s, got %s" % ( + o, to_tuple(ast_tree)) test_order(ast_tree, (0, 0)) # XXX: AugStore added for Jython. Short term it is too hard to emit just "Store" as CPython does. #### EVERYTHING BELOW IS GENERATED ##### exec_results = [ ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, []), [('Pass', (1, 9))], [])]), -('Module', [('ClassDef', (1, 0), 'C', [], [('Pass', (1, 8))])]), +('Module', [('ClassDef', (1, 0), 'C', [], [('Pass', (1, 8))],[])]), ('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], None, None, []), [('Return', (1, 8), ('Num', (1, 15), 1))], [])]), ('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])]), ('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Num', (1, 4), 1))]), Added: trunk/jython/Lib/test/test_classdecorators.py =================================================================== --- trunk/jython/Lib/test/test_classdecorators.py (rev 0) +++ trunk/jython/Lib/test/test_classdecorators.py 2008-10-20 17:19:57 UTC (rev 5482) @@ -0,0 +1,46 @@ +# This test is temporary until we can import test_decorators from CPython 3.x +# The reason for not doing that already is that in Python 3.x the name of a +# function is stored in func.__name__, in 2.x it's func.func_name +import unittest +from test import test_support + +class TestClassDecorators(unittest.TestCase): + + def test_simple(self): + def plain(x): + x.extra = 'Hello' + return x + @plain + class C(object): pass + self.assertEqual(C.extra, 'Hello') + + def test_double(self): + def ten(x): + x.extra = 10 + return x + def add_five(x): + x.extra += 5 + return x + + @add_five + @ten + class C(object): pass + self.assertEqual(C.extra, 15) + + def test_order(self): + def applied_first(x): + x.extra = 'first' + return x + def applied_second(x): + x.extra = 'second' + return x + @applied_second + @applied_first + class C(object): pass + self.assertEqual(C.extra, 'second') + +def test_main(): + test_support.run_unittest(TestClassDecorators) + +if __name__ == '__main__': + test_main() Modified: trunk/jython/ast/Python.asdl =================================================================== --- trunk/jython/ast/Python.asdl 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/ast/Python.asdl 2008-10-20 17:19:57 UTC (rev 5482) @@ -11,7 +11,8 @@ stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorators) - | ClassDef(identifier name, expr* bases, stmt* body) + | ClassDef(identifier name, expr* bases, + stmt* body, expr* decorators) | Return(expr? value) | Delete(expr* targets) Modified: trunk/jython/grammar/Python.g =================================================================== --- trunk/jython/grammar/Python.g 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/grammar/Python.g 2008-10-20 17:19:57 UTC (rev 5482) @@ -800,7 +800,7 @@ | for_stmt | try_stmt | with_stmt - | funcdef + | (decorators? DEF) => funcdef | classdef ; @@ -1421,10 +1421,16 @@ @after { $classdef.tree = stype; } - : CLASS NAME (LPAREN testlist[expr_contextType.Load]? RPAREN)? COLON suite[false] + : decorators? CLASS NAME (LPAREN testlist[expr_contextType.Load]? RPAREN)? COLON suite[false] { - stype = new ClassDef($CLASS, actions.cantBeNone($NAME), actions.makeBases(actions.castExpr($testlist.tree)), - actions.castStmts($suite.stypes)); + Token t = $CLASS; + if ($decorators.start != null) { + t = $decorators.start; + } + stype = new ClassDef(t, actions.cantBeNone($NAME), + actions.makeBases(actions.castExpr($testlist.tree)), + actions.castStmts($suite.stypes), + actions.castExprs($decorators.etypes)); } ; Modified: trunk/jython/grammar/PythonPartial.g =================================================================== --- trunk/jython/grammar/PythonPartial.g 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/grammar/PythonPartial.g 2008-10-20 17:19:57 UTC (rev 5482) @@ -298,7 +298,7 @@ | for_stmt | try_stmt | with_stmt - | funcdef + | (decorators? DEF) => funcdef | classdef ; @@ -455,7 +455,7 @@ dictmaker : test COLON test (options {k=2;}:COMMA test COLON test)* (COMMA)? ; -classdef: CLASS NAME (LPAREN testlist? RPAREN)? COLON suite +classdef: decorators? CLASS NAME (LPAREN testlist? RPAREN)? COLON suite ; arglist : argument (COMMA argument)* Modified: trunk/jython/src/org/python/antlr/GrammarActions.java =================================================================== --- trunk/jython/src/org/python/antlr/GrammarActions.java 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/src/org/python/antlr/GrammarActions.java 2008-10-20 17:19:57 UTC (rev 5482) @@ -489,14 +489,15 @@ return new Interactive(t, s); } - stmtType makeClassDef(PythonTree t, PythonTree nameToken, List bases, List body) { + stmtType makeClassDef(PythonTree t, PythonTree nameToken, List bases, List body, List decorators) { if (nameToken == null) { return errorHandler.errorStmt(t); } cantBeNone(nameToken); exprType[] b = castExprs(bases); stmtType[] s = castStmts(body); - return new ClassDef(t, nameToken.getText(), b, s); + exprType[] d = castExprs(decorators); + return new ClassDef(t, nameToken.getText(), b, s, d); } stmtType makeTryExcept(PythonTree t, List body, List handlers, List orelse, List finBody) { Modified: trunk/jython/src/org/python/antlr/ast/ClassDef.java =================================================================== --- trunk/jython/src/org/python/antlr/ast/ClassDef.java 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/src/org/python/antlr/ast/ClassDef.java 2008-10-20 17:19:57 UTC (rev 5482) @@ -10,11 +10,13 @@ public String name; public exprType[] bases; public stmtType[] body; + public exprType[] decorators; - public static final String[] _fields = new String[] {"name","bases","body"}; + public static final String[] _fields = new String[] + {"name","bases","body","decorators"}; public ClassDef(Token token, String name, exprType[] bases, stmtType[] - body) { + body, exprType[] decorators) { super(token); this.name = name; this.bases = bases; @@ -29,10 +31,16 @@ addChild(body[ibody]); } } + this.decorators = decorators; + if (decorators != null) { + for(int idecorators=0;idecorators<decorators.length;idecorators++) { + addChild(decorators[idecorators]); + } + } } public ClassDef(int ttype, Token token, String name, exprType[] bases, - stmtType[] body) { + stmtType[] body, exprType[] decorators) { super(ttype, token); this.name = name; this.bases = bases; @@ -47,10 +55,16 @@ addChild(body[ibody]); } } + this.decorators = decorators; + if (decorators != null) { + for(int idecorators=0;idecorators<decorators.length;idecorators++) { + addChild(decorators[idecorators]); + } + } } public ClassDef(PythonTree tree, String name, exprType[] bases, stmtType[] - body) { + body, exprType[] decorators) { super(tree); this.name = name; this.bases = bases; @@ -65,6 +79,12 @@ addChild(body[ibody]); } } + this.decorators = decorators; + if (decorators != null) { + for(int idecorators=0;idecorators<decorators.length;idecorators++) { + addChild(decorators[idecorators]); + } + } } public String toString() { @@ -82,6 +102,9 @@ sb.append("body="); sb.append(dumpThis(body)); sb.append(","); + sb.append("decorators="); + sb.append(dumpThis(decorators)); + sb.append(","); sb.append(")"); return sb.toString(); } @@ -103,6 +126,12 @@ body[i].accept(visitor); } } + if (decorators != null) { + for (int i = 0; i < decorators.length; i++) { + if (decorators[i] != null) + decorators[i].accept(visitor); + } + } } public int getLineno() { Modified: trunk/jython/src/org/python/compiler/CodeCompiler.java =================================================================== --- trunk/jython/src/org/python/compiler/CodeCompiler.java 2008-10-20 11:50:13 UTC (rev 5481) +++ trunk/jython/src/org/python/compiler/CodeCompiler.java 2008-10-20 17:19:57 UTC (rev 5482) @@ -422,19 +422,18 @@ } set(new Name(node, node.name, expr_contextType.Store)); - doDecorators(node); + doDecorators(node, node.decorators, node.name); return null; } - private void doDecorators(FunctionDef func) throws Exception { - if (func.decorators.length > 0) { - exprType currentExpr = new Name(func, func.name, expr_contextType.Load); - exprType[] decs = func.decorators; + private void doDecorators(stmtType node, exprType[] decs, String name) throws Exception { + if (decs.length > 0) { + exprType currentExpr = new Name(node, name, expr_contextType.Load); for (int i=decs.length - 1;i > -1;i--) { - currentExpr = new Call(func, decs[i], new exprType[]{currentExpr}, new keywordType[0], null, null); + currentExpr = new Call(node, decs[i], new exprType[]{currentExpr}, new keywordType[0], null, null); } visit(currentExpr); - set(new Name(func, func.name, expr_contextType.Store)); + set(new Name(node, name, expr_contextType.Store)); } } @@ -2007,6 +2006,7 @@ //Assign this new class to the given name set(new Name(node, node.name, expr_contextType.Store)); + doDecorators(node, node.decorators, node.name); return null; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |