Commits

Anonymous committed a6afe0e

Fix a bug in the ``compiler`` package that caused invalid code to be
generated for generator expressions.

Comments (0)

Files changed (5)

Lib/compiler/ast.py

     def __init__(self, code, lineno=None):
         self.code = code
         self.lineno = lineno
-        self.argnames = ['[outmost-iterable]']
+        self.argnames = ['.0']
         self.varargs = self.kwargs = None
 
-
-
     def getChildren(self):
         return self.code,
 

Lib/compiler/pycodegen.py

 
         stack = []
         for i, for_ in zip(range(len(node.quals)), node.quals):
-            start, anchor = self.visit(for_)
+            start, anchor, end = self.visit(for_)
             cont = None
             for if_ in for_.ifs:
                 if cont is None:
                     cont = self.newBlock()
                 self.visit(if_, cont)
-            stack.insert(0, (start, cont, anchor))
+            stack.insert(0, (start, cont, anchor, end))
 
         self.visit(node.expr)
         self.emit('YIELD_VALUE')
+        self.emit('POP_TOP')
 
-        for start, cont, anchor in stack:
+        for start, cont, anchor, end in stack:
             if cont:
                 skip_one = self.newBlock()
                 self.emit('JUMP_FORWARD', skip_one)
                 self.nextBlock(skip_one)
             self.emit('JUMP_ABSOLUTE', start)
             self.startBlock(anchor)
+            self.emit('POP_BLOCK')
+            self.setups.pop()
+            self.startBlock(end)
+
         self.emit('LOAD_CONST', None)
 
     def visitGenExprFor(self, node):
         start = self.newBlock()
         anchor = self.newBlock()
+        end = self.newBlock()
+
+        self.setups.push((LOOP, start))
+        self.emit('SETUP_LOOP', end)
 
         if node.is_outmost:
-            self.loadName('[outmost-iterable]')
+            self.loadName('.0')
         else:
             self.visit(node.iter)
             self.emit('GET_ITER')
         self.emit('FOR_ITER', anchor)
         self.nextBlock()
         self.visit(node.assign)
-        return start, anchor
+        return start, anchor, end
 
     def visitGenExprIf(self, node, branch):
         self.set_lineno(node, force=True)

Lib/compiler/symbols.py

         i = self.__counter
         self.__counter += 1
         self.__super_init("generator expression<%d>"%i, module, klass)
-        self.add_param('[outmost-iterable]')
+        self.add_param('.0')
 
     def get_names(self):
         keys = Scope.get_names(self)

Lib/test/test_compiler.py

         exec c in dct
         self.assertEquals(dct.get('result'), 3)
 
+    def testGenExp(self):
+        c = compiler.compile('list((i,j) for i in range(3) if i < 3'
+                             '           for j in range(4) if j > 2)',
+                             '<string>',
+                             'eval')
+        self.assertEquals(eval(c), [(0, 3), (1, 3), (2, 3)])
+
 
 NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard)
 
 Library
 -------
 
+- Fix a bug in the ``compiler`` package that caused invalid code to be
+  generated for generator expressions.
+
 - The distutils version has been changed to 2.5.0. The change to
   keep it programmatically in sync with the Python version running
   the code (introduced in 2.5b3) has been reverted. It will continue