Support class closures and nested classes.
authorVitja Makarov <vitja.makarov@gmail.com>
Thu, 18 Nov 2010 23:28:12 +0000 (02:28 +0300)
committerVitja Makarov <vitja.makarov@gmail.com>
Thu, 18 Nov 2010 23:28:12 +0000 (02:28 +0300)
Disable some pyregr tests. As side effect this seems to solve ticket #537

Cython/Compiler/Nodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.py
tests/bugs.txt

index 766d88d22732d08692784b4088df7a3f47af3192..794b7c518ab5c992c41dbe8ce7aa1ef344f6f005 100644 (file)
@@ -1177,7 +1177,7 @@ class FuncDefNode(StatNode, BlockNode):
     def create_local_scope(self, env):
         genv = env
         while genv.is_py_class_scope or genv.is_c_class_scope:
-            genv = env.outer_scope
+            genv = genv.outer_scope
         if self.needs_closure:
             lenv = ClosureScope(name=self.entry.name,
                                 outer_scope = genv,
@@ -1255,11 +1255,15 @@ class FuncDefNode(StatNode, BlockNode):
         self.generate_function_header(code,
             with_pymethdef = with_pymethdef)
         # ----- Local variable declarations
+        # Find function scope
+        cenv = env
+        while cenv.is_py_class_scope or cenv.is_c_class_scope:
+            cenv = cenv.outer_scope
         if lenv.is_closure_scope:
             code.put(lenv.scope_class.type.declaration_code(Naming.cur_scope_cname))
             code.putln(";")
-        elif env.is_closure_scope:
-            code.put(env.scope_class.type.declaration_code(Naming.outer_scope_cname))
+        elif cenv.is_closure_scope:
+            code.put(cenv.scope_class.type.declaration_code(Naming.outer_scope_cname))
             code.putln(";")
         self.generate_argument_declarations(lenv, code)
         for entry in lenv.var_entries:
@@ -1310,14 +1314,14 @@ class FuncDefNode(StatNode, BlockNode):
             code.putln("}")
             code.put_gotref(Naming.cur_scope_cname)
             # Note that it is unsafe to decref the scope at this point.
-        if env.is_closure_scope:
+        if cenv.is_closure_scope:
             code.putln("%s = (%s)%s;" % (
                             outer_scope_cname,
-                            env.scope_class.type.declaration_code(''),
+                            cenv.scope_class.type.declaration_code(''),
                             Naming.self_cname))
             if self.needs_closure:
                 # inner closures own a reference to their outer parent
-                code.put_incref(outer_scope_cname, env.scope_class.type)
+                code.put_incref(outer_scope_cname, cenv.scope_class.type)
                 code.put_giveref(outer_scope_cname)
         # ----- Trace function call
         if profile:
@@ -2211,18 +2215,21 @@ class DefNode(FuncDefNode):
 
     def synthesize_assignment_node(self, env):
         import ExprNodes
-        if env.is_py_class_scope:
-            rhs = ExprNodes.PyCFunctionNode(self.pos,
-                        pymethdef_cname = self.entry.pymethdef_cname)
-            if not self.is_staticmethod and not self.is_classmethod:
-                rhs.binding = True
+        genv = env
+        while genv.is_py_class_scope or genv.is_c_class_scope:
+            genv = genv.outer_scope
 
-        elif env.is_closure_scope:
+        if genv.is_closure_scope:
             rhs = ExprNodes.InnerFunctionNode(
                 self.pos, pymethdef_cname = self.entry.pymethdef_cname)
         else:
             rhs = ExprNodes.PyCFunctionNode(
                 self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding'])
+
+        if env.is_py_class_scope:
+            if not self.is_staticmethod and not self.is_classmethod:
+                rhs.binding = True
+
         self.assmt = SingleAssignmentNode(self.pos,
             lhs = ExprNodes.NameNode(self.pos, name = self.name),
             rhs = rhs)
@@ -3036,8 +3043,8 @@ class PyClassDefNode(ClassDefNode):
         
     def create_scope(self, env):
         genv = env
-        while env.is_py_class_scope or env.is_c_class_scope:
-            env = env.outer_scope
+        while genv.is_py_class_scope or genv.is_c_class_scope:
+            genv = genv.outer_scope
         cenv = self.scope = PyClassScope(name = self.name, outer_scope = genv)
         return cenv
     
index 9f5037fc53328599a89273855a11c3bba8f257c7..f3dc0c9debf87a2318af0f84fc66fbeca2a1527c 100644 (file)
@@ -1325,7 +1325,7 @@ class CreateClosureClasses(CythonTransform):
         return node
 
     def create_class_from_scope(self, node, target_module_scope):
-        as_name = "%s%s" % (Naming.closure_class_prefix, node.entry.cname)
+        as_name = '%s_%s' % (target_module_scope.next_id(Naming.closure_class_prefix), node.entry.cname)
         func_scope = node.local_scope
 
         entry = target_module_scope.declare_c_class(name = as_name,
@@ -1334,11 +1334,15 @@ class CreateClosureClasses(CythonTransform):
         class_scope = entry.type.scope
         class_scope.is_internal = True
         class_scope.directives = {'final': True}
-        if node.entry.scope.is_closure_scope:
+
+        cscope = node.entry.scope
+        while cscope.is_py_class_scope or cscope.is_c_class_scope:
+            cscope = cscope.outer_scope
+        if cscope.is_closure_scope:
             class_scope.declare_var(pos=node.pos,
                                     name=Naming.outer_scope_cname, # this could conflict?
                                     cname=Naming.outer_scope_cname,
-                                    type=node.entry.scope.scope_class.type,
+                                    type=cscope.scope_class.type,
                                     is_cdef=True)
         entries = func_scope.entries.items()
         entries.sort()
index 76847c28364d5bffa68542722c5f8524d6a02d31..4995bbdf1a3c9641872f3b46745a7e988f750863 100644 (file)
@@ -1740,7 +1740,7 @@ def p_statement(s, ctx, first_statement = 0):
             s.level = ctx.level
             return p_def_statement(s, decorators)
         elif s.sy == 'class':
-            if ctx.level != 'module':
+            if ctx.level not in ('module', 'function', 'class', 'other'):
                 s.error("class definition not allowed here")
             return p_class_statement(s, decorators)
         elif s.sy == 'include':
index 2f65cf15e48fbd6cdca543c092065d9f1aeff5d3..c9baa4fcb952f868be7a1c42ad87ca49dd0b9100 100644 (file)
@@ -23,6 +23,8 @@ closure_class_T596
 pyregr.test_threadsignals
 pyregr.test_module
 pyregr.test_capi
+pyregr.test_socket
+pyregr.test_threading
 
 # CPython regression tests that don't make sense
 pyregr.test_gdb