Add support for casting.
This commit is contained in:
121
src/eval/primtype.rs
Normal file
121
src/eval/primtype.rs
Normal file
@@ -0,0 +1,121 @@
|
||||
use crate::{
|
||||
eval::{PrimOpError, Value},
|
||||
syntax::ConstantType,
|
||||
};
|
||||
use std::{fmt::Display, str::FromStr};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum PrimitiveType {
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
}
|
||||
|
||||
impl Display for PrimitiveType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
PrimitiveType::I8 => write!(f, "i8"),
|
||||
PrimitiveType::I16 => write!(f, "i16"),
|
||||
PrimitiveType::I32 => write!(f, "i32"),
|
||||
PrimitiveType::I64 => write!(f, "i64"),
|
||||
PrimitiveType::U8 => write!(f, "u8"),
|
||||
PrimitiveType::U16 => write!(f, "u16"),
|
||||
PrimitiveType::U32 => write!(f, "u32"),
|
||||
PrimitiveType::U64 => write!(f, "u64"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Value> for PrimitiveType {
|
||||
fn from(value: &Value) -> Self {
|
||||
match value {
|
||||
Value::I8(_) => PrimitiveType::I8,
|
||||
Value::I16(_) => PrimitiveType::I16,
|
||||
Value::I32(_) => PrimitiveType::I32,
|
||||
Value::I64(_) => PrimitiveType::I64,
|
||||
Value::U8(_) => PrimitiveType::U8,
|
||||
Value::U16(_) => PrimitiveType::U16,
|
||||
Value::U32(_) => PrimitiveType::U32,
|
||||
Value::U64(_) => PrimitiveType::U64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConstantType> for PrimitiveType {
|
||||
fn from(value: ConstantType) -> Self {
|
||||
match value {
|
||||
ConstantType::I8 => PrimitiveType::I8,
|
||||
ConstantType::I16 => PrimitiveType::I16,
|
||||
ConstantType::I32 => PrimitiveType::I32,
|
||||
ConstantType::I64 => PrimitiveType::I64,
|
||||
ConstantType::U8 => PrimitiveType::U8,
|
||||
ConstantType::U16 => PrimitiveType::U16,
|
||||
ConstantType::U32 => PrimitiveType::U32,
|
||||
ConstantType::U64 => PrimitiveType::U64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for PrimitiveType {
|
||||
type Err = PrimOpError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"i8" => Ok(PrimitiveType::I8),
|
||||
"i16" => Ok(PrimitiveType::I16),
|
||||
"i32" => Ok(PrimitiveType::I32),
|
||||
"i64" => Ok(PrimitiveType::I64),
|
||||
"u8" => Ok(PrimitiveType::U8),
|
||||
"u16" => Ok(PrimitiveType::U16),
|
||||
"u32" => Ok(PrimitiveType::U32),
|
||||
"u64" => Ok(PrimitiveType::U64),
|
||||
_ => Err(PrimOpError::UnknownPrimType(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveType {
|
||||
/// Try to cast the given value to this type, returning the new value.
|
||||
///
|
||||
/// Returns an error if the cast is not safe *in* *general*. This means that
|
||||
/// this function will error even if the number will actually fit in the target
|
||||
/// type, but it would not be generally safe to cast a member of the given
|
||||
/// type to the target type. (So, for example, "1i64" is a number that could
|
||||
/// work as a "u64", but since negative numbers wouldn't work, a cast from
|
||||
/// "1i64" to "u64" will fail.)
|
||||
pub fn safe_cast(&self, source: &Value) -> Result<Value, PrimOpError> {
|
||||
match (self, source) {
|
||||
(PrimitiveType::U8, Value::U8(x)) => Ok(Value::U8(*x)),
|
||||
(PrimitiveType::U16, Value::U8(x)) => Ok(Value::U16(*x as u16)),
|
||||
(PrimitiveType::U16, Value::U16(x)) => Ok(Value::U16(*x)),
|
||||
(PrimitiveType::U32, Value::U8(x)) => Ok(Value::U32(*x as u32)),
|
||||
(PrimitiveType::U32, Value::U16(x)) => Ok(Value::U32(*x as u32)),
|
||||
(PrimitiveType::U32, Value::U32(x)) => Ok(Value::U32(*x)),
|
||||
(PrimitiveType::U64, Value::U8(x)) => Ok(Value::U64(*x as u64)),
|
||||
(PrimitiveType::U64, Value::U16(x)) => Ok(Value::U64(*x as u64)),
|
||||
(PrimitiveType::U64, Value::U32(x)) => Ok(Value::U64(*x as u64)),
|
||||
(PrimitiveType::U64, Value::U64(x)) => Ok(Value::U64(*x)),
|
||||
|
||||
(PrimitiveType::I8, Value::I8(x)) => Ok(Value::I8(*x)),
|
||||
(PrimitiveType::I16, Value::I8(x)) => Ok(Value::I16(*x as i16)),
|
||||
(PrimitiveType::I16, Value::I16(x)) => Ok(Value::I16(*x)),
|
||||
(PrimitiveType::I32, Value::I8(x)) => Ok(Value::I32(*x as i32)),
|
||||
(PrimitiveType::I32, Value::I16(x)) => Ok(Value::I32(*x as i32)),
|
||||
(PrimitiveType::I32, Value::I32(x)) => Ok(Value::I32(*x)),
|
||||
(PrimitiveType::I64, Value::I8(x)) => Ok(Value::I64(*x as i64)),
|
||||
(PrimitiveType::I64, Value::I16(x)) => Ok(Value::I64(*x as i64)),
|
||||
(PrimitiveType::I64, Value::I32(x)) => Ok(Value::I64(*x as i64)),
|
||||
(PrimitiveType::I64, Value::I64(x)) => Ok(Value::I64(*x)),
|
||||
|
||||
_ => Err(PrimOpError::UnsafeCast {
|
||||
from: source.into(),
|
||||
to: *self,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user