Fix some 3.7+ "if"/"and" logic bugs

This commit is contained in:
rocky
2019-12-11 06:56:43 -05:00
parent fb3761e4f3
commit 05f3dad32c
7 changed files with 67 additions and 74 deletions

View File

@@ -950,6 +950,8 @@ class Python37Parser(Python37BaseParser):
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond
jitop_come_from ::= JUMP_IF_TRUE_OR_POP COME_FROM
or ::= and jitop_come_from expr COME_FROM
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
or ::= expr JUMP_IF_TRUE expr COME_FROM
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM

View File

@@ -936,6 +936,7 @@ class Python37BaseParser(PythonParser):
self.check_reduce["iflaststmt"] = "AST"
self.check_reduce["iflaststmtl"] = "AST"
self.check_reduce["ifstmt"] = "AST"
self.check_reduce["ifstmtl"] = "AST"
self.check_reduce["annotate_tuple"] = "noAST"
# FIXME: remove parser errors caused by the below
@@ -1028,7 +1029,6 @@ class Python37BaseParser(PythonParser):
if lhs == "and" and ast:
# FIXME: put in a routine somewhere
# Compare with parse30.py of uncompyle6
jmp = ast[1]
if jmp.kind.startswith("jmp_"):
if last == n:
@@ -1043,7 +1043,11 @@ class Python37BaseParser(PythonParser):
return jmp_target != jmp2_target
elif rule == ("and", ("expr", "jmp_false", "expr")):
if tokens[last] == "POP_JUMP_IF_FALSE":
# Ok if jump it doesn't jump to last instruction
return jmp_target != tokens[last].attr
elif tokens[last] == "JUMP_IF_TRUE_OR_POP":
# Ok if jump it does jump right after last instruction
return jmp_target + 2 != tokens[last].attr
elif rule == ("and", ("expr", "jmp_false", "expr", "COME_FROM")):
return ast[-1].attr != jmp_offset
# elif rule == ("and", ("expr", "jmp_false", "expr", "COME_FROM")):
@@ -1153,8 +1157,36 @@ class Python37BaseParser(PythonParser):
else:
return tokens[pop_jump_index].offset > come_froms[-1].attr
elif lhs == "ifstmt" and ast:
elif lhs in ("ifstmt", "ifstmtl"):
# FIXME: put in a routine somewhere
n = len(tokens)
if lhs == "ifstmtl":
if last == n:
last -= 1
pass
if (tokens[last].attr and isinstance(tokens[last].attr, int)):
return tokens[first].offset < tokens[last].attr
pass
# Make sure jumps don't extend beyond the end of the if statement.
l = last
if l == n:
l -= 1
if isinstance(tokens[l].offset, str):
last_offset = int(tokens[l].offset.split("_")[0], 10)
else:
last_offset = tokens[l].offset
for i in range(first, l):
t = tokens[i]
if t.kind == "POP_JUMP_IF_FALSE":
if t.attr > last_offset:
return True
pass
pass
pass
if ast:
testexpr = ast[0]
if (last + 1) < n and tokens[last + 1] == "COME_FROM_LOOP":
@@ -1184,6 +1216,7 @@ class Python37BaseParser(PythonParser):
return True
pass
pass
return False
elif lhs in ("iflaststmt", "iflaststmtl") and ast:
# FIXME: put in a routine somewhere

View File

@@ -263,10 +263,8 @@ class Python38Parser(Python37Parser):
def customize_grammar_rules(self, tokens, customize):
super(Python37Parser, self).customize_grammar_rules(tokens, customize)
self.remove_rules_38()
self.check_reduce["ifstmt"] = "tokens"
self.check_reduce["whileTruestmt38"] = "tokens"
self.check_reduce["whilestmt38"] = "tokens"
self.check_reduce["ifstmtl"] = "tokens"
def reduce_is_invalid(self, rule, ast, tokens, first, last):
invalid = super(Python38Parser,
@@ -276,30 +274,7 @@ class Python38Parser(Python37Parser):
if invalid:
return invalid
lhs = rule[0]
if lhs == "ifstmt":
# Make sure jumps don't extend beyond the end of the if statement.
l = last
if l == len(tokens):
l -= 1
if isinstance(tokens[l].offset, str):
last_offset = int(tokens[l].offset.split("_")[0], 10)
else:
last_offset = tokens[l].offset
for i in range(first, l):
t = tokens[i]
if t.kind == "POP_JUMP_IF_FALSE":
if t.attr > last_offset:
return True
pass
pass
pass
elif lhs == "ifstmtl":
if last == len(tokens):
last -= 1
if (tokens[last].attr and isinstance(tokens[last].attr, int)):
return tokens[first].offset < tokens[last].attr
pass
elif lhs in ("whileTruestmt38", "whilestmt38"):
if lhs in ("whileTruestmt38", "whilestmt38"):
jb_index = last - 1
while jb_index > 0 and tokens[jb_index].kind.startswith("COME_FROM"):
jb_index -= 1

View File

@@ -776,25 +776,6 @@ class Scanner37Base(Scanner):
)
elif op in self.pop_jump_tf:
target = inst.argval
prev_op = self.prev_op
# FIXME: hack upon hack, test_pysource.py fails with this
# Until the grammar is corrected we do this fiction...
pretarget = self.get_inst(prev_op[target])
if (
pretarget.opcode in self.pop_jump_if_pop
and (target > offset)
and pretarget.offset != offset
):
if pretarget.argval != target:
# FIXME: this is not accurate The commented out below
# is what it should be. However grammar rules right now
# assume the incorrect offsets.
# self.fixed_jumps[offset] = target
self.fixed_jumps[offset] = pretarget.offset
return
self.fixed_jumps[offset] = target
elif self.version < 3.8 and op == self.opc.SETUP_EXCEPT:

View File

@@ -111,7 +111,7 @@ def customize_for_version38(self, version):
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
(1, "suite_stmts_opt"),
(6, "suite_stmts_opt") ),
'tryfinally38_return_stmt': (
'tryfinally38astmt': (
'%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
(2, "suite_stmts_opt"),
(8, "suite_stmts_opt") ),

View File

@@ -96,7 +96,8 @@ class TreeTransform(GenericASTTraversal, object):
jump_cond = testexpr[0][1]
expr = raise_stmt[0]
RAISE_VARARGS_1 = raise_stmt[1]
if expr[0] == "call":
call = expr[0]
if call == "call":
# ifstmt
# 0. testexpr
# testtrue (2)
@@ -116,7 +117,8 @@ class TreeTransform(GenericASTTraversal, object):
assert jump_cond == "jmp_false"
kind = "assert2not"
call = expr[0]
if call[0] != "LOAD_ASSERT":
return node
LOAD_ASSERT = call[0]
if isinstance(call[1], SyntaxTree):
expr = call[1][0]