3.7+ "or" disambiguation and assert2 handling

This commit is contained in:
rocky
2020-01-10 20:44:28 -05:00
parent eba8f04e29
commit 6cef42f6c7
5 changed files with 33 additions and 6 deletions

Binary file not shown.

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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'])),