use crate::values::InterfaceValue;
use crate::{ast::TypeKind, interpreter::Instruction, types::InterfaceType};
use std::{
error::Error,
fmt::{self, Display, Formatter},
num::TryFromIntError,
result::Result,
string::{self, ToString},
};
pub type InstructionResult<T> = Result<T, InstructionError>;
pub type InterpreterResult<T> = Result<T, InstructionError>;
#[derive(Debug)]
pub struct WasmValueNativeCastError {
pub from: InterfaceValue,
pub to: InterfaceType,
}
impl Error for WasmValueNativeCastError {}
impl Display for WasmValueNativeCastError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "{:?}", self)
}
}
#[derive(Debug)]
pub struct InstructionError {
pub instruction: Instruction,
pub error_kind: InstructionErrorKind,
}
impl InstructionError {
pub(crate) fn new(instruction: Instruction, error_kind: InstructionErrorKind) -> Self {
Self {
instruction,
error_kind,
}
}
}
impl Error for InstructionError {}
impl Display for InstructionError {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(
formatter,
"`{}` {}",
(&self.instruction).to_string(),
self.error_kind
)
}
}
#[derive(Debug)]
pub enum InstructionErrorKind {
InvocationInputIsMissing {
index: u32,
},
ToNative(WasmValueNativeCastError),
LoweringLifting {
from: InterfaceType,
to: InterfaceType,
},
InvalidValueOnTheStack {
expected_type: InterfaceType,
received_value: InterfaceValue,
},
StackIsTooSmall {
needed: usize,
},
LocalOrImportIsMissing {
function_index: u32,
},
LocalOrImportSignatureMismatch {
function_index: u32,
expected: (Vec<InterfaceType>, Vec<InterfaceType>),
received: (Vec<InterfaceType>, Vec<InterfaceType>),
},
LocalOrImportCall {
function_index: u32,
},
MemoryIsMissing {
memory_index: u32,
},
MemoryOutOfBoundsAccess {
index: usize,
length: usize,
},
String(string::FromUtf8Error),
NegativeValue {
subject: &'static str,
},
TypeIsMissing {
type_index: u32,
},
RecordTypeByNameIsMissing {
record_type_id: u64,
},
CorruptedArray(String),
CorruptedRecord(String),
InvalidTypeKind {
expected_kind: TypeKind,
received_kind: TypeKind,
},
SerdeError(String),
}
impl Error for InstructionErrorKind {}
impl Display for InstructionErrorKind {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
match self {
Self::InvocationInputIsMissing { index } => write!(
formatter,
"cannot access invocation inputs #{} because it doesn't exist",
index
),
Self::ToNative(WasmValueNativeCastError { from, .. }) => write!(
formatter,
"failed to cast the WIT value `{:?}` to its native type",
from,
),
Self::LoweringLifting { from, to } => {
write!(formatter, "failed to cast `{:?}` to `{:?}`", from, to)
}
Self::InvalidValueOnTheStack {
expected_type,
received_value,
} => write!(
formatter,
"read a value `{:?}` from the stack, that can't be converted to `{:?}`",
received_value, expected_type,
),
Self::StackIsTooSmall { needed } => write!(
formatter,
"needed to read `{}` value(s) from the stack, but it doesn't contain enough data",
needed
),
Self::LocalOrImportIsMissing { function_index } => write!(
formatter,
"the local or import function `{}` doesn't exist",
function_index
),
Self::LocalOrImportSignatureMismatch { function_index, expected, received } => write!(
formatter,
"the local or import function `{}` has the signature `{:?} -> {:?}` but it received values of kind `{:?} -> {:?}`",
function_index, expected.0, expected.1, received.0, received.1,
),
Self::LocalOrImportCall { function_index } => write!(
formatter,
"failed while calling the local or import function `{}`",
function_index
),
Self::MemoryIsMissing { memory_index } => write!(
formatter,
"memory `{}` does not exist",
memory_index,
),
Self::MemoryOutOfBoundsAccess { index, length } => write!(
formatter,
"read out of the memory bounds (index {} > memory length {})",
index, length,
),
Self::String(error) => write!(formatter, "{}", error),
Self::NegativeValue { subject } => write!(
formatter,
"attempted to convert `{}` but it appears to be a negative value",
subject
),
Self::TypeIsMissing { type_index } => write!(
formatter,
"the type `{}` doesn't exist",
type_index
),
Self::InvalidTypeKind { expected_kind, received_kind } => write!(
formatter,
"read a type of kind `{:?}`, but the kind `{:?}` was expected",
received_kind, expected_kind
),
Self::RecordTypeByNameIsMissing { record_type_id: type_name } => write!(
formatter,
"type with `{}` is missing in a Wasm binary",
type_name
),
Self::CorruptedArray(err) => write!(
formatter,
"{}",
err
),
Self::CorruptedRecord(err) => write!(
formatter,
"{}",
err
),
Self::SerdeError(err) => write!(
formatter,
"serde error: {}", err,
),
}
}
}
impl From<(TryFromIntError, &'static str)> for InstructionErrorKind {
fn from((_, subject): (TryFromIntError, &'static str)) -> Self {
InstructionErrorKind::NegativeValue { subject }
}
}