From fbda3ca695eb5bca80b70b99e14709c0e1a7d10c Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 7 Jan 2018 21:24:35 -0500 Subject: [PATCH] try/else on 2.6 fixup --- test/bytecode_2.5_run/02_try_else_loop.pyc | Bin 0 -> 582 bytes test/bytecode_2.5_run/03_try_else.pyc | Bin 0 -> 536 bytes test/bytecode_2.6_run/02_try_else_loop.pyc | Bin 0 -> 582 bytes test/bytecode_2.6_run/03_try_else.pyc | Bin 0 -> 476 bytes test/simple_source/bug25/02_try_else_loop.py | 17 +++++++++++++ test/simple_source/bug25/03_try_else.py | 18 ++++++++++++++ test/stdlib/runtests.sh | 10 +------- uncompyle6/parsers/parse24.py | 1 - uncompyle6/parsers/parse25.py | 8 ------- uncompyle6/parsers/parse26.py | 24 ++++++++++++++++++- 10 files changed, 59 insertions(+), 19 deletions(-) create mode 100644 test/bytecode_2.5_run/02_try_else_loop.pyc create mode 100644 test/bytecode_2.5_run/03_try_else.pyc create mode 100644 test/bytecode_2.6_run/02_try_else_loop.pyc create mode 100644 test/bytecode_2.6_run/03_try_else.pyc create mode 100644 test/simple_source/bug25/02_try_else_loop.py create mode 100644 test/simple_source/bug25/03_try_else.py diff --git a/test/bytecode_2.5_run/02_try_else_loop.pyc b/test/bytecode_2.5_run/02_try_else_loop.pyc new file mode 100644 index 0000000000000000000000000000000000000000..258951aca076fc2f4a21a5ece064062ba2992462 GIT binary patch literal 582 zcmb7B%SyvQ6g`u^Y{6Ra4PDfQG%H&Q?nD$H%Pv~6QjpMQ#u{leab^Mr>ZbY=?)(S; z%rEdxYU@hG3-`=P=G=2;l8?{T()C`a@8i1|ttZragMb6CKpzmm3&1!-*L7$km0M|v z`ixq?6Fj|v6x;#Nfafp*?o*Gu0?u!zcm|RR48xS%7-kH;a2;8C@lb*+fKi3pU^m7= zR0cETlC|QknFIFc=wtP_QQGOzRl07T4%wzWph<_DSF#|BRqqnpS2Z5+ux@H<5NJ`m zN+NNglvJ*jxmf~Zp)EsUibR$IlcT50!B`7ZCU&Z|P$rP!eA;Hyy@26>&#j0<*DVB- zXe>M}W95s+FdnrI8_kwyRN@J8^Ttv}2T@`wq%}et&zGS#D)x<3_Mhk-09Oi9*g5N(?W6W3yooF?f?J) literal 0 HcmV?d00001 diff --git a/test/bytecode_2.5_run/03_try_else.pyc b/test/bytecode_2.5_run/03_try_else.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77ad9785f73aa39eed7b1ecfcbd1a00d42790ef1 GIT binary patch literal 536 zcmb7AO-lnY5S_{PLszz-h~TXX#h$DvUW$mK#aq?3sPwYvZqU^2rX*RVP%qW9f5w02 zFK{Lm?*`t>?99BGxB2>x!mZEiVFJG=p!ImJ~4aT9W9HdIh{8R5>9k#M zSjBb~%bFaykm%+P1V_xD!!)EW2ohNPBQ17Gn0ILu9n^RPCvkRFZ(N(%$fezWGJfKB~n^(FZi&gIu+f#KO@~C0zY7lBs zze;0qp_Ejfm3esrW1%f0VM;`n0^`!t0ZEaz~@%Pp&J&$ zNjw(5mWc{PbC`?{4x6n5->B3Vu&5p?_gr=6CfqxH*y(yJcCFBQ zl7$R#bvIj>eqFmdY~xv&+MU}c>#eI|bv@ZcYrQ83vo3o;ir_`ryqGeykZ5-sj1Tfp z{4Rhv=S)K7oFHrS7DpQ+X%6G|k!%lbz^V794u8@z@}H1={?Xj&#mpQ>CGoVG{{TS$ BOr`(; literal 0 HcmV?d00001 diff --git a/test/simple_source/bug25/02_try_else_loop.py b/test/simple_source/bug25/02_try_else_loop.py new file mode 100644 index 00000000..ab3248f2 --- /dev/null +++ b/test/simple_source/bug25/02_try_else_loop.py @@ -0,0 +1,17 @@ +# From 2.4 test_binop.py bug is missing 'else:' in 2nd try. +def test_constructor(): + for bad in "0", 0.0, 0j, (), [], {}, None: + try: + raise TypeError(bad) + except TypeError: + pass + else: + assert False, "%r didn't raise TypeError" % bad + try: + raise TypeError(bad) + except TypeError: + pass + else: + assert False, "%r didn't raise TypeError" % bad + +test_constructor() diff --git a/test/simple_source/bug25/03_try_else.py b/test/simple_source/bug25/03_try_else.py new file mode 100644 index 00000000..ca0c736d --- /dev/null +++ b/test/simple_source/bug25/03_try_else.py @@ -0,0 +1,18 @@ +# From Python 2.4. test_cgi.py +# Bug was in putting try block inside the ifelse statement. + +# Note: this is a self testing program - will assert on failure. +def do_test(method): + if method == "GET": + rc = 0 + elif method == "POST": + rc = 1 + else: + raise ValueError, "unknown method: %s" % method + try: + rc = 2 + except ZeroDivisionError: + rc = 3 + return rc + +assert 2 == do_test("GET") diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index d268576a..9923e226 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -47,27 +47,19 @@ case $PYVERSION in [test_sax.py]=1 # Control flow? [test_trace.py]=1 # Line numbers are expected to be different [test_types.py]=1 # Control flow? - [test_zipfile64.py]=1 # Runs ok but takes 204 seconds +nn [test_zipfile64.py]=1 # Runs ok but takes 204 seconds ) ;; 2.6) SKIP_TESTS=( - [test_binop.py]=1 # need to fix tryelse [test_cmath.py]=1 # Control flow? [test_codecs.py]=1 # need to fix tryelse [test_coercion.py]=1 # Control flow? - [test_cookielib.py]=1 # Control flow? [test_decorators.py]=1 # Syntax Error - look at - [test_enumerate.py]=1 # Control flow? - [test_file.py]=1 # Control flow? [test_frozen.py]=1 # Control flow? [test_ftplib.py]=1 # Control flow? - [test_funcattrs.py]=1 # Control flow? [test_grp.py]=1 # Long test - might work Control flow? [test_imp.py]=1 - [test_int.py]=1 - [test_long.py]=1 - [test_pty.py]=1 [test_pwd.py]=1 # Long test - might work? Control flow? [test_queue.py]=1 # Control flow? [test_re.py]=1 # Probably Control flow? diff --git a/uncompyle6/parsers/parse24.py b/uncompyle6/parsers/parse24.py index 2c4584af..6a18b317 100644 --- a/uncompyle6/parsers/parse24.py +++ b/uncompyle6/parsers/parse24.py @@ -69,7 +69,6 @@ class Python24Parser(Python25Parser): super(Python24Parser, self).customize_grammar_rules(tokens, customize) if self.version == 2.4: self.check_reduce['nop_stmt'] = 'tokens' - self.check_reduce['try_except'] = 'tokens' def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python24Parser, diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index cba2cdce..6830fec3 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -19,9 +19,6 @@ class Python25Parser(Python26Parser): return_if_stmt ::= ret_expr RETURN_END_IF JUMP_BACK - # We have no jumps to jumps, so no "come_froms" but a single "COME_FROM" - ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite COME_FROM - # Python 2.6 uses ROT_TWO instead of the STORE_xxx # withas is allowed as a "from future" in 2.5 # 2.6 and 2.7 do something slightly different @@ -39,8 +36,6 @@ class Python25Parser(Python26Parser): # loop. FIXME: should "come_froms" below be a single COME_FROM? tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK except_handler else_suite come_froms - tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK - except_handler else_suitel # Python 2.6 omits the LOAD_FAST DELETE_FAST below # withas is allowed as a "from future" in 2.5 @@ -59,9 +54,6 @@ class Python25Parser(Python26Parser): def customize_grammar_rules(self, tokens, customize): # Remove grammar rules inherited from Python 2.6 or Python 2 self.remove_rules(""" - # No jump to jumps in 2.4 so we have a single "COME_FROM", not "come_froms" - ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite come_froms - setupwith ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 POP_TOP withstmt ::= expr setupwith SETUP_FINALLY suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index 97b5fcea..5dd388eb 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -40,6 +40,8 @@ class Python26Parser(Python2Parser): tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK except_handler else_suite come_froms + tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK + except_handler else_suitel _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP @@ -155,10 +157,12 @@ class Python26Parser(Python2Parser): ifstmt ::= testexpr_then _ifstmts_jump # Semantic actions want the else to be at position 3 - ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite come_froms ifelsestmt ::= testexpr_then c_stmts_opt jf_cf_pop else_suite come_froms ifelsestmt ::= testexpr_then c_stmts_opt filler else_suitel come_froms POP_TOP + # We have no jumps to jumps, so no "come_froms" but a single "COME_FROM" + ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite COME_FROM + # Semantic actions want else_suitel to be at index 3 ifelsestmtl ::= testexpr_then c_stmts_opt jb_cf_pop else_suitel ifelsestmtc ::= testexpr_then c_stmts_opt ja_cf_pop else_suitec @@ -307,6 +311,7 @@ class Python26Parser(Python2Parser): super(Python26Parser, self).customize_grammar_rules(tokens, customize) self.check_reduce['and'] = 'AST' self.check_reduce['list_for'] = 'AST' + self.check_reduce['try_except'] = 'tokens' def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python26Parser, @@ -333,6 +338,23 @@ class Python26Parser(Python2Parser): # The JUMP_ABSOLUTE has to be to the last POP_TOP or this is invalid ja_attr = ast[4].attr return tokens[last].offset != ja_attr + elif rule[0] == 'try_except': + # We need to distingush try_except from try_except_else and we do that + # by checking the jump before the END_FINALLY + # If we have: + # insn + # POP_TOP + # END_FINALLY + # COME_FROM + # then insn has to be either a JUMP_FORWARD or a RETURN_VALUE + if last == len(tokens): + last -= 1 + if tokens[last] != 'COME_FROM' and tokens[last-1] == 'COME_FROM': + last -= 1 + return (tokens[last] == 'COME_FROM' + and tokens[last-1] == 'END_FINALLY' + and tokens[last-2] == 'POP_TOP' + and tokens[last-3].kind not in frozenset(('JUMP_FORWARD', 'RETURN_VALUE'))) return False class Python26ParserSingle(Python2Parser, PythonParserSingle): pass