diff --git a/test/bytecode_2.7/03_map.pyc b/test/bytecode_2.7/03_map.pyc new file mode 100644 index 00000000..024ec3c1 Binary files /dev/null and b/test/bytecode_2.7/03_map.pyc differ diff --git a/test/bytecode_2.7/05_set_comprehension.pyc b/test/bytecode_2.7/05_set_comprehension.pyc new file mode 100644 index 00000000..c781075b Binary files /dev/null and b/test/bytecode_2.7/05_set_comprehension.pyc differ diff --git a/test/bytecode_3.4/03_map.pyc b/test/bytecode_3.4/03_map.pyc new file mode 100644 index 00000000..7834fb41 Binary files /dev/null and b/test/bytecode_3.4/03_map.pyc differ diff --git a/test/bytecode_3.4/05_set_comprehension.pyc b/test/bytecode_3.4/05_set_comprehension.pyc index 062ffce4..62416ac4 100644 Binary files a/test/bytecode_3.4/05_set_comprehension.pyc and b/test/bytecode_3.4/05_set_comprehension.pyc differ diff --git a/test/simple_source/comprehension/05_set_comprehension.py b/test/simple_source/comprehension/05_set_comprehension.py index 9c6a3821..940e4f8a 100644 --- a/test/simple_source/comprehension/05_set_comprehension.py +++ b/test/simple_source/comprehension/05_set_comprehension.py @@ -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 diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 7cb0dc42..5625e9b2 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -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': diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index cfed1aa9..345617d8 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -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: diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index 415dd40f..8cf9a023 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -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([ diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 5897ea64..ea058a34 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -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: diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 202f29c2..cf9eb09e 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -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: