Debugger closure support
authorMark Florisson <markflorisson88@gmail.com>
Sat, 18 Dec 2010 18:51:51 +0000 (19:51 +0100)
committerMark Florisson <markflorisson88@gmail.com>
Sat, 18 Dec 2010 18:51:51 +0000 (19:51 +0100)
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Tests/TestParseTreeTransforms.py
Cython/Debugger/Tests/codefile
Cython/Debugger/Tests/test_libcython_in_gdb.py

index ad3b390babfa29368b09c3bf679402ae20a0f8f6..b982fc08fa7f5ff67bf761878391c3a2f44acc8f 100644 (file)
@@ -1591,6 +1591,11 @@ class DebugTransform(CythonTransform):
         #self.c_output_file = options.output_file 
         self.c_output_file = result.c_file
         
+        # Closure support, basically treat nested functions as if the AST were
+        # never nested
+        self.in_funcdef = False
+        self.nested_funcdefs = []
+        
         # tells visit_NameNode whether it should register step-into functions
         self.register_stepinto = False
         
@@ -1606,6 +1611,8 @@ class DebugTransform(CythonTransform):
         # serialize functions
         self.tb.start('Functions')
         self.visitchildren(node)
+        for nested_funcdef in self.nested_funcdefs:
+            self.visit_FuncDefNode(nested_funcdef)
         self.tb.end('Functions')
         
         # 2.3 compatibility. Serialize global variables
@@ -1625,8 +1632,14 @@ class DebugTransform(CythonTransform):
         # Cython.Compiler.ModuleNode.ModuleNode._serialize_lineno_map
         return node
     
-    def visit_FuncDefNode(self, node):
+    def visit_FuncDefNode(self, node):        
         self.visited.add(node.local_scope.qualified_name)
+
+        if self.in_funcdef:
+            if not self.register_stepinto:
+                self.nested_funcdefs.append(node)
+            return node
+        
         # node.entry.visibility = 'extern'
         if node.py_func is None:
             pf_cname = ''
@@ -1654,7 +1667,9 @@ class DebugTransform(CythonTransform):
 
         self.tb.start('StepIntoFunctions')
         self.register_stepinto = True
+        self.in_funcdef = True
         self.visitchildren(node)
+        self.in_funcdef = False
         self.register_stepinto = False
         self.tb.end('StepIntoFunctions')
         self.tb.end('Function')
index adf8105fc57a695ce7bf527f5fb0345064adcc1e..9361de5828268d69591e1e30ee4bc9322ca5e389 100644 (file)
@@ -182,7 +182,8 @@ class TestDebugTransform(DebuggerTestCase):
             self.assertEqual('PythonObject', xml_globals.get('python_var'))
             
             # test functions
-            funcnames = 'codefile.spam', 'codefile.ham', 'codefile.eggs'
+            funcnames = ('codefile.spam', 'codefile.ham', 'codefile.eggs', 
+                         'codefile.closure', 'codefile.inner')
             required_xml_attrs = 'name', 'cname', 'qualified_name'
             assert all([f in xml_funcs for f in funcnames])
             spam, ham, eggs = [xml_funcs[funcname] for funcname in funcnames]
index 53d6518d551302ecca2dc17facc91b984f1e4d97..95279818dd6c1284c15b2a85b92120809222df35 100644 (file)
@@ -21,16 +21,22 @@ def spam(a=0):
     puts("spam")
     os.path.join("foo", "bar")
     some_c_function()
+
+cpdef eggs():
+    pass    
     
 cdef ham():
     pass
     
-cpdef eggs():
-    pass
-
 cdef class SomeClass(object):
     def spam(self):
         pass
 
+def closure():
+    a = 1
+    def inner():
+        b = 2
+    return inner
+
 spam()
 print "bye!"
index 2c9e7ef5eb55363681f1c6ba683cc2ecb557482e..b68d36c746385bc3acdb8428473dbf9f9272c401 100644 (file)
@@ -98,7 +98,7 @@ class TestDebugInformationClasses(DebugTestCase):
                          'codefile.SomeClass.spam')
         self.assertEqual(self.spam_func.module, self.module)
         
-        assert self.eggs_func.pf_cname
+        assert self.eggs_func.pf_cname, (self.eggs_func, self.eggs_func.pf_cname)
         assert not self.ham_func.pf_cname
         assert not self.spam_func.pf_cname
         assert not self.spam_meth.pf_cname