2.7 and 3.x bug in dict comprehensions

This commit is contained in:
rocky 2016-06-19 13:41:49 -04:00
parent 520290898b
commit 5c268ee2a6
10 changed files with 43 additions and 14 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,10 @@
# Bug in python 3.x handling set comprehensions
# Bug from python 3.x handling set comprehensions
{y for y in range(3)}
# Bug in python 3.4 (base64.py) in handling dict comprehension
b = {v: k for k, v in enumerate(b3)}
# Bug from Python 3.4 enum
def __new__(classdict):
members = {k: classdict[k] for k in classdict._member_names}
return members

View File

@ -24,6 +24,10 @@ class Python2Parser(PythonParser):
super(Python2Parser, self).__init__(AST, 'stmts', debug=debug_parser)
self.customized = {}
# FIXME: redo with parse3's add_unique_rule.
self.seen32 = False
self.seen1024 = False
def p_list_comprehension2(self, args):
"""
list_for ::= expr _for designator list_iter JUMP_BACK
@ -331,8 +335,23 @@ class Python2Parser(PythonParser):
op = k[:k.rfind('_')]
if op in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET'):
rule = ('build_list ::= ' + 'expr1024 '*(v//1024) +
'expr32 '*((v//32)%32) + 'expr '*(v%32) + k)
thousands = (v//1024)
thirty32s = ((v//32)%32)
if thirty32s > 0 and not self.seen32:
rule = "expr32 ::=%s" % (' expr' * 32)
self.addRule(rule, nop_func)
self.seen32 = True
if thousands > 0 and not self.seen1025:
self.addRule("expr1024 ::=%s" % (' expr32' * 32), nop_func)
self.seen1024 = True
rule = ('build_list ::= ' + 'expr1024 '*thousands +
'expr32 '*thirty32s + 'expr '*(v%32) + k)
elif op == 'BUILD_MAP':
kvlist_n = "kvlist_%s" % v
rule = kvlist_n + ' ::= ' + ' kv3' * v
self.addRule(rule, nop_func)
rule = "mapexpr ::= %s %s" % (k, kvlist_n)
self.addRule(rule, nop_func)
elif op in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
rule = 'unpack ::= ' + k + ' designator'*v
elif op == 'UNPACK_LIST':

View File

@ -336,11 +336,13 @@ class Python3Parser(PythonParser):
# Is there something general going on here?
genexpr ::= LOAD_GENEXPR LOAD_CONST MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1
genexpr ::= load_closure LOAD_GENEXPR LOAD_CONST MAKE_CLOSURE_0 expr GET_ITER CALL_FUNCTION_1
dictcomp ::= load_closure LOAD_DICTCOMP LOAD_CONST MAKE_CLOSURE_0 expr GET_ITER CALL_FUNCTION_1
'''
def p_expr3(self, args):
'''
expr ::= LOAD_CLASSNAME
expr ::= LOAD_ASSERT
# Python3 drops slice0..slice3
# Python 3.3+ adds yield from
@ -502,7 +504,6 @@ class Python3Parser(PythonParser):
if opname_base == 'BUILD_TUPLE':
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
self.add_unique_rule(rule, opname, token.attr, customize)
elif opname_base == 'BUILD_MAP':
kvlist_n = "kvlist_%s" % token.attr
if self.version >= 3.5:

View File

@ -55,7 +55,7 @@ class Scanner27(Scanner2):
self.opc.CALL_FUNCTION_KW, self.opc.CALL_FUNCTION_VAR_KW,
self.opc.DUP_TOPX, self.opc.RAISE_VARARGS,
# New in Python 2.7
self.opc.BUILD_SET])
self.opc.BUILD_SET, self.opc.BUILD_MAP])
# "setup" opcodes
self.setup_ops = frozenset([

View File

@ -1140,7 +1140,7 @@ class FragmentsWalker(pysource.SourceWalker, object):
pass
else:
# Python 2 style kvlist
assert node[-1] == 'kvlist'
assert node[-1].type.startswith('kvlist')
kv_node = node[-1] # goto kvlist
for kv in kv_node:

View File

@ -1006,21 +1006,25 @@ class SourceWalker(GenericASTTraversal, object):
def comprehension_walk(self, node, iter_index, code_index=-5):
p = self.prec
self.prec = 27
if hasattr(node[code_index], 'attr'):
# FIXME: clean this up
if self.version > 3.0 and node == 'dictcomp':
cn = node[1]
elif hasattr(node[code_index], 'attr'):
# Python 2.5+ (and earlier?) does this
code = node[code_index].attr
cn = node[code_index]
else:
if len(node[1]) > 1 and hasattr(node[1][1], 'attr'):
# Python 3.3+ does this
code = node[1][1].attr
cn = node[1][1]
elif hasattr(node[1][0], 'attr'):
# Python 3.2 does this
code = node[1][0].attr
cn = node[1][0]
else:
assert False, "Can't find code for comprehension"
assert iscode(code)
code = Code(code, self.scanner, self.currentclass)
assert iscode(cn.attr)
code = Code(cn.attr, self.scanner, self.currentclass)
ast = self.build_ast(code._tokens, code._customize)
self.customize(code._customize)
ast = ast[0][0][0]
@ -1308,7 +1312,7 @@ class SourceWalker(GenericASTTraversal, object):
sep = INDENT_PER_LEVEL[:-1]
self.write('{')
if self.version > 3.0:
if self.version >= 3.0:
if node[0].type.startswith('kvlist'):
# Python 3.5+ style key/value list in mapexpr
kv_node = node[0]
@ -1342,7 +1346,7 @@ class SourceWalker(GenericASTTraversal, object):
pass
else:
# Python 2 style kvlist
assert node[-1] == 'kvlist'
assert node[-1].type.startswith('kvlist')
kv_node = node[-1] # goto kvlist
for kv in kv_node: