fix ticket #606: move scoped local variables back into ScopedExprNode/GeneratorExpres...
authorStefan Behnel <scoder@users.berlios.de>
Tue, 30 Nov 2010 22:52:57 +0000 (23:52 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Tue, 30 Nov 2010 22:52:57 +0000 (23:52 +0100)
Cython/Compiler/ExprNodes.py
Cython/Compiler/Symtab.py

index 80ba4c7e3e9afc290fbf1c05d5b5e7d36750154f..5c00a1ddbaadc554b6380bdb6d4da8e8836e8796 100755 (executable)
@@ -4161,6 +4161,54 @@ class ScopedExprNode(ExprNode):
         # this is called with the expr_scope as env
         pass
 
+    def generate_evaluation_code(self, code):
+        # set up local variables and free their references on exit
+        generate_inner_evaluation_code = super(ScopedExprNode, self).generate_evaluation_code
+        if not self.has_local_scope or not self.expr_scope.var_entries:
+            # no local variables => delegate, done
+            generate_inner_evaluation_code(code)
+            return
+
+        code.putln('{ /* enter inner scope */')
+        py_entries = []
+        for entry in self.expr_scope.var_entries:
+            if not entry.in_closure:
+                code.put_var_declaration(entry)
+                if entry.type.is_pyobject and entry.used:
+                    py_entries.append(entry)
+                    code.put_init_var_to_py_none(entry)
+        if not py_entries:
+            # no local Python references => no cleanup required
+            generate_inner_evaluation_code(code)
+            code.putln('} /* exit inner scope */')
+            return
+
+        # must free all local Python references at each exit point
+        old_loop_labels = tuple(code.new_loop_labels())
+        old_error_label = code.new_error_label()
+
+        generate_inner_evaluation_code(code)
+
+        # normal (non-error) exit
+        for entry in py_entries:
+            code.put_var_decref(entry)
+
+        # error/loop body exit points
+        exit_scope = code.new_label('exit_scope')
+        code.put_goto(exit_scope)
+        for label, old_label in ([(code.error_label, old_error_label)] +
+                                 list(zip(code.get_loop_labels(), old_loop_labels))):
+            if code.label_used(label):
+                code.put_label(label)
+                for entry in py_entries:
+                    code.put_var_decref(entry)
+                code.put_goto(old_label)
+        code.put_label(exit_scope)
+        code.putln('} /* exit inner scope */')
+
+        code.set_loop_labels(old_loop_labels)
+        code.error_label = old_error_label
+
 
 class ComprehensionNode(ScopedExprNode):
     subexprs = ["target"]
index 1dec232167ad070f1975eb6c77dd0ac2c5a17cda..5ee19ae76e12ce7a240555492c84d9feba5c524b 100644 (file)
@@ -1313,7 +1313,9 @@ class GeneratorExpressionScope(Scope):
         # the parent scope needs to generate code for the variable, but
         # this scope must hold its name exclusively
         cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name))
-        entry = self.parent_scope.declare_var(None, type, pos, cname, visibility, is_cdef = True)
+        entry = self.declare(name, cname, type, pos, visibility)
+        entry.is_variable = 1
+        self.var_entries.append(entry)
         self.entries[name] = entry
         return entry