def generate_code(self, code_builder: OpCodeBuilder):
        self.expr1.generate_code(code_builder)
        self.expr2.generate_code(code_builder)

        if self.op_type is BinaryOpType.Eq or self.op_type is BinaryOpType.Neq or self.op_type is BinaryOpType.Add:
            t1, t2 = code_builder.get_type(self.expr1), code_builder.get_type(self.expr2)

            subst = t1.unify(t2)  # To handle cases with empty list
            t1, t2 = t1.substitute(subst), t2.substitute(subst)

            if self.op_type is BinaryOpType.Eq:
                code = codes.Eq()
                name = '__refeq'
            elif self.op_type is BinaryOpType.Neq:
                code = codes.Ne()
                name = '__neq'  # TODO
            elif self.op_type is BinaryOpType.Add:
                if isinstance(t1, InferenceBool) or isinstance(t1, InferenceTuple):
                    raise NoFunctionInstanceError('__add', [t1, t2])
                code = codes.Add()
                name = '__add'

            if t1.is_scalar() and t2.is_scalar():  # If scalar, compare directly with appropriate instruction
                code_builder.add(code)
            else:  # Else call custom equality testing function
                code_builder.add_call(
                    fun_name=name,
                    arg_types=[t1, t2],
                    hide=True
                )
        else:
            code = {
                BinaryOpType.Add: codes.Add(),
                BinaryOpType.Sub: codes.Sub(),
                BinaryOpType.Mul: codes.Mul(),
                BinaryOpType.Div: codes.Div(),
                BinaryOpType.Lt: codes.Lt(),
                BinaryOpType.Leq: codes.Le(),
                BinaryOpType.Geq: codes.Ge(),
                BinaryOpType.Gt: codes.Gt(),
                BinaryOpType.Mod: codes.Mod(),
                BinaryOpType.And: codes.And(),
                BinaryOpType.Or: codes.Or(),
                BinaryOpType.Cons: codes.CreateListCons(),
            }.get(self.op_type)
            assert code is not None, 'Unknown binary operator'
            code_builder.add(code)
 def generate_code(self, code_builder: OpCodeBuilder):
     arg_types = [code_builder.get_type(e) for e in self.expressions]
     for e in self.expressions:
         e.generate_code(code_builder)
     code_builder.add_call(self.function_name.value, arg_types)