use std::{fmt::Display, ops::Range};
#[derive(Debug, PartialEq, Eq)]
pub enum PcodeErrorTy {
RangeOutOfBounds {
range: Range<usize>,
available: usize,
},
ArgumentCountMismatch {
expected: usize,
actual: usize,
},
UnknownSize,
UnknownMacro(Box<str>),
MultipleExports,
ExportNotLast,
FunctionStatement,
Unsupported(Box<str>),
}
#[derive(Debug)]
pub struct PcodeError {
pub ty: PcodeErrorTy,
pub span: Option<(usize, usize)>,
}
pub type PcodeResult<T> = std::result::Result<T, PcodeError>;
impl std::error::Error for PcodeError {}
impl PartialEq for PcodeError {
fn eq(&self, other: &Self) -> bool {
self.ty == other.ty
}
}
impl Eq for PcodeError {}
impl PcodeError {
pub fn new(ty: PcodeErrorTy, span: (usize, usize)) -> Self {
Self {
ty,
span: Some(span),
}
}
pub fn spanless(ty: PcodeErrorTy) -> Self {
Self { ty, span: None }
}
pub fn with_span(mut self, span: (usize, usize)) -> Self {
self.span = Some(span);
self
}
pub fn range_out_of_bounds(range: Range<usize>, span: (usize, usize)) -> Self {
Self::new(
PcodeErrorTy::RangeOutOfBounds {
range,
available: 0,
},
span,
)
}
pub fn argument_count_mismatch(expected: usize, actual: usize, span: (usize, usize)) -> Self {
Self::new(
PcodeErrorTy::ArgumentCountMismatch { expected, actual },
span,
)
}
pub fn unknown_size(span: (usize, usize)) -> Self {
Self::new(PcodeErrorTy::UnknownSize, span)
}
pub fn unknown_macro(name: &str, span: (usize, usize)) -> Self {
Self::new(PcodeErrorTy::UnknownMacro(name.into()), span)
}
pub fn multiple_exports(span: (usize, usize)) -> Self {
Self::new(PcodeErrorTy::MultipleExports, span)
}
pub fn export_not_last(span: (usize, usize)) -> Self {
Self::new(PcodeErrorTy::ExportNotLast, span)
}
pub fn function_is_a_statement(span: (usize, usize)) -> Self {
Self::new(PcodeErrorTy::FunctionStatement, span)
}
}
impl Display for PcodeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let message = match &self.ty {
PcodeErrorTy::RangeOutOfBounds { range, available } => {
format!("Range {range:?} is out of bounds for available size {available}")
}
PcodeErrorTy::ArgumentCountMismatch { expected, actual } => {
format!("Expected {expected} arguments but got {actual}")
}
PcodeErrorTy::UnknownSize => {
"Could not determine the size of this expression".to_string()
}
PcodeErrorTy::UnknownMacro(name) => format!("Unknown macro: {name}"),
PcodeErrorTy::MultipleExports => {
"A macro definition contains multiple exports".to_string()
}
PcodeErrorTy::ExportNotLast => {
"The export statement is not the last statement in a macro definition".to_string()
}
PcodeErrorTy::FunctionStatement => {
"Attempted to use a function as an expression, but it is a statement".to_string()
}
PcodeErrorTy::Unsupported(what) => what.to_string(),
};
if let Some((start, end)) = self.span {
write!(f, "{message} (bytes {start}..{end})")
} else {
write!(f, "{message}")
}
}
}