#include "irgen/IRGen.h"

#include <stdexcept>

#include "SysYParser.h"
#include "ir/IR.h"
#include "utils/Log.h"

namespace {

std::string GetLValueName(SysYParser::LValueContext& lvalue) {
  if (!lvalue.ID()) {
    throw std::runtime_error(FormatError("irgen", "非法左值"));
  }
  return lvalue.ID()->getText();
}

}  // namespace

std::any IRGenImpl::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少语句块"));
  }
  for (auto* item : ctx->blockItem()) {
    if (item) {
      if (VisitBlockItemResult(*item) == BlockFlow::Terminated) {
        // 当前语法要求 return 为块内最后一条语句；命中后可停止生成。
        break;
      }
    }
  }
  return {};
}

IRGenImpl::BlockFlow IRGenImpl::VisitBlockItemResult(
    SysYParser::BlockItemContext& item) {
  return std::any_cast<BlockFlow>(item.accept(this));
}

std::any IRGenImpl::visitBlockItem(SysYParser::BlockItemContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少块内项"));
  }
  if (ctx->decl()) {
    ctx->decl()->accept(this);
    return BlockFlow::Continue;
  }
  if (ctx->stmt()) {
    return ctx->stmt()->accept(this);
  }
  throw std::runtime_error(FormatError("irgen", "暂不支持的语句或声明"));
}

// 变量声明的 IR 生成目前也是最小实现：
// - 先检查声明的基础类型，当前仅支持局部 int；
// - 再把 Decl 中的变量定义交给 visitVarDef 继续处理。
//
// 和更完整的版本相比，这里还没有：
// - 一个 Decl 中多个变量定义的顺序处理；
// - const、数组、全局变量等不同声明形态；
// - 更丰富的类型系统。
std::any IRGenImpl::visitDecl(SysYParser::DeclContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少变量声明"));
  }
  if (!ctx->btype() || !ctx->btype()->INT()) {
    throw std::runtime_error(FormatError("irgen", "当前仅支持局部 int 变量声明"));
  }
  auto* var_def = ctx->varDef();
  if (!var_def) {
    throw std::runtime_error(FormatError("irgen", "非法变量声明"));
  }
  var_def->accept(this);
  return {};
}


// 当前仍是教学用的最小版本，因此这里只支持：
// - 局部 int 变量；
// - 标量初始化；
// - 一个 VarDef 对应一个槽位。
std::any IRGenImpl::visitVarDef(SysYParser::VarDefContext* ctx) {
  if (!ctx) {
    throw std::runtime_error(FormatError("irgen", "缺少变量定义"));
  }
  if (!ctx->lValue()) {
    throw std::runtime_error(FormatError("irgen", "变量声明缺少名称"));
  }
  GetLValueName(*ctx->lValue());
  if (storage_map_.find(ctx) != storage_map_.end()) {
    throw std::runtime_error(FormatError("irgen", "声明重复生成存储槽位"));
  }
  auto* slot = builder_.CreateAllocaI32(module_.GetContext().NextTemp());
  storage_map_[ctx] = slot;

  ir::Value* init = nullptr;
  if (auto* init_value = ctx->initValue()) {
    if (!init_value->exp()) {
      throw std::runtime_error(FormatError("irgen", "当前不支持聚合初始化"));
    }
    init = EvalExpr(*init_value->exp());
  } else {
    init = builder_.CreateConstInt(0);
  }
  builder_.CreateStore(init, slot);
  return {};
}
