From 6cef42f6c7e296865eb44ec2116e57d94fde6a9e Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 10 Jan 2020 20:44:28 -0500 Subject: [PATCH] 3.7+ "or" disambiguation and assert2 handling --- test/bytecode_3.7_run/01_assert2.pyc | Bin 272 -> 394 bytes test/simple_source/bug37/01_assert2.py | 10 ++++++++++ uncompyle6/parsers/parse37.py | 4 ++++ uncompyle6/parsers/reducecheck/or_check.py | 21 +++++++++++++++++---- uncompyle6/semantics/customize.py | 4 ++-- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/test/bytecode_3.7_run/01_assert2.pyc b/test/bytecode_3.7_run/01_assert2.pyc index 87af4c3913edc36fee80d7746847808dd6bd6b75..f911ce15834097bf1860ed7fd23a6dc72d8172ef 100644 GIT binary patch delta 220 zcmbQh)Wuxy#LLUY00gosl5uYs85kaeI55BrWH&hW)q!MhF;?8-b1W`SEh@>( a&vPv*$}gJuT$vB#3l0_z7A{5sAO-+>6Dei@ delta 92 zcmeBTp1|bb#LLUY00fEaJ7RYL>Bk@r3@`y14nSNi0whuxQW#qpq8L&cQka?<85vTT dgBdhgCRWVn@Y7^0Vgss}9LcE62GYa90sx=_4Z#2a diff --git a/test/simple_source/bug37/01_assert2.py b/test/simple_source/bug37/01_assert2.py index 2973bb3f..cc26879c 100644 --- a/test/simple_source/bug37/01_assert2.py +++ b/test/simple_source/bug37/01_assert2.py @@ -6,3 +6,13 @@ def test_assert2(c): raise SyntaxError('Oops') test_assert2(5) + +# Bug is handling "assert" and confusing it with "or". +# It is important that the assert be at the end of the loop. +for x in (2, 4, 6): + assert x == x + +# Bug in 3.7 was not having a rule for 2-arg assert. +# 2-arg assert code doesn't match "if not ... raise " +for x in (1, 3, 5): + assert x == x, "foo" diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index e9355cfe..5184d7bf 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -760,6 +760,10 @@ class Python37Parser(Python37BaseParser): stmt ::= classdefdeco classdefdeco ::= classdefdeco1 store + # In 3.7 there are some LOAD_GLOBALs we don't convert to LOAD_ASSERT + stmt ::= assert2 + assert2 ::= expr jmp_true LOAD_GLOBAL expr CALL_FUNCTION_1 RAISE_VARARGS_1 + expr ::= LOAD_ASSERT ifstmt ::= testexpr _ifstmts_jump diff --git a/uncompyle6/parsers/reducecheck/or_check.py b/uncompyle6/parsers/reducecheck/or_check.py index 3fea3eb9..ed12a798 100644 --- a/uncompyle6/parsers/reducecheck/or_check.py +++ b/uncompyle6/parsers/reducecheck/or_check.py @@ -3,6 +3,23 @@ def or_check(self, lhs, n, rule, ast, tokens, first, last): if rule == ("or", ("expr", "jmp_true", "expr")): + if tokens[last] in ( + "LOAD_ASSERT", + "RAISE_VARARGS_1", + ): + return True + + # The following test is be the most accurate. It prevents "or" from being + # mistake for part of an "assert". + # There one might conceivably be "expr or AssertionError" code, but the + # likelihood of that is vanishingly small. + # The below then is useful until we get better control-flow analysis. + # Note it is too hard in the scanner right nowto turn the LOAD_GLOBAL into + # int LOAD_ASSERT, however in 3.9ish code generation does this by default. + load_global = tokens[last-1] + if load_global == "LOAD_GLOBAL" and load_global.attr == "AssertionError": + return True + jmp_true_target = ast[1][0].attr jmp_false = tokens[last] # If the jmp is backwards @@ -13,9 +30,5 @@ def or_check(self, lhs, n, rule, ast, tokens, first, last): jmp_false = tokens[last+1] return not (jmp_true_target == jmp_false.off2int() or jmp_true_target < tokens[first].off2int()) - return tokens[last] in ( - "LOAD_ASSERT", - "RAISE_VARARGS_1", - ) return False diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py index f632fac8..e4aa2e56 100644 --- a/uncompyle6/semantics/customize.py +++ b/uncompyle6/semantics/customize.py @@ -48,8 +48,8 @@ def customize_for_version(self, is_pypy, version): ####################### TABLE_DIRECT.update({ # "assert" and "assert_expr" are added via transform rules. - "assert": ("%|assert %c\n", (0, "assert_expr")), - "assert2": ("%|assert %c, %c\n", (0, "assert_expr"), 3), + "assert": ("%|assert %c\n", 0), + "assert2": ("%|assert %c, %c\n", 0, 3), # Created only via transformation "assertnot": ("%|assert not %p\n", (0, PRECEDENCE['unary_not'])),