from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
    from lib.core.translator import Translator
    from lib.core.LlvmCodeGenerator import LlvmCodeGenerator
from lib.core.Handles.HandlesBase import BaseHandle
import ast
import llvmlite.ir as ir


class ExprOpsHandle(BaseHandle):
    def _HandleBinOpLlvm(self, Node: ast.BinOp, VarType: ir.Type | str | None = None) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        Gen._set_node_info(Node, "BinOp")
        LeftVal: Any = self.HandleExprLlvm(Node.left, VarType)
        if not LeftVal:
            return None
        RightVal: Any = self.HandleExprLlvm(Node.right, VarType)
        if not RightVal:
            return None
        Op: str | None = self.Trans.ExprHandler.GetOpSymbol(Node.op)
        if not Op:
            return None
        OP_OVERLOAD_MAP: dict[str, str] = {
            '+': '__add__', '-': '__sub__', '*': '__mul__',
            '/': '__truediv__', '//': '__floordiv__', '%': '__mod__',
            '**': '__pow__',
        }
        if Op in OP_OVERLOAD_MAP:
            LeftClassName: str | None = None
            if isinstance(LeftVal.type, ir.PointerType):
                pointee: ir.Type = LeftVal.type.pointee
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    for CN, ST in Gen.structs.items():
                        if pointee == ST:
                            LeftClassName = CN
                            break
                elif isinstance(pointee, ir.IntType) and pointee.width == 8:
                    LeftClassName = self.Trans.ExprUtils._get_var_class(Node.left, Gen)
                    if LeftClassName and LeftClassName in Gen.structs:
                        TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[LeftClassName])
                        LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
            if LeftClassName is None and isinstance(Node.left, ast.Name):
                LeftClassName = Gen.var_struct_class.get(Node.left.id)
                if LeftClassName and LeftClassName in Gen.structs:
                    if isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
                        TargetStructPtr = ir.PointerType(Gen.structs[LeftClassName])
                        LeftVal = Gen.builder.bitcast(LeftVal, TargetStructPtr, name=f"bitcast_to_{LeftClassName}")
            if LeftClassName:
                op_name: str = OP_OVERLOAD_MAP[Op]
                result: Any = self.Trans.ExprUtils._try_operator_overLoad(LeftClassName, op_name, LeftVal, Gen, RightVal)
                if result is not None:
                    return result
        if Op in ('+', 'Add') and isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
            if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8:
                if isinstance(Node.left, ast.Constant) and isinstance(Node.left.value, str) and len(Node.left.value) == 1:
                    CharVal: Any = Gen._load(LeftVal, name="Load_char_const")
                    CharAsInt: Any = Gen.builder.zext(CharVal, RightVal.type, name="char_to_int")
                    result = Gen.builder.add(CharAsInt, RightVal, name="char_add")
                    TruncResult: Any = Gen.builder.trunc(result, ir.IntType(8), name="add_to_char")
                    return TruncResult
        is_unsigned: bool = Gen._check_node_unsigned(Node.left) or Gen._check_node_unsigned(Node.right)
        if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
            if LeftVal.type.width < RightVal.type.width:
                need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
                if not need_zext and isinstance(RightVal, ir.Constant):
                    signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
                    try:
                        if RightVal.constant > signed_max:
                            need_zext = True
                    except (TypeError, ValueError):
                        pass
                if need_zext:
                    LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left")
                else:
                    LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left")
            elif LeftVal.type.width > RightVal.type.width:
                need_zext = is_unsigned or Gen._check_node_unsigned(Node.right) or RightVal.type.width == 8 or RightVal.type.width == 1
                if not need_zext and isinstance(LeftVal, ir.Constant):
                    signed_max = (1 << (RightVal.type.width - 1)) - 1
                    try:
                        if LeftVal.constant > signed_max:
                            need_zext = True
                    except (TypeError, ValueError):
                        pass
                if need_zext:
                    RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right")
                else:
                    RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right")
        elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
            if Op not in ('+', '-', 'Add', 'Sub') and isinstance(LeftVal.type.pointee, ir.IntType):
                LeftVal = Gen._load(LeftVal, name="deref_ptr_binop")
                if LeftVal.type.width < RightVal.type.width:
                    LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_deref_left")
                elif LeftVal.type.width > RightVal.type.width:
                    RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_deref")
        elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
            if Op not in ('+', '-', 'Add', 'Sub') and isinstance(RightVal.type.pointee, ir.IntType):
                RightVal = Gen._load(RightVal, name="deref_ptr_binop_r")
                if RightVal.type.width < LeftVal.type.width:
                    RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_deref_right")
                elif RightVal.type.width > LeftVal.type.width:
                    LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_deref")
        if Op in ('>>', 'RShift') and isinstance(Node.left, ast.Name):
            vname: str = Node.left.id
            if vname in Gen.var_signedness and Gen.var_signedness[vname]:
                is_unsigned = True
        result = Gen.emit_binary_op(Op, LeftVal, RightVal, is_unsigned=is_unsigned)
        return result

    def _HandleBoolOpLlvm(self, Node: ast.BoolOp) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen

        def _to_bool(val: Any, name: str) -> Any:
            if isinstance(val.type, (ir.FloatType, ir.DoubleType)):
                return Gen.builder.fcmp_ordered('!=', val, ir.Constant(val.type, 0.0), name=name)
            if not isinstance(val.type, ir.IntType) or val.type.width != 1:
                return Gen.builder.icmp_signed('!=', val, Gen._ZeroConst(val.type), name=name)
            return val

        values: list[ast.expr] = Node.values
        if len(values) < 2:
            return self.HandleExprLlvm(values[0]) if values else None
        if isinstance(Node.op, ast.And):
            phi_incomings: list[tuple[ir.Constant, ir.Block]] = []
            end_bb: ir.Block = Gen.func.append_basic_block(name="and.end")
            for idx in range(len(values) - 1):
                val: Any = self.HandleExprLlvm(values[idx])
                if not val:
                    if not end_bb.is_terminated:
                        saved_block: ir.Block = Gen.builder.block
                        Gen.builder.position_at_start(end_bb)
                        Gen.builder.unreachable()
                        Gen.builder.position_at_end(saved_block)
                    return None
                if not isinstance(val.type, ir.IntType) or val.type.width != 1:
                    val = _to_bool(val, f"andcond{idx}")
                cur_bb: ir.Block = Gen.builder.block
                next_bb: ir.Block = Gen.func.append_basic_block(name=f"and.rhs{idx}")
                Gen.builder.cbranch(val, next_bb, end_bb)
                phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
                Gen.builder.position_at_start(next_bb)
            last_val: Any = self.HandleExprLlvm(values[-1])
            if not last_val:
                last_val = ir.Constant(ir.IntType(1), 0)
            if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
                last_val = _to_bool(last_val, "andcond_last")
            last_bb: ir.Block = Gen.builder.block
            Gen.builder.branch(end_bb)
            Gen.builder.position_at_start(end_bb)
            result_phi: Any = Gen.builder.phi(ir.IntType(1), name="and.result")
            for const_val, bb in phi_incomings:
                result_phi.add_incoming(const_val, bb)
            result_phi.add_incoming(last_val, last_bb)
            return result_phi
        elif isinstance(Node.op, ast.Or):
            phi_incomings = []
            end_bb = Gen.func.append_basic_block(name="or.end")
            for idx in range(len(values) - 1):
                val = self.HandleExprLlvm(values[idx])
                if not val:
                    if not end_bb.is_terminated:
                        saved_block = Gen.builder.block
                        Gen.builder.position_at_start(end_bb)
                        Gen.builder.unreachable()
                        Gen.builder.position_at_end(saved_block)
                    return None
                if not isinstance(val.type, ir.IntType) or val.type.width != 1:
                    val = _to_bool(val, f"orcond{idx}")
                cur_bb = Gen.builder.block
                next_bb = Gen.func.append_basic_block(name=f"or.rhs{idx}")
                Gen.builder.cbranch(val, end_bb, next_bb)
                phi_incomings.append((ir.Constant(ir.IntType(1), 1), cur_bb))
                Gen.builder.position_at_start(next_bb)
            last_val = self.HandleExprLlvm(values[-1])
            if not last_val:
                last_val = ir.Constant(ir.IntType(1), 1)
            if not isinstance(last_val.type, ir.IntType) or last_val.type.width != 1:
                last_val = _to_bool(last_val, "orcond_last")
            last_bb = Gen.builder.block
            Gen.builder.branch(end_bb)
            Gen.builder.position_at_start(end_bb)
            result_phi = Gen.builder.phi(ir.IntType(1), name="or.result")
            for const_val, bb in phi_incomings:
                result_phi.add_incoming(const_val, bb)
            result_phi.add_incoming(last_val, last_bb)
            return result_phi
        return None

    def _HandleUnaryOpLlvm(self, Node: ast.UnaryOp) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        OperandVal: Any = self.HandleExprLlvm(Node.operand)
        if not OperandVal:
            return None
        OpSymbol: str | None = self.Trans.ExprHandler.GetUnaryOpSymbol(Node.op)
        if not OpSymbol:
            return None
        UNARY_OVERLOAD_MAP: dict[str, str] = {
            '-': '__neg__',
            '+': '__pos__',
            '~': '__invert__',
        }
        if OpSymbol in UNARY_OVERLOAD_MAP:
            ClassName: str | None = None
            if isinstance(OperandVal.type, ir.PointerType):
                pointee: ir.Type = OperandVal.type.pointee
                if isinstance(pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
                    for CN, ST in Gen.structs.items():
                        if pointee == ST:
                            ClassName = CN
                            break
                elif isinstance(pointee, ir.IntType) and pointee.width == 8:
                    ClassName = self.Trans.ExprUtils._get_var_class(Node.operand, Gen)
                    if ClassName and ClassName in Gen.structs:
                        TargetStructPtr: ir.PointerType = ir.PointerType(Gen.structs[ClassName])
                        OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
            if ClassName is None and isinstance(Node.operand, ast.Name):
                ClassName = Gen.var_struct_class.get(Node.operand.id)
                if ClassName and ClassName in Gen.structs:
                    if isinstance(OperandVal.type, ir.PointerType) and isinstance(OperandVal.type.pointee, ir.IntType) and OperandVal.type.pointee.width == 8:
                        TargetStructPtr = ir.PointerType(Gen.structs[ClassName])
                        OperandVal = Gen.builder.bitcast(OperandVal, TargetStructPtr, name=f"bitcast_to_{ClassName}")
            if ClassName:
                op_name: str = UNARY_OVERLOAD_MAP[OpSymbol]
                result: Any = self.Trans.ExprUtils._try_operator_overLoad(ClassName, op_name, OperandVal, Gen)
                if result is not None:
                    return result
        if OpSymbol == 'not':
            if isinstance(OperandVal.type, ir.IntType) and OperandVal.type.width == 1:
                return Gen.builder.not_(OperandVal, name="not_result")
            if isinstance(OperandVal.type, ir.PointerType):
                null_val: ir.Constant = ir.Constant(OperandVal.type, None)
                return Gen.builder.icmp_signed('==', OperandVal, null_val, name="not_result")
            zero: ir.Constant = ir.Constant(OperandVal.type, 0)
            return Gen.builder.icmp_signed('==', OperandVal, zero, name="not_result")
        elif OpSymbol == '~':
            if isinstance(OperandVal.type, ir.IntType):
                mask: int = (1 << OperandVal.type.width) - 1
                return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, mask), name="bnot_result")
            return Gen.builder.xor(OperandVal, ir.Constant(OperandVal.type, -1), name="bnot_result")
        elif OpSymbol == '+':
            return OperandVal
        elif OpSymbol == '-':
            if isinstance(OperandVal.type, ir.IntType):
                return Gen.builder.neg(OperandVal, name="neg_result")
            elif isinstance(OperandVal.type, (ir.FloatType, ir.DoubleType)):
                return Gen.builder.fneg(OperandVal, name="fneg_result")
        return None

    def _HandleCompareLlvm(self, Node: ast.Compare) -> ir.Value | None:
        Gen: LlvmCodeGenerator = self.Trans.LlvmGen
        LeftVal: Any = self.HandleExprLlvm(Node.left)
        if not LeftVal:
            return None
        is_unsigned: bool = Gen._check_node_unsigned(Node.left) or (Gen._check_node_unsigned(Node.comparators[0]) if Node.comparators else False)
        if len(Node.ops) == 1:
            Op: ast.cmpop = Node.ops[0]
            # in/not in: 调用 __contains__
            if isinstance(Op, (ast.In, ast.NotIn)):
                RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
                if RightVal:
                    ClassName: str | None = self.Trans.ExprHandler._get_var_class(Node.comparators[0], Gen)
                    if ClassName and Gen._has_function(f'{ClassName}.__contains__'):
                        # 处理 RightVal 为 i8（整数）的情况：联合类型 | t.CPtr 降级后可能被 load 为 i8
                        if isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
                            RightVal = Gen.builder.inttoptr(RightVal, ir.PointerType(ir.IntType(8)), name=f"i8_to_ptr_{ClassName}")
                        if isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8:
                            RightVal = Gen.builder.bitcast(RightVal, ir.PointerType(Gen.structs[ClassName]), name=f"cast_{ClassName}")
                        contains_func: ir.Function = Gen._get_function(f'{ClassName}.__contains__')
                        result: ir.Value = Gen.builder.call(contains_func, [RightVal, LeftVal], name=f"call_{ClassName}.__contains__")
                        # 归一化为 i1
                        if isinstance(result.type, ir.IntType) and result.type.width > 1:
                            zero: ir.Constant = ir.Constant(result.type, 0)
                            result = Gen.builder.icmp_signed('!=', result, zero, name="contains_bool")
                        if isinstance(Op, ast.NotIn):
                            result = Gen.builder.not_(result, name="not_in_result")
                        return result
                return ir.Constant(ir.IntType(1), 0)
            ComparatorSymbol: str | None = self.Trans.ExprHandler.GetComparatorSymbol(Op)
            if not ComparatorSymbol:
                return None
            RightVal: Any = self.HandleExprLlvm(Node.comparators[0])
            if not RightVal:
                return None
            if isinstance(LeftVal, ir.Constant) and isinstance(RightVal, ir.Constant):
                if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
                    lv: int = LeftVal.constant
                    rv: int = RightVal.constant
                    lw: int = LeftVal.type.width
                    rw: int = RightVal.type.width
                    if lw < rw:
                        lv = lv if lv >= 0 else lv + (1 << lw)
                    elif rw < lw:
                        rv = rv if rv >= 0 else rv + (1 << rw)
                    if is_unsigned:
                        mask_l: int = (1 << max(lw, rw)) - 1
                        lv = lv & mask_l
                        rv = rv & mask_l
                    cmp_map: dict[str, bool] = {
                        '==': lv == rv, '!=': lv != rv,
                        '<': lv < rv, '>': lv > rv,
                        '<=': lv <= rv, '>=': lv >= rv,
                    }
                    result: bool = cmp_map.get(ComparatorSymbol, False)
                    return ir.Constant(ir.IntType(1), 1 if result else 0)
            if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
                if LeftVal.type.width < RightVal.type.width:
                    # 如果宽类型常量值超出窄类型有符号范围，则必须用zext
                    # i8 类型默认使用 zext（系统编程中 i8 几乎总是无符号字节）
                    need_zext: bool = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
                    if not need_zext and isinstance(RightVal, ir.Constant):
                        signed_max: int = (1 << (LeftVal.type.width - 1)) - 1
                        try:
                            if RightVal.constant > signed_max or RightVal.constant < 0:
                                need_zext = True
                        except (TypeError, ValueError):
                            pass
                    if need_zext:
                        LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name="zext_left_cmp")
                    else:
                        LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name="sext_left_cmp")
                elif LeftVal.type.width > RightVal.type.width:
                    need_zext = is_unsigned or Gen._check_node_unsigned(Node.comparators[0]) or RightVal.type.width == 8 or RightVal.type.width == 1
                    if not need_zext and isinstance(LeftVal, ir.Constant):
                        signed_max = (1 << (RightVal.type.width - 1)) - 1
                        try:
                            if LeftVal.constant > signed_max or LeftVal.constant < 0:
                                need_zext = True
                        except (TypeError, ValueError):
                            pass
                    if need_zext:
                        RightVal = Gen.builder.zext(RightVal, LeftVal.type, name="zext_right_cmp")
                    else:
                        RightVal = Gen.builder.sext(RightVal, LeftVal.type, name="sext_right_cmp")
            elif isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.IntType):
                if isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8 and isinstance(RightVal.type, ir.IntType) and RightVal.type.width == 8:
                    LeftVal = Gen._load(LeftVal, name="Load_char_ptr_cmp")
                else:
                    if isinstance(RightVal, ir.Constant) and RightVal.constant == 0:
                        RightVal = ir.Constant(LeftVal.type, None)
                    else:
                        # 不将整数转为指针（避免 strcmp 解引用无效地址），改为将指针转为整数走正常 ==
                        LeftVal = Gen.builder.ptrtoint(LeftVal, RightVal.type, name="ptr2int_cmp")
            elif isinstance(RightVal.type, ir.PointerType) and isinstance(LeftVal.type, ir.IntType):
                if isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8 and isinstance(LeftVal.type, ir.IntType) and LeftVal.type.width == 8:
                    RightVal = Gen._load(RightVal, name="Load_char_ptr_cmp")
                else:
                    if isinstance(LeftVal, ir.Constant) and LeftVal.constant == 0:
                        LeftVal = ir.Constant(RightVal.type, None)
                    else:
                        # 不将整数转为指针（避免 strcmp 解引用无效地址），改为将指针转为整数走正常 ==
                        RightVal = Gen.builder.ptrtoint(RightVal, LeftVal.type, name="ptr2int_cmp")
            # is / is not: 地址比较（指针）或值比较（int）
            if ComparatorSymbol in ('is', 'is not'):
                if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
                    addr_cmp = Gen.builder.icmp_unsigned('==', LeftVal, RightVal, name="is_cmp")
                    if ComparatorSymbol == 'is not':
                        addr_cmp = Gen.builder.not_(addr_cmp, name="is_not_result")
                    return addr_cmp
                if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
                    val_cmp = Gen.builder.icmp_signed('==', LeftVal, RightVal, name="is_cmp")
                    if ComparatorSymbol == 'is not':
                        val_cmp = Gen.builder.not_(val_cmp, name="is_not_result")
                    return val_cmp
            # str/bytes == str/bytes: 值比较（调用 strcmp），None 比较用地址
            if ComparatorSymbol in ('==', '!='):
                if (isinstance(LeftVal.type, ir.PointerType) and isinstance(LeftVal.type.pointee, ir.IntType) and LeftVal.type.pointee.width == 8
                    and isinstance(RightVal.type, ir.PointerType) and isinstance(RightVal.type.pointee, ir.IntType) and RightVal.type.pointee.width == 8):
                    left_is_null: bool = isinstance(LeftVal, ir.Constant) and LeftVal.constant is None
                    right_is_null: bool = isinstance(RightVal, ir.Constant) and RightVal.constant is None
                    if not (left_is_null or right_is_null):
                        strcmp_func = Gen.get_or_declare_c_func('strcmp', ir.FunctionType(ir.IntType(32), [ir.IntType(8).as_pointer(), ir.IntType(8).as_pointer()]))
                        cmp_result = Gen.builder.call(strcmp_func, [LeftVal, RightVal], name="str_eq_cmp")
                        zero = ir.Constant(ir.IntType(32), 0)
                        eq_result = Gen.builder.icmp_signed('==', cmp_result, zero, name="str_eq")
                        if ComparatorSymbol == '!=':
                            eq_result = Gen.builder.not_(eq_result, name="str_neq")
                        return eq_result
            if isinstance(LeftVal.type, ir.PointerType) and isinstance(RightVal.type, ir.PointerType):
                result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
            elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
                if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
                    RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name="int_to_float_cmp")
                elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
                    LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name="int_to_float_cmp")
                result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
            elif is_unsigned:
                result = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
            else:
                result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name="cmpresult")
            return result
        EndBB: ir.Block = Gen.func.append_basic_block(name="cmp.end")
        phi_incomings: list[tuple[ir.Value, ir.Block]] = []
        for i, (Op, Comparator) in enumerate(zip(Node.ops, Node.comparators)):
            ComparatorSymbol = self.Trans.ExprHandler.GetComparatorSymbol(Op)
            if not ComparatorSymbol:
                continue
            RightVal = self.HandleExprLlvm(Comparator)
            if not RightVal:
                continue
            if isinstance(LeftVal.type, ir.IntType) and isinstance(RightVal.type, ir.IntType):
                if LeftVal.type.width < RightVal.type.width:
                    need_zext = is_unsigned or Gen._check_node_unsigned(Node.left) or LeftVal.type.width == 8 or LeftVal.type.width == 1
                    if not need_zext and isinstance(RightVal, ir.Constant):
                        signed_max = (1 << (LeftVal.type.width - 1)) - 1
                        try:
                            if RightVal.constant > signed_max or RightVal.constant < 0:
                                need_zext = True
                        except (TypeError, ValueError):
                            pass
                    if need_zext:
                        LeftVal = Gen.builder.zext(LeftVal, RightVal.type, name=f"zext_left_{i}")
                    else:
                        LeftVal = Gen.builder.sext(LeftVal, RightVal.type, name=f"sext_left_{i}")
                elif LeftVal.type.width > RightVal.type.width:
                    need_zext = is_unsigned or Gen._check_node_unsigned(Comparator) or RightVal.type.width == 8 or RightVal.type.width == 1
                    if not need_zext and isinstance(LeftVal, ir.Constant):
                        signed_max = (1 << (RightVal.type.width - 1)) - 1
                        try:
                            if LeftVal.constant > signed_max or LeftVal.constant < 0:
                                need_zext = True
                        except (TypeError, ValueError):
                            pass
                    if need_zext:
                        RightVal = Gen.builder.zext(RightVal, LeftVal.type, name=f"zext_right_{i}")
                    else:
                        RightVal = Gen.builder.sext(RightVal, LeftVal.type, name=f"sext_right_{i}")
            if is_unsigned:
                cmp_result: Any = Gen.builder.icmp_unsigned(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
            elif isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) or isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)):
                if isinstance(LeftVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(RightVal.type, ir.IntType):
                    RightVal = Gen.builder.sitofp(RightVal, LeftVal.type, name=f"int_to_float_cmp_{i}")
                elif isinstance(RightVal.type, (ir.FloatType, ir.DoubleType)) and isinstance(LeftVal.type, ir.IntType):
                    LeftVal = Gen.builder.sitofp(LeftVal, RightVal.type, name=f"int_to_float_cmp_{i}")
                cmp_result = Gen.builder.fcmp_unordered(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
            else:
                cmp_result = Gen.builder.icmp_signed(ComparatorSymbol, LeftVal, RightVal, name=f"cmp_{i}")
            if i < len(Node.ops) - 1:
                NextBB: ir.Block = Gen.func.append_basic_block(name=f"cmp.next.{i}")
                cur_bb: ir.Block = Gen.builder.block
                Gen.builder.cbranch(cmp_result, NextBB, EndBB)
                phi_incomings.append((ir.Constant(ir.IntType(1), 0), cur_bb))
                Gen.builder.position_at_start(NextBB)
                LeftVal = RightVal
            else:
                cur_bb = Gen.builder.block
                Gen.builder.branch(EndBB)
                phi_incomings.append((cmp_result, cur_bb))
        Gen.builder.position_at_start(EndBB)
        final_result: Any = Gen.builder.phi(ir.IntType(1), name="final_cmp")
        for val, bb in phi_incomings:
            final_result.add_incoming(val, bb)
        return final_result