From 09c4d9a3fb43d6a438a93134a03a03c34cd9f132 Mon Sep 17 00:00:00 2001 From: Mark Florisson Date: Mon, 10 Jan 2011 13:36:07 +0100 Subject: [PATCH] Debugger: Fix accessing cell variables in outer scopes --- Cython/Compiler/ParseTreeTransforms.py | 6 ++++- Cython/Debugger/Tests/codefile | 13 +++------- .../Debugger/Tests/test_libcython_in_gdb.py | 26 ++++++++++++++----- Cython/Debugger/libcython.py | 14 ++++++++-- 4 files changed, 39 insertions(+), 20 deletions(-) diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 59c9a2cd..e3c70310 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -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 diff --git a/Cython/Debugger/Tests/codefile b/Cython/Debugger/Tests/codefile index 4a251e89..953ada31 100644 --- a/Cython/Debugger/Tests/codefile +++ b/Cython/Debugger/Tests/codefile @@ -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 diff --git a/Cython/Debugger/Tests/test_libcython_in_gdb.py b/Cython/Debugger/Tests/test_libcython_in_gdb.py index 5775969a..89ff7fdd 100644 --- a/Cython/Debugger/Tests/test_libcython_in_gdb.py +++ b/Cython/Debugger/Tests/test_libcython_in_gdb.py @@ -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') diff --git a/Cython/Debugger/libcython.py b/Cython/Debugger/libcython.py index 7ce9c5bc..d5f0c48d 100644 --- a/Cython/Debugger/libcython.py +++ b/Cython/Debugger/libcython.py @@ -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): -- 2.26.2