From 0bb793239bd5a414d2e93ec90c1d888afbe419eb Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 8 Nov 2017 10:31:38 -0500 Subject: [PATCH] Add 3.6+ grammar for except's ending in RETURN... Not totally out of the maze in 3.6 control flow... There are still problems with erroneous RETURN_VALUEs becoming RETURN_END_IF, --- uncompyle6/parser.py | 4 ++++ uncompyle6/parsers/parse36.py | 6 ++++++ uncompyle6/scanners/scanner3.py | 3 +++ 3 files changed, 13 insertions(+) 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'