AstroLang/src/errors.rs
2025-06-18 14:21:31 +02:00

285 lines
No EOL
10 KiB
Rust

use crate::Context;
#[derive(Debug, Clone)]
pub enum ErrorType {
SyntaxError,
SemanticError,
TypeError,
MathError,
MachineError,
IOError,
}
#[derive(Debug, Clone)]
pub enum ErrorSubType {
//Syntax errors
UnexpectedEnd,
Expected,
Unexpected,
UnknownOperation,
InvalidTableKeys,
Unclosed,
//Semantic errors
ElseWithoutIf,
BreakContinueWithoutLoop,
UnexpectedOperation,
VariableNotFound,
VariableAlreadyExists,
ArgumentDuplication,
TooManyArguments,
NoExpression,
//Machine errors
RegisterNotFound,
MemoryOutOfBounds,
UnknownOPCode,
UnknownFunction,
UnknownString,
UnknownMemoryLocation,
NonFunctionCall,
RuntimeError,
//Math errors
DivisionByZero,
//Type errors
WrongType,
//IO errors
FileError
}
#[derive(Debug, Clone)]
pub struct ASLError {
pub message: String,
pub position: usize,
pub typ: ErrorType,
pub subtype: ErrorSubType,
pub code: String,
}
pub 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: "),
ErrorType::IOError => String::from("IO 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:"),
ErrorType::IOError => String::from("IO:"),
}
}
pub fn reverse_type_short(str: String) -> ErrorType {
match str.as_str() {
"ST" => ErrorType::SyntaxError,
"TP" => ErrorType::TypeError,
"MT" => ErrorType::MathError,
"SM" => ErrorType::SemanticError,
"MC" => ErrorType::MachineError,
"IO" => ErrorType::IOError,
_ => panic!("Unknown error type short: {}", str),
}
}
pub 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"),
ErrorSubType::FileError => String::from("File error"),
ErrorSubType::RuntimeError => String::from("Runtime error"),
ErrorSubType::NoExpression => String::from("No expression found"),
}
}
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:"),
ErrorSubType::FileError => String::from("FE:"),
ErrorSubType::RuntimeError => String::from("RE:"),
ErrorSubType::NoExpression => String::from("NE:"),
}
}
pub fn reverse_subtype_short(str: String) -> ErrorSubType {
match str.as_str() {
"UE" => ErrorSubType::UnexpectedEnd,
"UP" => ErrorSubType::UnexpectedOperation,
"EX" => ErrorSubType::Expected,
"UN" => ErrorSubType::Unexpected,
"IK" => ErrorSubType::InvalidTableKeys,
"UC" => ErrorSubType::Unclosed,
"EW" => ErrorSubType::ElseWithoutIf,
"BC" => ErrorSubType::BreakContinueWithoutLoop,
"UO" => ErrorSubType::UnknownOperation,
"VN" => ErrorSubType::VariableNotFound,
"VE" => ErrorSubType::VariableAlreadyExists,
"AD" => ErrorSubType::ArgumentDuplication,
"RF" => ErrorSubType::RegisterNotFound,
"MO" => ErrorSubType::MemoryOutOfBounds,
"OC" => ErrorSubType::UnknownOPCode,
"UF" => ErrorSubType::UnknownFunction,
"US" => ErrorSubType::UnknownString,
"UM" => ErrorSubType::UnknownMemoryLocation,
"NF" => ErrorSubType::NonFunctionCall,
"DZ" => ErrorSubType::DivisionByZero,
"WT" => ErrorSubType::WrongType,
"TA" => ErrorSubType::TooManyArguments,
"FE" => ErrorSubType::FileError,
"RE" => ErrorSubType::RuntimeError,
"NE" => ErrorSubType::NoExpression,
_ => panic!("Unknown error subtype short: {}", str),
}
}
pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: ErrorSubType, ctx: &Context) -> ASLError {
let mut code = convert_types_to_short(&typ);
code.push_str(&convert_subtypes_to_short(&stype));
code.push_str(ctx.c_funcid.to_string().as_str());
code.push(':');
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;
if pos < 1 {
return (line, column);
}
for (i, c) in file.chars().enumerate() {
if i == pos-1 {
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(&current);
out.push_str("\n");
out.push_str(" ");
out.push_str(&" ".repeat(line.to_string().len()));
out.push_str(&" ".repeat(column - 1));
out.push_str("^ ");
if error.message.len() < 1 {
out.push_str(&convert_subtypes_to_string(&error.subtype));
} else {
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);
println!("{}", out);
}