From d7b79c2b59eb1fb49614300d7033c69568b7f43b Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 19 Jun 2016 00:49:22 -0400 Subject: [PATCH] 3.4 dictionary comprehension bug Sync up fragment code with recent changesa --- test/bytecode_3.4/05_set_comprehension.pyc | Bin 0 -> 443 bytes .../comprehension/05_set_comprehension.py | 3 +++ uncompyle6/parser.py | 5 +---- uncompyle6/parsers/parse2.py | 5 +++++ uncompyle6/parsers/parse3.py | 18 ++++++++++++++++++ uncompyle6/semantics/fragments.py | 14 +++++++------- uncompyle6/semantics/pysource.py | 4 ++-- 7 files changed, 36 insertions(+), 13 deletions(-) create mode 100644 test/bytecode_3.4/05_set_comprehension.pyc 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 0000000000000000000000000000000000000000..062ffce4b08a836b0995a7c8e4f7a4889ae853cc GIT binary patch literal 443 zcmY+A&q~8U5XNUWNin4!)uZ4om$p#71rhY@r3axXp-n~`Z2q|02!-^dPoPhszR_Mi zdGP^qawfqXT3OdS5k~r_2r1z;T0ZM?I0c-`70$wCM^kDi1icfgb$l=(CO}(p2 zHPLaBuQ1SAp+X#mS&}PUVyfdT9gR-{jqBi_Im|be>yypyDFbLOE+~h7Urf{D@x~_A zc!$))4c;DHOD5b(hAbt#Hk=)oXDLoK;@*hI&Q_dO_5COgoB2HRcfL#grDq#Q&C@$H hE~Z6-YQDyqTuh8u{E6Y$sI$zDpJY+7!tN#q)(@F6RImU5 literal 0 HcmV?d00001 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