diff --git a/test/bytecode_3.0/02_while1_if_while1.pyc b/test/bytecode_3.0/02_while1_if_while1.pyc new file mode 100644 index 00000000..c4282d8e Binary files /dev/null and b/test/bytecode_3.0/02_while1_if_while1.pyc differ diff --git a/test/simple_source/bug30/02_while1_if_while1.py b/test/simple_source/bug30/02_while1_if_while1.py new file mode 100644 index 00000000..849bf110 --- /dev/null +++ b/test/simple_source/bug30/02_while1_if_while1.py @@ -0,0 +1,9 @@ +# From python 3.4 sre.pyc +while 1: + if __file__: + while 1: + if __file__: + break + raise RuntimeError + else: + raise RuntimeError diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 8a448efe..d5cbb7c5 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -337,6 +337,9 @@ class Python3Parser(PythonParser): whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK else_suite COME_FROM_LOOP + + # FIXME: This gets confused with if/else in a loop. But while/else in Python + # is probably pretty rare. while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suite COME_FROM_LOOP diff --git a/uncompyle6/parsers/parse30.py b/uncompyle6/parsers/parse30.py index c8dfdb77..c492d8e2 100644 --- a/uncompyle6/parsers/parse30.py +++ b/uncompyle6/parsers/parse30.py @@ -23,7 +23,16 @@ class Python30Parser(Python3Parser): jmp_true ::= JUMP_IF_TRUE POP_TOP jmp_false ::= JUMP_IF_FALSE POP_TOP - while1elsestmt ::= SETUP_LOOP l_stmts POP_TOP else_suite COME_FROM_LOOP JUMP_BACK + # Used to keep index order the same in semantic actions + jb_pop_top ::= JUMP_BACK POP_TOP + + # FIXME: Add COME_FROM designators + # This gets confused with while1elsestmt. But this is probably more common + while1stmt ::= SETUP_LOOP l_stmts COME_FROM_LOOP + + else_suitel ::= l_stmts COME_FROM_LOOP JUMP_BACK + + ifelsestmtl ::= testexpr c_stmts_opt jb_pop_top else_suitel withasstmt ::= expr setupwithas designator suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_FINALLY diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 324b8231..bd294d55 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -149,7 +149,7 @@ class Scanner3(Scanner): """ show_asm = self.show_asm if not show_asm else show_asm - # show_asm = 'before' + # show_asm = 'after' if show_asm in ('both', 'before'): bytecode = Bytecode(co, self.opc) for instr in bytecode.get_instructions(co): @@ -314,7 +314,9 @@ class Scanner3(Scanner): if target <= inst.offset: next_opname = self.opname[self.code[inst.offset+3]] if (inst.offset in self.stmts and - next_opname not in ('END_FINALLY', 'POP_BLOCK') + next_opname not in ('END_FINALLY', 'POP_BLOCK', + # Python 3.0 only uses POP_TOP + 'POP_TOP') and inst.offset not in self.not_continue): opname = 'CONTINUE' else: diff --git a/uncompyle6/semantics/fragments.py b/uncompyle6/semantics/fragments.py index d32a1ae4..732782ef 100644 --- a/uncompyle6/semantics/fragments.py +++ b/uncompyle6/semantics/fragments.py @@ -1772,7 +1772,7 @@ def deparse_code(version, co, out=StringIO(), showasm=False, showast=False, if deparsed.ast_errors: deparsed.write("# NOTE: have decompilation errors.\n") - deparsed.write("# Use -t option to show full of errors.") + deparsed.write("# Use -t option to show full context.") for err in deparsed.ast_errors: deparsed.write(err) deparsed.ERROR = True diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index fcf44bd5..f7b32fa6 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -311,7 +311,7 @@ TABLE_DIRECT = { 'whileTruestmt': ( '%|while True:\n%+%c%-\n\n', 1 ), 'whilestmt': ( '%|while %c:\n%+%c%-\n\n', 1, 2 ), 'while1stmt': ( '%|while 1:\n%+%c%-\n\n', 1 ), - 'while1elsestmt': ( '%|while 1:\n%+%c%-%|else:\n%+%c%-\n\n', 1, 3 ), + 'while1elsestmt': ( '%|while 1:\n%+%c%-%|else:\n%+%c%-\n\n', 1, -2 ), 'whileelsestmt': ( '%|while %c:\n%+%c%-%|else:\n%+%c%-\n\n', 1, 2, -2 ), 'whileelselaststmt': ( '%|while %c:\n%+%c%-%|else:\n%+%c%-', 1, 2, -2 ), 'forstmt': ( '%|for %c in %c:\n%+%c%-\n\n', 3, 1, 4 ), @@ -1010,7 +1010,10 @@ class SourceWalker(GenericASTTraversal, object): def n_ifelsestmt(self, node, preprocess=False): else_suite = node[3] - n = else_suite[0] + try: + n = else_suite[0] + except: + from trepan.api import debug; debug() if len(n) == 1 == len(n[0]) and n[0] == '_stmts': n = n[0][0][0] @@ -2322,7 +2325,7 @@ def deparse_code(version, co, out=sys.stdout, showasm=None, showast=False, if deparsed.ast_errors: deparsed.write("# NOTE: have decompilation errors.\n") - deparsed.write("# Use -t option to full context of errors.") + deparsed.write("# Use -t option to show full context.") for err in deparsed.ast_errors: deparsed.write(err) raise SourceWalkerError("Deparsing hit an internal grammar-rule bug")