diff --git a/uncompyle6/parser.py b/uncompyle6/parser.py index 9ec2b28f..29e4e2ed 100644 --- a/uncompyle6/parser.py +++ b/uncompyle6/parser.py @@ -262,6 +262,10 @@ class PythonParser(GenericASTBuilder): return_stmt ::= ret_expr RETURN_VALUE return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA + # return_stmts are a sequence of statements that ends in a RETURN statement. + # In later Python versions with jump optimization, this can cause JUMPs + # that would normally appear to be omitted. + return_stmts ::= return_stmt return_stmts ::= _stmts return_stmt diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 9933e5b1..4a21d0b1 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -57,6 +57,12 @@ class Python36Parser(Python35Parser): WITH_CLEANUP_FINISH END_FINALLY except_suite ::= c_stmts_opt COME_FROM POP_EXCEPT jump_except COME_FROM + + # In 3.6+, A sequence of statements ending in a RETURN can cause + # JUMP_FORWARD END_FINALLY to be omitted from try middle + + except_return ::= POP_TOP POP_TOP POP_TOP return_stmts + try_middle ::= JUMP_FORWARD COME_FROM_EXCEPT except_return """ def add_custom_rules(self, tokens, customize): diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index f7dfdd5c..58ede5e6 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -384,9 +384,12 @@ class Scanner3(Scanner): if last_op_was_break and opname == 'CONTINUE': last_op_was_break = False continue + + # FIXME: go over for Python 3.6+. This is sometimes wrong elif op == self.opc.RETURN_VALUE: if inst.offset in self.return_end_ifs: opname = 'RETURN_END_IF' + elif inst.offset in self.load_asserts: opname = 'LOAD_ASSERT'