From 657eeb7de80bd8304233a04301bdb4e9dc6e6d33 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 30 Dec 2015 09:46:52 -0500 Subject: [PATCH] Towards Python3 getting try/except working more often. --- ...ry_except.pyc => 05_try_except.pyc-notyet} | Bin test/bytecode_3.4/20_try_except.pyc | Bin 225 -> 0 bytes test/bytecode_3.4/25_try_except.pyc | Bin 322 -> 342 bytes test/simple_source/exception/25_try_except.py | 20 ++++++++ test/test_pythonlib.py | 2 + uncompyle6/parsers/parse3.py | 25 +++++++--- uncompyle6/scanners/scanner27.py | 3 +- uncompyle6/scanners/scanner3.py | 5 +- uncompyle6/scanners/scanner34.py | 44 +----------------- uncompyle6/semantics/pysource.py | 9 +--- 10 files changed, 49 insertions(+), 59 deletions(-) rename test/bytecode_3.4/{05_try_except.pyc => 05_try_except.pyc-notyet} (100%) delete mode 100644 test/bytecode_3.4/20_try_except.pyc diff --git a/test/bytecode_3.4/05_try_except.pyc b/test/bytecode_3.4/05_try_except.pyc-notyet similarity index 100% rename from test/bytecode_3.4/05_try_except.pyc rename to test/bytecode_3.4/05_try_except.pyc-notyet diff --git a/test/bytecode_3.4/20_try_except.pyc b/test/bytecode_3.4/20_try_except.pyc deleted file mode 100644 index c76636711319b414b88d0e8ddc257f8336862572..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 225 zcmX|(!D@q06h!B$pgiJ#L<&jT?n((=q`Q($z$8ME;(H6JiS`;ne<6R8UwYfF+~fnY z>U|V)VGc9HWv-K0ozH#x0pM43zlpdvQTrn3pP_xMJ|B<)gMtP!!uBUbU_5*)@FR#w z6EYursdu8S_OMBUkz`=>1nb0O7uba)uvA*=txCVD&b%|%Y-zZFL-*ovo3`blsZ8G1 q9T#S9`oc7)vOdnA7Ws*X{J)qrgN*9S<+ptmn;P0n7{xj~S4FJdo`G#Kj#Gl|v0GxfoIy7@`;$!t+!aSW=l8 zvbh+F$`}|K8B-WR!jXA=U=9<6!#J@_j*(^JR0XM9T)~yaC8@ct6`3U~8HzZ8CW47y e8WVq-%Si#bY>do|T#USo{7fLs&J5vk0Yw2DfgIZa delta 143 zcmcb{bcjj$9S<)T%b$uc0cHk<#|%h79LRP6;^MH0%Apfi$uKfcJg(rflA(wLCn(3FM b7MJKxW@I!M;sct(#>mXb#mLLZ&ji8%BKIT1 diff --git a/test/simple_source/exception/25_try_except.py b/test/simple_source/exception/25_try_except.py index 31763ae4..21da5113 100644 --- a/test/simple_source/exception/25_try_except.py +++ b/test/simple_source/exception/25_try_except.py @@ -19,3 +19,23 @@ except ImportError: x = 3 finally: x = 4 + +# Tests Python3: +# trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle come_froms +# come_froms ::= COME_FROM COME_FROM +# START ::= |- stmts +# stmts ::= sstmt +# sstmt ::= stmt +# stmt ::= trystmt +# trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK try_middle come_froms +# come_froms ::= COME_FROM +# try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY COME_FROM +# Python2 doesn't have the come_froms (which allows for 3 successive COME_FROMs) +# it does place 2 COME_FROMs at the end of this code. + +try: + x = 1 +except SystemExit: + x = 2 +except: + x = 3 diff --git a/test/test_pythonlib.py b/test/test_pythonlib.py index 27da8dc9..530e6d9e 100755 --- a/test/test_pythonlib.py +++ b/test/test_pythonlib.py @@ -76,6 +76,8 @@ for vers in (2.5, 2.6, 2.7, 3.2, 3.3, 3.4): test_options[key] = (bytecode, PYC, bytecode, vers) key = "%s" % vers pythonlib = "python%s" % vers + if vers >= 3.0: + pythonlib = os.path.join(pythonlib, '__pycache__') test_options[key] = (os.path.join(lib_prefix, pythonlib), PYC, pythonlib, vers) #----- diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index 129889d8..d091ad30 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -228,8 +228,7 @@ class Python3Parser(PythonParser): ''' def p_grammar(self, args): - ''' - stmts ::= stmts sstmt + '''stmts ::= stmts sstmt stmts ::= sstmt sstmt ::= stmt sstmt ::= ifelsestmtr @@ -405,6 +404,10 @@ class Python3Parser(PythonParser): testfalse ::= expr jmp_false testtrue ::= expr jmp_true + come_froms :: = COME_FROM COME_FROM + come_froms :: = COME_FROM + + _ifstmts_jump ::= return_if_stmts _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM _come_from @@ -421,8 +424,16 @@ class Python3Parser(PythonParser): ifelsestmtl ::= testexpr c_stmts_opt JUMP_BACK else_suitel + # FIXME: this feels like a hack. Is it just 1 or two + # COME_FROMs? the parsed tree for this and even with just the + # one COME_FROM for Python 2.7 seems to associate the + # COME_FROM targets from the wrong places + + come_froms ::= COME_FROM COME_FROM + come_froms ::= COME_FROM + trystmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK - try_middle COME_FROM + try_middle come_froms # this is nested inside a trystmt tryfinallystmt ::= SETUP_FINALLY suite_stmts @@ -450,6 +461,7 @@ class Python3Parser(PythonParser): except_stmt ::= except_cond2 except_suite except_stmt ::= except_cond2 except_suite_finalize except_stmt ::= except + except_stmt ::= except_pop_except # Python3 introduced POP_EXCEPT except_suite ::= c_stmts_opt POP_EXCEPT JUMP_FORWARD @@ -471,11 +483,12 @@ class Python3Parser(PythonParser): except_cond2 ::= DUP_TOP expr COMPARE_OP jmp_false POP_TOP designator POP_TOP - except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt JUMP_FORWARD - except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt JUMP_FORWARD - except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt jmp_abs + except ::= POP_TOP POP_TOP POP_TOP c_stmts_opt POP_EXCEPT JUMP_FORWARD except ::= POP_TOP POP_TOP POP_TOP return_stmts + except_pop_except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt JUMP_FORWARD + except_pop_except ::= POP_TOP POP_TOP POP_TOP POP_EXCEPT c_stmts_opt jmp_abs + jmp_abs ::= JUMP_ABSOLUTE jmp_abs ::= JUMP_BACK diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index fb4c642a..fca1f938 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -618,7 +618,8 @@ class Scanner27(scan.Scanner): for i in self.op_range(0, n): op = code[i] - # Determine structures and fix jumps for 2.3+ + # Determine structures and fix jumps in Python versions + # since 2.3 self.detect_structure(i, op) if op >= HAVE_ARGUMENT: diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index fcbd418c..4dcd57a9 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -313,7 +313,8 @@ class Scanner3(scan.Scanner): for offset in self.op_range(0, codelen): op = code[offset] - # Determine structures and fix jumps for 2.3+ + # Determine structures and fix jumps in Python versions + # since 2.3 self.detect_structure(offset) if op >= op3.HAVE_ARGUMENT: @@ -322,7 +323,7 @@ class Scanner3(scan.Scanner): if label is None: if op in op3.hasjrel and op != FOR_ITER: - label = offset + 3 + oparg + label = offset + self.op_size(op) + oparg elif op in op3.hasjabs: if op in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP): if oparg > offset: diff --git a/uncompyle6/scanners/scanner34.py b/uncompyle6/scanners/scanner34.py index f429f662..10445d1a 100644 --- a/uncompyle6/scanners/scanner34.py +++ b/uncompyle6/scanners/scanner34.py @@ -183,49 +183,7 @@ class Scanner34(scan3.Scanner3): parent = struct pass - if op == SETUP_EXCEPT: - start = offset + 3 - target = self.get_target(offset) - end = self.restrict_to_parent(target, parent) - if target != end: - self.fixed_jumps[pos] = end - # print target, end, parent - # Add the try block - self.structs.append({'type': 'try', - 'start': start, - 'end': end-4}) - # Now isolate the except and else blocks - end_else = start_else = self.get_target(self.prev_op[end]) - - # Add the except blocks - i = end - while self.code[i] != END_FINALLY: - jmp = self.next_except_jump(i) - if self.code[jmp] == RETURN_VALUE: - self.structs.append({'type': 'except', - 'start': i, - 'end': jmp+1}) - i = jmp + 1 - else: - if self.get_target(jmp) != start_else: - end_else = self.get_target(jmp) - if self.code[jmp] == JUMP_FORWARD: - self.fixed_jumps[jmp] = -1 - self.structs.append({'type': 'except', - 'start': i, - 'end': jmp}) - i = jmp + 3 - - # Add the try-else block - if end_else != start_else: - r_end_else = self.restrict_to_parent(end_else, parent) - self.structs.append({'type': 'try-else', - 'start': i+1, - 'end': r_end_else}) - self.fixed_jumps[i] = r_end_else - else: - self.fixed_jumps[i] = i+1 - elif op in (POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE): + if op in (POP_JUMP_IF_FALSE, POP_JUMP_IF_TRUE): start = offset + self.op_size(op) target = self.get_target(offset) rtarget = self.restrict_to_parent(target, parent) diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 8996ebbc..634c180f 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -317,6 +317,8 @@ TABLE_DIRECT = { 'tryelsestmtl': ( '%|try:\n%+%c%-%c%|else:\n%+%c%-', 1, 3, 4 ), 'tf_trystmt': ( '%c%-%c%+', 1, 3 ), 'tf_tryelsestmt': ( '%c%-%c%|else:\n%+%c', 1, 3, 4 ), + 'except': ('%|except:\n%+%c%-', 3 ), + 'except_pop_except': ('%|except:\n%+%c%-', 4 ), 'except_cond1': ( '%|except %c:\n', 1 ), 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ), 'except_suite': ( '%+%c%-%C', 0, (1, maxint, '') ), @@ -503,12 +505,6 @@ class Walker(GenericASTTraversal, object): self.pending_newlines = 0 self.hide_internal = True - if version >= 3.0: - # Python 3 adds a POP_EXCEPT instruction - TABLE_DIRECT['except'] = ('%|except:\n%+%c%-', 4 ) - else: - TABLE_DIRECT['except'] = ('%|except:\n%+%c%-', 3 ) - pass return f = property(lambda s: s.params['f'], @@ -1251,7 +1247,6 @@ class Walker(GenericASTTraversal, object): # self.print_("-----") # self.print(startnode) - fmt = entry[0] arg = 1 i = 0