use crate::Context; pub enum ErrorType { SyntaxError, SemanticError, TypeError, MathError, MachineError, } pub enum ErrorSubType { //Syntax errors UnexpectedEnd, Expected, Unexpected, UnknownOperation, InvalidTableKeys, Unclosed, //Semantic errors ElseWithoutIf, BreakContinueWithoutLoop, UnexpectedOperation, VariableNotFound, VariableAlreadyExists, ArgumentDuplication, TooManyArguments, //Machine errors RegisterNotFound, MemoryOutOfBounds, UnknownOPCode, UnknownFunction, UnknownString, UnknownMemoryLocation, NonFunctionCall, //Math errors DivisionByZero, //Type errors WrongType, } pub struct ASLError { pub message: String, pub position: usize, pub typ: ErrorType, pub subtype: ErrorSubType, pub code: String, } fn convert_types_to_string(typ: &ErrorType) -> String { match typ { ErrorType::SyntaxError => String::from("Syntax Error: "), ErrorType::TypeError => String::from("Type Error: "), ErrorType::MathError => String::from("Math Error: "), ErrorType::SemanticError => String::from("Semantic Error: "), ErrorType::MachineError => String::from("Machine Error: "), } } fn convert_types_to_short(typ: &ErrorType) -> String { match typ { ErrorType::SyntaxError => String::from("ST:"), ErrorType::TypeError => String::from("TP:"), ErrorType::MathError => String::from("MT:"), ErrorType::SemanticError => String::from("SM:"), ErrorType::MachineError => String::from("MC:"), } } fn convert_subtypes_to_string(stype: &ErrorSubType) -> String { match stype { ErrorSubType::UnexpectedEnd => String::from("Unexpected end"), ErrorSubType::UnexpectedOperation => String::from("Unexpected operation"), ErrorSubType::Expected => String::from("Expected"), ErrorSubType::Unexpected => String::from("Unexpected"), ErrorSubType::InvalidTableKeys => String::from("Invalid table keys"), ErrorSubType::Unclosed => String::from("Unclosed structure"), ErrorSubType::ElseWithoutIf => String::from("Else/elseif without if"), ErrorSubType::BreakContinueWithoutLoop => String::from("Break/continue without loop"), ErrorSubType::UnknownOperation => String::from("Unknown operation"), ErrorSubType::VariableNotFound => String::from("Variable not found"), ErrorSubType::VariableAlreadyExists => String::from("Variable already exists"), ErrorSubType::ArgumentDuplication => String::from("Argument duplication"), ErrorSubType::RegisterNotFound => String::from("Register not found"), ErrorSubType::MemoryOutOfBounds => String::from("Memory out of bounds"), ErrorSubType::UnknownOPCode => String::from("Unknown OP code"), ErrorSubType::UnknownFunction => String::from("Unknown function"), ErrorSubType::UnknownString => String::from("Unknown string"), ErrorSubType::UnknownMemoryLocation => String::from("Unknown memory location"), ErrorSubType::NonFunctionCall => String::from("Non-function call"), ErrorSubType::DivisionByZero => String::from("Division by zero"), ErrorSubType::WrongType => String::from("Wrong type"), ErrorSubType::TooManyArguments => String::from("Too many arguments"), } } fn convert_subtypes_to_short(stype: &ErrorSubType) -> String { match stype { ErrorSubType::UnexpectedEnd => String::from("UE:"), ErrorSubType::UnexpectedOperation => String::from("UP:"), ErrorSubType::Expected => String::from("EX:"), ErrorSubType::Unexpected => String::from("UN:"), ErrorSubType::InvalidTableKeys => String::from("IK:"), ErrorSubType::Unclosed => String::from("UC:"), ErrorSubType::ElseWithoutIf => String::from("EW:"), ErrorSubType::BreakContinueWithoutLoop => String::from("BC:"), ErrorSubType::UnknownOperation => String::from("UO:"), ErrorSubType::VariableNotFound => String::from("VN:"), ErrorSubType::VariableAlreadyExists => String::from("VE:"), ErrorSubType::ArgumentDuplication => String::from("AD:"), ErrorSubType::RegisterNotFound => String::from("RF:"), ErrorSubType::MemoryOutOfBounds => String::from("MO:"), ErrorSubType::UnknownOPCode => String::from("OC:"), ErrorSubType::UnknownFunction => String::from("UF:"), ErrorSubType::UnknownString => String::from("US:"), ErrorSubType::UnknownMemoryLocation => String::from("UM:"), ErrorSubType::NonFunctionCall => String::from("NF:"), ErrorSubType::DivisionByZero => String::from("DZ:"), ErrorSubType::WrongType => String::from("WT:"), ErrorSubType::TooManyArguments => String::from("TA:"), } } pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: ErrorSubType) -> ASLError { let mut code = convert_types_to_short(&typ); code.push_str(&convert_subtypes_to_short(&stype)); code.push_str(&position.to_string()); ASLError { message: String::from(message), position, typ, subtype: stype, code, } } fn get_exact_pos(file: &String, pos: usize) -> (usize, usize) { let mut line = 1; let mut column = 1; for (i, c) in file.char_indices() { if i == pos { return (line, column); } if c == '\n' { line += 1; column = 1; } else { column += 1; } } (line, column) } fn get_sorrunding_lines(file: &String, line: usize) -> (String, String, String) { let lines = file.lines(); let mut before = String::new(); let mut current = String::new(); let mut after = String::new(); let mut current_line = 1; for l in lines { if current_line == line - 1 { before = l.to_string(); } else if current_line == line { current = l.to_string(); } else if current_line == line + 1 { after = l.to_string(); break; } current_line += 1; } (before, current, after) } pub fn print_error(error: &ASLError, ctx: &Context) { let mut out = String::new(); out.push_str(&convert_types_to_string(&error.typ)); if error.message.len() < 1 { out.push_str(&convert_subtypes_to_string(&error.subtype)); } else { out.push_str(&error.message); } if ctx.known { out.push_str(" at position "); let (line, column) = get_exact_pos(&ctx.raw_file, error.position); out.push_str(&ctx.file); out.push_str(":"); out.push_str(&line.to_string()); out.push_str(":"); out.push_str(&column.to_string()); out.push_str("\n"); let (before, current, after) = get_sorrunding_lines(&ctx.raw_file, line); if line > 1 { out.push_str(&(line-1).to_string()); out.push_str(" | "); } else { out.push_str(" | "); } out.push_str(&before); out.push_str("\n"); out.push_str(&line.to_string()); out.push_str(" | "); out.push_str(¤t); out.push_str("\n"); out.push_str(" "); out.push_str(&" ".repeat(column - 1)); out.push_str("^ "); out.push_str(&error.message); out.push_str("\n"); out.push_str(&(line+1).to_string()); out.push_str(" | "); out.push_str(&after); } out.push_str("\n"); out.push_str("Error Code: "); out.push_str(&error.code); out.push_str(":"); out.push_str(&ctx.c_funcid.to_string()); println!("{}", out); }