From 0c386d2c39c7a85b8b4c2fff878ddfa618be610d Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 24 Nov 2017 08:55:26 -0500 Subject: [PATCH] Fix bug where lambda has a yield in it --- test/bytecode_2.6/10_lambda.pyc | Bin 1133 -> 1392 bytes test/bytecode_3.2/10_lambda.pyc | Bin 539 -> 1558 bytes test/simple_source/expression/10_lambda.py | 8 +++++ uncompyle6/semantics/make_function.py | 38 +++++++++++++++++++-- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/test/bytecode_2.6/10_lambda.pyc b/test/bytecode_2.6/10_lambda.pyc index 63e2a4088b4fd2ca3ad078f070795a370d3040df..b64c483408499216f10f70e48dbbcb92571c691e 100644 GIT binary patch delta 245 zcmaFM@qtVF;wN6NNy-vY$qZ1y0;C;)xHw{>w7ncBLkc@X3j;$l14CpK3quMAh!e%i zkiy6itiiQ0KZ)5hnGvWOhMhq=xqt*v0YqD{1{09$2R9$2vKWL}L8=%S!h$tGLVg+y zlUtc>CpR#%h^j!9FlYc73}ERX?#W%u<|-w;K!K9f;*xmJlGLKaq?}Y`kXn!p42%%f hY?E&=+c5^2XYM$lQ0V#qcF2DHvnu5Bxl-^N=Ko#mG7X*h~tWDMlTkU3}c#VQoPN`_l zd@=9YP1*<|6tLE_v*Yo2{N~N(t^MZDlcU~19*i3Fx0v=5M2bgAF47Y*B3DY%NYa|z zh|EQ)5f&mbkzCchYwQ;yQ6JJe)wCh=NP4lPJN)d`8SP_d7m+he>AF40VL2_5>T8la zGf*^R@Xh%i)5Z{$U?VMEFCAlOJ$;3`a6OM=|^F6b=#P&ndj)%2SAI zkqgwMhnk2-7nLEp%xXZ$I0yOcg4|_~nGl9p>ku zOWh7sYX*K7uVGC-^mzVbHJ>pC(`u&8lLMkWoG$q}rUllQWE ObFl&Cd6= 3.0 else 0 + kw_pairs = 0 indent = self.indent # build parameters @@ -379,6 +378,22 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None): # dump parameter list (with default values) if isLambda: self.write("lambda ", ", ".join(params)) + # If the last statement is None (which is the + # same thing as "return None" in a lambda) and the + # next to last statement is a "yield". Then we want to + # drop the (return) None since that was just put there + # to have something to after the yield finishes. + # FIXME: this is a bit hoaky and not general + if (len(ast) > 1 and + self.traverse(ast[-1]) == 'None' and + self.traverse(ast[-2]).strip().startswith('yield')): + del ast[-1] + # Now pick out the expr part of the last statement + ast_expr = ast[-1] + while ast_expr.kind != 'expr': + ast_expr = ast_expr[0] + ast[-1] = ast_expr + pass else: self.write("(", ", ".join(params)) @@ -416,7 +431,8 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None): print_docstring(self, indent, code.co_consts[0]) code._tokens = None # save memory - assert ast == 'stmts' + if not isLambda: + assert ast == 'stmts' all_globals = find_all_globals(ast, set()) for g in ((all_globals & self.mod_globs) | find_globals(ast, set())): @@ -559,6 +575,22 @@ def make_function3(self, node, isLambda, nested=1, codeNode=None): # dump parameter list (with default values) if isLambda: self.write("lambda ", ", ".join(params)) + # If the last statement is None (which is the + # same thing as "return None" in a lambda) and the + # next to last statement is a "yield". Then we want to + # drop the (return) None since that was just put there + # to have something to after the yield finishes. + # FIXME: this is a bit hoaky and not general + if (len(ast) > 1 and + self.traverse(ast[-1]) == 'None' and + self.traverse(ast[-2]).strip().startswith('yield')): + del ast[-1] + # Now pick out the expr part of the last statement + ast_expr = ast[-1] + while ast_expr.kind != 'expr': + ast_expr = ast_expr[0] + ast[-1] = ast_expr + pass else: self.write("(", ", ".join(params)) # self.println(indent, '#flags:\t', int(code.co_flags))