diff --git a/__pkginfo__.py b/__pkginfo__.py index 73952536..950bd5b5 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -47,7 +47,7 @@ ] } ftp_url = None -install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 4.6.0, < 4.7.0"] +install_requires = ["spark-parser >= 1.8.9, < 1.9.0", "xdis >= 4.6.1, < 4.7.0"] license = "GPL3" mailing_list = "python-debugger@googlegroups.com" diff --git a/decompyle3/parsers/p37/full.py b/decompyle3/parsers/p37/full.py index 48810e4f..9e5a86f3 100644 --- a/decompyle3/parsers/p37/full.py +++ b/decompyle3/parsers/p37/full.py @@ -626,6 +626,8 @@ def p_grammar(self, args): testtruec ::= c_nand testtrue ::= compare_chained37 + testtrue ::= compare_chained_and + testtrue ::= nor_cond testfalse ::= and_not diff --git a/decompyle3/parsers/p37/lambda_expr.py b/decompyle3/parsers/p37/lambda_expr.py index 29611d9c..84dc5db5 100644 --- a/decompyle3/parsers/p37/lambda_expr.py +++ b/decompyle3/parsers/p37/lambda_expr.py @@ -185,6 +185,18 @@ def p_37chained(self, args): compare_chained ::= compare_chained37 compare_chained ::= compare_chained37_false + compare_chained_and ::= expr chained_parts + compare_chained2a_false_37 + come_froms + POP_TOP JUMP_FORWARD COME_FROM + negated_testtrue + come_froms + + # We don't use testtrue directly because we need to tell the semantic + # action to negate the testtrue + negated_testtrue ::= testtrue + + c_compare_chained ::= c_compare_chained37_false compare_chained37 ::= expr chained_parts diff --git a/decompyle3/semantics/customize37.py b/decompyle3/semantics/customize37.py index 70837078..49ac8e35 100644 --- a/decompyle3/semantics/customize37.py +++ b/decompyle3/semantics/customize37.py @@ -160,6 +160,22 @@ def customize_for_version37(self, version): ' %[3]{pattr.replace("-", " ")} %p', (0, "expr", PRECEDENCE["compare"]-1), ), + + "compare_chained_and": ( + "%c%c and %c", + (0, "expr"), + (1, "chained_parts"), + -2, # Is often a transformed negated_testtrue + ), + + # This is eliminated in the transform phase, but + # we have it here to be logically complete and more robust + # if something goes wrong. + "negated_testtrue": ( + "not %c", + (0, "testtrue"), + ), + "compare_chained1c_37": ( "%p %p", (0, PRECEDENCE["compare"]-1), diff --git a/decompyle3/semantics/customize38.py b/decompyle3/semantics/customize38.py index 46513a30..b416e7d6 100644 --- a/decompyle3/semantics/customize38.py +++ b/decompyle3/semantics/customize38.py @@ -51,6 +51,7 @@ def customize_for_version38(self, version): (2, "store"), (0, "expr"), (3, "for_block"), -1 ), + "except_cond1a": ( "%|except %c:\n", (1, "expr"), ), diff --git a/decompyle3/semantics/transform.py b/decompyle3/semantics/transform.py index e8e8c931..4b1773d7 100644 --- a/decompyle3/semantics/transform.py +++ b/decompyle3/semantics/transform.py @@ -380,6 +380,12 @@ def n_list_for(self, list_for_node): list_for_node.transformed_by = ("n_list_for",) return list_for_node + def n_negated_testtrue(self, node): + assert node[0] == "testtrue" + test_node = node[0][0] + test_node.transformed_by = "n_negated_testtrue" + return test_node + def n_stmts(self, node): if node.first_child() == "SETUP_ANNOTATIONS": prev = node[0] diff --git a/test/bytecode_3.7/02_and_chained_compare.pyc b/test/bytecode_3.7/02_and_chained_compare.pyc new file mode 100644 index 00000000..92867ef1 Binary files /dev/null and b/test/bytecode_3.7/02_and_chained_compare.pyc differ diff --git a/test/bytecode_3.8/02_and_chained_compare.pyc b/test/bytecode_3.8/02_and_chained_compare.pyc new file mode 100644 index 00000000..007a93bf Binary files /dev/null and b/test/bytecode_3.8/02_and_chained_compare.pyc differ diff --git a/test/simple_source/bug37/02_and_chained_compare.py b/test/simple_source/bug37/02_and_chained_compare.py new file mode 100644 index 00000000..eb302a9f --- /dev/null +++ b/test/simple_source/bug37/02_and_chained_compare.py @@ -0,0 +1,28 @@ +# In Python 3.7+ and/or's have gotten a lot smarter and are harder to +# deal with. + +# See: +# https://github.com/rocky/python-uncompyle6/issues/317 + +"""This program is self-checking!""" + +def chained_compare_and(a, b): + assert (0 <= a <= 10 and + 10 <= b <= 20) + return 6 + +assert chained_compare_and(5, 15) == 6 +try: + chained_compare_and(13, 16) +except: + pass +else: + raise + + +try: + chained_compare_and(4, 8) +except: + pass +else: + raise