diff --git a/test/bytecode_2.6/10_lambda.pyc b/test/bytecode_2.6/10_lambda.pyc index 63e2a408..b64c4834 100644 Binary files a/test/bytecode_2.6/10_lambda.pyc and b/test/bytecode_2.6/10_lambda.pyc differ diff --git a/test/bytecode_3.2/10_lambda.pyc b/test/bytecode_3.2/10_lambda.pyc index 32a80130..969ace01 100644 Binary files a/test/bytecode_3.2/10_lambda.pyc and b/test/bytecode_3.2/10_lambda.pyc differ diff --git a/test/simple_source/expression/10_lambda.py b/test/simple_source/expression/10_lambda.py index 48aa3c90..9631fff5 100644 --- a/test/simple_source/expression/10_lambda.py +++ b/test/simple_source/expression/10_lambda.py @@ -26,3 +26,11 @@ class ExtendedInterpolation(): value_getter = lambda option: self._interpolation.before_get(self, section, option, d[option], d) return value_getter + +# Bug from Python 2.7's test_collections.py +# is that the lambda function has two +# statements in it, one for returning *after* the yield +# The return None statement should be removed and the +# yield should be turned into a statement +def test_Iterable(self): + return (lambda: (yield))() diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index bcdb798a..f24a6709 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -332,7 +332,6 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None): else: defparams = node[:args_node.attr] kw_args = 0 - annotate_argc = 0 pass lambda_index = None @@ -364,7 +363,7 @@ def make_function2(self, node, isLambda, nested=1, codeNode=None): self.ERROR = p return - kw_pairs = args_node.attr[1] if self.version >= 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))