You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Both 2.7 bytecode broken from the refactor have now been reinstated, but two 3.5 and 3.6 bytecode have moved into the "todo" category.
63 lines
2.3 KiB
Python
63 lines
2.3 KiB
Python
# Copyright (c) 2020 Rocky Bernstein
|
|
|
|
ASSERT_OPS = frozenset(["LOAD_ASSERT", "RAISE_VARARGS_1"])
|
|
def or_check(self, lhs, n, rule, ast, tokens, first, last):
|
|
rhs = rule[1]
|
|
|
|
# print("XXX", first, last, rule)
|
|
# for t in range(first, last): print(tokens[t])
|
|
# print("="*40)
|
|
|
|
if rhs[0:2] in (("expr_jt", "expr"),
|
|
("expr_jitop", "expr"),
|
|
("expr_jit", "expr")):
|
|
if tokens[last] in ASSERT_OPS or tokens[last-1] in ASSERT_OPS:
|
|
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
|
|
|
|
first_offset = tokens[first].off2int()
|
|
expr_jt = ast[0]
|
|
|
|
if expr_jt == "expr_jitop":
|
|
jump_true = expr_jt[1]
|
|
else:
|
|
jump_true = expr_jt[1][0]
|
|
|
|
jmp_true_target = jump_true.attr
|
|
|
|
last_token = tokens[last]
|
|
last_token_offset = last_token.off2int()
|
|
|
|
if jmp_true_target < first_offset:
|
|
return False
|
|
elif jmp_true_target < last_token_offset:
|
|
return True
|
|
|
|
# If the jmp is backwards
|
|
if last_token == "POP_JUMP_IF_FALSE":
|
|
if last_token.attr < last_token_offset:
|
|
# For a backwards loop, well compare to the instruction *after*
|
|
# then POP_JUMP...
|
|
last_token = tokens[last + 1]
|
|
return not (
|
|
(last_token_offset <= jmp_true_target <= last_token_offset + 2)
|
|
or jmp_true_target < tokens[first].off2int()
|
|
)
|
|
elif last_token == "JUMP_FORWARD" and expr_jt.kind != "expr_jitop":
|
|
# "or" has to fall through to the next statement
|
|
# FIXME: use instructions for all of this
|
|
return True
|
|
|
|
|
|
return False
|