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 00000000..258951ac Binary files /dev/null and b/test/bytecode_2.5_run/02_try_else_loop.pyc differ 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 00000000..77ad9785 Binary files /dev/null and b/test/bytecode_2.5_run/03_try_else.pyc differ diff --git a/test/bytecode_2.6_run/02_try_else_loop.pyc b/test/bytecode_2.6_run/02_try_else_loop.pyc new file mode 100644 index 00000000..074d3ccf Binary files /dev/null and b/test/bytecode_2.6_run/02_try_else_loop.pyc differ diff --git a/test/bytecode_2.6_run/03_try_else.pyc b/test/bytecode_2.6_run/03_try_else.pyc new file mode 100644 index 00000000..baf232e8 Binary files /dev/null and b/test/bytecode_2.6_run/03_try_else.pyc differ 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