You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +08:00
Add "if_not_and" rule similar to "if_not_or" rule.
This commit is contained in:
BIN
test/bytecode_3.6_run/02_if_not_or.pyc
Normal file
BIN
test/bytecode_3.6_run/02_if_not_or.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_3.7_run/02_if_not_or.pyc
Normal file
BIN
test/bytecode_3.7_run/02_if_not_or.pyc
Normal file
Binary file not shown.
43
test/simple_source/bug37/02_if_not_or.py
Normal file
43
test/simple_source/bug37/02_if_not_or.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# from 3.7 inspect.py
|
||||
# Bug was "if not predicate or" inside "for".
|
||||
# Jump optimization turns a POP_JUMP_IF_TRUE into
|
||||
# a POP_JUMP_IF_FALSE and this has to be
|
||||
# dealt with at the "if" (or actually "testfalse") level.
|
||||
|
||||
# RUNNABLE!
|
||||
def getmembers(names, object, predicate):
|
||||
for key in names:
|
||||
if not predicate or object:
|
||||
object = 2
|
||||
object += 1
|
||||
return object
|
||||
|
||||
assert getmembers([1], 0, False) == 3
|
||||
assert getmembers([1], 1, True) == 3
|
||||
assert getmembers([1], 0, True) == 1
|
||||
assert getmembers([1], 1, False) == 3
|
||||
assert getmembers([], 1, False) == 1
|
||||
assert getmembers([], 2, True) == 2
|
||||
|
||||
def _shadowed_dict(klass, a, b, c):
|
||||
for entry in klass:
|
||||
if not (a and b):
|
||||
c = 1
|
||||
return c
|
||||
|
||||
assert _shadowed_dict([1], True, True, 3) == 3
|
||||
assert _shadowed_dict([1], True, False, 3) == 1
|
||||
assert _shadowed_dict([1], False, True, 3) == 1
|
||||
assert _shadowed_dict([1], False, False, 3) == 1
|
||||
assert _shadowed_dict([], False, False, 3) == 3
|
||||
|
||||
# Bug: the double "and" comes out as if .. if not and
|
||||
def _shadowed_dict2(klass, a, b, c, d):
|
||||
for entry in klass:
|
||||
if not (a and b and c):
|
||||
d = 1
|
||||
return d
|
||||
|
||||
# Not yet --
|
||||
# assert _shadowed_dict2([1], False, False, False, 3) == 1
|
||||
# assert _shadowed_dict2([1], True, True, True, 3) == 3
|
@@ -954,13 +954,21 @@ class Python37Parser(Python37BaseParser):
|
||||
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
|
||||
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
|
||||
|
||||
testfalse_not_or ::= expr jmp_false expr jmp_false COME_FROM
|
||||
testfalse_not_and ::= and jmp_true come_froms
|
||||
|
||||
testfalse_not_and ::= expr jmp_false expr jmp_true COME_FROM
|
||||
testfalse ::= testfalse_not_or
|
||||
testfalse ::= testfalse_not_and
|
||||
testfalse ::= or jmp_false COME_FROM
|
||||
or ::= expr jmp_true expr
|
||||
|
||||
|
||||
|
||||
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
|
||||
and ::= expr JUMP_IF_FALSE expr COME_FROM
|
||||
and ::= expr jmp_false expr
|
||||
|
@@ -1046,7 +1046,7 @@ class Python37BaseParser(PythonParser):
|
||||
if tokens[last] == "POP_JUMP_IF_FALSE":
|
||||
# Ok if jump_target doesn't jump to last instruction
|
||||
return jmp_target != tokens[last].attr
|
||||
elif tokens[last] == "JUMP_IF_TRUE_OR_POP":
|
||||
elif tokens[last] in ("POP_JUMP_IF_TRUE", "JUMP_IF_TRUE_OR_POP"):
|
||||
# Ok if jump_target jumps to a COME_FROM after
|
||||
# the last instruction or jumps right after last instruction
|
||||
if last + 1 < n and tokens[last + 1] == "COME_FROM":
|
||||
|
@@ -888,32 +888,6 @@ class Scanner37Base(Scanner):
|
||||
elif op in self.setup_opts_no_loop:
|
||||
count_SETUP_ += 1
|
||||
|
||||
def rem_or(self, start, end, instr, target=None, include_beyond_target=False):
|
||||
"""
|
||||
Find offsets of all requested <instr> between <start> and <end>,
|
||||
optionally <target>ing specified offset, and return list found
|
||||
<instr> offsets which are not within any POP_JUMP_IF_TRUE jumps.
|
||||
"""
|
||||
assert start >= 0 and end <= len(self.code) and start <= end
|
||||
|
||||
# Find all offsets of requested instructions
|
||||
instr_offsets = self.inst_matches(
|
||||
start, end, instr, target, include_beyond_target
|
||||
)
|
||||
# Get all POP_JUMP_IF_TRUE (or) offsets
|
||||
jump_true_op = self.opc.POP_JUMP_IF_TRUE
|
||||
pjit_offsets = self.inst_matches(start, end, jump_true_op)
|
||||
filtered = []
|
||||
for pjit_offset in pjit_offsets:
|
||||
pjit_tgt = self.get_target(pjit_offset) - 3
|
||||
for instr_offset in instr_offsets:
|
||||
if instr_offset <= pjit_offset or instr_offset >= pjit_tgt:
|
||||
filtered.append(instr_offset)
|
||||
instr_offsets = filtered
|
||||
filtered = []
|
||||
return instr_offsets
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from uncompyle6 import PYTHON_VERSION
|
||||
|
||||
|
@@ -67,5 +67,7 @@ def customize_for_version37(self, version):
|
||||
'%[3]{pattr.replace("-", " ")} %p %p', (0, 19), (6, 19) ),
|
||||
'if_exp_37a': ( '%p if %p else %p', (1, 'expr', 27), (0, 27), (4, 'expr', 27) ),
|
||||
'if_exp_37b': ( '%p if %p else %p', (2, 'expr', 27), (0, 'expr', 27), (5, 'expr', 27) ),
|
||||
|
||||
'testfalse_not_or': ( "not %c or %c",
|
||||
(0, "expr"),
|
||||
(2, "expr") ),
|
||||
})
|
||||
|
Reference in New Issue
Block a user