use bitwidth::BitWidth;
use bitpos::BitPos;
use radix::Radix;
use apint::{ApInt, ShiftAmount};
use apint::{PrimitiveTy};
use std::result;
use std::error;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ErrorKind {
InvalidRadix(u8),
InvalidStringRepr{
input: String,
radix: Radix,
pos_char: Option<(usize, char)>
},
InvalidBitAccess{
pos: BitPos,
width: BitWidth
},
InvalidShiftAmount{
shift_amount: ShiftAmount,
width: BitWidth
},
ValueUnrepresentable{
value: ApInt,
destination_ty: PrimitiveTy
},
UnmatchingBitwidth(BitWidth, BitWidth),
InvalidBitWidth(usize),
TruncationBitWidthTooLarge{
target: BitWidth,
current: BitWidth
},
ExtensionBitWidthTooSmall{
target: BitWidth,
current: BitWidth
},
DivisionByZero {
op: DivOp,
lhs: ApInt
},
ExpectedNonEmptyDigits,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DivOp {
SignedDiv,
SignedRem,
UnsignedDiv,
UnsignedRem
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Error {
kind : ErrorKind,
message : String,
annotation: Option<String>
}
impl Error {
#[inline]
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
#[inline]
pub fn message(&self) -> &str {
self.message.as_str()
}
#[inline]
pub fn annotation(&self) -> Option<&str> {
match self.annotation {
Some(ref ann) => Some(ann.as_str()),
None => None
}
}
}
impl Error {
#[inline]
pub(crate) fn with_annotation<A>(mut self, annotation: A) -> Error
where A: Into<String>
{
self.annotation = Some(annotation.into());
self
}
}
impl Error {
pub(crate) fn invalid_radix(val: u8) -> Error {
Error{
kind: ErrorKind::InvalidRadix(val),
message: format!("Encountered an invalid parsing radix of {:?}.", val),
annotation: None
}
}
pub(crate) fn invalid_string_repr<S>(input: S, radix: Radix) -> Error
where S: Into<String>
{
let input = input.into();
Error{
kind: ErrorKind::InvalidStringRepr{input, radix, pos_char: None},
message: format!("Encountered an invalid string representation for the given radix (= {:?}).", radix),
annotation: None
}
}
pub(crate) fn invalid_char_in_string_repr<S>(input: S, radix: Radix, pos: usize, ch: char) -> Error
where S: Into<String>
{
let input = input.into();
Error{
kind: ErrorKind::InvalidStringRepr{input, radix, pos_char: None},
message: format!("Encountered an invalid character (= '{:?}') at position {:?} within the given string \
representation for the given radix (= {:?}).", ch, pos, radix),
annotation: None
}
}
pub(crate) fn invalid_bitwidth(val: usize) -> Error {
Error{
kind: ErrorKind::InvalidBitWidth(val),
message: format!("Encountered invalid bitwidth of {:?}.", val),
annotation: None
}
}
pub(crate) fn invalid_zero_bitwidth() -> Error {
Error::invalid_bitwidth(0)
}
pub(crate) fn extension_bitwidth_too_small<W1, W2>(target: W1, current: W2) -> Error
where W1: Into<BitWidth>,
W2: Into<BitWidth>
{
let target = target.into();
let current = current.into();
Error{
kind: ErrorKind::ExtensionBitWidthTooSmall{target, current},
message: format!("Tried to extend an `ApInt` with a width of {:?} to a smaller target width of {:?}", current, target),
annotation: None
}
}
pub(crate) fn truncation_bitwidth_too_large<W1, W2>(target: W1, current: W2) -> Error
where W1: Into<BitWidth>,
W2: Into<BitWidth>
{
let target = target.into();
let current = current.into();
Error{
kind: ErrorKind::TruncationBitWidthTooLarge{target, current},
message: format!("Tried to truncate an `ApInt` with a width of {:?} to a larger target width of {:?}", current, target),
annotation: None
}
}
pub(crate) fn unmatching_bitwidths<W1, W2>(lhs: W1, rhs: W2) -> Error
where W1: Into<BitWidth>,
W2: Into<BitWidth>
{
let lhs = lhs.into();
let rhs = rhs.into();
Error{
kind: ErrorKind::UnmatchingBitwidth(lhs, rhs),
message: format!("Encountered invalid operation on entities with non-matching bit-widths of {:?} and {:?}.", lhs, rhs),
annotation: None
}
}
pub(crate) fn invalid_shift_amount<S, W>(shift_amount: S, width: W) -> Error
where S: Into<ShiftAmount>,
W: Into<BitWidth>
{
let shift_amount = shift_amount.into();
let width = width.into();
Error{
kind: ErrorKind::InvalidShiftAmount{shift_amount, width},
message: format!("Encountered invalid shift amount of {:?} on bit-width with {:?} bits.", shift_amount, width),
annotation: None
}
}
pub(crate) fn invalid_bit_access<P, W>(pos: P, width: W) -> Error
where P: Into<BitPos>,
W: Into<BitWidth>
{
let pos = pos.into();
let width = width.into();
Error{
kind: ErrorKind::InvalidBitAccess{pos, width},
message: format!("Encountered invalid bit access at position {:?} with a total bit-width of {:?}.", pos, width),
annotation: None
}
}
pub(crate) fn expected_non_empty_digits() -> Error {
Error{
kind: ErrorKind::ExpectedNonEmptyDigits,
message: "Encountered an empty iterator upon construction of an `ApInt` from a digit iterator.".to_owned(),
annotation: None
}
}
pub(crate) fn encountered_unrepresentable_value(
value: ApInt,
destination_ty: PrimitiveTy
)
-> Error
{
let message = format!(
"Encountered a value ({:?}) that is unrepresentable \
by the destination type {:?}.", value, destination_ty);
Error{
kind: ErrorKind::ValueUnrepresentable{value, destination_ty},
message,
annotation: None
}
}
pub(crate) fn division_by_zero(op: DivOp, lhs: ApInt) -> Error {
let message = format!(
"Encountered a division-by-zero for operation (= {:?}) with the left hand-side value: (= {:?})",
op, lhs
);
Error{
kind: ErrorKind::DivisionByZero{op, lhs},
message,
annotation: None
}
}
}
impl<T> Into<Result<T>> for Error {
fn into(self) -> Result<T> {
Err(self)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
self.message.as_str()
}
}
pub type Result<T> = result::Result<T, Error>;