Commit 4c6b0d5b authored by Neil Schemenauer's avatar Neil Schemenauer

Fix a bug in the ``compiler`` package that caused invalid code to be

generated for generator expressions.
parent 7ae35484
...@@ -583,11 +583,9 @@ class GenExpr(Node): ...@@ -583,11 +583,9 @@ class GenExpr(Node):
def __init__(self, code, lineno=None): def __init__(self, code, lineno=None):
self.code = code self.code = code
self.lineno = lineno self.lineno = lineno
self.argnames = ['[outmost-iterable]'] self.argnames = ['.0']
self.varargs = self.kwargs = None self.varargs = self.kwargs = None
def getChildren(self): def getChildren(self):
return self.code, return self.code,
......
...@@ -658,18 +658,19 @@ class CodeGenerator: ...@@ -658,18 +658,19 @@ class CodeGenerator:
stack = [] stack = []
for i, for_ in zip(range(len(node.quals)), node.quals): for i, for_ in zip(range(len(node.quals)), node.quals):
start, anchor = self.visit(for_) start, anchor, end = self.visit(for_)
cont = None cont = None
for if_ in for_.ifs: for if_ in for_.ifs:
if cont is None: if cont is None:
cont = self.newBlock() cont = self.newBlock()
self.visit(if_, cont) self.visit(if_, cont)
stack.insert(0, (start, cont, anchor)) stack.insert(0, (start, cont, anchor, end))
self.visit(node.expr) self.visit(node.expr)
self.emit('YIELD_VALUE') self.emit('YIELD_VALUE')
self.emit('POP_TOP')
for start, cont, anchor in stack: for start, cont, anchor, end in stack:
if cont: if cont:
skip_one = self.newBlock() skip_one = self.newBlock()
self.emit('JUMP_FORWARD', skip_one) self.emit('JUMP_FORWARD', skip_one)
...@@ -678,14 +679,22 @@ class CodeGenerator: ...@@ -678,14 +679,22 @@ class CodeGenerator:
self.nextBlock(skip_one) self.nextBlock(skip_one)
self.emit('JUMP_ABSOLUTE', start) self.emit('JUMP_ABSOLUTE', start)
self.startBlock(anchor) self.startBlock(anchor)
self.emit('POP_BLOCK')
self.setups.pop()
self.startBlock(end)
self.emit('LOAD_CONST', None) self.emit('LOAD_CONST', None)
def visitGenExprFor(self, node): def visitGenExprFor(self, node):
start = self.newBlock() start = self.newBlock()
anchor = self.newBlock() anchor = self.newBlock()
end = self.newBlock()
self.setups.push((LOOP, start))
self.emit('SETUP_LOOP', end)
if node.is_outmost: if node.is_outmost:
self.loadName('[outmost-iterable]') self.loadName('.0')
else: else:
self.visit(node.iter) self.visit(node.iter)
self.emit('GET_ITER') self.emit('GET_ITER')
...@@ -695,7 +704,7 @@ class CodeGenerator: ...@@ -695,7 +704,7 @@ class CodeGenerator:
self.emit('FOR_ITER', anchor) self.emit('FOR_ITER', anchor)
self.nextBlock() self.nextBlock()
self.visit(node.assign) self.visit(node.assign)
return start, anchor return start, anchor, end
def visitGenExprIf(self, node, branch): def visitGenExprIf(self, node, branch):
self.set_lineno(node, force=True) self.set_lineno(node, force=True)
......
...@@ -188,7 +188,7 @@ class GenExprScope(Scope): ...@@ -188,7 +188,7 @@ class GenExprScope(Scope):
i = self.__counter i = self.__counter
self.__counter += 1 self.__counter += 1
self.__super_init("generator expression<%d>"%i, module, klass) self.__super_init("generator expression<%d>"%i, module, klass)
self.add_param('[outmost-iterable]') self.add_param('.0')
def get_names(self): def get_names(self):
keys = Scope.get_names(self) keys = Scope.get_names(self)
......
...@@ -116,6 +116,13 @@ class CompilerTest(unittest.TestCase): ...@@ -116,6 +116,13 @@ class CompilerTest(unittest.TestCase):
exec c in dct exec c in dct
self.assertEquals(dct.get('result'), 3) 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) NOLINENO = (compiler.ast.Module, compiler.ast.Stmt, compiler.ast.Discard)
......
...@@ -64,6 +64,9 @@ Core and builtins ...@@ -64,6 +64,9 @@ Core and builtins
Library 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 - The distutils version has been changed to 2.5.0. The change to
keep it programmatically in sync with the Python version running keep it programmatically in sync with the Python version running
the code (introduced in 2.5b3) has been reverted. It will continue the code (introduced in 2.5b3) has been reverted. It will continue
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment