diff --git a/test/stdlib/3.3-exclude.sh b/test/stdlib/3.3-exclude.sh index 55550084..d97b2103 100644 --- a/test/stdlib/3.3-exclude.sh +++ b/test/stdlib/3.3-exclude.sh @@ -15,7 +15,7 @@ SKIP_TESTS=( [test_io.py]=1 # test takes too long to run: 34 seconds [test_lib2to3.py]=1 [test_logging.py]=1 # test takes too long to run: 13 seconds - [test_long.py]=1 # FIX: if boundaries wrong in Rat __init__ was okay in 3.6.2 though + [test_long.py]=1 # test assert failure AttributeError: 'Rat' object has no attribute 'd' [test_math.py]=1 [test_modulefinder.py]=1 [test_multiprocessing.py]=1 @@ -34,7 +34,6 @@ SKIP_TESTS=( [test_socket.py]=1 [test_ssl.py]=1 # too installation specific [test_strlit.py]=1 - [test_strtod.py]=1 # FIX: works on release 3.6.2; must be if stmt nesting/handling [test_subprocess.py]=1 # test takes too long to run: 28 seconds [test_symtable.py]=1 [test_sys_setprofile.py]=1 # test assertion errors diff --git a/test/stdlib/3.4-exclude.sh b/test/stdlib/3.4-exclude.sh index f1a599ed..542e10d4 100644 --- a/test/stdlib/3.4-exclude.sh +++ b/test/stdlib/3.4-exclude.sh @@ -77,7 +77,6 @@ SKIP_TESTS=( [test_socketserver.py]=1 # long 25 seconds [test_struct.py]=1 # Doesn't terminate [test_strlit.py]=1 # test failure - [test_strtod.py]=1 # test assertion error [test_subprocess.py]=1 # Too long [test_symtable.py]=1 # Investigate bad output [test_sys_settrace.py]=1 # test assert failures diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index aae71807..fbf5c420 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -34,6 +34,7 @@ from uncompyle6.parsers.reducecheck import ( # iflaststmt, testtrue, tryelsestmtl3, + tryexcept, while1stmt ) from uncompyle6.parsers.treenode import SyntaxTree @@ -217,8 +218,7 @@ class Python3Parser(PythonParser): except_handler ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY COME_FROM_EXCEPT - except_stmts ::= except_stmts except_stmt - except_stmts ::= except_stmt + except_stmts ::= except_stmt+ except_stmt ::= except_cond1 except_suite except_stmt ::= except_cond2 except_suite @@ -1509,8 +1509,9 @@ class Python3Parser(PythonParser): self.check_reduce["testtrue"] = "tokens" if not PYTHON3: self.check_reduce["kwarg"] = "noAST" - if self.version < 3.6: + if self.version < 3.6 and not self.is_pypy: # 3.6+ can remove a JUMP_FORWARD which messes up our testing here + # Pypy we need to go over in better detail self.check_reduce["try_except"] = "AST" self.check_reduce["tryelsestmtl3"] = "AST" @@ -1618,24 +1619,8 @@ class Python3Parser(PythonParser): return False # 3.8+ Doesn't have SETUP_LOOP return self.version < 3.8 and tokens[first].attr > tokens[last].offset - - elif rule == ( - "try_except", - ( - "SETUP_EXCEPT", - "suite_stmts_opt", - "POP_BLOCK", - "except_handler", - "opt_come_from_except", - ), - ): - come_from_except = ast[-1] - if come_from_except[0] == "COME_FROM": - # There should be at last two COME_FROMs, one from an - # exception handler and one from the try. Otherwise - # we have a try/else. - return True - pass + elif lhs == "try_except": + return tryexcept(self, lhs, n, rule, ast, tokens, first, last) elif rule == ( "ifelsestmt", ( diff --git a/uncompyle6/parsers/reducecheck/__init__.py b/uncompyle6/parsers/reducecheck/__init__.py index daa842c3..0ab057ae 100644 --- a/uncompyle6/parsers/reducecheck/__init__.py +++ b/uncompyle6/parsers/reducecheck/__init__.py @@ -7,6 +7,7 @@ from uncompyle6.parsers.reducecheck.ifstmts_jump import * from uncompyle6.parsers.reducecheck.or_check import * from uncompyle6.parsers.reducecheck.testtrue import * from uncompyle6.parsers.reducecheck.tryelsestmt import * +from uncompyle6.parsers.reducecheck.tryexcept import * from uncompyle6.parsers.reducecheck.tryelsestmtl3 import * from uncompyle6.parsers.reducecheck.while1elsestmt import * from uncompyle6.parsers.reducecheck.while1stmt import * diff --git a/uncompyle6/parsers/reducecheck/tryexcept.py b/uncompyle6/parsers/reducecheck/tryexcept.py new file mode 100644 index 00000000..33b07d67 --- /dev/null +++ b/uncompyle6/parsers/reducecheck/tryexcept.py @@ -0,0 +1,59 @@ +# Copyright (c) 2020 Rocky Bernstein + +def tryexcept(self, lhs, n, rule, ast, tokens, first, last): + come_from_except = ast[-1] + if rule == ( + "try_except", + ( + "SETUP_EXCEPT", + "suite_stmts_opt", + "POP_BLOCK", + "except_handler", + "opt_come_from_except", + ), + ): + if come_from_except[0] == "COME_FROM": + # There should be at last two COME_FROMs, one from an + # exception handler and one from the try. Otherwise + # we have a try/else. + return True + pass + + elif rule == ( + 'try_except', + ( + 'SETUP_EXCEPT', + 'suite_stmts_opt', + 'POP_BLOCK', + 'except_handler', + '\\e_opt_come_from_except' + ), + ): + # Find END_FINALLY. + for i in range(last, first, -1): + if tokens[i] == "END_FINALLY": + jump_before_finally = tokens[i-1] + if jump_before_finally.kind.startswith("JUMP"): + if jump_before_finally == "JUMP_FORWARD": + # If there is a JUMP_FORWARD before + # the END_FINALLY to some jumps place + # beyond tokens[last].off2int() then + # this is a try/else rather than an + # try (no else). + return tokens[i-1].attr > tokens[last].off2int(prefer_last=True) + elif jump_before_finally == "JUMP_BACK": + # If there is a JUMP_BACK before the + # END_FINALLY then this is a looping + # jump, but then jumps in the except + # handlers have to also be a looping + # jump or this is a try/else rather + # than an try (no else). + except_handler = ast[3] + if (except_handler == "except_handler" and + except_handler[0] == "JUMP_FORWARD"): + return True + return False + pass + pass + pass + return False