// rasm-core/src/lexer/token.rs
//
//! Модель токена.
use crate::{
    isa::{DataType, MnemonicKind, Registers},
    str_pool::StrId,
};
use std::{
    fmt::{Display, Formatter},
    ops::Range,
};

/// Разновидности токена
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TokenKind {
    /// Известная мнемоника (mov, add, push и т.д.)
    Mnemonic(MnemonicKind),

    /// Известный регистр (rax, xmm0, fs и т.д.)
    Register(Registers),

    /// Тип данных
    Type(DataType),

    /// Всё остальное, названия пользовательских меток, функций или неизвестные слова
    Ident(StrId),

    /// Целое число
    Integer(i64),

    /// Дробное число
    Float(f64),

    /// Строка
    StringLiteral(StrId),

    // Знаки препинания и операторы
    Comma,                //< `,`
    Colon,                //< `:`
    Dot,                  //< '.'
    OpeningSquareBracket, //< `[`
    EndingSquareBracket,  //< `]`
    Plus,                 //< `+`
    Minus,                //< `-`
    Asterisk,             //< `*`
    Newline,              //< Перевод строки
    End,                  //< Конец кода
}

impl Display for TokenKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            // Комплексные токены с внутренними данными
            Self::Mnemonic(m) => write!(f, "{m:?}"),
            Self::Register(r) => write!(f, "{r:?}"),
            Self::Type(t) => write!(f, "{t:?}"),
            Self::Integer(i) => write!(f, "{i}"),
            Self::Float(fl) => write!(f, "{fl}"),

            Self::Ident(_) => write!(f, "<identifier>"),

            // Операторы и знаки препинания
            Self::Comma => write!(f, ","),
            Self::Colon => write!(f, ":"),
            Self::Dot => write!(f, "."),
            Self::OpeningSquareBracket => write!(f, "["),
            Self::EndingSquareBracket => write!(f, "]"),
            Self::Plus => write!(f, "+"),
            Self::Minus => write!(f, "-"),
            Self::Asterisk => write!(f, "*"),
            Self::StringLiteral(_) => write!(f, "<string>"),

            // Специальные символы управления потоком
            Self::Newline => write!(f, "'\n'"),
            Self::End => write!(f, "<EOF>"),
        }
    }
}

/// # Позиция в исходном коде
///
/// Хранит плоские байтовые смещения от начала файла `[start..end)`.
/// Занимает всего 8 байт, поддерживает [`Copy`] и легко превращается в стандартный [`Range`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Span {
    pub start: u32,
    pub end: u32,
}

impl Span {
    /// Создает новый Span
    pub const fn new(start: u32, end: u32) -> Self {
        Self { start, end }
    }

    /// Легкая конвертация в стандартный диапазон Rust, если он нужен для встроенных методов
    pub fn as_range(&self) -> Range<usize> {
        (self.start as usize)..(self.end as usize)
    }

    /// Позволяет объединить два спана (например, начало и конец выражения)
    pub fn to(&self, other: Self) -> Self {
        Self {
            start: self.start,
            end: other.end,
        }
    }
}

// Позволяет писать:
// ```
// let range: Range<usize> = span.into();
// ```
impl From<Span> for Range<usize> {
    fn from(span: Span) -> Self {
        span.as_range()
    }
}

/// # Модель токена
///
/// Содержит в себе:
/// - [`TokenKind`]: Вид токена.
/// - [`Span`]: Позиция токена в исходном коде.
#[derive(Clone, Copy, Debug)]
pub struct Token {
    pub kind: TokenKind,
    pub pos: Span,
}

impl Token {
    pub fn new(kind: TokenKind, pos: Span) -> Self {
        Self { kind, pos }
    }
}
