From b6fd9088b875ec6334b96e8c323655f1e5806ba2 Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 3 Sep 2016 08:02:22 -0400 Subject: [PATCH] Python 2.3..2.6 "return" bug In Python 2.6 and possibly down to 2.3 we need to issue "return" not "return None" inside a generator. So check for that "return None" inside n_return and issue "return" for that. --- test/bytecode_2.6/07_generator_return.pyc | Bin 0 -> 410 bytes .../bug26/07_generator_return.py | 12 +++++++++ uncompyle6/semantics/pysource.py | 24 +++++++++++++++--- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 test/bytecode_2.6/07_generator_return.pyc create mode 100644 test/simple_source/bug26/07_generator_return.py diff --git a/test/bytecode_2.6/07_generator_return.pyc b/test/bytecode_2.6/07_generator_return.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0cb71a0972dc2fbdf4cba4117d5f02c23f6f4aab GIT binary patch literal 410 zcmbV|u}T9$5QhJ`yJ$F!h1ytH3Wtah3)6_$SXh|C1W#-hy<5Y{%nSSmNxhP^1CbK=03O8M|U0Mr2;VSgQ=i*Qfk%LpTxdfNi!d9#Pa5nfZ6K1f1P6MFEP`Ss&U1eK=+ zu1myCxz#QebJLW1dChD%42P!G^^0tjM?v2+u?S+1#Mx@TsI{`Dq9ua(x+Bs&bl@@>shg0@|RMVr)`MJ=&#h8fTt%=Re|)^>5(C+>~vt JF9Xo?egJ9pOVt1X literal 0 HcmV?d00001 diff --git a/test/simple_source/bug26/07_generator_return.py b/test/simple_source/bug26/07_generator_return.py new file mode 100644 index 00000000..56dc80d1 --- /dev/null +++ b/test/simple_source/bug26/07_generator_return.py @@ -0,0 +1,12 @@ +# From python2.6/_abcoll.py +# Bug was producing "return None" which isn't +# allowed in a generator, instead of "return" +def __iter__(self): + i = 0 + try: + while True: + v = self[i] + yield v + i += 1 + except IndexError: + return diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index c08cc8ab..cf56dcac 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -456,7 +456,7 @@ def find_all_globals(node, globs): def find_none(node): for n in node: if isinstance(n, AST): - if not (n == 'return_stmt' or n == 'return_if_stmt'): + if not n in ('return_stmt', 'return_if_stmt'): if find_none(n): return True elif n.type == 'LOAD_CONST' and n.pattr is None: @@ -772,13 +772,30 @@ class SourceWalker(GenericASTTraversal, object): self.println( indent, line ) self.println(indent, trimmed[-1], quote) + def is_return_none(self, node): + # Is there a better way? + if self.version <= 2.6: + return (node == 'return_stmt' + and node[0] == 'ret_expr' + and node[0][0] == 'expr' + and node[0][0][0] == 'LOAD_CONST' + and node[0][0][0].pattr is None) + else: + # FIXME: should the AST expression be folded into + # the global RETURN_NONE constant? + node == AST('return_stmt', + [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]) + def n_return_stmt(self, node): if self.params['isLambda']: self.preorder(node[0]) self.prune() else: self.write(self.indent, 'return') - if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]): + # One reason we worry over whether we use "return None" or "return" + # is that inside a generator, "return None" is illegal. + # Thank you, Python! + if (self.return_none or not self.is_return_none(node)): self.write(' ') self.preorder(node[0]) self.println() @@ -2089,7 +2106,8 @@ class SourceWalker(GenericASTTraversal, object): for g in ((all_globals & self.mod_globs) | find_globals(ast, set())): self.println(self.indent, 'global ', g) self.mod_globs -= all_globals - rn = ('None' in code.co_names) and not find_none(ast) + has_none = 'None' in code.co_names + rn = has_none and not find_none(ast) self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda, returnNone=rn) code._tokens = None; code._customize = None # save memory