lyanglyang 0.1.0

Lyangpiler - A VM for the LyangLang programming language with native Nepali syntax
use std::io;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum NepalError {
    #[error("Lexical error: {0}")]
    LexError(&'static str),

    #[error("Parse error: {0}")]
    ParseError(&'static str),

    #[error("Runtime error: {0}")]
    RuntimeError(&'static str),

    #[error("Type error: {0}")]
    #[allow(dead_code)]
    TypeError(&'static str),

    #[error("Name error: {0}")]
    #[allow(dead_code)]
    NameError(&'static str),
    
    #[error("IO error: {0}")]
    IoError(#[from] io::Error),
    
    #[error("Error at line {line}: {error_type}\nDetails: {message}\nCode: {code}\n{pointer}")]
    #[allow(dead_code)]
    FormattedError {
        line: usize,
        error_type: String,
        message: String,
        code: String,
        pointer: String,
    },
}

impl NepalError {
    /// Create a formatted error with line number and code snippet
    #[allow(dead_code)]
    pub fn with_location(
        error: NepalError, 
        line: usize, 
        code: &str, 
        column: usize
    ) -> Self {
        let error_message = error.to_string();
        let error_parts: Vec<&str> = error_message.splitn(2, ':').collect();
        let error_type = error_parts.get(0).unwrap_or(&"Error").to_string();
        let message = error_parts.get(1).unwrap_or(&"Unknown error").trim().to_string();

        // Lines are 1-based; guard against line == 0 to avoid usize underflow.
        let code_line = if line == 0 {
            String::new()
        } else {
            code.lines().nth(line - 1).unwrap_or("").to_string()
        };
        // Clamp column to the displayed line's character length so the caret
        // never points past the end, and so byte-derived columns don't misalign
        // on multi-byte UTF-8 (Devanagari/Nepali) lines.
        let column = column.min(code_line.chars().count());
        let pointer = format!("{}^---- Error location", " ".repeat(column));
        
        Self::FormattedError {
            line,
            error_type,
            message,
            code: code_line,
            pointer,
        }
    }
    
    /// Convert standard Nepali error messages
    #[allow(dead_code)]
    pub fn to_nepali_message(&self) -> String {
        match self {
            NepalError::NameError(_) => "अपरिभाषित चर".to_string(),
            NepalError::TypeError(_) => "प्रकार बेमेल".to_string(),
            NepalError::RuntimeError(_) if self.to_string().contains("Invalid operation") => 
                "अमान्य संचालन".to_string(),
            NepalError::ParseError(_) => "वाक्य रचना त्रुटि".to_string(),
            _ => self.to_string()
        }
    }
}