// Copyright 2023 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
#include <variant>

namespace Common::GekkoAssembler
{
struct Interval
{
  size_t begin;
  size_t len;
  constexpr size_t End() const { return begin + len; }
};

struct AssemblerError
{
  std::string message;
  std::string_view error_line;
  size_t line;
  size_t col;
  size_t len;

  std::string FormatError() const;
};

template <typename Tag, typename T>
using Tagged = std::pair<Tag, T>;
template <typename Tag, typename T>
constexpr const Tag& TagOf(const Tagged<Tag, T>& val)
{
  return std::get<0>(val);
}
template <typename Tag, typename T>
constexpr Tag& TagOf(Tagged<Tag, T>& val)
{
  return std::get<0>(val);
}
template <typename Tag, typename T>
constexpr const T& ValueOf(const Tagged<Tag, T>& val)
{
  return std::get<1>(val);
}
template <typename Tag, typename T>
constexpr T& ValueOf(Tagged<Tag, T>& val)
{
  return std::get<1>(val);
}

template <typename T>
using FailureOr = std::variant<AssemblerError, T>;
template <typename T>
constexpr bool IsFailure(const FailureOr<T>& var)
{
  return std::holds_alternative<AssemblerError>(var);
}
template <typename T>
constexpr AssemblerError& GetFailure(FailureOr<T>& var)
{
  return std::get<AssemblerError>(var);
}
template <typename T>
constexpr const AssemblerError& GetFailure(const FailureOr<T>& var)
{
  return std::get<AssemblerError>(var);
}
template <typename T>
constexpr const T& GetT(const FailureOr<T>& var)
{
  return std::get<T>(var);
}
template <typename T>
constexpr T& GetT(FailureOr<T>& var)
{
  return std::get<T>(var);
}

enum class GekkoDirective
{
  Byte,
  _2byte,
  _4byte,
  _8byte,
  Float,
  Double,
  Locate,
  PadAlign,
  Align,
  Zeros,
  Skip,
  DefVar,
  Ascii,
  Asciz
};

enum class GekkoMnemonic : size_t
{
  Add,
  Addc,
  Adde,
  Addi,
  Addic,
  AddicDot,
  Addis,
  Addme,
  Addze,
  Divw,
  Divwu,
  Mulhw,
  Mulhwu,
  Mulli,
  Mullw,
  Neg,
  Subf,
  Subfc,
  Subfe,
  Subfic,
  Subfme,
  Subfze,
  Cmp,
  Cmpi,
  Cmpl,
  Cmpli,
  And,
  Andc,
  AndiDot,
  AndisDot,
  Cntlzw,
  Eqv,
  Extsb,
  Extsh,
  Nand,
  Nor,
  Or,
  Orc,
  Ori,
  Oris,
  Xor,
  Xori,
  Xoris,
  Rlwimi,
  Rlwinm,
  Rlwnm,
  Slw,
  Sraw,
  Srawi,
  Srw,
  Fadd,
  Fadds,
  Fdiv,
  Fdivs,
  Fmul,
  Fmuls,
  Fres,
  Frsqrte,
  Fsub,
  Fsubs,
  Fsel,
  Fmadd,
  Fmadds,
  Fmsub,
  Fmsubs,
  Fnmadd,
  Fnmadds,
  Fnmsub,
  Fnmsubs,
  Fctiw,
  Fctiwz,
  Frsp,
  Fcmpo,
  Fcmpu,
  Mcrfs,
  Mffs,
  Mtfsb0,
  Mtfsb1,
  Mtfsf,
  Mtfsfi,
  Lbz,
  Lbzu,
  Lbzux,
  Lbzx,
  Lha,
  Lhau,
  Lhaux,
  Lhax,
  Lhz,
  Lhzu,
  Lhzux,
  Lhzx,
  Lwz,
  Lwzu,
  Lwzux,
  Lwzx,
  Stb,
  Stbu,
  Stbux,
  Stbx,
  Sth,
  Sthu,
  Sthux,
  Sthx,
  Stw,
  Stwu,
  Stwux,
  Stwx,
  Lhbrx,
  Lwbrx,
  Sthbrx,
  Stwbrx,
  Lmw,
  Stmw,
  Lswi,
  Lswx,
  Stswi,
  Stswx,
  Eieio,
  Isync,
  Lwarx,
  StwcxDot,
  Sync,
  Lfd,
  Lfdu,
  Lfdux,
  Lfdx,
  Lfs,
  Lfsu,
  Lfsux,
  Lfsx,
  Stfd,
  Stfdu,
  Stfdux,
  Stfdx,
  Stfiwx,
  Stfs,
  Stfsu,
  Stfsux,
  Stfsx,
  Fabs,
  Fmr,
  Fnabs,
  Fneg,
  B,
  Bc,
  Bcctr,
  Bclr,
  Crand,
  Crandc,
  Creqv,
  Crnand,
  Crnor,
  Cror,
  Crorc,
  Crxor,
  Mcrf,
  Rfi,
  Sc,
  Tw,
  Twi,
  Mcrxr,
  Mfcr,
  Mfmsr,
  Mfspr_nobitswap,
  Mftb_nobitswap,
  Mtcrf,
  Mtmsr,
  Mtspr_nobitswap,
  Dcbf,
  Dcbi,
  Dcbst,
  Dcbt,
  Dcbtst,
  Dcbz,
  Icbi,
  Mfsr,
  Mfsrin,
  Mtsr,
  Mtsrin,
  Tlbie,
  Tlbsync,
  Eciwx,
  Ecowx,
  Psq_lx,
  Psq_stx,
  Psq_lux,
  Psq_stux,
  Psq_l,
  Psq_lu,
  Psq_st,
  Psq_stu,
  Ps_div,
  Ps_sub,
  Ps_add,
  Ps_sel,
  Ps_res,
  Ps_mul,
  Ps_rsqrte,
  Ps_msub,
  Ps_madd,
  Ps_nmsub,
  Ps_nmadd,
  Ps_neg,
  Ps_mr,
  Ps_nabs,
  Ps_abs,
  Ps_sum0,
  Ps_sum1,
  Ps_muls0,
  Ps_muls1,
  Ps_madds0,
  Ps_madds1,
  Ps_cmpu0,
  Ps_cmpo0,
  Ps_cmpu1,
  Ps_cmpo1,
  Ps_merge00,
  Ps_merge01,
  Ps_merge10,
  Ps_merge11,
  Dcbz_l,
  LastMnemonic = Dcbz_l,
  InvalidMnemonic,
};

enum class ExtendedGekkoMnemonic : size_t
{
  Subi,
  Subis,
  Subic,
  SubicDot,
  Sub,
  Subc,
  Cmpwi,
  Cmpw,
  Cmplwi,
  Cmplw,
  Extlwi,
  Extrwi,
  Inslwi,
  Insrwi,
  Rotlwi,
  Rotrwi,
  Rotlw,
  Slwi,
  Srwi,
  Clrlwi,
  Clrrwi,
  Clrlslwi,
  Bt,
  Bf,
  Bdnz,
  Bdnzt,
  Bdnzf,
  Bdz,
  Bdzt,
  Bdzf,
  BtPredict,
  BfPredict,
  BdnzPredict,
  BdnztPredict,
  BdnzfPredict,
  BdzPredict,
  BdztPredict,
  BdzfPredict,
  Blr,
  Btlr,
  Bflr,
  Bdnzlr,
  Bdnztlr,
  Bdnzflr,
  Bdzlr,
  Bdztlr,
  Bdzflr,
  BtlrPredict,
  BflrPredict,
  BdnzlrPredict,
  BdnztlrPredict,
  BdnzflrPredict,
  BdzlrPredict,
  BdztlrPredict,
  BdzflrPredict,
  Bctr,
  Btctr,
  Bfctr,
  BtctrPredict,
  BfctrPredict,
  Blt,
  Ble,
  Beq,
  Bge,
  Bgt,
  Bnl,
  Bne,
  Bng,
  Bso,
  Bns,
  Bun,
  Bnu,
  BltPredict,
  BlePredict,
  BeqPredict,
  BgePredict,
  BgtPredict,
  BnlPredict,
  BnePredict,
  BngPredict,
  BsoPredict,
  BnsPredict,
  BunPredict,
  BnuPredict,
  Bltlr,
  Blelr,
  Beqlr,
  Bgelr,
  Bgtlr,
  Bnllr,
  Bnelr,
  Bnglr,
  Bsolr,
  Bnslr,
  Bunlr,
  Bnulr,
  BltlrPredict,
  BlelrPredict,
  BeqlrPredict,
  BgelrPredict,
  BgtlrPredict,
  BnllrPredict,
  BnelrPredict,
  BnglrPredict,
  BsolrPredict,
  BnslrPredict,
  BunlrPredict,
  BnulrPredict,
  Bltctr,
  Blectr,
  Beqctr,
  Bgectr,
  Bgtctr,
  Bnlctr,
  Bnectr,
  Bngctr,
  Bsoctr,
  Bnsctr,
  Bunctr,
  Bnuctr,
  BltctrPredict,
  BlectrPredict,
  BeqctrPredict,
  BgectrPredict,
  BgtctrPredict,
  BnlctrPredict,
  BnectrPredict,
  BngctrPredict,
  BsoctrPredict,
  BnsctrPredict,
  BunctrPredict,
  BnuctrPredict,
  Crset,
  Crclr,
  Crmove,
  Crnot,
  Twlt,
  Twlti,
  Twle,
  Twlei,
  Tweq,
  Tweqi,
  Twge,
  Twgei,
  Twgt,
  Twgti,
  Twnl,
  Twnli,
  Twne,
  Twnei,
  Twng,
  Twngi,
  Twllt,
  Twllti,
  Twlle,
  Twllei,
  Twlge,
  Twlgei,
  Twlgt,
  Twlgti,
  Twlnl,
  Twlnli,
  Twlng,
  Twlngi,
  Trap,
  Mtxer,
  Mfxer,
  Mtlr,
  Mflr,
  Mtctr,
  Mfctr,
  Mtdsisr,
  Mfdsisr,
  Mtdar,
  Mfdar,
  Mtdec,
  Mfdec,
  Mtsdr1,
  Mfsdr1,
  Mtsrr0,
  Mfsrr0,
  Mtsrr1,
  Mfsrr1,
  Mtasr,
  Mfasr,
  Mtear,
  Mfear,
  Mttbl,
  Mftbl,
  Mttbu,
  Mftbu,
  Mtsprg,
  Mfsprg,
  Mtibatu,
  Mfibatu,
  Mtibatl,
  Mfibatl,
  Mtdbatu,
  Mfdbatu,
  Mtdbatl,
  Mfdbatl,
  Nop,
  Li,
  Lis,
  La,
  Mr,
  Not,
  Mtcr,
  Mfspr,
  Mftb,
  Mtspr,
  LastMnemonic = Mtspr,
  InvalidMnemonic
};
}  // namespace Common::GekkoAssembler
