'Detect structures and their boundaries to fix optimizied jumps
in python2.3+'

def detect_structure(self, pos, op=None):

    code = self.code
    if (op is None):
        op = code[pos]
    parent = self.structs[0]
    start = parent['start']
    end = parent['end']
    for s in self.structs:
        _start = s['start']
        _end = s['end']
        if ((_start <= pos < _end) and ((_start >= start) and (_end <= end))):
            start = _start
            end = _end
            parent = s
    origStructCount = len(self.structs)
    if (op == SETUP_LOOP):
        start = (pos + 3)
        target = self.get_target(pos, op)
        end = self.restrict_to_parent(target, parent)
        if (target != end):
            self.fixed_jumps[pos] = end
        (line_no, next_line_byte) = self.lines[pos]
        jump_back = self.last_instr(start, end, JA, next_line_byte, False)
        if (jump_back and (jump_back != self.prev[end]) and (code[(jump_back + 3)] in (JA, JF))):
            if ((code[self.prev[end]] == RETURN_VALUE) or ((code[self.prev[end]] == POP_BLOCK) and (code[self.prev[self.prev[end]]] == RETURN_VALUE))):
                jump_back = None
        if (not jump_back):
            jump_back = (self.last_instr(start, end, RETURN_VALUE) + 1)
            if (not jump_back):
                return
            if (code[self.prev[next_line_byte]] not in (PJIF, PJIT)):
                loop_type = 'for'
            else:
                loop_type = 'while'
                self.ignore_if.add(self.prev[next_line_byte])
            target = next_line_byte
            end = (jump_back + 3)
        else:
            if (self.get_target(jump_back) >= next_line_byte):
                jump_back = self.last_instr(start, end, JA, start, False)
            if ((end > (jump_back + 4)) and (code[end] in (JF, JA))):
                if (code[(jump_back + 4)] in (JA, JF)):
                    if (self.get_target((jump_back + 4)) == self.get_target(end)):
                        self.fixed_jumps[pos] = (jump_back + 4)
                        end = (jump_back + 4)
            elif (target < pos):
                self.fixed_jumps[pos] = (jump_back + 4)
                end = (jump_back + 4)
            target = self.get_target(jump_back, JA)
            if (code[target] in (FOR_ITER, GET_ITER)):
                loop_type = 'for'
            else:
                loop_type = 'while'
                test = self.prev[next_line_byte]
                if (test == pos):
                    loop_type = 'while    1'
                else:
                    self.ignore_if.add(test)
                    test_target = self.get_target(test)
                    if (test_target > (jump_back + 3)):
                        jump_back = test_target
            self.not_continue.add(jump_back)
        self.loops.append(target)
        self.structs.append({'type': (loop_type + '-loop'), 'start': target, 'end': jump_back})
        if ((jump_back + 3) != end):
            self.structs.append({'type': (loop_type + '-else'), 'start': (jump_back + 3), 'end': end})
    elif (op == SETUP_EXCEPT):
        start = (pos + 3)
        target = self.get_target(pos, op)
        end = self.restrict_to_parent(target, parent)
        if (target != end):
            self.fixed_jumps[pos] = end
        self.structs.append({'type': 'try', 'start': start, 'end': (end - 4)})
        end_else = start_else = self.get_target(self.prev[end])
        i = end
        while (self.code[i] != END_FINALLY):
            jmp = self.next_except_jump(i)
            if (self.code[jmp] == RETURN_VALUE):
                self.structs.append({'type': 'except', 'start': i, 'end': (jmp + 1)})
                i = (jmp + 1)
            else:
                if (self.get_target(jmp) != start_else):
                    end_else = self.get_target(jmp)
                if (self.code[jmp] == JF):
                    self.fixed_jumps[jmp] = (-1)
                self.structs.append({'type': 'except', 'start': i, 'end': jmp})
                i = (jmp + 3)
        if (end_else != start_else):
            r_end_else = self.restrict_to_parent(end_else, parent)
            self.structs.append({'type': 'try-else', 'start': (i + 1), 'end': r_end_else})
            self.fixed_jumps[i] = r_end_else
        else:
            self.fixed_jumps[i] = (i + 1)
    elif (op in (PJIF, PJIT)):
        start = (pos + 3)
        target = self.get_target(pos, op)
        rtarget = self.restrict_to_parent(target, parent)
        pre = self.prev
        if ((target != rtarget) and (parent['type'] == 'and/or')):
            self.fixed_jumps[pos] = rtarget
            return
        if ((code[pre[target]] in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP, PJIF, PJIT)) and (target > pos)):
            self.fixed_jumps[pos] = pre[target]
            self.structs.append({'type': 'and/or', 'start': start, 'end': pre[target]})
            return
        if (op == PJIF):
            match = self.rem_or(start, self.next_stmt[pos], PJIF, target)
            match = self.remove_mid_line_ifs(match)
            if match:
                if ((code[pre[rtarget]] in (JF, JA)) and (pre[rtarget] not in self.stmts) and (self.restrict_to_parent(self.get_target(pre[rtarget]), parent) == rtarget)):
                    if ((code[pre[pre[rtarget]]] == JA) and self.remove_mid_line_ifs([pos]) and (target == self.get_target(pre[pre[rtarget]])) and ((pre[pre[rtarget]] not in self.stmts) or (self.get_target(pre[pre[rtarget]]) > pre[pre[rtarget]])) and (1 == len(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], (PJIF, PJIT), target))))):
                        pass
                    elif ((code[pre[pre[rtarget]]] == RETURN_VALUE) and self.remove_mid_line_ifs([pos]) and (1 == len((set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], (PJIF, PJIT), target))) | set(self.remove_mid_line_ifs(self.rem_or(start, pre[pre[rtarget]], (PJIF, PJIT, JA), pre[rtarget], True))))))):
                        pass
                    else:
                        fix = None
                        jump_ifs = self.all_instr(start, self.next_stmt[pos], PJIF)
                        last_jump_good = True
                        for j in jump_ifs:
                            if (target == self.get_target(j)):
                                if ((self.lines[j].next == (j + 3)) and last_jump_good):
                                    fix = j
                                    break
                            else:
                                last_jump_good = False
                        self.fixed_jumps[pos] = (fix or match[(-1)])
                        return
                else:
                    self.fixed_jumps[pos] = match[(-1)]
                    return
        else:
            if ((pos + 3) in self.load_asserts):
                if (code[pre[rtarget]] == RAISE_VARARGS):
                    return
                self.load_asserts.remove((pos + 3))
            next = self.next_stmt[pos]
            if (pre[next] == pos):
                pass
            elif ((code[next] in (JF, JA)) and (target == self.get_target(next))):
                if (code[pre[next]] == PJIF):
                    if ((code[next] == JF) or (target != rtarget) or (code[pre[pre[rtarget]]] not in (JA, RETURN_VALUE))):
                        self.fixed_jumps[pos] = pre[next]
                        return
            elif ((code[next] == JA) and (code[target] in (JA, JF))):
                next_target = self.get_target(next)
                if (self.get_target(target) == next_target):
                    self.fixed_jumps[pos] = pre[next]
                    return
                elif ((code[next_target] in (JA, JF)) and (self.get_target(next_target) == self.get_target(target))):
                    self.fixed_jumps[pos] = pre[next]
                    return
        if (pos in self.ignore_if):
            return
        if ((code[pre[rtarget]] == JA) and (pre[rtarget] in self.stmts) and (pre[rtarget] != pos) and (pre[pre[rtarget]] != pos)):
            if ((code[rtarget] == JA) and (code[(rtarget + 3)] == POP_BLOCK)):
                if (code[pre[pre[rtarget]]] != JA):
                    pass
                elif (self.get_target(pre[pre[rtarget]]) != target):
                    pass
                else:
                    rtarget = pre[rtarget]
            else:
                rtarget = pre[rtarget]
        if (code[pre[rtarget]] in (JA, JF)):
            if_end = self.get_target(pre[rtarget])
            if ((if_end < pre[rtarget]) and (code[pre[if_end]] == SETUP_LOOP)):
                if (if_end > start):
                    return
            end = self.restrict_to_parent(if_end, parent)
            self.structs.append({'type': 'if-then', 'start': start, 'end': pre[rtarget]})
            self.not_continue.add(pre[rtarget])
            if (rtarget < end):
                self.structs.append({'type': 'if-else', 'start': rtarget, 'end': end})
        elif (code[pre[rtarget]] == RETURN_VALUE):
            self.structs.append({'type': 'if-then', 'start': start, 'end': rtarget})
            self.return_end_ifs.add(pre[rtarget])
    elif (op in (JUMP_IF_FALSE_OR_POP, JUMP_IF_TRUE_OR_POP)):
        target = self.get_target(pos, op)
        self.fixed_jumps[pos] = self.restrict_to_parent(target, parent)
