// rasm-core/src/parser/err.rs
//
//! Ошибки синтаксического анализа.

use crate::lexer::token::{Span, TokenKind};
use std::fmt::Display;

/// Вид ошибки парсера.
#[derive(Debug, Clone)]
pub enum ParserErrorKind {
    /// Ожидался один токен, получили другой.
    /// Например: ожидали `:` после имени метки, но встретили `\n`.
    ExpectedTokenButFound { expected: TokenKind, got: TokenKind },

    /// Операнд не имеет смысла в данном контексте.
    /// Например: `mov 5, rax` — источником не может быть immediate-операнд слева.
    UnexpectedOperand(TokenKind),

    /// Неожиданный токен в начале строки.
    /// Например: встретили `,` там, где ожидали инструкцию или метку.
    UnexpectedToken(TokenKind),

    /// Незакрытая скобка `[` при разборе адресации памяти.
    UnclosedMemoryBracket,

    /// Недопустимый масштаб при адресации памяти.
    /// В x86_64 scale может быть только 1, 2, 4 или 8.
    InvalidScale(i64),

    /// Директива используется с неверным набором аргументов.
    /// Например: `.align` без числа.
    MissingDirectiveOperand,

    /// Переполнение: число не помещается в i32 для смещения в MemoryAddress.
    DisplacementOverflow(i64),
}

impl Display for ParserErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::ExpectedTokenButFound { expected, got } => {
                write!(f, "expected '{expected}', got '{got}'")
            }
            Self::UnexpectedOperand(tok) => write!(f, "unexpected operand: '{tok}'"),
            Self::UnexpectedToken(tok) => match tok {
                TokenKind::Ident(_) => write!(f, "unexpected ident"),
                TokenKind::Float(_) => write!(f, "unexpected float"),
                TokenKind::Integer(_) => write!(f, "unexpected integer"),
                TokenKind::StringLiteral(_) => write!(f, "unexpected string"),
                TokenKind::Newline => write!(f, "unexpected newline"),
                TokenKind::End => write!(f, "unexpected end of code"),
                _ => write!(f, "unexpected token: '{tok}'"),
            },
            Self::UnclosedMemoryBracket => write!(f, "unclosed '[' in memory operand"),
            Self::InvalidScale(n) => write!(f, "invalid scale '{n}': must be 1, 2, 4 or 8"),
            Self::MissingDirectiveOperand => write!(f, "directive requires an operand"),
            Self::DisplacementOverflow(n) => {
                write!(f, "displacement '{n}' overflows i32 (must fit in 32 bits)")
            }
        }
    }
}

/// Ошибка парсера с позицией в исходном коде.
#[derive(Debug)]
pub struct ParserError {
    pub kind: ParserErrorKind,
    pub pos: Span,
}

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

impl Display for ParserError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.kind)
    }
}
