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

@@ -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,36 +1157,65 @@ 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
testexpr = ast[0]
if (last + 1) < n and tokens[last + 1] == "COME_FROM_LOOP":
# iflastsmtl jumped outside of loop. No good.
return True
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
if testexpr[0] in ("testtrue", "testfalse"):
test = testexpr[0]
if len(test) > 1 and test[1].kind.startswith("jmp_"):
if last == n:
last -= 1
jmp_target = test[1][0].attr
if tokens[first].off2int() <= jmp_target < tokens[last].off2int():
return True
# jmp_target less than tokens[first] is okay - is to a loop
# jmp_target equal tokens[last] is also okay: normal non-optimized non-loop jump
if jmp_target > tokens[last].off2int():
# One more weird case to look out for
# if c1:
# if c2: # Jumps around the *outer* "else"
# ...
# else:
if jmp_target == tokens[last - 1].attr:
return False
if last < n and tokens[last].kind.startswith("JUMP"):
return False
# 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":
# iflastsmtl jumped outside of loop. No good.
return True
if testexpr[0] in ("testtrue", "testfalse"):
test = testexpr[0]
if len(test) > 1 and test[1].kind.startswith("jmp_"):
if last == n:
last -= 1
jmp_target = test[1][0].attr
if tokens[first].off2int() <= jmp_target < tokens[last].off2int():
return True
# jmp_target less than tokens[first] is okay - is to a loop
# jmp_target equal tokens[last] is also okay: normal non-optimized non-loop jump
if jmp_target > tokens[last].off2int():
# One more weird case to look out for
# if c1:
# if c2: # Jumps around the *outer* "else"
# ...
# else:
if jmp_target == tokens[last - 1].attr:
return False
if last < n and tokens[last].kind.startswith("JUMP"):
return False
return True
pass
pass
return False
elif lhs in ("iflaststmt", "iflaststmtl") and ast: