From 9a77dfaf955cf1b999cbb402b16360d09de720fb Mon Sep 17 00:00:00 2001 From: rocky Date: Tue, 7 Jan 2020 04:39:34 -0500 Subject: [PATCH] Use copysign() in 2.6 nuke -0.0 test if < 2.6 --- pytest/test_grammar.py | 3 +++ test/stdlib/runtests.sh | 17 +++++----------- uncompyle6/parsers/parse2.py | 37 ++++++++++++++++++++++++----------- uncompyle6/parsers/parse27.py | 35 ++++++++++----------------------- 4 files changed, 44 insertions(+), 48 deletions(-) diff --git a/pytest/test_grammar.py b/pytest/test_grammar.py index f20cfacd..0b6bd7e0 100644 --- a/pytest/test_grammar.py +++ b/pytest/test_grammar.py @@ -42,6 +42,9 @@ def test_grammar(): expect_lhs.add("kvlist") expect_lhs.add("kv3") unused_rhs.add("dict") + else: + # NOTE: this may disappear + expect_lhs.add("except_handler_else") if PYTHON3: expect_lhs.add("load_genexpr") diff --git a/test/stdlib/runtests.sh b/test/stdlib/runtests.sh index 35ef669b..65f8f176 100755 --- a/test/stdlib/runtests.sh +++ b/test/stdlib/runtests.sh @@ -71,26 +71,16 @@ case $PYVERSION in 2.6) SKIP_TESTS=( [test_aepack.py]=1 # Fails on its own - [test_cmath.py]=1 # Investigate: probably fixable like in later versions - [test_coercion.py]=1 - [test_codeccallbacks.py]=1 # Fails on its own [test_compile.py]=1 # Intermittent - sometimes works and sometimes doesn't [test_dis.py]=1 # We change line numbers - duh! - [test_exceptions.py]=1 - [test_float.py]=1 # Investigate: probably fixable like in later versions [test_generators.py]=1 # Investigate [test_grp.py]=1 # Long test - might work Control flow? - [test_itertools.py]=1 # complex numbers. Fix as we do in later versions - [test_math.py]=1 # Probably fixable like later versions [test_pep352.py]=1 # Investigate - [test_pprint.py]=1 [test_pyclbr.py]=1 # Investigate [test_pwd.py]=1 # Long test - might work? Control flow? [test_trace.py]=1 # Line numbers are expected to be different - [test_types.py]=1 # Probably fixable like later versions - [test_urllib2net.py]=1 # Fails on its own. May need interactive input [test_zipfile64.py]=1 # Skip Long test - [test_zlib.py]=1 # Takes too long to run (more than 3 minutes 39 seconds) + [test_zlib.py]=1 # # .pyenv/versions/2.6.9/lib/python2.6/lib2to3/refactor.pyc # .pyenv/versions/2.6.9/lib/python2.6/pyclbr.pyc ) @@ -362,7 +352,10 @@ for file in $files; do # If the fails *before* decompiling, skip it! typeset -i STARTTIME=$(date +%s) - if ! python $file >/dev/null 2>&1 ; then + if [ ! -r $file ]; then + echo "Skipping test $file -- not readable. Does it exist?" + continue + elif ! python $file >/dev/null 2>&1 ; then echo "Skipping test $file -- it fails on its own" continue fi diff --git a/uncompyle6/parsers/parse2.py b/uncompyle6/parsers/parse2.py index cdc3d757..1851ab76 100644 --- a/uncompyle6/parsers/parse2.py +++ b/uncompyle6/parsers/parse2.py @@ -648,6 +648,7 @@ class Python2Parser(PythonParser): self.addRule(rule, nop_func) pass + self.check_reduce["and"] = "AST" self.check_reduce["except_handler"] = "tokens" self.check_reduce["except_handler_else"] = "tokens" self.check_reduce["raise_stmt1"] = "tokens" @@ -668,10 +669,34 @@ class Python2Parser(PythonParser): return False lhs = rule[0] + if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")): + # If the instruction after the instructions forming the "and" is an "YIELD_VALUE" + # then this is probably an "if" inside a comprehension. + if tokens[last] == "YIELD_VALUE": + # Note: We might also consider testing last+1 being "POP_TOP" + return True + + # Test that jump_false jump somewhere beyond the end of the "and" + # it might not be exactly the end of the "and" because this and can + # be a part of a larger condition. Oddly in 2.7 there doesn't seem to be + # an optimization where the "and" jump_false is back to a loop. + jmp_false = ast[1] + if jmp_false[0] == "POP_JUMP_IF_FALSE": + while (first < last and isinstance(tokens[last].offset, str)): + last -= 1 + if jmp_false[0].attr < tokens[last].offset: + return True + + # Test that jmp_false jumps to the end of "and" + # or that it jumps to the same place as the end of "and" + jmp_false = ast[1][0] + jmp_target = jmp_false.offset + jmp_false.attr + 3 + return not (jmp_target == tokens[last].offset or + tokens[last].pattr == jmp_false.pattr) # Dead code testing... # if lhs == 'while1elsestmt': # from trepan.api import debug; debug() - if ( + elif ( lhs in ("aug_assign1", "aug_assign2") and ast[0] and ast[0][0] in ("and", "or") @@ -706,16 +731,6 @@ class Python2Parser(PythonParser): pass pass pass - elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): - # FIXME: move this into 2.7-specific code? - if self.version == 2.7: - for i in range(last-1, last-4, -1): - t = tokens[i] - if t == "JUMP_FORWARD": - return t.attr > tokens[min(last, len(tokens)-1)].off2int() - elif t not in ("POP_TOP", "COME_FROM"): - break - pass elif lhs in ("raise_stmt1",): # We will assume 'LOAD_ASSERT' will be handled by an assert grammar rule return tokens[first] == "LOAD_ASSERT" and (last >= len(tokens)) diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index f36f9de7..e099f8a1 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -239,31 +239,7 @@ class Python27Parser(Python2Parser): if invalid: return invalid - if rule == ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")): - # If the instruction after the instructions forming the "and" is an "YIELD_VALUE" - # then this is probably an "if" inside a comprehension. - if tokens[last] == "YIELD_VALUE": - # Note: We might also consider testing last+1 being "POP_TOP" - return True - - # Test that jump_false jump somewhere beyond the end of the "and" - # it might not be exactly the end of the "and" because this and can - # be a part of a larger condition. Oddly in 2.7 there doesn't seem to be - # an optimization where the "and" jump_false is back to a loop. - jmp_false = ast[1] - if jmp_false[0] == "POP_JUMP_IF_FALSE": - while (first < last and isinstance(tokens[last].offset, str)): - last -= 1 - if jmp_false[0].attr < tokens[last].offset: - return True - - # Test that jmp_false jumps to the end of "and" - # or that it jumps to the same place as the end of "and" - jmp_false = ast[1][0] - jmp_target = jmp_false.offset + jmp_false.attr + 3 - return not (jmp_target == tokens[last].offset or - tokens[last].pattr == jmp_false.pattr) - elif rule == ("comp_if", ("expr", "jmp_false", "comp_iter")): + if rule == ("comp_if", ("expr", "jmp_false", "comp_iter")): jmp_false = ast[1] if jmp_false[0] == "POP_JUMP_IF_FALSE": return tokens[first].offset < jmp_false[0].attr < tokens[last].offset @@ -287,6 +263,15 @@ class Python27Parser(Python2Parser): return not (last >= len(tokens) or jump_target == tokens[last].offset or jump_target == next_offset(ast[-1].op, ast[-1].opc, ast[-1].offset)) + elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")): + for i in range(last-1, last-4, -1): + t = tokens[i] + if t == "JUMP_FORWARD": + return t.attr > tokens[min(last, len(tokens)-1)].off2int() + elif t not in ("POP_TOP", "COME_FROM"): + break + pass + pass elif rule == ("iflaststmtl", ("testexpr", "c_stmts")): testexpr = ast[0] if testexpr[0] in ("testfalse", "testtrue"):