pub use crate::vm::VmError;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Ior(pub isize);
macro_rules! impl_ior {
($($(#[$attr:meta])* $name:ident = $val:literal),+ $(,)?) => {
impl Ior {
$($(#[$attr])* pub const $name: Self = Self($val);)+
}
}
}
impl_ior!(
STACK_OVERFLOW = -3,
STACK_UNDERFLOW = -4,
RETURN_STACK_OVERFLOW = -5,
RETURN_STACK_UNDERFLOW = -6,
INVALID_MEMORY_ADDRESS = -9,
DIVISION_BY_ZERO = -10,
UNDEFINED_WORD = -13,
ATTEMPT_TO_USE_ZERO_LENGTH_STRING_AS_NAME = -16,
PARSED_STRING_OVERFLOW = -18,
DEFINITION_NAME_TOO_LONG = -19,
ADDRESS_ALIGNMENT_EXCEPTION = -23,
);
impl_ior!(INVALID_ESCAPE = -256,);
impl core::fmt::Display for Ior {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<isize> for Ior {
fn from(i: isize) -> Self {
Self(i)
}
}
impl From<Ior> for isize {
fn from(ior: Ior) -> Self {
ior.0
}
}
impl From<Ior> for usize {
fn from(ior: Ior) -> Self {
ior.0 as usize
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Severity {
Throw(Ior),
Abort,
}
#[derive(Debug, PartialEq)]
pub enum Error {
Vm(VmError),
Io,
Throw(Ior),
Kernel(KernelError),
}
impl Error {
pub fn severity(&self) -> Severity {
use Severity::{Abort, Throw};
match self {
Error::Throw(n) => Throw(*n),
Error::Vm(v) => match v {
VmError::StackOverflow
| VmError::ReturnStackOverflow
| VmError::InvalidOpCode(_)
| VmError::MemoryTooSmall(_) => Abort,
VmError::StackUnderflow => Throw(Ior::STACK_UNDERFLOW),
VmError::ReturnStackUnderflow => Throw(Ior::RETURN_STACK_UNDERFLOW),
VmError::DivisionByZero => Throw(Ior::DIVISION_BY_ZERO),
VmError::AddressOutOfRange(_) => Throw(Ior::INVALID_MEMORY_ADDRESS),
VmError::AddressMisaligned(_) => Throw(Ior::ADDRESS_ALIGNMENT_EXCEPTION),
VmError::ParsedStringOverflow => Throw(Ior::PARSED_STRING_OVERFLOW),
VmError::InvalidEscape(_) => Throw(Ior::INVALID_ESCAPE),
},
Error::Io | Error::Kernel(_) => Abort,
}
}
}
#[derive(Debug, PartialEq)]
pub enum KernelError {
InvalidBuiltin(u8),
BuiltinTableFull,
MissingEntryPoint(&'static str),
XtTooLarge(usize),
DataSpaceTooSmall(usize),
}
impl From<KernelError> for Error {
fn from(e: KernelError) -> Self {
Self::Kernel(e)
}
}
impl From<VmError> for Error {
fn from(e: VmError) -> Self {
Self::Vm(e)
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Vm(e) => write!(f, "{e}"),
Self::Io => write!(f, "I/O error"),
Self::Throw(n) => write!(f, "error: {n}"),
Self::Kernel(fault) => write!(f, "fatal error: {}", fault),
}
}
}
impl core::fmt::Display for KernelError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidBuiltin(idx) => write!(f, "invalid builtin: 0x{idx:02x}"),
Self::BuiltinTableFull => write!(f, "builtin table full"),
Self::MissingEntryPoint(name) => write!(f, "missing entry point: {name}"),
Self::XtTooLarge(xt) => write!(f, "xt too large to pack: {xt:#x}"),
Self::DataSpaceTooSmall(n) => write!(f, "data space must be at least {n} bytes"),
}
}
}
impl core::error::Error for Error {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Vm(e) => Some(e),
_ => None,
}
}
}