Backed out changeset 291e2bdd20d5 - currently breaks Sage build
authorStefan Behnel <scoder@users.berlios.de>
Thu, 30 Dec 2010 00:22:20 +0000 (01:22 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 30 Dec 2010 00:22:20 +0000 (01:22 +0100)
Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Tests/TestDecorators.py [new file with mode: 0644]

index 0e7af2d449b1c594aa774f6e0fe4776a13b3c8b5..92c051acf7fc422f2b0813b302f0f3d427399904 100644 (file)
@@ -2252,13 +2252,6 @@ class DefNode(FuncDefNode):
             if not self.is_staticmethod and not self.is_classmethod:
                 rhs.binding = True
 
-        if self.decorators:
-            for decorator in self.decorators[::-1]:
-                rhs = ExprNodes.SimpleCallNode(
-                    decorator.pos,
-                    function = decorator.decorator,
-                    args = [rhs])
-
         self.assmt = SingleAssignmentNode(self.pos,
             lhs = ExprNodes.NameNode(self.pos, name = self.name),
             rhs = rhs)
@@ -2974,9 +2967,8 @@ class PyClassDefNode(ClassDefNode):
     #  classobj ClassNode  Class object
     #  target   NameNode   Variable to assign class object to
 
-    child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", "target"]
+    child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "classobj", "target"]
     decorators = None
-    class_result = None
     py3_style_class = False # Python3 style class (bases+kwargs)
 
     def __init__(self, pos, name, bases, doc, body, decorators = None,
@@ -3079,16 +3071,6 @@ class PyClassDefNode(ClassDefNode):
         return cenv
 
     def analyse_declarations(self, env):
-        class_result = self.classobj
-        if self.decorators:
-            from ExprNodes import SimpleCallNode
-            for decorator in self.decorators[::-1]:
-                class_result = SimpleCallNode(
-                    decorator.pos,
-                    function = decorator.decorator,
-                    args = [class_result])
-        self.class_result = class_result
-        self.class_result.analyse_declarations(env)
         self.target.analyse_target_declaration(env)
         cenv = self.create_scope(env)
         cenv.directives = env.directives
@@ -3101,7 +3083,7 @@ class PyClassDefNode(ClassDefNode):
             self.metaclass.analyse_expressions(env)
             self.mkw.analyse_expressions(env)
         self.dict.analyse_expressions(env)
-        self.class_result.analyse_expressions(env)
+        self.classobj.analyse_expressions(env)
         genv = env.global_scope()
         cenv = self.scope
         self.body.analyse_expressions(cenv)
@@ -3121,9 +3103,9 @@ class PyClassDefNode(ClassDefNode):
         self.dict.generate_evaluation_code(code)
         cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
         self.body.generate_execution_code(code)
-        self.class_result.generate_evaluation_code(code)
+        self.classobj.generate_evaluation_code(code)
         cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
-        self.target.generate_assignment_code(self.class_result, code)
+        self.target.generate_assignment_code(self.classobj, code)
         self.dict.generate_disposal_code(code)
         self.dict.free_temps(code)
         if self.py3_style_class:
@@ -3182,9 +3164,6 @@ class CClassDefNode(ClassDefNode):
         if env.in_cinclude and not self.objstruct_name:
             error(self.pos, "Object struct name specification required for "
                 "C class defined in 'extern from' block")
-        if self.decorators:
-            error(self.pos,
-                  "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name)
         self.base_type = None
         # Now that module imports are cached, we need to
         # import the modules for extern classes.
index 166ceec766bedd87b4996e034ee2451320229a6b..76e7ea97ed708639dc30c32bf21a472e2acca0c3 100644 (file)
@@ -945,23 +945,39 @@ class WithTransform(CythonTransform, SkipDeclarations):
         return node
 
 
-class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations):
-    """Originally, this was the only place where decorators were
-    transformed into the corresponding calling code.  Now, this is
-    done directly in DefNode and PyClassDefNode to avoid reassignments
-    to the function/class name - except for cdef class methods.  For
-    those, the reassignment is required as methods are originally
-    defined in the PyMethodDef struct.
-    """
+class DecoratorTransform(CythonTransform, SkipDeclarations):
 
     def visit_DefNode(self, func_node):
-        scope_type = self.scope_type
-        func_node = self.visit_FuncDefNode(func_node)
-        if scope_type is not 'cclass' or not func_node.decorators:
+        self.visitchildren(func_node)
+        if not func_node.decorators:
             return func_node
         return self._handle_decorators(
             func_node, func_node.name)
 
+    def visit_CClassDefNode(self, class_node):
+        # This doesn't currently work, so it's disabled.
+        #
+        # Problem: assignments to cdef class names do not work.  They
+        # would require an additional check anyway, as the extension
+        # type must not change its C type, so decorators cannot
+        # replace an extension type, just alter it and return it.
+
+        self.visitchildren(class_node)
+        if not class_node.decorators:
+            return class_node
+        error(class_node.pos,
+              "Decorators not allowed on cdef classes (used on type '%s')" % class_node.class_name)
+        return class_node
+        #return self._handle_decorators(
+        #    class_node, class_node.class_name)
+
+    def visit_ClassDefNode(self, class_node):
+        self.visitchildren(class_node)
+        if not class_node.decorators:
+            return class_node
+        return self._handle_decorators(
+            class_node, class_node.name)
+
     def _handle_decorators(self, node, name):
         decorator_result = ExprNodes.NameNode(node.pos, name = name)
         for decorator in node.decorators[::-1]:
diff --git a/Cython/Compiler/Tests/TestDecorators.py b/Cython/Compiler/Tests/TestDecorators.py
new file mode 100644 (file)
index 0000000..5b9286f
--- /dev/null
@@ -0,0 +1,25 @@
+import unittest
+from Cython.TestUtils import TransformTest
+from Cython.Compiler.ParseTreeTransforms import DecoratorTransform
+
+class TestDecorator(TransformTest):
+
+    def test_decorator(self):
+        t = self.run_pipeline([DecoratorTransform(None)], u"""
+        def decorator(fun):
+            return fun
+        @decorator
+        def decorated():
+            pass
+        """)
+
+        self.assertCode(u"""
+        def decorator(fun):
+            return fun
+        def decorated():
+            pass
+        decorated = decorator(decorated)
+        """, t)
+
+if __name__ == '__main__':
+    unittest.main()