# Copyright (c) 2020 Rocky Bernstein def ifstmt(self, lhs, n, rule, ast, tokens, first, last): 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 ("POP_JUMP_IF_FALSE", "POP_JUMP_IF_TRUE"): pjif_target = t.attr target_instr = self.insts[self.offset2inst_index[pjif_target]] if lhs == "iflaststmtl" and target_instr.opname == "JUMP_ABSOLUTE": pjif_target = target_instr.arg if pjif_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 != pjif_target return True elif lhs == "ifstmtl" and tokens[first].off2int() > pjif_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] if len(test) > 1 and test[1].kind.startswith("jmp_"): jmp_target = test[1][0].attr if ( tokens[first].off2int(prefer_last=True) <= jmp_target < tokens[last].off2int(prefer_last=False) ): 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