mirror of https://github.com/python/cpython
Fix a bug in the ``compiler`` package that caused invalid code to be
generated for generator expressions.
This commit is contained in:
parent
7ae354846f
commit
4c6b0d5bec
|
@ -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:
|
||||||
|
|
||||||
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:
|
||||||
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:
|
||||||
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):
|
||||||
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):
|
||||||
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
|
||||||
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
|
||||||
|
|
Loading…
Reference in New Issue