#include "irgen/IRGen.h"

#include <stdexcept>

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

// 表达式生成当前也只实现了很小的一个子集。
// 目前支持：
// - 整数字面量
// - 普通局部变量读取
// - 括号表达式
// - 二元加法
//
// 还未支持：
// - 减乘除与一元运算
// - 赋值表达式
// - 函数调用
// - 数组、指针、下标访问
// - 条件与比较表达式
// - ...
ir::Value* IRGenImpl::EvalExpr(SysYParser::ExpContext& expr) {
  return std::any_cast<ir::Value*>(expr.accept(this));
}


std::any IRGenImpl::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
  if (!ctx) throw std::runtime_error(FormatError("irgen", "非法 primary 表达式"));
  if (ctx->exp()) return EvalExpr(*ctx->exp());
  if (ctx->lVal()) return ctx->lVal()->accept(this);
  if (ctx->number()) return ctx->number()->accept(this);
  throw std::runtime_error(FormatError("irgen", "不支持的 primary 表达式"));
}


std::any IRGenImpl::visitNumber(SysYParser::NumberContext* ctx) {
  if (!ctx || !ctx->IntConst()) {
    throw std::runtime_error(FormatError("irgen", "当前仅支持整数字面量"));
  }
  return static_cast<ir::Value*>(
      builder_.CreateConstInt(std::stoi(ctx->getText())));
}

// 变量使用的处理流程：
// 1. 先通过语义分析结果把变量使用绑定回声明；
// 2. 再通过 storage_map_ 找到该声明对应的栈槽位；
// 3. 最后生成 load，把内存中的值读出来。
//
// 因此当前 IRGen 自己不再做名字查找，而是直接消费 Sema 的绑定结果。
std::any IRGenImpl::visitLVal(SysYParser::LValContext* ctx) {
  if (!ctx || !ctx->Ident()) {
    throw std::runtime_error(FormatError("irgen", "当前仅支持普通整型变量"));
  }
  // find storage by matching declaration node stored in Sema context
  // Sema stores types/decl contexts in IRGenContext maps; here we search storage_map_ by name
  std::string name = ctx->Ident()->getText();
  for (auto& kv : storage_map_) {
    // kv.first is VarDefContext*, try to get Ident text
    if (kv.first && kv.first->Ident() && kv.first->Ident()->getText() == name) {
      return static_cast<ir::Value*>(
          builder_.CreateLoad(kv.second, module_.GetContext().NextTemp()));
    }
  }
  throw std::runtime_error(FormatError("irgen", "变量声明缺少存储槽位: " + name));
}


std::any IRGenImpl::visitAddExp(SysYParser::AddExpContext* ctx) {
  if (!ctx) throw std::runtime_error(FormatError("irgen", "非法加法表达式"));
  // left-associative: evaluate first two mulExp as a simple binary add
  if (ctx->mulExp().size() == 1) return ctx->mulExp(0)->accept(this);
  ir::Value* lhs = std::any_cast<ir::Value*>(ctx->mulExp(0)->accept(this));
  ir::Value* rhs = std::any_cast<ir::Value*>(ctx->mulExp(1)->accept(this));
  return static_cast<ir::Value*>(
      builder_.CreateBinary(ir::Opcode::Add, lhs, rhs,
                            module_.GetContext().NextTemp()));
}
