| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- # Copyright (c) 2022 Rocky Bernstein
- """
- If statement reduction check for Python 2.6 (and older?)
- """
- def ifstmt2(self, lhs, n, rule, ast, tokens, first, last):
- # for t in range(first, last):
- # print(tokens[t])
- # print("=" * 30)
- if lhs == "ifstmtl":
- if last == n:
- last -= 1
- pass
- if tokens[last].attr and isinstance(tokens[last].attr, int):
- if tokens[first].offset >= tokens[last].attr:
- return True
- pass
- 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]
- # instead of POP_JUMP_IF, should we use op attributes?
- if t.kind in ("JUMP_IF_FALSE", "JUMP_IF_TRUE"):
- jif_target = int(t.pattr)
- target_instr = self.insts[self.offset2inst_index[jif_target]]
- if lhs == "iflaststmtl" and target_instr.opname == "JUMP_ABSOLUTE":
- jif_target = target_instr.arg
- if jif_target > last_offset:
- # In come cases, where we have long bytecode, a
- # "POP_JUMP_IF_TRUE/FALSE" offset might be too
- # large for the instruction; so instead it
- # jumps to a JUMP_FORWARD. Allow that here.
- if tokens[l] == "JUMP_FORWARD":
- return tokens[l].attr != jif_target
- return True
- elif lhs == "ifstmtl" and tokens[first].off2int() > jif_target:
- # A conditional JUMP to the loop is expected for "ifstmtl"
- return False
- 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]
- jmp = test[1]
- if len(test) > 1 and jmp.kind.startswith("jmp_"):
- jmp_target = int(jmp[0].pattr)
- if last == len(tokens):
- last -= 1
- if_end_offset = tokens[last].off2int(prefer_last=False)
- if (
- tokens[first].off2int(prefer_last=True)
- <= jmp_target
- < if_end_offset
- ):
- # In 2.6 (and before?) we need to check if the previous instruction
- # is a jump to the last token. If so, testexpr is negated? and so
- # jmp_target < if_end_offset.
- previous_inst_index = self.offset2inst_index[jmp_target] - 1
- previous_inst = self.insts[previous_inst_index]
- if previous_inst.opname != "JUMP_ABSOLUTE" and previous_inst.argval != if_end_offset:
- 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
|