#include "irgen/IRGen.h"

#include <stdexcept>
#include <string>

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

// 内部辅助：不依赖类成员，只需 ConstEnv。
namespace {

int EvalAddExp(SysYParser::AddExpContext* ctx,
               const IRGenImpl::ConstEnv& env);
int EvalMulExp(SysYParser::MulExpContext* ctx,
               const IRGenImpl::ConstEnv& env);
int EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
                 const IRGenImpl::ConstEnv& env);

int EvalPrimary(SysYParser::PrimaryExpContext* ctx,
                const IRGenImpl::ConstEnv& env) {
  if (!ctx) throw std::runtime_error(FormatError("consteval", "空主表达式"));
  if (ctx->number()) {
    if (!ctx->number()->ILITERAL())
      throw std::runtime_error(
          FormatError("consteval", "constExp 不支持浮点字面量"));
    return std::stoi(ctx->number()->getText());
  }
  if (ctx->exp()) return EvalAddExp(ctx->exp()->addExp(), env);
  if (ctx->lValue()) {
    if (!ctx->lValue()->ID())
      throw std::runtime_error(FormatError("consteval", "非法 lValue"));
    const std::string name = ctx->lValue()->ID()->getText();
    auto it = env.find(name);
    if (it == env.end())
      throw std::runtime_error(
          FormatError("consteval", "constExp 引用非 const 变量: " + name));
    return it->second;
  }
  throw std::runtime_error(FormatError("consteval", "不支持的主表达式形式"));
}

int EvalUnaryExp(SysYParser::UnaryExpContext* ctx,
                 const IRGenImpl::ConstEnv& env) {
  if (!ctx) throw std::runtime_error(FormatError("consteval", "空一元表达式"));
  if (ctx->primaryExp()) return EvalPrimary(ctx->primaryExp(), env);
  if (ctx->unaryOp() && ctx->unaryExp()) {
    int v = EvalUnaryExp(ctx->unaryExp(), env);
    if (ctx->unaryOp()->SUB()) return -v;
    if (ctx->unaryOp()->ADD()) return v;
    if (ctx->unaryOp()->NOT()) return (v == 0) ? 1 : 0;
  }
  throw std::runtime_error(
      FormatError("consteval", "函数调用不能出现在 constExp 中"));
}

int EvalMulExp(SysYParser::MulExpContext* ctx,
               const IRGenImpl::ConstEnv& env) {
  if (!ctx) throw std::runtime_error(FormatError("consteval", "空乘法表达式"));
  if (ctx->mulExp()) {
    int lhs = EvalMulExp(ctx->mulExp(), env);
    int rhs = EvalUnaryExp(ctx->unaryExp(), env);
    if (ctx->MUL()) return lhs * rhs;
    if (ctx->DIV()) { if (!rhs) throw std::runtime_error("除以零"); return lhs / rhs; }
    if (ctx->MOD()) { if (!rhs) throw std::runtime_error("模零"); return lhs % rhs; }
    throw std::runtime_error(FormatError("consteval", "未知乘法运算符"));
  }
  return EvalUnaryExp(ctx->unaryExp(), env);
}

int EvalAddExp(SysYParser::AddExpContext* ctx,
               const IRGenImpl::ConstEnv& env) {
  if (!ctx) throw std::runtime_error(FormatError("consteval", "空加法表达式"));
  if (ctx->addExp()) {
    int lhs = EvalAddExp(ctx->addExp(), env);
    int rhs = EvalMulExp(ctx->mulExp(), env);
    if (ctx->ADD()) return lhs + rhs;
    if (ctx->SUB()) return lhs - rhs;
    throw std::runtime_error(FormatError("consteval", "未知加法运算符"));
  }
  return EvalMulExp(ctx->mulExp(), env);
}

}  // namespace

int IRGenImpl::EvalConstExpr(SysYParser::ConstExpContext* ctx) const {
  if (!ctx || !ctx->addExp())
    throw std::runtime_error(FormatError("consteval", "空 constExp"));
  return EvalAddExp(ctx->addExp(), const_env_);
}

int IRGenImpl::EvalExpAsConst(SysYParser::ExpContext* ctx) const {
  if (!ctx || !ctx->addExp())
    throw std::runtime_error(FormatError("consteval", "空 exp"));
  return EvalAddExp(ctx->addExp(), const_env_);
}
