use kerbalobjects::ko::errors::KOParseError;
use std::{
error::Error,
ffi::OsString,
fmt::{Display, Formatter},
};
pub type LinkResult<T> = Result<T, LinkError>;
#[derive(Debug)]
pub enum LinkError {
IOError(OsString, std::io::ErrorKind),
FileReadError(OsString, KOParseError),
InvalidPathError(String),
MissingSectionError(String, String),
MissingFileSymbolNameError(String),
FileContextError(FileErrorContext, ProcessingError),
FuncContextError(FuncErrorContext, ProcessingError),
MissingFileSymbolError(String),
MissingFunctionNameError(String, String, u16),
StringConversionError,
InternalError(String),
DataIndexOverflowError,
MissingEntryPointError(String),
MissingInitFunctionError,
EntryInSharedError,
UnresolvedExternalSymbolError(String),
InvalidSymbolRefError(String, usize, u64),
}
#[derive(Debug)]
pub enum ProcessingError {
MissingNameError(String),
InvalidDataIndexError(usize, usize),
InvalidSymbolIndexError(usize, usize),
MissingSymbolNameError(usize, usize),
InvalidSymbolDataIndexError(String, usize),
DuplicateSymbolError(String, String),
FuncMissingSymbolError,
FuncSymbolInvalidTypeError,
}
impl Error for LinkError {}
impl Error for ProcessingError {}
impl Display for LinkError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
LinkError::IOError(file_name, error_kind) => {
write!(
f,
"Link error: I/O error reading {:?}, {}",
file_name,
std::io::Error::from(*error_kind)
)
}
LinkError::FileReadError(file_name, e) => {
write!(f, "Link error: Error reading {:?}, {}", file_name, e)
}
LinkError::InvalidPathError(path) => {
write!(f, "Link error: I/O error, path {} invalid", path)
}
LinkError::StringConversionError => {
write!(f, "Link error: File name is invalid UTF-8")
}
LinkError::MissingSectionError(file_name, section_name) => {
write!(
f,
"Error linking {}.\nMissing required section {}",
file_name, section_name
)
}
LinkError::MissingFileSymbolError(file_name) => {
write!(f, "Error linking {}.\nMissing FILE symbol", file_name)
}
LinkError::MissingFileSymbolNameError(file_name) => {
write!(f, "Error linking {}.\nMissing FILE symbol name", file_name)
}
LinkError::FuncContextError(ctx, e) => {
write!(
f,
"Error linking {}, in function {}:\n{}: {}",
ctx.file_context.input_file_name,
ctx.func_name,
ctx.file_context.source_file_name,
e
)
}
LinkError::FileContextError(ctx, e) => {
write!(
f,
"Error linking {}:\n{}: {}",
ctx.input_file_name, ctx.source_file_name, e
)
}
LinkError::MissingFunctionNameError(file_name, source_file_name, section_num) => {
write!(
f,
"Error linking {}:\n{}: Missing function name for section {}",
file_name, source_file_name, section_num
)
}
LinkError::InternalError(message) => {
write!(f, "Internal error: {}", message)
}
LinkError::DataIndexOverflowError => {
write!(f, "All of the instruction data takes more than 4 bytes to index. The maximum instruction operand width is 4 bytes. Try to reduce file size and try again.")
}
LinkError::MissingEntryPointError(entry_point) => {
write!(
f,
"Cannot create executable, missing entry point: {}.",
entry_point
)
}
LinkError::MissingInitFunctionError => {
write!(f, "Cannot create shared object, missing _init function.")
}
LinkError::EntryInSharedError => {
write!(
f,
"Cannot create shared object, _start or other entry point is present"
)
}
LinkError::UnresolvedExternalSymbolError(name) => {
write!(
f,
"Unresolved external symbol error. External symbol \"{}\" has no definition",
name
)
}
LinkError::InvalidSymbolRefError(name, instr_index, sym_hash) => {
write!(
f,
"Error in {}:\nInstruction at index {} references invalid symbol, hash: {}",
name, instr_index, sym_hash
)
}
}
}
}
impl Display for ProcessingError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ProcessingError::MissingNameError(object) => {
write!(f, "{} is missing a name entry", object)
}
ProcessingError::InvalidDataIndexError(instr_index, data_index) => {
write!(
f,
"Instruction number {} has invalid data index {}",
instr_index, data_index
)
}
ProcessingError::InvalidSymbolIndexError(instr_index, symbol_index) => {
write!(
f,
"Instruction number {} has invalid symbol index {}",
instr_index, symbol_index
)
}
ProcessingError::MissingSymbolNameError(symbol_index, name_index) => {
write!(
f,
"Symbol at index {} references invalid name index {}",
symbol_index, name_index
)
}
ProcessingError::InvalidSymbolDataIndexError(symbol_name, value_index) => {
write!(
f,
"Symbol `{}` references invalid data index {}",
symbol_name, value_index
)
}
ProcessingError::DuplicateSymbolError(symbol_name, original_file) => {
write!(
f,
"Multiple definitions of '{}', first defined in {}",
symbol_name, original_file
)
}
ProcessingError::FuncMissingSymbolError => {
write!(f, "Function missing associated symbol table entry")
}
ProcessingError::FuncSymbolInvalidTypeError => {
write!(f, "Function symbol has invalid type, a symbol entry with the same name as a function must be of SymType::Func")
}
}
}
}
#[derive(Debug, Clone)]
pub struct FileErrorContext {
pub input_file_name: String,
pub source_file_name: String,
}
#[derive(Debug, Clone)]
pub struct FuncErrorContext {
pub file_context: FileErrorContext,
pub func_name: String,
}