Debugger: Fix accessing cell variables in outer scopes
authorMark Florisson <markflorisson88@gmail.com>
Mon, 10 Jan 2011 12:36:07 +0000 (13:36 +0100)
committerMark Florisson <markflorisson88@gmail.com>
Mon, 10 Jan 2011 12:36:07 +0000 (13:36 +0100)
Cython/Compiler/ParseTreeTransforms.py
Cython/Debugger/Tests/codefile
Cython/Debugger/Tests/test_libcython_in_gdb.py
Cython/Debugger/libcython.py

index 59c9a2cd0ce8104b385247cf727b7016e891ef05..e3c7031032ed548ec36cbfd0eeeed710cc5340cc 100644 (file)
@@ -1760,10 +1760,14 @@ class DebugTransform(CythonTransform):
                 qname = '%s.%s.%s' % (entry.scope.outer_scope.qualified_name,
                                       entry.scope.name, 
                                       entry.name)
+            elif entry.in_closure:
+                cname = '%s->%s' % (Naming.cur_scope_cname, 
+                                    entry.cname)
+                qname = entry.qualified_name
             else:
                 cname = entry.cname
                 qname = entry.qualified_name
-                
+
             if not entry.pos:
                 # this happens for variables that are not in the user's code,
                 # e.g. for the global __builtins__, __doc__, etc. We can just
index 4a251e898df5a46b95379fca2f5aece3ec51d305..953ada31946bc515c686143050b9083cbc2dbc9c 100644 (file)
@@ -32,23 +32,16 @@ cdef class SomeClass(object):
     def spam(self):
         pass
 
-def closure():
-    a = 1
+def outer():
+    cdef object a = "an object"
     def inner():
         b = 2
         # access closed over variables
         print a, b
     return inner
 
-def closure_without_closing_variables():
-    a = 1
-    def inner2():
-        b = 2
-        print b
-    return inner2
 
-closure()()
-closure_without_closing_variables()()
+outer()()
 
 spam()
 print "bye!"
\ No newline at end of file
index 5775969af2b69f0426685eafa7d7233a2219edbe..89ff7fdd5674b259f396ec3e902d82cb3a0fd6a7 100644 (file)
@@ -182,6 +182,7 @@ class TestKilled(DebugTestCase):
         output = gdb.execute('cy run', to_string=True)
         assert 'abort' in output.lower()
 
+
 class DebugStepperTestCase(DebugTestCase):
 
     def step(self, varnames_and_values, source_line=None, lineno=None):
@@ -377,19 +378,30 @@ class TestExec(DebugTestCase):
 
 class TestClosure(DebugTestCase):
 
-    def test_cython_closure(self):
-        self.break_and_run('def inner():')
+    def break_and_run_func(self, funcname):
+        gdb.execute('cy break ' + funcname)
+        gdb.execute('cy run')
+
+    def test_inner(self):
+        self.break_and_run_func('inner')
 
         # Allow the Cython-generated code to initialize the scope variable
         gdb.execute('cy step')
 
-        self.assertEqual(str(self.read_var('a')), '1')
+        self.assertEqual(str(self.read_var('a')), "'an object'")
         print_result = gdb.execute('cy print a', to_string=True).strip()
-        self.assertEqual(print_result, 'a = 1')
+        self.assertEqual(print_result, "a = 'an object'")
 
-    def test_cython_closure_no_closing_variables(self):
-        self.break_and_run('def inner2():')
-        self.assertEqual(gdb.execute('cy locals', to_string=True), '')
+    def test_outer(self):
+        self.break_and_run_func('outer')
+
+        # Initialize scope with 'a' uninitialized
+        gdb.execute('cy step')
+
+        # Initialize 'a' to 1
+        gdb.execute('cy step')
+        print_result = gdb.execute('cy print a', to_string=True).strip()
+        self.assertEqual(print_result, "a = 'an object'")
 
 
 _do_debug = os.environ.get('GDB_DEBUG')
index 7ce9c5bc48110afa8427ab4047c1447a228505ce..d5f0c48db67f5e486659faef38efe0edf397589d 100644 (file)
@@ -389,10 +389,20 @@ class CythonBase(object):
                                      value)
 
     def is_initialized(self, cython_func, local_name):
+        islocal = local_name in cython_func.locals
+        if islocal:
+            cyvar = cython_func.locals[local_name]
+            if '->' in cyvar.cname:
+                # Closed over free variable 
+                try:
+                    gdb.parse_and_eval(cyvar.cname)
+                    return True
+                except RuntimeError:
+                    return False
+        
         cur_lineno = self.get_cython_lineno()
         return (local_name in cython_func.arguments or
-                (local_name in cython_func.locals and
-                 cur_lineno > cython_func.locals[local_name].lineno))
+                (islocal and cur_lineno > cyvar.lineno))
 
 class SourceFileDescriptor(object):
     def __init__(self, filename, lexer, formatter=None):