use crate::frontend::source_registry::{SourcePosition, SourceRegistry, SourceSlice}; #[derive(Debug, Clone)] pub enum LoxError { LexicalError { source_slice: SourceSlice, message: String, }, RuntimeError { source_slice: SourceSlice, message: String, }, ParseError { source_slice: SourceSlice, message: String, }, IoError { message: String, }, TypeMismatch { source_slice: SourceSlice, expected: String, found: String, }, } impl LoxError { pub fn get_message(&self) -> String { match self { LoxError::LexicalError { message, .. } => message.clone(), LoxError::RuntimeError { message, .. } => message.clone(), LoxError::ParseError { message, .. } => message.clone(), LoxError::IoError { message } => message.clone(), LoxError::TypeMismatch { expected, found, .. } => { format!("expected {}, found {}", expected, found) } } } pub fn get_source_slice(&self) -> Option { match self { LoxError::LexicalError { source_slice, .. } => Some(source_slice.clone()), LoxError::RuntimeError { source_slice, .. } => Some(source_slice.clone()), LoxError::ParseError { source_slice, .. } => Some(source_slice.clone()), LoxError::IoError { .. } => None, LoxError::TypeMismatch { source_slice, .. } => Some(source_slice.clone()), } } pub fn print_with_context(&self, source_registry: &SourceRegistry) { match self.get_source_slice() { Some(source_slice) => { let source_code = source_registry.get_source_code(&source_slice); println!( "\n =============================================== \n DATA:{} \n CODE \n {} | {}", self, source_slice.start_position.line ,source_code ); } None => println!("{}", self), } } } fn fetch_source_code(path: &str, start: SourcePosition, end: SourcePosition) -> LoxResult { let source_code = std::fs::read_to_string(path).map_err(|e| LoxError::IoError { message: format!("Failed to read file: {}", e), })?; let lines: Vec<&str> = source_code.split('\n').collect(); // Verifica bounds if start.line >= lines.len() || end.line >= lines.len() { return Err(LoxError::IoError { message: "Line number out of bounds".to_string(), }); } let mut result = String::new(); if start.line == end.line { // Caso speciale: stessa riga let line = lines[start.line]; if end.column <= line.len() && start.column <= end.column { result.push_str(&line[start.column..end.column]); } } else { // Caso generale: righe multiple // Prima riga: da start.column alla fine della riga let first_line = lines[start.line]; if start.column < first_line.len() { result.push_str(&first_line[start.column..]); } result.push('\n'); // Righe intermedie: complete for i in (start.line + 1)..end.line { result.push_str(lines[i]); result.push('\n'); } // Ultima riga: dall'inizio fino a end.column let last_line = lines[end.line]; if end.column <= last_line.len() { result.push_str(&last_line[..end.column]); } } Ok(result) } impl std::fmt::Display for LoxError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { LoxError::LexicalError { source_slice, message, } => { write!(f, "Lexical error on {:?}: \n {}", source_slice, message) } LoxError::RuntimeError { source_slice, message, } => { write!(f, "Runtime error on {:?}: \n{}", source_slice, message) } LoxError::ParseError { source_slice, message, } => { write!(f, "Parse error on {:?}: \n{}", source_slice, message) } LoxError::IoError { message } => write!(f, "IO error: {}", message), LoxError::TypeMismatch { source_slice, expected, found, } => { write!( f, "Type mismatch on {:?}: \n expected {}, found {}", source_slice, expected, found ) } } } } impl std::error::Error for LoxError {} pub type LoxResult = Result;