diff --git a/test/bytecode_2.7/06_return_bug.pyc b/test/bytecode_2.7/06_return_bug.pyc new file mode 100644 index 00000000..b78466ca Binary files /dev/null and b/test/bytecode_2.7/06_return_bug.pyc differ diff --git a/test/ok_lib2.7/functools.pyc b/test/ok_lib2.7/functools.pyc deleted file mode 100644 index cb22b91f..00000000 Binary files a/test/ok_lib2.7/functools.pyc and /dev/null differ diff --git a/test/simple_source/def/06_ifTrue_optimize_bug.py b/test/simple_source/def/06_ifTrue_optimize_bug.py new file mode 100644 index 00000000..f115fa7e --- /dev/null +++ b/test/simple_source/def/06_ifTrue_optimize_bug.py @@ -0,0 +1,11 @@ +# Bug in uncompyle6 and pycdc for (some) Python 3 bytecodes. +# Problem is JUMP_IF_FALSE is optimized away leaving +# the unreachible LOAD_CONST below + +# Disassembly of lambda is: +# 0 LOAD_CONST 2: 2 +# 3 RETURN_VALUE +# 4 LOAD_CONST 3: 3 +# 7 RETURN_VALUE + +lambda: 2 if True else 3 diff --git a/test/simple_source/def/06_return_bug.py b/test/simple_source/def/06_return_bug.py new file mode 100644 index 00000000..bad81354 --- /dev/null +++ b/test/simple_source/def/06_return_bug.py @@ -0,0 +1,7 @@ +# But is that we were removing the return 3 at the end of the function +# and a the end of *any* function. We do want to remove "return None" +# at the end of a main program, but that's something different. +def fn(self): + if self.id == 'hat': + return 4 + return 3 diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index ed221c07..e0eb3039 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -550,7 +550,7 @@ class SourceWalker(GenericASTTraversal, object): def indentLess(self, indent=TAB): self.indent = self.indent[:-len(indent)] - def traverse(self, node, indent=None, isLambda=0): + def traverse(self, node, indent=None, isLambda=False): self.param_stack.append(self.params) if indent is None: indent = self.indent p = self.pending_newlines @@ -1059,7 +1059,10 @@ class SourceWalker(GenericASTTraversal, object): self.customize(code._customize) ast = ast[0][0][0][0][0] - n = ast[iter_index] + try: + n = ast[iter_index] + except: + from trepan.api import debug; debug() assert n == 'list_iter' # find innermost node @@ -1814,7 +1817,8 @@ class SourceWalker(GenericASTTraversal, object): self.println(self.text) self.return_none = rn - def build_ast(self, tokens, customize, isLambda=0, noneInNames=False): + def build_ast(self, tokens, customize, isLambda=False, + noneInNames=False, isTopLevel=False): # assert isinstance(tokens[0], Token) @@ -1835,8 +1839,12 @@ class SourceWalker(GenericASTTraversal, object): if self.hide_internal: if len(tokens) >= 2 and not noneInNames: if tokens[-1].type == 'RETURN_VALUE': + # Should we also check for returning None? if tokens[-2].type == 'LOAD_CONST': - del tokens[-2:] + if True or isTopLevel: + del tokens[-2:] + else: + tokens.append(Token('RETURN_LAST')) else: tokens.append(Token('RETURN_LAST')) if len(tokens) == 0: @@ -1877,7 +1885,8 @@ def deparse_code(version, co, out=sys.stdout, showasm=False, showast=False, deparsed = SourceWalker(version, out, scanner, showast=showast, debug_parser=debug_parser, compile_mode=compile_mode) - deparsed.ast = deparsed.build_ast(tokens, customize) + isTopLevel = co.co_name == '' + deparsed.ast = deparsed.build_ast(tokens, customize, isTopLevel=isTopLevel) assert deparsed.ast == 'stmts', 'Should have parsed grammar start'