285 lines
No EOL
10 KiB
Rust
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(¤t);
|
|
|
|
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);
|
|
} |