#include "IRBuilder.h"
using namespace std;
namespace SysYF
{
    namespace IR
    {
#define CONST_INT(num) ConstantInt::create(num, module)
#define CONST_FLOAT(num) ConstantFloat::create(num, module)

        // You can define global variables here
        // to store state
        enum
        {
            INT = 0,
            VOID,
            STRING,
            BOOL,
            FLOAT
        };
        
        std::vector<BasicBlock *> tmp_condbb_while;
        std::vector<BasicBlock *> tmp_falsebb_while;
        std::vector<BasicBlock *> tmp_truebb;
        std::vector<BasicBlock *> tmp_falsebb;
        std::map<SyntaxTree::Type, Ptr<Type>> type_map; // 把类型转换成类型指针
        // store temporary value
        Ptr<Value> tmp_val = nullptr;
        vector<Ptr<Value>> init_list;
        // types
        Ptr<Type> VOID_T;
        Ptr<Type> INT1_T;
        Ptr<Type> INT32_T;
        Ptr<Type> FLOAT_T;
        Ptr<Type> INT32PTR_T;
        Ptr<Type> FLOATPTR_T;

        #define LVal_to_RVal(lval) \
        if(lval->get_type()==INT32PTR_T || lval->get_type()==FLOATPTR_T){\
            lval=builder->create_load(lval);\
        }

        void IRBuilder::visit(SyntaxTree::Assembly &node)
        {
            VOID_T = Type::get_void_type(module);
            INT1_T = Type::get_int1_type(module);
            INT32_T = Type::get_int32_type(module);
            FLOAT_T = Type::get_float_type(module);
            INT32PTR_T = Type::get_int32_ptr_type(module);
            FLOATPTR_T = Type::get_float_ptr_type(module);
            // type mapping
            type_map[SyntaxTree::Type::VOID] = VOID_T;
            type_map[SyntaxTree::Type::BOOL] = INT1_T;
            type_map[SyntaxTree::Type::INT] = INT32_T;
            type_map[SyntaxTree::Type::FLOAT] = FLOAT_T;

            for (const auto &def : node.global_defs)
            {
                def->accept(*this);
            }
        }

        // You need to fill them

        void IRBuilder::visit(SyntaxTree::InitVal &node)
        {
            if (!node.isExp) // is not exp, values are in node.elementList
            {
                for (const auto &element : node.elementList)
                {
                    element->accept(*this); // 这里是嵌套定义，读取的是elementList里面的element，肯能会在下一次进入的时候赋值给元素
                }
            }
            else // is exp, values are in node.expr
            {
                node.expr->accept(*this);     // 有可能是计算表达式，也有可能是赋值语句
                LVal_to_RVal(tmp_val);
                init_list.push_back(tmp_val); // 把tmp_val放到init_list里面
            }
        } // init values

        void IRBuilder::visit(SyntaxTree::FuncDef &node) // 考虑一下什么时候要用scope.enter()和scope.exit()
        {
            auto return_type = type_map[node.ret_type];
            auto func_name = node.name;
            // deal with param_list
            PtrVec<Type> params;
            for (const auto &param : node.param_list->params)
            {
                if (param->array_index.empty()) // not array
                {
                    params.push_back(type_map[param->param_type]);
                }
                else
                {
                    params.push_back(type_map[param->param_type]->get_pointer_element_type()); // 这里是指针
                }
            }
            // build function
            auto Func_Type = FunctionType::create(return_type, params);
            auto func = Function::create(Func_Type, func_name, module);
            scope.push(func_name, func);
            // deal with block
            auto block = BasicBlock::create(module, "entry", func);
            builder->set_insert_point(block);
            scope.enter();
            // read param_list
            node.param_list->accept(*this);
            // read body
            bool is_return = false;
            for (const auto &stmt : node.body->body)
            {
                stmt->accept(*this);
                if (dynamic_cast<SyntaxTree::ReturnStmt *>(stmt.get()))
                {
                    is_return = true;
                    break; // 如果有return语句，就不用再往下读了
                }
            }
            scope.exit();
            // 处理一些不写返回值的情况（不会有代码不写返回值吧，不会吧不会吧）
            if (!is_return)
            {
                switch (node.ret_type)
                {
                case SyntaxTree::Type::VOID:
                    builder->create_void_ret();
                case SyntaxTree::Type::INT:
                    builder->create_ret(CONST_INT(0));
                case SyntaxTree::Type::FLOAT:
                    builder->create_ret(CONST_FLOAT(0));
                default:
                    break;
                }
            }
        }

        void IRBuilder::visit(SyntaxTree::FuncFParamList &node)
        {
            auto func_arg_list = module->get_functions().back()->arg_begin(); // 取出堆栈中最后一个函数的参数列表，并且指向第一个参数
            for (const auto &param : node.params)
            {
                param->accept(*this); // 获取数据
                // 处理获取的数据
                if ((*func_arg_list)->get_type()->is_pointer_type()) // 如果是指针类型，传址调用
                {
                    scope.push(param->name, *func_arg_list); // 这里是指针
                }
                else // 传值调用，要分配空间
                {
                    auto alloca = builder->create_alloca((*func_arg_list)->get_type());
                    builder->create_store(*func_arg_list, alloca);
                    scope.push(param->name, alloca);
                }
                func_arg_list++;
            }
        }

        void IRBuilder::visit(SyntaxTree::FuncParam &node)
        {
            auto param_name = node.name;
            auto param_type = node.param_type;
            auto param_value = node.array_index;
            // deal with array_index
            if (!node.array_index.empty()) // array
            {
                for (const auto &exp : param_value)
                {
                    exp->accept(*this);
                }
            }
        }

        void IRBuilder::visit(SyntaxTree::VarDef &node)
        {
            bool is_const = node.is_constant;
            auto var_name = node.name;
            auto var_type = type_map[node.btype];
            auto is_initialized = node.is_inited;
            auto length = node.array_length;
            auto init_val = node.initializers;
            // deal with array_length
            if (length.empty()) // 说明不是数组
            {
                if (scope.in_global()) // 如果是全局变量
                {
                    auto global_var = GlobalVariable::create(var_name, module, var_type, is_const, ConstantZero::create(var_type, module));
                    if (is_initialized)
                    {
                        init_val->accept(*this);
                        LVal_to_RVal(tmp_val);
                        builder->create_store(tmp_val, global_var);
                    }
                    else if (is_const) // 说明是const，但是没有初始化
                        cout << "const variable must be initialized" << endl;
                    scope.push(var_name, global_var);
                }
                else // 如果是局部变量
                {
                    auto var = builder->create_alloca(var_type);
                    if (is_initialized)
                    {
                        init_val->accept(*this);
                        LVal_to_RVal(tmp_val);
                        builder->create_store(tmp_val , var);
                    }
                    else if (is_const) // 说明是const，但是没有初始化
                        cout << "const variable must be initialized" << endl;
                    scope.push(var_name, var);
                }
            }
            else // 数组
            {
                auto arrayType = ArrayType::get(var_type, length.size());

                if (scope.in_global()) // 如果是全局变量
                {
                    auto global_array = GlobalVariable::create(var_name, module, arrayType, is_const, ConstantZero::create(var_type, module));

                    if (is_initialized)
                    {
                        init_list.clear();                       // 清空init_list
                        init_val->accept(*this);                 // 把init_val里面的值放到init_list里面
                        while (init_list.size() < length.size()) // 如果init_list的长度小于length的长度，就把init_list其他的值补上0
                        {
                            init_list.push_back(ConstantZero::create(type_map[node.btype], module));
                        }
                        // initilize
                        for (auto i = 0; i < static_cast<int>(init_list.size()); i++)
                        {
                            auto GEP = builder->create_gep(global_array, {CONST_INT(0), CONST_INT(i)});
                            builder->create_store(init_list[i], GEP);
                        }
                    }
                    else if (is_const) // 说明是const，但是没有初始化
                        cout << "const variable must be initialized" << endl;

                    scope.push(var_name, global_array);
                }
                else
                {
                    auto array = builder->create_alloca(arrayType);

                    if (is_initialized)
                    {
                        init_list.clear();                       // 清空init_list
                        init_val->accept(*this);                 // 把init_val里面的值放到init_list里面
                        while (init_list.size() < length.size()) // 如果init_list的长度小于length的长度，就把init_list其他的值补上0
                        {
                            init_list.push_back(ConstantZero::create(type_map[node.btype], module));
                        }
                        // initilize
                        for (int i = 0; i < static_cast<int>(init_list.size()); i++)
                        {
                            auto GEP = builder->create_gep(array, {CONST_INT(0), CONST_INT(i)});
                            builder->create_store(init_list[i], GEP);
                        }
                    }
                    else if (is_const) // 说明是const，但是没有初始化
                        cout << "const variable must be initialized" << endl;

                    scope.push(var_name, array);
                }
            }
        }

        void IRBuilder::visit(SyntaxTree::LVal &node)
        {
            auto name = node.name;
            auto index = node.array_index;
            auto lval = scope.find(name, false);
            if (lval)
            {
                if (!index.empty())
                {
                    for (const auto &exp : index)
                    {
                        exp->accept(*this);
                        auto tmp = tmp_val;
                        auto GEP = builder->create_gep(lval, {tmp});
                        lval = GEP;
                    }
                }
                else
                { // 从符号表中取出的是字面值
                    tmp_val = lval;
                }
            }
            else
            {
                std::cout << "LVal pointer or literal not found" << std::endl;
            }
        } // lval: Identifier|Identifier LeftBracket exp RightBracket

        void IRBuilder::visit(SyntaxTree::AssignStmt &node)
        {
            node.target->accept(*this);
            auto target = builder->create_load(tmp_val);//?
            auto name = target->get_name();
            node.value->accept(*this);//?
            LVal_to_RVal(tmp_val);
            auto value = tmp_val;

            builder->create_store(value, target);
        }

        void IRBuilder::visit(SyntaxTree::Literal &node)
        {
            auto type = node.literal_type;
            switch (type)
            {
            case SyntaxTree::Type::INT:
                tmp_val = CONST_INT(node.int_const);
            case SyntaxTree::Type::FLOAT:
                tmp_val = CONST_FLOAT(node.float_const);
            default:
                break;
            }
        } // literal: IntegerLiteral|FloatLiteral

        void IRBuilder::visit(SyntaxTree::ReturnStmt &node)
        {
            auto return_value = node.ret;
            if (return_value != nullptr)
            {
                return_value->accept(*this);
                LVal_to_RVal(tmp_val);
                auto value_type = tmp_val->get_type();
                auto ret_type = module->get_functions().back()->get_return_type();
                // 类型检查
                if(ret_type == INT32_T)
                {
                    if(value_type == FLOAT_T)
                        tmp_val = builder->create_fptosi(tmp_val, INT32_T);
                    else if(value_type == INT1_T)
                        tmp_val = builder->create_zext(tmp_val, INT32_T);
                }
                auto value = tmp_val;
                builder->create_ret(value);
            }
            else
            {
                builder->create_void_ret();
            }
        }

        void IRBuilder::visit(SyntaxTree::BlockStmt &node)
        {
            scope.enter();
            for (const auto &stmt : node.body)
            {
                stmt->accept(*this);
                if (dynamic_cast<SyntaxTree::BreakStmt *>(stmt.get()) != nullptr || dynamic_cast<SyntaxTree::ContinueStmt *>(stmt.get()) != nullptr || dynamic_cast<SyntaxTree::ReturnStmt *>(stmt.get()) != nullptr)
                { // break,continue,return后面的语句不再编译
                    break;
                }
            }
            scope.exit();
        }

        void IRBuilder::visit(SyntaxTree::EmptyStmt &node)
        {
            node.accept(*this);
        }

        void IRBuilder::visit(SyntaxTree::ExprStmt &node)
        {
            node.exp->accept(*this);
        }

        void IRBuilder::visit(SyntaxTree::UnaryCondExpr &node)
        {
            node.rhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto rhs = tmp_val;
            // 整数
            if (rhs->get_type() == INT32_T)
            {
                auto UnaryCondExpr = builder->create_icmp_eq(rhs, CONST_INT(0));
                scope.push("CondExpr", UnaryCondExpr);
            }
            else
            {
                auto UnaryCondExpr = builder->create_fcmp_eq(rhs, CONST_FLOAT(0));
                scope.push("CondExpr", UnaryCondExpr);
            }
        }

        void IRBuilder::visit(SyntaxTree::BinaryCondExpr &node)
        {
            node.rhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto rhs = tmp_val;
            auto rhs_type = rhs->get_type();
            node.lhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto lhs = tmp_val;
            auto lhs_type = lhs->get_type();

            if (node.op == SyntaxTree::BinaryCondOp::LAND)
            {
                auto falseBB = scope.find("falseBB", 0);
                auto trueBB = BasicBlock::create(module,
                                                 "trueBB_lhs", module->get_functions().back());

                if (lhs_type == INT1_T)
                {
                    builder->create_cond_br(lhs, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
                }
                else if (lhs_type == INT32_T)
                {
                    auto lhs_cond = builder->create_icmp_eq(lhs, CONST_INT(0));
                    builder->create_cond_br(lhs_cond, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
                }
                else if (lhs_type == FLOAT_T)
                {
                    auto lhs_cond = builder->create_fcmp_eq(lhs, CONST_FLOAT(0));
                    builder->create_cond_br(lhs_cond, trueBB, dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
                }
                builder->set_insert_point(trueBB);
                node.rhs->accept(*this);
            }
            else if (node.op == SyntaxTree::BinaryCondOp::LOR)
            {
                auto trueBB = scope.find("trueBB", 0);
                auto falseBB = BasicBlock::create(module,
                                                  "falseBB_lhs", module->get_functions().back());

                if (lhs_type == INT1_T)
                {
                    builder->create_cond_br(lhs, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
                }
                else if (lhs_type == INT32_T)
                {
                    auto lhs_cond = builder->create_icmp_eq(lhs, CONST_INT(0));
                    builder->create_cond_br(lhs_cond, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
                }
                else if (lhs_type == FLOAT_T)
                {
                    auto lhs_cond = builder->create_fcmp_eq(lhs, CONST_FLOAT(0));
                    builder->create_cond_br(lhs_cond, dynamic_pointer_cast<SysYF::IR::BasicBlock>(trueBB), falseBB);
                }
                builder->set_insert_point(falseBB);
                node.rhs->accept(*this);
            }
            else
            {
                auto expr_type = FLOAT_T;

                if (lhs_type == INT1_T && rhs_type == INT32_T)
                {
                    lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, INT32_T));
                }
                else if (lhs_type == INT1_T && rhs_type == FLOAT_T)
                {
                    lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, FLOAT_T));
                }
                else if (lhs_type == INT32_T && rhs_type == INT1_T)
                {
                    rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, INT32_T));
                }
                else if (lhs_type == FLOAT_T && rhs_type == INT1_T)
                {
                    rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, FLOAT_T));
                }
                else if (lhs_type == FLOAT_T && rhs_type == INT32_T)
                {
                    rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(rhs, FLOAT_T));
                }
                else if (lhs_type == INT32_T && rhs_type == FLOAT_T)
                {
                    lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(lhs, FLOAT_T));
                }
                else if (lhs_type == INT1_T && rhs_type == INT1_T)
                {
                    lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(lhs, INT32_T));
                    rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_zext(rhs, INT32_T));
                }
                // 整数
                if (rhs->get_type() == INT32_T)
                {
                    switch (node.op)
                    {
                    case SysYF::SyntaxTree::BinaryCondOp::LT:
                    {
                        tmp_val = builder->create_icmp_lt(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::LTE:
                    {
                        tmp_val = builder->create_icmp_le(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::GT:
                    {
                        tmp_val = builder->create_icmp_gt(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::GTE:
                    {
                        tmp_val = builder->create_icmp_ge(lhs, rhs);
                        break;
                    }
                    case SysYF::SyntaxTree::BinaryCondOp::EQ:
                    {
                        tmp_val = builder->create_icmp_eq(lhs, rhs);
                    }
                    default:
                        break;
                    }
                }
                else
                {
                    switch (node.op)
                    {
                    case SysYF::SyntaxTree::BinaryCondOp::LT:
                    {
                        tmp_val = builder->create_fcmp_lt(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::LTE:
                    {
                        tmp_val = builder->create_fcmp_le(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::GT:
                    {
                        tmp_val = builder->create_fcmp_gt(lhs, rhs);
                        break;
                    }

                    case SysYF::SyntaxTree::BinaryCondOp::GTE:
                    {
                        tmp_val = builder->create_fcmp_ge(lhs, rhs);
                        break;
                    }
                    case SysYF::SyntaxTree::BinaryCondOp::EQ:
                    {
                        tmp_val = builder->create_fcmp_eq(lhs, rhs);
                    }
                    default:
                        break;
                    }
                }
                scope.push("CondExpr", tmp_val);
            }
        }
        void IRBuilder::visit(SyntaxTree::BinaryExpr &node)
        {
            // 整数
            node.rhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto rhs = tmp_val;
            auto rhs_type = rhs->get_type();
            node.lhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto lhs = tmp_val;
            auto lhs_type = lhs->get_type();
            if (lhs_type == FLOAT_T && rhs_type == INT32_T)
            {
                rhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(rhs, FLOAT_T));
            }
            else if (lhs_type == INT32_T && rhs_type == FLOAT_T)
            {
                lhs = dynamic_pointer_cast<SysYF::IR::LoadInst>(builder->create_sitofp(lhs, FLOAT_T));
            }
            auto expr_type = lhs->get_type();

            // 计算出可以直接计算的值
            if ((dynamic_pointer_cast<ConstantFloat>(lhs) || dynamic_pointer_cast<ConstantFloat>(lhs)) && (dynamic_pointer_cast<ConstantFloat>(rhs) || dynamic_pointer_cast<ConstantFloat>(rhs)))
            { // 简单字面量计算
                int lhs_int;
                int rhs_int;
                float lhs_float;
                float rhs_float;
                if (expr_type == INT32_T)
                {
                    lhs_int = dynamic_pointer_cast<ConstantInt>(lhs)->get_value();
                    rhs_int = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
                }
                else
                {
                    lhs_float = dynamic_pointer_cast<ConstantFloat>(lhs)->get_value();
                    rhs_float = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
                }

                switch (node.op)
                {
                case SyntaxTree::BinOp::PLUS:
                    if (expr_type == INT32_T)
                    {
                        tmp_val = CONST_INT(lhs_int + rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(lhs_float + rhs_float);
                    }
                    break;
                case SyntaxTree::BinOp::MINUS:
                    if (expr_type == INT32_T)
                    {
                        tmp_val = CONST_INT(lhs_int - rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(lhs_float - rhs_float);
                    }
                    break;
                case SyntaxTree::BinOp::MULTIPLY:
                    if (expr_type == INT32_T)
                    {
                        tmp_val = CONST_INT(lhs_int * rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(lhs_float * rhs_float);
                    }
                    break;
                case SyntaxTree::BinOp::DIVIDE:
                    if (expr_type == INT32_T)
                    {
                        tmp_val = CONST_INT(lhs_int / rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(lhs_float / rhs_float);
                    }
                    break;
                case SyntaxTree::BinOp::MODULO:
                    if (expr_type == INT32_T)
                    {
                        tmp_val = CONST_INT(lhs_int % rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_INT(static_cast<int>(lhs_float) % static_cast<int>(rhs_float));
                    }
                    break;
                }
                return;
            }
            if (lhs_type == INT32_T)
            {

                switch (node.op)
                {
                case SyntaxTree::BinOp::PLUS:
                {
                    builder->create_iadd(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MINUS:
                {
                    builder->create_isub(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MULTIPLY:
                {
                    builder->create_imul(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::DIVIDE:
                {
                    builder->create_isdiv(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MODULO:
                {
                    builder->create_isrem(lhs, rhs);
                    break;
                }
                }
            }
            else if (lhs_type == FLOAT_T)
            {
                switch (node.op)
                {
                case SyntaxTree::BinOp::PLUS:
                {
                    builder->create_fadd(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MINUS:
                {
                    builder->create_fsub(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MULTIPLY:
                {
                    builder->create_fmul(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::DIVIDE:
                {
                    builder->create_fdiv(lhs, rhs);
                    break;
                }
                case SyntaxTree::BinOp::MODULO:
                {
                    // builder->create_isrem(static_pointer_cast<ConstantInt>(lhs), static_pointer_cast<ConstantInt>(rhs));
                    break;
                }
                }
            }
        }

        void IRBuilder::visit(SyntaxTree::UnaryExpr &node)
        {
            // 整数
            node.rhs->accept(*this);
            LVal_to_RVal(tmp_val);
            auto rhs = tmp_val;
            auto rhs_type = rhs->get_type();

            // 直接计算的
            if (dynamic_pointer_cast<ConstantInt>(rhs) || dynamic_pointer_cast<ConstantFloat>(rhs))
            {
                int rhs_int;
                float rhs_float;
                if (rhs_type == INT32_T)
                {
                    rhs_int = dynamic_pointer_cast<ConstantInt>(rhs)->get_value();
                }
                else
                {
                    rhs_float = dynamic_pointer_cast<ConstantFloat>(rhs)->get_value();
                }
                switch (node.op)
                {
                case SyntaxTree::UnaryOp::PLUS:
                    if (rhs_type == INT32_T)
                    {
                        tmp_val = CONST_INT(rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(rhs_float);
                    }
                    break;
                case SyntaxTree::UnaryOp::MINUS:
                    if (rhs_type == INT32_T)
                    {
                        tmp_val = CONST_INT(-rhs_int);
                    }
                    else
                    {
                        tmp_val = CONST_FLOAT(-rhs_float);
                    }
                    break;
                }
                return;
            }
            if (rhs_type == INT32_T)
            {
                switch (node.op)
                {
                case SyntaxTree::UnaryOp::PLUS:
                {
                    builder->create_iadd(rhs, CONST_INT(0));
                    break;
                }
                case SyntaxTree::UnaryOp::MINUS:
                {
                    builder->create_isub(CONST_INT(0), rhs);
                    break;
                }
                }
            }
            else if (rhs_type == FLOAT_T)
            {
                switch (node.op)
                {
                case SyntaxTree::UnaryOp::PLUS:
                {
                    builder->create_fadd(rhs, CONST_FLOAT(0));
                    break;
                }
                case SyntaxTree::UnaryOp::MINUS:
                {
                    builder->create_fsub(CONST_FLOAT(0), rhs);
                    break;
                }
                }
            }
        }

        void IRBuilder::visit(SyntaxTree::FuncCallStmt &node)
        {
            auto func = scope.find(node.name, true);
            if (func)
            {
                PtrVec<Value> args{};

                auto arg_func = dynamic_pointer_cast<SysYF::IR::Function>(func)->arg_begin();

                for (auto &arg : node.params)
                {
                    auto arg_func_type = (*arg_func)->get_type();

                    arg->accept(*this);
                    LVal_to_RVal(tmp_val);
                    auto value = tmp_val;

                    // 数组
                    if (arg_func_type == INT32PTR_T || arg_func_type == FLOATPTR_T)
                    {
                        // if(value->get_type() == INT32PTR_T || value->get_type() == FLOATPTR_T){
                        //     tmp_val = value;
                        // }
                        // else{
                        //     tmp_val = builder->create_alloca(arg_func_type);
                        //     builder->create_store(value, tmp_val);
                        // }
                    }
                    else
                    {
                        if (value->get_type() == INT32_T && arg_func_type == FLOAT_T)
                        {
                            tmp_val = builder->create_sitofp(value, FLOAT_T);
                        }
                        else if (value->get_type() == FLOAT_T && arg_func_type == INT32_T)
                        {
                            tmp_val = builder->create_fptosi(value, INT32_T);
                        }
                    }

                    args.push_back(tmp_val);
                }

                builder->create_call(func, args);
            }
        }

        void IRBuilder::visit(SyntaxTree::IfStmt &node)
        {
            scope.enter();
            auto trueBB = BasicBlock::create(module, "trueBB_if",
                                             module->get_functions().back());
            auto nextBB = BasicBlock::create(module, "nextBB_if",
                                             module->get_functions().back());

            scope.push("trueBB", trueBB);
            scope.push("falseBB", nextBB);

            node.cond_exp->accept(*this);
            LVal_to_RVal(tmp_val);
            auto cond = tmp_val;

            builder->create_cond_br(cond, trueBB, nextBB);
            builder->set_insert_point(trueBB);
            node.if_statement->accept(*this);

            builder->set_insert_point(nextBB);
            if (node.else_statement)
            {
                node.else_statement->accept(*this);
            }
            scope.exit();
        }

        void IRBuilder::visit(SyntaxTree::WhileStmt &node)
        {
            // auto func_name = scope.find("func", 0);
            scope.enter();
            auto condBB = BasicBlock::create(module, "condBB_while",
                                             module->get_functions().back());
            auto trueBB = BasicBlock::create(module, "trueBB_while",
                                             module->get_functions().back());
            auto falseBB = BasicBlock::create(module, "falseBB_while",
                                              module->get_functions().back());

            scope.push("condBB", condBB);
            scope.push("trueBB", trueBB);
            scope.push("falseBB", falseBB);

            builder->create_br(condBB);
            node.cond_exp->accept(*this);
            LVal_to_RVal(tmp_val);
            auto cond = tmp_val;
            builder->create_cond_br(cond, trueBB, falseBB);

            auto cond_val = tmp_val;
            scope.exit();
        }

        void IRBuilder::visit(SyntaxTree::BreakStmt &node)
        {
            node.accept(*this);
            auto falseBB = scope.find("falseBB", 0);
            builder->create_br(dynamic_pointer_cast<SysYF::IR::BasicBlock>(falseBB));
        }

        void IRBuilder::visit(SyntaxTree::ContinueStmt &node)
        {
            node.accept(*this);
            auto condBB = scope.find("condBB", 0);
            builder->create_br(dynamic_pointer_cast<SysYF::IR::BasicBlock>(condBB));
        }
    }
}