diff --git a/test/bytecode_3.4/05_set_comprehension.pyc b/test/bytecode_3.4/05_set_comprehension.pyc new file mode 100644 index 00000000..062ffce4 Binary files /dev/null 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 87444cca..9c6a3821 100644 --- a/test/simple_source/comprehension/05_set_comprehension.py +++ b/test/simple_source/comprehension/05_set_comprehension.py @@ -1,2 +1,5 @@ # Bug in 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)} diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index c80d0638..02688097 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -121,12 +121,9 @@ class PythonParser(GenericASTBuilder): def p_dictcomp(self, args): ''' expr ::= dictcomp - dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 stmt ::= dictcomp_func - - dictcomp_func ::= BUILD_MAP LOAD_FAST FOR_ITER designator + dictcomp_func ::= BUILD_MAP_0 LOAD_FAST FOR_ITER designator comp_iter JUMP_BACK RETURN_VALUE RETURN_LAST - ''' def p_augmented_assign(self, args): diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index 3fdec304..4ec83330 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -287,6 +287,11 @@ class Python2Parser(PythonParser): ''' + def p_dictcomp2(self, args): + """" + dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 + """ + def p_genexpr2(self, args): ''' genexpr ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 12c9ff81..14b26b3a 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -56,6 +56,11 @@ class Python3Parser(PythonParser): # See also common Python p_list_comprehension """ + def p_dictcomp3(self, args): + """" + dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 + """ + def p_grammar(self, args): ''' sstmt ::= stmt @@ -428,6 +433,10 @@ class Python3Parser(PythonParser): GET_ITER CALL_FUNCTION_1 listcomp ::= {expr}^n LOAD_LISTCOMP MAKE_CLOSURE GET_ITER CALL_FUNCTION_1 + + dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr + GET_ITER CALL_FUNCTION_1 + Python < 3.4 listcomp ::= LOAD_LISTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 @@ -439,6 +448,7 @@ class Python3Parser(PythonParser): dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 + # build_class (see load_build_class) build_list ::= {expr}^n BUILD_LIST_n @@ -476,6 +486,14 @@ class Python3Parser(PythonParser): rule = ("listcomp ::= LOAD_LISTCOMP MAKE_FUNCTION_0 expr " "GET_ITER CALL_FUNCTION_1") self.add_unique_rule(rule, opname, token.attr, customize) + elif opname == 'LOAD_DICTCOMP': + if self.version >= 3.4: + rule = ("dictcomp ::= LOAD_DICTCOMP LOAD_CONST MAKE_FUNCTION_0 expr " + "GET_ITER CALL_FUNCTION_1") + else: + rule = ("dictcomp ::= LOAD_DICTCOMP MAKE_FUNCTION_0 expr " + "GET_ITER CALL_FUNCTION_1") + self.add_unique_rule(rule, opname, token.attr, customize) elif opname == 'LOAD_SETCOMP': if self.version >= 3.4: rule = ("setcomp ::= LOAD_SETCOMP LOAD_CONST MAKE_FUNCTION_0 expr " diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index 0a84d222..e85054f0 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -588,7 +588,7 @@ class FragmentsWalker(pysource.SourceWalker, object): # skip over stmts sstmt smt ast = ast[0][0][0] - if ast == 'setcomp_func': + if ast in ['setcomp_func', 'dictcomp_func']: for k in ast: if k == 'comp_iter': n = k @@ -605,15 +605,15 @@ class FragmentsWalker(pysource.SourceWalker, object): ## FIXME: I'm not totally sure this is right. # find innermost node - list_if_node = None + if_node = None while n in ('list_iter', 'comp_iter'): n = n[0] # recurse one step if n == 'list_for': if n[2] == 'designator': designator = n[2] n = n[3] - elif n in ['list_if', 'list_if_not']: - list_if_node = n[0] + elif n in ['list_if', 'list_if_not', 'comp_if']: + if_node = n[0] if n[1] == 'designator': designator = n[1] n = n[2] @@ -633,9 +633,9 @@ class FragmentsWalker(pysource.SourceWalker, object): node[-3].parent = node self.preorder(node[-3]) self.set_pos_info(node[-3], start, len(self.f.getvalue())) - if list_if_node: + if if_node: self.write(' if ') - self.preorder(list_if_node) + self.preorder(if_node) self.prec = p def listcomprehension_walk2(self, node): @@ -703,7 +703,7 @@ class FragmentsWalker(pysource.SourceWalker, object): def n_setcomp(self, node): start = len(self.f.getvalue()) self.write('{') - if node[0] == 'LOAD_SETCOMP': + if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']: start = len(self.f.getvalue()) self.set_pos_info(node[0], start-1, start) self.listcomprehension_walk3(node, 1, 0) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index ec251f95..ea932203 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -1053,7 +1053,7 @@ class SourceWalker(GenericASTTraversal, object): def n_setcomp(self, node): self.write('{') - if node[0] == 'LOAD_SETCOMP': + if node[0] in ['LOAD_SETCOMP', 'LOAD_DICTCOMP']: self.listcomprehension_walk3(node, 1, 0) else: self.comprehension_walk(node, iter_index=4) @@ -1078,7 +1078,7 @@ class SourceWalker(GenericASTTraversal, object): # skip over stmts sstmt smt ast = ast[0][0][0] designator = None - if ast == 'setcomp_func': + if ast in ['setcomp_func', 'dictcomp_func']: for k in ast: if k == 'comp_iter': n = k