1
0
dust/dust-lang/src/value/concrete_value.rs

344 lines
12 KiB
Rust
Raw Normal View History

2024-11-15 21:42:27 -05:00
use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
use smartstring::{LazyCompact, SmartString};
2024-12-21 13:20:57 -05:00
use tracing::trace;
2024-11-15 21:42:27 -05:00
2024-12-17 03:22:44 -05:00
use crate::{Type, Value, ValueError};
2024-11-15 21:42:27 -05:00
use super::RangeValue;
pub type DustString = SmartString<LazyCompact>;
2024-11-15 21:42:27 -05:00
#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
pub enum ConcreteValue {
Boolean(bool),
Byte(u8),
Character(char),
Float(f64),
Integer(i64),
List(Vec<ConcreteValue>),
Range(RangeValue),
String(DustString),
2024-11-15 21:42:27 -05:00
}
impl ConcreteValue {
pub fn to_value(self) -> Value {
Value::Concrete(self)
}
2024-11-15 21:42:27 -05:00
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
ConcreteValue::List(into_list.into())
}
pub fn string<T: Into<SmartString<LazyCompact>>>(to_string: T) -> Self {
ConcreteValue::String(to_string.into())
2024-11-15 21:42:27 -05:00
}
pub fn as_string(&self) -> Option<&DustString> {
2024-11-15 21:42:27 -05:00
if let ConcreteValue::String(string) = self {
Some(string)
} else {
None
}
}
2024-12-14 16:17:02 -05:00
pub fn display(&self) -> DustString {
DustString::from(self.to_string())
}
2024-11-15 21:42:27 -05:00
pub fn r#type(&self) -> Type {
match self {
ConcreteValue::Boolean(_) => Type::Boolean,
ConcreteValue::Byte(_) => Type::Byte,
ConcreteValue::Character(_) => Type::Character,
ConcreteValue::Float(_) => Type::Float,
ConcreteValue::Integer(_) => Type::Integer,
ConcreteValue::List(list) => {
let item_type = list.first().map_or(Type::Any, |item| item.r#type());
Type::List(Box::new(item_type))
2024-11-15 21:42:27 -05:00
}
ConcreteValue::Range(range) => range.r#type(),
ConcreteValue::String(_) => Type::String,
2024-11-15 21:42:27 -05:00
}
}
2024-12-04 05:10:53 -05:00
#[inline(always)]
2024-12-17 03:22:44 -05:00
pub fn add(&self, other: &Self) -> ConcreteValue {
2024-11-15 21:42:27 -05:00
use ConcreteValue::*;
2024-12-17 03:22:44 -05:00
match (self, other) {
(Byte(left), Byte(right)) => {
let sum = left.saturating_add(*right);
Byte(sum)
}
(Character(left), Character(right)) => {
2024-12-17 03:22:44 -05:00
let mut concatenated = DustString::new();
concatenated.push(*left);
concatenated.push(*right);
String(concatenated)
}
2024-12-25 10:04:35 -05:00
(Character(left), String(right)) => {
let mut concatenated = DustString::new();
concatenated.push(*left);
concatenated.push_str(right);
String(concatenated)
}
2024-12-17 03:22:44 -05:00
(Float(left), Float(right)) => {
let sum = left + right;
Float(sum)
}
2024-12-17 03:22:44 -05:00
(Integer(left), Integer(right)) => {
let sum = left.saturating_add(*right);
2024-11-15 21:42:27 -05:00
2024-12-17 03:22:44 -05:00
Integer(sum)
}
(String(left), Character(right)) => {
let concatenated = format!("{}{}", left, right);
String(DustString::from(concatenated))
}
(String(left), String(right)) => {
let concatenated = format!("{}{}", left, right);
String(DustString::from(concatenated))
}
2024-12-17 03:22:44 -05:00
_ => panic!(
"{}",
ValueError::CannotAdd(
Value::Concrete(self.clone()),
Value::Concrete(other.clone())
)
),
}
2024-11-15 21:42:27 -05:00
}
pub fn subtract(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let difference = match (self, other) {
2024-11-16 01:29:21 -05:00
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_sub(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left - right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_sub(*right)),
_ => {
return Err(ValueError::CannotSubtract(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(difference)
}
pub fn multiply(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let product = match (self, other) {
2024-11-16 01:29:21 -05:00
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_mul(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left * right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_mul(*right)),
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(product)
}
pub fn divide(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let quotient = match (self, other) {
2024-11-16 01:29:21 -05:00
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_div(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left / right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_div(*right)),
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(quotient)
}
pub fn modulo(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let product = match (self, other) {
2024-11-16 01:29:21 -05:00
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.wrapping_rem(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left % right),
2024-11-15 21:42:27 -05:00
(Integer(left), Integer(right)) => {
2024-11-16 01:29:21 -05:00
ConcreteValue::Integer(left.wrapping_rem_euclid(*right))
2024-11-15 21:42:27 -05:00
}
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(product)
}
2024-12-17 03:22:44 -05:00
pub fn negate(&self) -> ConcreteValue {
2024-11-15 21:42:27 -05:00
use ConcreteValue::*;
2024-12-17 03:22:44 -05:00
match self {
2024-11-16 01:29:21 -05:00
Boolean(value) => ConcreteValue::Boolean(!value),
Byte(value) => ConcreteValue::Byte(value.wrapping_neg()),
Float(value) => ConcreteValue::Float(-value),
Integer(value) => ConcreteValue::Integer(value.wrapping_neg()),
2024-12-17 03:22:44 -05:00
_ => panic!("{}", ValueError::CannotNegate(self.clone().to_value())),
}
2024-11-15 21:42:27 -05:00
}
pub fn not(&self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let not = match self {
2024-11-16 01:29:21 -05:00
Boolean(value) => ConcreteValue::Boolean(!value),
_ => return Err(ValueError::CannotNot(self.clone().to_value())),
2024-11-15 21:42:27 -05:00
};
Ok(not)
}
pub fn equal(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let equal = match (self, other) {
2024-11-16 01:29:21 -05:00
(Boolean(left), Boolean(right)) => ConcreteValue::Boolean(left == right),
(Byte(left), Byte(right)) => ConcreteValue::Boolean(left == right),
(Character(left), Character(right)) => ConcreteValue::Boolean(left == right),
(Float(left), Float(right)) => ConcreteValue::Boolean(left == right),
(Integer(left), Integer(right)) => ConcreteValue::Boolean(left == right),
(List(left), List(right)) => ConcreteValue::Boolean(left == right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left == right),
(String(left), String(right)) => ConcreteValue::Boolean(left == right),
_ => {
return Err(ValueError::CannotCompare(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(equal)
}
2024-12-04 05:10:53 -05:00
#[inline(always)]
2024-11-15 21:42:27 -05:00
pub fn less_than(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let less_than = match (self, other) {
2024-11-16 01:29:21 -05:00
(Boolean(left), Boolean(right)) => ConcreteValue::Boolean(left < right),
(Byte(left), Byte(right)) => ConcreteValue::Boolean(left < right),
(Character(left), Character(right)) => ConcreteValue::Boolean(left < right),
(Float(left), Float(right)) => ConcreteValue::Boolean(left < right),
(Integer(left), Integer(right)) => ConcreteValue::Boolean(left < right),
(List(left), List(right)) => ConcreteValue::Boolean(left < right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left < right),
(String(left), String(right)) => ConcreteValue::Boolean(left < right),
_ => {
return Err(ValueError::CannotCompare(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(less_than)
}
pub fn less_than_or_equal(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let less_than_or_equal = match (self, other) {
2024-11-16 01:29:21 -05:00
(Boolean(left), Boolean(right)) => ConcreteValue::Boolean(left <= right),
(Byte(left), Byte(right)) => ConcreteValue::Boolean(left <= right),
(Character(left), Character(right)) => ConcreteValue::Boolean(left <= right),
(Float(left), Float(right)) => ConcreteValue::Boolean(left <= right),
(Integer(left), Integer(right)) => ConcreteValue::Boolean(left <= right),
(List(left), List(right)) => ConcreteValue::Boolean(left <= right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left <= right),
(String(left), String(right)) => ConcreteValue::Boolean(left <= right),
_ => {
return Err(ValueError::CannotCompare(
self.clone().to_value(),
other.clone().to_value(),
))
}
2024-11-15 21:42:27 -05:00
};
Ok(less_than_or_equal)
}
}
impl Clone for ConcreteValue {
fn clone(&self) -> Self {
2024-12-21 13:20:57 -05:00
trace!("Cloning concrete value {}", self);
2024-11-15 21:42:27 -05:00
match self {
ConcreteValue::Boolean(boolean) => ConcreteValue::Boolean(*boolean),
ConcreteValue::Byte(byte) => ConcreteValue::Byte(*byte),
ConcreteValue::Character(character) => ConcreteValue::Character(*character),
ConcreteValue::Float(float) => ConcreteValue::Float(*float),
ConcreteValue::Integer(integer) => ConcreteValue::Integer(*integer),
ConcreteValue::List(list) => ConcreteValue::List(list.clone()),
ConcreteValue::Range(range) => ConcreteValue::Range(*range),
ConcreteValue::String(string) => ConcreteValue::String(string.clone()),
}
}
}
impl Display for ConcreteValue {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ConcreteValue::Boolean(boolean) => write!(f, "{boolean}"),
ConcreteValue::Byte(byte) => write!(f, "0x{byte:02x}"),
ConcreteValue::Character(character) => write!(f, "{character}"),
ConcreteValue::Float(float) => {
write!(f, "{float}")?;
if float.fract() == 0.0 {
write!(f, ".0")?;
}
Ok(())
}
ConcreteValue::Integer(integer) => write!(f, "{integer}"),
ConcreteValue::List(list) => {
write!(f, "[")?;
for (index, item) in list.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{item}")?;
}
write!(f, "]")
}
ConcreteValue::Range(range_value) => {
write!(f, "{range_value}")
}
ConcreteValue::String(string) => write!(f, "{string}"),
}
}
}