//! # **ISA** (**`I`**nstruction **`S`**et **`A`**rchitecture) — модуль архитектуры `x86_64`.
//!
//! ## **Анатомия x86_64 в контексте компилятора**
//!
//! ### 1. Регистровая память (`Registers`)
//! В отличие от 32-битного x86, количество регистров общего назначения (GPR)
//! здесь удвоено (с 8 до 16), а их разрядность составляет 64 бита (8 байт):
//! * **Классические (расширенные)**: `RAX`, `RCX`, `RDX`, `RBX`, `RSP`, `RBP`, `RSI`, `RDI`.
//! * **Новые (введенные в x86_64)**: `R8`, `R9`, `R10`, `R11`, `R12`, `R13`, `R14`, `R15`.
//!
//! > **Примечание**: Архитектура поддерживает обратную совместимость, позволяя обращаться
//! > к младшим частям регистров (например, 32-битный `EAX` или 8-битный `AL` внутри `RAX`),
//! > однако для упрощения на первом этапе компилятор работает со значениями фиксированной длины (64 бита).
//!
//! ### 2. Система операндов (`Operands`)
//! x86_64 относится к CISC-архитектурам. Инструкции могут принимать различные комбинации аргументов:
//! * **Immediate**: Прямое числовое значение (константа до 64 бит), например: `MOV RAX, 0x10203040`.
//! * **Register**: Операнд, находящийся в одном из 16 регистров, например: `MOV RAX, RBX`.
//! * **Memory**: Ссылка на адрес в ОЗУ. Поддерживает сложную адресацию вида `[база + индекс * масштаб + смещение]`.
//!
//! ### 3. Набор инструкций (`Instructions`)
//! Перечисление `enum Instruction` определяет поддерживаемые мнемоники. Базовый набор включает:
//! * **Управление данными**: `MOV` (копирование), `PUSH` / `POP` (работа со стеком).
//! * **Арифметика и Логика**: `ADD`, `SUB`, `CMP` (сравнение), `XOR`, `AND`.
//! * **Управление потоком**: `JMP` (безусловный переход), `JE` / `JNE` (условные переходы).
//! * **Системные**: `SYSCALL` (быстрый переход в пространство ядра ОС вместо старого `INT 0x80`), `NOP`, `RET`.
//!
//! ---
//!
//! ## **Специфика кодирования машинного кода x86_64**
//!
//! Инструкции x86_64 имеют **переменную длину** (от 1 до 15 байт). Главная сложность
//! и отличие от 32-битного режима — необходимость формирования **REX-префикса** (`0x40`–`0x4F`).
//!
//! Префикс REX (Register Extension) необходим, если:
//! 1. Инструкция оперирует 64-битными данными (выставляется бит `REX.W`).
//! 2. В инструкции используются новые регистры `R8`–`R15` (выставляются биты `REX.R`, `REX.X` или `REX.B`).
//!
//! Структура генерируемого байт-кода для каждой инструкции в методе эмиттера будет иметь вид:
//! `[Префиксы (REX)] -> [Опкод команды] -> [Байт ModR/M (мод/регистр)] -> [Байт SIB (масштаб)] -> [Смещение / Константа]`
use crate::{
    isa::err::{ISAError, ISAErrorKind},
    str_pool::StrId,
};
use std::str::FromStr;

pub mod directive;
pub mod err;

/// # Регистры общего назначения (General Purpose Registers - GPR)
///
/// Сюда входят только 16 классических 64-битных регистров.
/// Они используются в 90% стандартных инструкций (`MOV`, `ADD`, `PUSH` и т.д.).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GPRs {
    /// # RAX
    ///
    /// RAX — **64-битный регистр общего назначения** в архитектуре x86_64.
    ///
    /// В большинстве ABI (System V AMD64 и Windows x64) используется
    /// как регистр возвращаемого значения функций.
    ///
    /// RAX является расширением 32-битного регистра `EAX`.
    Rax,

    /// # RCX
    ///
    /// RCX — **64-битный регистр общего назначения** в архитектуре x86_64.
    ///
    /// Основные особенности:
    /// - В Windows x64 ABI используется как **первый регистр аргумента функции**
    /// - В System V AMD64 ABI является обычным регистром общего назначения
    /// - Исторически связан с операциями счётчика (loop, rep-инструкции)
    ///
    /// RCX является расширением 32-битного регистра `ECX`.
    Rcx,

    /// # RDX
    ///
    /// RDX — 64-битный регистр общего назначения.
    ///
    /// В ABI часто используется:
    /// - как второй аргумент функции (Windows x64 и System V AMD64)
    /// - как часть результата умножения/деления вместе с RAX
    ///
    /// Расширение регистра `EDX`.
    Rdx,

    /// # RBX
    ///
    /// RBX — регистр общего назначения.
    ///
    /// Особенность:
    /// - обычно является **callee-saved** (сохраняется вызываемой функцией)
    ///
    /// Расширение `EBX`.
    Rbx,

    /// # RSP
    ///
    /// RSP — **stack pointer (указатель стека)**.
    ///
    /// Используется для:
    /// - управления стеком вызовов
    /// - доступа к локальным переменным и аргументам
    ///
    /// Один из самых критичных регистров архитектуры.
    Rsp,

    /// # RBP
    ///
    /// RBP — **base/frame pointer (указатель кадра стека)**.
    ///
    /// Используется:
    /// - как опорный регистр для адресации локальных переменных
    /// - для отладки (stack frames)
    ///
    /// Может быть опциональным (frame pointer omission).
    Rbp,

    /// # RSI
    ///
    /// RSI — регистр общего назначения.
    ///
    /// В ABI часто используется:
    /// - как 3-й аргумент функции (System V AMD64)
    /// - как source pointer в string/array операциях
    Rsi,

    /// # RDI
    ///
    /// RDI — регистр общего назначения.
    ///
    /// В ABI часто используется:
    /// - как 1-й аргумент функции (System V AMD64)
    /// - как destination pointer в string/array операциях
    Rdi,

    /// # R8
    ///
    /// R8 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Используется в ABI:
    /// - как дополнительный регистр аргумента (Windows x64: 3-й аргумент)
    /// - как временный регистр общего назначения
    ///
    /// Является расширением `R8D` (32-битная часть).
    R8,

    /// # R9
    ///
    /// R9 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Используется в ABI:
    /// - как аргумент функции (Windows x64: 4-й аргумент)
    /// - как временный регистр общего назначения
    ///
    /// Расширение `R9D`.
    R9,

    /// # R10
    ///
    /// R10 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Часто используется как:
    /// - caller-saved временный регистр
    /// - регистр для системных вызовов (SysV ABI: сохраняет syscall ABI значение)
    ///
    /// Расширение `R10D`.
    R10,

    /// # R11
    ///
    /// R11 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Используется как:
    /// - временный caller-saved регистр
    /// - часто используется компилятором для промежуточных значений
    ///
    /// Расширение `R11D`.
    R11,

    /// # R12
    ///
    /// R12 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Особенность:
    /// - обычно является **callee-saved** регистром
    ///
    /// Расширение `R12D`.
    R12,

    /// # R13
    ///
    /// R13 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Особенность:
    /// - обычно **callee-saved**
    ///
    /// Расширение `R13D`.
    R13,

    /// # R14
    ///
    /// R14 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Особенность:
    /// - обычно **callee-saved**
    ///
    /// Расширение `R14D`.
    R14,

    /// # R15
    ///
    /// R15 — 64-битный регистр общего назначения архитектуры x86_64.
    ///
    /// Особенность:
    /// - обычно **callee-saved**
    ///
    /// Расширение `R15D`.
    R15,
}

/// # Векторные SIMD-регистры (SSE / AVX)
///
/// Используются для вычислений с плавающей точкой и векторных операций.
/// Кодируются принципиально иными опкодами.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum XMMRs {
    /// # XMM0
    ///
    /// XMM0 — 128-битный SIMD-регистр (SSE) в архитектуре x86_64.
    ///
    /// Используется для:
    /// - операций с плавающей точкой (float/double)
    /// - SIMD инструкций SSE
    /// - передачи возвращаемых значений с плавающей точкой (ABI)
    ///
    /// В System V AMD64 и Windows x64 XMM0 используется как регистр возврата для float/double
    Xmm0,

    /// # XMM1
    ///
    /// XMM1 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **2-й регистр для аргументов** с плавающей точкой (`f32`/`f64`).
    /// - В Windows x64: **2-й регистр для аргументов** с плавающей точкой.
    /// - Является **caller-saved** (разрушаемым при вызове).
    Xmm1,

    /// # XMM2
    ///
    /// XMM2 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **3-й регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: **3-й регистр для аргументов** с плавающей точкой.
    /// - Является **caller-saved**.
    Xmm2,

    /// # XMM3
    ///
    /// XMM3 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **4-й регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: **4-й регистр для аргументов** с плавающей точкой.
    /// - Является **caller-saved**.
    Xmm3,

    /// # XMM4
    ///
    /// XMM4 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **5-й регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: временный/скрэтч регистр.
    /// - Является **caller-saved**.
    Xmm4,

    /// # XMM5
    ///
    /// XMM5 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **6-й регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: временный/скрэтч регистр.
    /// - Является **caller-saved**.
    Xmm5,

    /// # XMM6
    ///
    /// XMM6 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **7-й регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: **callee-saved** (сохраняется вызываемой функцией!).
    /// - Важное различие между ОС при генерации кода функций.
    Xmm6,

    /// # XMM7
    ///
    /// XMM7 — 128-битный SIMD-регистр (SSE).
    ///
    /// Использование в ABI:
    /// - В System V AMD64: **8-й (последний) регистр для аргументов** с плавающей точкой.
    /// - В Windows x64: **callee-saved** (сохраняется вызываемой функцией).
    Xmm7,

    /// # XMM8
    ///
    /// XMM8 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm8,

    /// # XMM9
    ///
    /// XMM9 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm9,

    /// # XMM10
    ///
    /// XMM10 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm10,

    /// # XMM11
    ///
    /// XMM11 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm11,

    /// # XMM12
    ///
    /// XMM12 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm12,

    /// # XMM13
    ///
    /// XMM13 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm13,

    /// # XMM14
    ///
    /// XMM14 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm14,

    /// # XMM15
    ///
    /// XMM15 — 128-битный SIMD-регистр (SSE).
    ///
    /// Введен в архитектуре x86_64.
    /// - В System V AMD64: временный **caller-saved** регистр.
    /// - В Windows x64: **callee-saved** регистр.
    Xmm15,
}

/// # Сегментные регистры
///
/// Имеют фиксированную логику и используются в основном для системных операций или TLS.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SegmentRegisters {
    /// # FS
    ///
    /// FS — **сегментный регистр**.
    ///
    /// В x86_64 один из двух сегментных регистров (вместе с GS), который сохранил
    /// возможность задавать базовый адрес.
    /// Активно используется в операционных системах (например, в Linux) для реализации
    /// **Thread Local Storage (TLS)** — хранения данных, уникальных для каждого потока.
    Fs,

    /// # GS
    ///
    /// GS — **сегментный регистр**.
    ///
    /// Как и FS, сохранил базовый адрес в 64-битном режиме.
    /// В Windows x64 используется для указания на структуру данных потока (TEB)
    /// и процессора (KPCR), а в Linux — для некоторых внутренних нужд ядра.
    Gs,

    /// # CS
    ///
    /// CS — **code segment (сегмент кода)**.
    ///
    /// Определяет права доступа и текущий уровень привилегий (Ring 0 для ядра, Ring 3 для пользователя).
    Cs,

    /// # SS
    ///
    /// SS — **stack segment (сегмент стека)**.
    ///
    /// Исторический сегмент для работы со стеком, в x86_64 его база жестко зафиксирована на 0.
    Ss,

    /// # DS
    ///
    /// DS — **data segment (сегмент данных)**.
    ///
    /// Исторический сегмент для данных, в x86_64 его база равна 0.
    Ds,

    /// # ES
    ///
    /// ES — **extra segment (дополнительный сегмент)**.
    ///
    /// Исторический сегмент для строковых операций, в x86_64 его база равна 0.
    Es,
}

/// # Регистры в архитектуре x86_64
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Registers {
    /// Регистры общего назначения
    GPR(GPRs),

    /// Векторные SIMD регистры
    XMM(XMMRs),

    /// Сегментные регистры
    SR(SegmentRegisters),

    /// # RFLAGS
    ///
    /// RFLAGS — **64-битный регистр флагов (состояния)**.
    ///
    /// Содержит биты состояния процессора, которые меняются после арифметических
    /// и логических операций (например, `CMP`, `ADD`, `TEST`).
    /// Важнейшие флаги для компилятора:
    /// - **ZF (Zero Flag)**: устанавливается, если результат операции равен нулю.
    /// - **SF (Sign Flag)**: устанавливается, если результат отрицательный.
    /// - **CF (Carry Flag) / OF (Overflow Flag)**: флаги переноса и переполнения.
    ///
    /// На основе этого регистра работают все инструкции условных переходов (`JE`, `JNE`, `JG` и т.д.).
    Rflags,

    /// # RIP
    ///
    /// RIP — **instruction pointer (указатель инструкции)**.
    ///
    /// Содержит адрес памяти следующей исполняемой инструкции.
    /// В архитектуре x86_64 RIP критически важен, так как введена **RIP-относительная адресация**
    /// (RIP-relative addressing), позволяющая генерировать позиционно-независимый код (PIC)
    /// для обращения к глобальным переменным: `[RIP + offset]`.
    Rip,
}

/// # Масштаб для индексного регистра (Scale)
///
/// Используется при адресации памяти в x86_64 для умножения значения
/// в индексном регистре на 1, 2, 4 или 8 байт.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Scale {
    One = 1,
    Two = 2,
    Four = 4,
    Eight = 8,
}

/// # Структура адресации памяти (Memory Access)
///
/// Описывает сложную CISC-адресацию x86_64.
/// Например: `[rax + rbx * 4 + 0x20]` или `[rip + 0x10]`
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MemoryAddress {
    /// Базовый регистр (например, `rax` в `[rax + rbx]`)
    pub base: Option<Registers>,

    /// Индексный регистр (например, `rbx` в `[rax + rbx * 4]`)
    pub index: Option<GPRs>,

    /// Масштаб (множитель) для индексного регистра
    pub scale: Option<Scale>,

    /// Смещение (константа / displacement)
    pub displacement: i32,

    /// Символьное смещение для RIP-relative адресации, например `[rip + msg]`.
    pub label: Option<StrId>,
}

/// # Операнд инструкции x86_64
///
/// Описывает тип аргумента, переданного в команду компилятора.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Operand {
    /// Регистр (любой: GPR, XMM, Сегментный, RIP или RFLAGS)
    Register(Registers),

    /// Непосредственное значение (числовая константа до 64-бит)
    Immediate(i64),

    /// Ссылка на ячейку памяти `[адрес]`
    Memory(MemoryAddress),

    /// Ссылка на метку / функцию для инструкций переходов (jmp, call и т.д.)
    Label(StrId),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DataType {
    Byte,  // 1 байт (8 бит)  -> BYTE PTR
    Word,  // 2 байта (16 бит) -> WORD PTR
    Dword, // 4 байта (32 бита) -> DWORD PTR
    Qword, // 8 байт (64 бита)  -> QWORD PTR
}

/// # Виды мнемоник для **x86_64**
///
///
/// Перечисление мнемоник, для архитектуры x86_64.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MnemonicKind {
    // ====== Работа с данными ======
    /// # Перемещение значения в регистр
    ///
    /// Перемещает значение в регистр назначения.
    ///
    /// ## Как он используется
    /// ```text
    /// mov <куда>, <откуда>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// mov rax, 5
    /// ```
    Mov,

    // ====== Работа со стеком ======
    /// # Поместить в стек (Push Word, Doubleword or Quadword onto the Stack)
    ///
    /// Уменьшает указатель стека `RSP` (на 8 байт в 64-битном режиме)
    /// и записывает операнд в вершину стека.
    ///
    /// ## Как используется
    /// ```text
    /// push <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// push rax
    /// ```
    Push,

    /// # Извлечь из стека (Pop a Value from the Stack)
    ///
    /// Читает значение из вершины стека, записывает его в операнд назначения
    /// и увеличивает указатель стека `RSP` (на 8 байт).
    ///
    /// ## Как используется
    /// ```text
    /// pop <куда>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// pop rbx
    /// ```
    Pop,

    // ====== Арифметика и Логика ======
    /// # Сложение (Add)
    ///
    /// Складывает источник и назначение, результат сохраняется в назначение.
    /// Меняет флаги состояния в `RFLAGS` (ZF, SF, CF, OF).
    ///
    /// ## Как используется
    /// ```text
    /// add <куда>, <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// add rax, rbx
    /// ```
    Add,

    /// # Вычитание (Subtract)
    ///
    /// Вычитает источник из назначения, результат сохраняется в назначение.
    /// Меняет флаги состояния в `RFLAGS` (ZF, SF, CF, OF).
    ///
    /// ## Как используется
    /// ```text
    /// sub <куда>, <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// sub rax, 1
    /// ```
    Sub,

    /// **MUL** — Беззнаковое умножение (Unsigned Multiply).
    ///
    /// Принимает один операнд (регистр или память). Вторым сомножителем неявно выступает `RAX`.
    /// Результат имеет двойную разрядность и сохраняется в связку регистров **`RDX:RAX`**
    /// (старшие биты в `RDX`, младшие в `RAX`).
    ///
    /// *Пример:* `mul rbx` -> `RDX:RAX = RAX * rbx`.
    Mul,

    /// **IMUL** — Знаковое умножение (Signed Multiply).
    ///
    /// Поддерживает знаковые числа (в дополнении до двух). В x86_64 имеет три синтаксические формы:
    /// 1. `imul reg` — неявное умножение на `RAX`, результат в `RDX:RAX`.
    /// 2. `imul reg, reg/mem` — умножает первый на второй, результат в первом.
    /// 3. `imul reg, reg/mem, imm` — умножает второй на константу, результат в первом.
    Imul,

    /// **DIV** — Беззнаковое деление (Unsigned Divide).
    ///
    /// Принимает один операнд — делитель. Делимое неявно сцепляется из регистров **`RDX:RAX`**.
    /// Перед вызовом `RDX` должен быть обнулен.
    ///
    /// **Результат**:
    /// * **`RAX`** = Частное (Quotient)
    /// * **`RDX`** = Остаток (Remainder)
    ///
    /// *Пример:* `div rcx` -> `RAX = RDX:RAX / rcx`, `RDX = RDX:RAX % rcx`.
    Div,

    /// **IDIV** — Знаковое деление (Signed Divide).
    ///
    /// Принимает один операнд — делитель. Работает со знаковыми числами.
    /// Делимое неявно сцепляется из регистров **`RDX:RAX`**. Перед вызовом необходимо
    /// знаково расширить `RAX` на `RDX` (например, инструкцией `cqo` / `cdq`).
    ///
    /// **Результат**:
    /// * **`RAX`** = Знаковое частное
    /// * **`RDX`** = Знаковый остаток
    Idiv,

    /// # Логическое ИСКЛЮЧАЮЩЕЕ ИЛИ (Exclusive OR)
    ///
    /// Выполняет побитовую операцию XOR. Часто используется в компиляторах
    /// для быстрой и эффективной очистки регистра в ноль (работает быстрее, чем `mov rax, 0`).
    ///
    /// ## Как используется
    /// ```text
    /// xor <куда>, <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// xor rax, rax
    /// ```
    Xor,

    /// # Логическое И (Logical AND)
    ///
    /// Выполняет побитовую операцию AND между операндами.
    /// Часто используется для маскирования битов или проверки флагов.
    ///
    /// Меняет флаги состояния в `RFLAGS` (ZF, SF), очищает OF и CF.
    ///
    /// ## Как используется
    /// ```text
    /// and <куда>, <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// and rax, 0xff
    /// ```
    And,

    /// # Логическое ИЛИ (Logical OR)
    ///
    /// Выполняет побитовое OR между операндами.
    ///
    /// Используется для установки определённых битов.
    ///
    /// ## Как используется
    /// ```text
    /// or <куда>, <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// or rax, 1
    /// ```
    Or,

    /// # Проверка битов (Test)
    ///
    /// Выполняет побитовый AND между операндами,
    /// но не сохраняет результат.
    ///
    /// Используется исключительно для установки флагов.
    ///
    /// ## Как используется
    /// ```text
    /// test <левый>, <правый>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// test rax, rax
    /// ```
    Test,

    /// # Загрузить эффективный адрес (Load Effective Address)
    ///
    /// Вычисляет адрес операнда памяти и сохраняет его в регистр.
    ///
    /// Не обращается к памяти — копируется именно адрес.
    ///
    /// ## Как используется
    /// ```text
    /// lea <регистр>, [адрес]
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// lea rax, [rbx + rcx * 4]
    /// ```
    Lea,

    /// # Увеличение на единицу (Increment)
    ///
    /// Увеличивает значение операнда на единицу.
    ///
    /// ## Как используется
    /// ```text
    /// inc <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// inc rax
    /// ```
    Inc,

    /// # Уменьшение на единицу (Decrement)
    ///
    /// Уменьшает значение операнда на единицу.
    ///
    /// ## Как используется
    /// ```text
    /// dec <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// dec rcx
    /// ```
    Dec,

    /// # Арифметическое отрицание (Negate)
    ///
    /// Вычисляет дополнение до двух (`0 - operand`).
    ///
    /// ## Как используется
    /// ```text
    /// neg <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// neg rax
    /// ```
    Neg,

    /// # Побитовое отрицание (Bitwise NOT)
    ///
    /// Инвертирует каждый бит операнда.
    ///
    /// ## Как используется
    /// ```text
    /// not <что>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// not rax
    /// ```
    Not,

    /// # Логический сдвиг влево (Shift Left)
    ///
    /// Сдвигает все биты операнда влево.
    ///
    /// ## Как используется
    /// ```text
    /// shl <что>, <на сколько>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// shl rax, 1
    /// ```
    Shl,

    /// # Логический сдвиг вправо (Shift Right)
    ///
    /// Сдвигает биты вправо, заполняя старшие нулями.
    ///
    /// ## Как используется
    /// ```text
    /// shr <что>, <на сколько>
    /// ```
    Shr,

    /// # Арифметический сдвиг вправо (Arithmetic Shift Right)
    ///
    /// Сдвигает биты вправо с сохранением знакового бита.
    ///
    /// ## Как используется
    /// ```text
    /// sar <что>, <на сколько>
    /// ```
    Sar,

    /// # Знаковое расширение RAX в RDX:RAX
    ///
    /// Копирует знаковый бит регистра `RAX`
    /// во все биты регистра `RDX`.
    ///
    /// Обычно используется перед инструкцией `idiv`.
    ///
    /// ## Как используется
    /// ```text
    /// cqo
    /// ```
    Cqo,

    /// # Сравнение операндов (Compare)
    ///
    /// Выполняет неявное вычитание (`левый` минус `правый`). Сам результат отбрасывается,
    /// но выставляются флаги в `RFLAGS` (например, ZF если они равны).
    /// Используется в связке с условными переходами.
    ///
    /// ## Как используется
    /// ```text
    /// cmp <левый>, <правый>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// cmp rax, 0
    /// ```
    Cmp,

    // ====== Управление потоком (Ветвление) ======
    /// # Безусловный переход (Jump)
    ///
    /// Передает управление на указанный адрес или метку, принудительно
    /// перезаписывая адрес в регистре указателя инструкций `RIP`.
    ///
    /// ## Как используется
    /// ```text
    /// jmp <метка>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// jmp .loop_start
    /// ```
    Jmp,

    /// # Переход, если равно (Jump if Equal)
    ///
    /// Делает переход на метку, если флаг нуля установлен (`ZF == 1`).
    /// Обычно вызывается после команды `CMP`, если проверяемые значения оказались равны.
    ///
    /// ## Как используется
    /// ```text
    /// je <метка>
    /// ```
    Je,

    /// # Переход, если НЕ равно (Jump if Not Equal)
    ///
    /// Делает переход на метку, если флаг нуля сброшен (`ZF == 0`).
    /// Вызывается, если проверяемые в `CMP` значения различаются.
    ///
    /// ## Как используется
    /// ```text
    /// jne <метка>
    /// ```
    Jne,

    /// # Переход, если больше (Jump if Greater)
    ///
    /// Делает переход, если:
    /// - `ZF == 0`
    /// - `SF == OF`
    ///
    /// Обычно используется после `cmp` для **знакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jg <метка>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// cmp rax, rbx
    /// jg .greater
    /// ```
    Jg,

    /// # Переход, если больше или равно (Jump if Greater or Equal)
    ///
    /// Делает переход, если:
    /// - `SF == OF`
    ///
    /// Обычно используется после `cmp` для **знакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jge <метка>
    /// ```
    Jge,

    /// # Переход, если меньше (Jump if Less)
    ///
    /// Делает переход, если:
    /// - `SF != OF`
    ///
    /// Обычно используется после `cmp` для **знакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jl <метка>
    /// ```
    Jl,

    /// # Переход, если меньше или равно (Jump if Less or Equal)
    ///
    /// Делает переход, если:
    /// - `ZF == 1`
    /// - `SF != OF`
    ///
    /// Обычно используется после `cmp` для **знакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jle <метка>
    /// ```
    Jle,

    /// # Переход, если выше (Jump if Above)
    ///
    /// Делает переход, если:
    /// - `CF == 0`
    /// - `ZF == 0`
    ///
    /// Обычно используется после `cmp` для **беззнакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// ja <метка>
    /// ```
    Ja,

    /// # Переход, если выше или равно (Jump if Above or Equal)
    ///
    /// Делает переход, если:
    /// - `CF == 0`
    ///
    /// Обычно используется после `cmp` для **беззнакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jae <метка>
    /// ```
    Jae,

    /// # Переход, если ниже (Jump if Below)
    ///
    /// Делает переход, если:
    /// - `CF == 1`
    ///
    /// Обычно используется после `cmp` для **беззнакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jb <метка>
    /// ```
    Jb,

    /// # Переход, если ниже или равно (Jump if Below or Equal)
    ///
    /// Делает переход, если:
    /// - `CF == 1`
    /// - `ZF == 1`
    ///
    /// Обычно используется после `cmp` для **беззнакового** сравнения.
    ///
    /// ## Как используется
    /// ```text
    /// jbe <метка>
    /// ```
    Jbe,

    /// # Переход, если переполнение (Jump if Overflow)
    ///
    /// Делает переход, если флаг переполнения установлен (`OF == 1`).
    Jo,

    /// # Переход, если нет переполнения (Jump if Not Overflow)
    ///
    /// Делает переход, если флаг переполнения сброшен (`OF == 0`).
    Jno,

    /// # Переход, если знаковый (Jump if Sign)
    ///
    /// Делает переход, если флаг знака установлен (`SF == 1`).
    Js,

    /// # Переход, если без знака (Jump if Not Sign)
    ///
    /// Делает переход, если флаг знака сброшен (`SF == 0`).
    Jns,

    /// # Переход, если чётность (Jump if Parity / Parity Even)
    ///
    /// Делает переход, если флаг чётности установлен (`PF == 1`).
    Jp,

    /// # Переход, если нечётность (Jump if Not Parity / Parity Odd)
    ///
    /// Делает переход, если флаг чётности сброшен (`PF == 0`).
    Jnp,

    /// # Вызов функции (Call Procedure)
    ///
    /// Сохраняет текущий адрес возврата (следующую за `call` инструкцию) в стек
    /// и осуществляет переход на указанную функцию (процедуру).
    ///
    /// ## Как используется
    /// ```text
    /// call <имя_функции>
    /// ```
    ///
    /// ### Пример
    /// ```x86asm
    /// call my_function
    /// ```
    Call,

    /// # Возврат из функции (Return from Procedure)
    ///
    /// Извлекает адрес возврата из вершины стека, помещает его в `RIP`
    /// и передает управление обратно вызывающему коду. Используется в конце функций.
    ///
    /// ## Как используется
    /// ```text
    /// ret
    /// ```
    Ret,

    // ====== Системные команды ======
    /// # Системный вызов (Fast System Call)
    ///
    /// В x86_64 — это основной способ общения с операционной системой (ядерным пространством).
    /// Заменяет старое прерывание `int 0x80`. Перед вызовом номер системной функции передается в `RAX`.
    ///
    /// ## Как используется
    /// ```text
    /// syscall
    /// ```
    Syscall,

    /// # Пустая операция (No Operation)
    ///
    /// Ничего не делает, просто занимает 1 байт памяти (код `0x90`).
    /// Используется компиляторами для выравнивания адресов кода ради оптимизации кэша процессора.
    ///
    /// ## Как используется
    /// ```text
    /// nop
    /// ```
    Nop,
}

/// # Полная инструкция x86_64
///
/// Представляет собой законченную команду ассемблера, состоящую из мнемоники
/// и списка её аргументов (операндов).
///
/// ## Пример трансформации
///
/// Исходный код ассемблера:
/// ```x86asm
/// mov rax, 5
/// ```
///
/// Внутри компилятора эта строка превратится в следующую структуру [`Instruction`]:
/// ```text
/// Instruction {
///     mnemonic: MnemonicKind::Mov,
///     operands: vec![
///         Operand::Register(Registers::GPR(GPRs::Rax)),
///         Operand::Immediate(5),
///     ],
/// }
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Instruction {
    /// Тип выполняемой команды (например, [`MnemonicKind::Mov`])
    pub mnemonic: MnemonicKind,

    /// Список аргументов инструкции (в x86_64 обычно не больше 3)
    pub operands: Vec<Operand>,
}

// ========== Трейты `FromStr` для структур и перечислений ==========
impl FromStr for MnemonicKind {
    type Err = ISAError;

    fn from_str(s: &str) -> Result<Self, ISAError> {
        match s.to_lowercase().trim() {
            "mov" => Ok(Self::Mov),
            "push" => Ok(Self::Push),
            "pop" => Ok(Self::Pop),
            "add" => Ok(Self::Add),
            "sub" => Ok(Self::Sub),
            "imul" => Ok(Self::Imul),
            "div" => Ok(Self::Div),
            "idiv" => Ok(Self::Idiv),
            "mul" => Ok(Self::Mul),
            "xor" => Ok(Self::Xor),
            "and" => Ok(Self::And),
            "or" => Ok(Self::Or),
            "test" => Ok(Self::Test),
            "lea" => Ok(Self::Lea),
            "inc" => Ok(Self::Inc),
            "dec" => Ok(Self::Dec),
            "neg" => Ok(Self::Neg),
            "not" => Ok(Self::Not),
            "shl" | "sal" => Ok(Self::Shl),
            "shr" => Ok(Self::Shr),
            "sar" => Ok(Self::Sar),
            "cqo" => Ok(Self::Cqo),
            "cmp" => Ok(Self::Cmp),
            "jmp" => Ok(Self::Jmp),
            "je" => Ok(Self::Je),
            "jne" => Ok(Self::Jne),
            "jg" => Ok(Self::Jg),
            "jge" => Ok(Self::Jge),
            "jl" => Ok(Self::Jl),
            "jle" => Ok(Self::Jle),
            "ja" => Ok(Self::Ja),
            "jae" => Ok(Self::Jae),
            "jb" => Ok(Self::Jb),
            "jbe" => Ok(Self::Jbe),
            "jo" => Ok(Self::Jo),
            "jno" => Ok(Self::Jno),
            "js" => Ok(Self::Js),
            "jns" => Ok(Self::Jns),
            "jp" => Ok(Self::Jp),
            "jnp" => Ok(Self::Jnp),

            // алиасы
            "jpe" => Ok(Self::Jp),
            "jpo" => Ok(Self::Jnp),
            "jc" | "jnae" => Ok(Self::Jb),
            "jnc" | "jnb" => Ok(Self::Jae),
            "jz" => Ok(Self::Je),
            "jnz" => Ok(Self::Jne),
            "call" => Ok(Self::Call),
            "ret" => Ok(Self::Ret),
            "syscall" => Ok(Self::Syscall),
            "nop" => Ok(Self::Nop),
            some => Err(ISAError::new(ISAErrorKind::UnknownMnemonic(
                some.to_string(),
            ))),
        }
    }
}

impl FromStr for GPRs {
    type Err = ISAError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "rax" => Ok(Self::Rax),
            "rcx" => Ok(Self::Rcx),
            "rdx" => Ok(Self::Rdx),
            "rbx" => Ok(Self::Rbx),
            "rsp" => Ok(Self::Rsp),
            "rbp" => Ok(Self::Rbp),
            "rsi" => Ok(Self::Rsi),
            "rdi" => Ok(Self::Rdi),
            "r8" => Ok(Self::R8),
            "r9" => Ok(Self::R9),
            "r10" => Ok(Self::R10),
            "r11" => Ok(Self::R11),
            "r12" => Ok(Self::R12),
            "r13" => Ok(Self::R13),
            "r14" => Ok(Self::R14),
            "r15" => Ok(Self::R15),
            some => Err(ISAError::new(ISAErrorKind::UnknownRegister(
                some.to_string(),
            ))),
        }
    }
}

impl FromStr for XMMRs {
    type Err = ISAError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "xmm0" => Ok(Self::Xmm0),
            "xmm1" => Ok(Self::Xmm1),
            "xmm2" => Ok(Self::Xmm2),
            "xmm3" => Ok(Self::Xmm3),
            "xmm4" => Ok(Self::Xmm4),
            "xmm5" => Ok(Self::Xmm5),
            "xmm6" => Ok(Self::Xmm6),
            "xmm7" => Ok(Self::Xmm7),
            "xmm8" => Ok(Self::Xmm8),
            "xmm9" => Ok(Self::Xmm9),
            "xmm10" => Ok(Self::Xmm10),
            "xmm11" => Ok(Self::Xmm11),
            "xmm12" => Ok(Self::Xmm12),
            "xmm13" => Ok(Self::Xmm13),
            "xmm14" => Ok(Self::Xmm14),
            "xmm15" => Ok(Self::Xmm15),
            some => Err(ISAError::new(ISAErrorKind::UnknownRegister(
                some.to_string(),
            ))),
        }
    }
}

impl FromStr for SegmentRegisters {
    type Err = ISAError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "fs" => Ok(Self::Fs),
            "gs" => Ok(Self::Gs),
            "cs" => Ok(Self::Cs),
            "ss" => Ok(Self::Ss),
            "ds" => Ok(Self::Ds),
            "es" => Ok(Self::Es),
            some => Err(ISAError::new(ISAErrorKind::UnknownRegister(
                some.to_string(),
            ))),
        }
    }
}

impl FromStr for Registers {
    type Err = ISAError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let cleaned = s.to_lowercase().trim().to_string();

        if cleaned == "rflags" {
            return Ok(Self::Rflags);
        }
        if cleaned == "rip" {
            return Ok(Self::Rip);
        }

        // Пытаемся распарсить сначала как GPR, затем как XMM, затем как сегментный
        if let Ok(gpr) = GPRs::from_str(&cleaned) {
            return Ok(Self::GPR(gpr));
        }
        if let Ok(xmm) = XMMRs::from_str(&cleaned) {
            return Ok(Self::XMM(xmm));
        }
        if let Ok(seg) = SegmentRegisters::from_str(&cleaned) {
            return Ok(Self::SR(seg));
        }

        Err(ISAError::new(ISAErrorKind::UnknownRegister(cleaned)))
    }
}

impl FromStr for DataType {
    type Err = crate::isa::err::ISAError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_lowercase().trim() {
            "byte" => Ok(Self::Byte),
            "word" => Ok(Self::Word),
            "dword" => Ok(Self::Dword),
            "qword" => Ok(Self::Qword),
            // Ошибку можно прокинуть через твой ISAErrorKind, добавив туда при желании UnknownType
            some => Err(ISAError::new(ISAErrorKind::UnknownDataType(
                some.to_string(),
            ))),
        }
    }
}
