use failure::Fail;
use smpl::ModuleId;
use smpl::error::Error as StaticError;
use smpl::byte_gen::{ Instruction, InstructionPointerType };
#[derive(Debug, Clone)]
pub enum VmError {
StaticError(StaticError),
BuiltinCollision(ModuleFnPair),
NotABuiltin(ModuleFnPair),
NotAFn(ModuleFnPair),
NotAModule(String),
}
impl<T> From<T> for VmError where T: Into<StaticError> {
fn from(e: T) -> VmError {
VmError::StaticError(e.into())
}
}
#[derive(Debug, Clone)]
pub struct ModuleFnPair {
pub module: String,
pub function: String,
}
#[derive(Fail, Debug, Clone)]
pub enum InternalError {
#[fail(display = "Invalid number of arguments. Found {}. {}", _0, _1)]
InvalidArgCount(usize, ExpectedArgCount),
#[fail(
display = "Unexpected argument type at {}. Found {}. Expected {}",
index, found, expected
)]
InvalidArgType {
index: usize,
found: String,
expected: String,
},
#[fail(display = "Invalid instruction pointer {}. Max: {}", ip, max)]
InstructionPointerOutOfBounds {
ip: InstructionPointerType,
max: usize
},
#[fail(display = "Integer {} out of the range [{}, {}", v, min_inclusive, max_inclusive)]
IntegerOutOfRange {
v: i64,
min_inclusive: i64,
max_inclusive: i64,
},
#[fail(display = "InvalidInstruction: {}", _0)]
InvalidInstruction(IIReason),
#[fail(display = "Runtime instruction error: {}", _0)]
RuntimeInstructionError(RuntimeInstructionError),
}
#[derive(Fail, Debug, Clone)]
pub enum RuntimeInstructionError {
#[fail(display = "Expected int in: {:?}", _0)]
ExpectedInt(Instruction),
#[fail(display = "Expected float in: {:?}", _0)]
ExpectedFloat(Instruction),
#[fail(display = "Expected bool in: {:?}", _0)]
ExpectedBool(Instruction),
#[fail(display = "Expected function in: {:?}", _0)]
ExpectedFunction(Instruction),
#[fail(display = "No return found for instruction at {}", _0)]
NoReturnValue(InstructionPointerType),
#[fail(display = "Attempting to add {} to current IP({}) results in underflow", addition, current)]
IPUnderflow {
current: InstructionPointerType,
addition: i64,
},
#[fail(display = "Attempting to add {} to current IP({}) results in overflow", addition, current)]
IPOverflow {
current: InstructionPointerType,
addition: i64,
},
}
#[derive(Fail, Debug, Clone)]
pub enum IIReason {
#[fail(display = "Expected int in: {:?}", _0)]
ExpectedInt(Instruction),
#[fail(display = "Expected float in: {:?}", _0)]
ExpectedFloat(Instruction),
#[fail(display = "Expected bool in: {:?}", _0)]
ExpectedBool(Instruction),
}
#[derive(Fail, Debug, Clone)]
pub enum ExpectedArgCount {
#[fail(display = "Expected {}..={}", _0, _1)]
Range(usize, usize),
#[fail(display = "Expected >= {}", _0)]
Min(usize),
#[fail(display = "Expected <= {}", _0)]
Max(usize),
#[fail(display = "Expected == {}", _0)]
Exact(usize),
}
#[macro_export]
macro_rules! no_args {
($args: expr) => {{
use crate::err::*;
if $args.len() != 0 {
Err(InternalError::InvalidArgCount(
$args.len(),
ExpectedArgCount::Exact(0),
))
} else {
Ok(())
}
}};
}
#[macro_export]
macro_rules! exact_args {
($exact: expr, $args: expr) => {{
use crate::err::*;
if $args.len() != $exact {
Err(InternalError::InvalidArgCount(
$args.len(),
ExpectedArgCount::Exact($exact),
))
} else {
Ok($args)
}
}};
}
#[macro_export]
macro_rules! min_args {
($min: expr, $args: expr) => {{
use crate::err::*;
if $args.len() < $min {
Err(InternalError::InvalidArgCount(
$args.len(),
ExpectedArgCount::Min($min),
))
} else {
Ok($args)
}
}};
}
#[macro_export]
macro_rules! max_args {
($max: expr, $args: expr) => {{
use crate::err::*;
if $args.len() > $max {
Err(InternalError::InvalidArgCount(
$args.len(),
ExpectedArgCount::Max($max),
))
} else {
Ok($args)
}
}};
}
#[macro_export]
macro_rules! arg_range_inclusive {
($min_inclusive: expr, $max_inclusive: expr, $args: expr) => {{
use crate::err::*;
if $min_inclusive <= $args.len() && $max_inclusive >= $args.len() {
Ok($args)
} else {
Err(InternalError::InvalidArgCount(
$args.len(),
ExpectedArgCount::Range($min_inclusive, $max_inclusive),
))
}
}};
}