Complete value overhaul

This commit is contained in:
Jeff 2024-08-23 03:04:11 -04:00
parent 87bced9719
commit 23782c37a3
6 changed files with 322 additions and 190 deletions

View File

@ -17,8 +17,8 @@ use crate::{
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition, PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
StructExpression, TupleAccessExpression, StructExpression, TupleAccessExpression,
}, },
core_library, parse, Context, ContextError, DustError, Expression, Identifier, Rangeable, core_library, parse, Context, ContextError, DustError, Expression, Identifier, RangeableType,
RangeableType, StructType, Type, StructType, Type,
}; };
/// Analyzes the abstract syntax tree for errors. /// Analyzes the abstract syntax tree for errors.

View File

@ -31,7 +31,7 @@ pub struct UnitConstructor {
impl UnitConstructor { impl UnitConstructor {
pub fn construct(self) -> Value { pub fn construct(self) -> Value {
Value::Struct(Struct::Unit { name: self.name }) Value::r#struct(Struct::Unit { name: self.name })
} }
} }
@ -42,7 +42,7 @@ pub struct TupleConstructor {
impl TupleConstructor { impl TupleConstructor {
pub fn construct(self, fields: Vec<Value>) -> Value { pub fn construct(self, fields: Vec<Value>) -> Value {
Value::Struct(Struct::Tuple { Value::r#struct(Struct::Tuple {
name: self.name, name: self.name,
fields, fields,
}) })
@ -56,7 +56,7 @@ pub struct FieldsConstructor {
impl FieldsConstructor { impl FieldsConstructor {
pub fn construct(self, fields: HashMap<Identifier, Value>) -> Value { pub fn construct(self, fields: HashMap<Identifier, Value>) -> Value {
Value::Struct(Struct::Fields { Value::r#struct(Struct::Fields {
name: self.name, name: self.name,
fields, fields,
}) })

View File

@ -347,7 +347,7 @@ mod tests {
assert_eq!( assert_eq!(
run_with_context(source, context.clone()), run_with_context(source, context.clone()),
Ok(Some(Value::Integer(15))) Ok(Some(Value::integer(15)))
); );
assert_eq!(context.association_count().unwrap(), 0); assert_eq!(context.association_count().unwrap(), 0);

View File

@ -10,7 +10,7 @@ pub fn core_library<'a>() -> &'a Context {
( (
Identifier::new("to_string"), Identifier::new("to_string"),
( (
ContextData::VariableValue(Value::Function(Function::BuiltIn( ContextData::VariableValue(Value::function(Function::BuiltIn(
BuiltInFunction::ToString, BuiltInFunction::ToString,
))), ))),
(0, 0), (0, 0),
@ -19,7 +19,7 @@ pub fn core_library<'a>() -> &'a Context {
( (
Identifier::new("read_line"), Identifier::new("read_line"),
( (
ContextData::VariableValue(Value::Function(Function::BuiltIn( ContextData::VariableValue(Value::function(Function::BuiltIn(
BuiltInFunction::ReadLine, BuiltInFunction::ReadLine,
))), ))),
(0, 0), (0, 0),
@ -28,7 +28,7 @@ pub fn core_library<'a>() -> &'a Context {
( (
Identifier::new("write_line"), Identifier::new("write_line"),
( (
ContextData::VariableValue(Value::Function(Function::BuiltIn( ContextData::VariableValue(Value::function(Function::BuiltIn(
BuiltInFunction::WriteLine, BuiltInFunction::WriteLine,
))), ))),
(0, 0), (0, 0),

View File

@ -5,12 +5,11 @@ use std::{
error::Error, error::Error,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
ops::{Range, RangeInclusive}, ops::{Range, RangeInclusive},
ptr::read,
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
use serde::{ use serde::{
de::{self, EnumAccess, MapAccess, SeqAccess, Visitor}, de::{self, MapAccess, SeqAccess, Visitor},
ser::SerializeMap, ser::SerializeMap,
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
}; };
@ -25,30 +24,29 @@ use crate::{
/// Each type of value has a corresponding constructor, here are some simple examples: /// Each type of value has a corresponding constructor, here are some simple examples:
/// ///
/// ``` /// ```
/// # use dust_lang::ValueData; /// # use dust_lang::Value;
/// let boolean = ValueData::boolean(true); /// let boolean = Value::boolean(true);
/// let float = ValueData::float(3.14); /// let float = Value::float(3.14);
/// let integer = ValueData::integer(42); /// let integer = Value::integer(42);
/// let string = ValueData::string("Hello, world!"); /// let string = Value::string("Hello, world!");
/// ``` /// ```
/// ///
/// Values can be combined into more complex values: /// Values can be combined into more complex values:
/// ///
/// ``` /// ```
/// # use dust_lang::ValueData; /// # use dust_lang::Value;
/// let list = ValueData::list(vec![ /// let list = Value::list(vec![
/// ValueData::integer(1), /// Value::integer(1),
/// ValueData::integer(2), /// Value::integer(2),
/// ValueData::integer(3), /// Value::integer(3),
/// ]); /// ]);
/// ``` /// ```
/// ///
/// Values have a type, which can be retrieved using the `type` method: /// Values have a type, which can be retrieved using the `type` method:
/// ///
/// ``` /// ```
/// # use std::collections::HashMap;
/// # use dust_lang::*; /// # use dust_lang::*;
/// let value = ValueData::integer(42); /// let value = Value::integer(42);
/// ///
/// assert_eq!(value.r#type(), Type::Integer); /// assert_eq!(value.r#type(), Type::Integer);
/// ``` /// ```
@ -76,8 +74,8 @@ impl Value {
Value::Raw(ValueData::Float(value)) Value::Raw(ValueData::Float(value))
} }
pub fn integer(value: i64) -> Self { pub fn integer<T: Into<i64>>(into_i64: T) -> Self {
Value::Raw(ValueData::Integer(value)) Value::Raw(ValueData::Integer(into_i64.into()))
} }
pub fn string<T: ToString>(to_string: T) -> Self { pub fn string<T: ToString>(to_string: T) -> Self {
@ -88,8 +86,8 @@ impl Value {
Value::Raw(ValueData::List(value)) Value::Raw(ValueData::List(value))
} }
pub fn map(value: HashMap<Identifier, Value>) -> Self { pub fn map<T: Into<HashMap<Identifier, Value>>>(into_map: T) -> Self {
Value::Raw(ValueData::Map(value)) Value::Raw(ValueData::Map(into_map.into()))
} }
pub fn mutable(value: Value) -> Self { pub fn mutable(value: Value) -> Self {
@ -104,12 +102,12 @@ impl Value {
Value::Raw(ValueData::Function(value)) Value::Raw(ValueData::Function(value))
} }
pub fn range<T: Into<Rangeable>>(start: T, end: T) -> Self { pub fn range<T: Into<RangeValue>>(range: T) -> Self {
Value::Raw(ValueData::Range(start.into()..end.into())) Value::Raw(ValueData::Range(range.into()))
} }
pub fn range_inclusive<T: Into<Rangeable>>(start: T, end: T) -> Self { pub fn r#struct(value: Struct) -> Self {
Value::Raw(ValueData::RangeInclusive(start.into()..=end.into())) Value::Raw(ValueData::Struct(value))
} }
pub fn reference(value: Value) -> Self { pub fn reference(value: Value) -> Self {
@ -282,6 +280,40 @@ impl Value {
value: self.clone(), value: self.clone(),
index: *index, index: *index,
}), }),
(ValueData::List(values), ValueData::Range(RangeValue::IntegerRange(range))) => {
if range.start < 0 || range.start > values.len() as i64 {
return Err(ValueError::IndexOutOfBounds {
value: self.clone(),
index: range.start,
});
}
if range.end < 0 || range.end > values.len() as i64 {
return Err(ValueError::IndexOutOfBounds {
value: self.clone(),
index: range.end,
});
}
let slice = values
.get(range.start as usize..range.end as usize)
.unwrap();
Ok(Value::list(slice.to_vec()))
}
(ValueData::String(string), ValueData::Integer(index)) => {
let index = *index as usize;
let character =
string
.chars()
.nth(index)
.ok_or_else(|| ValueError::IndexOutOfBounds {
value: self.clone(),
index: index as i64,
})?;
Ok(Value::character(character))
}
_ => Err(ValueError::CannotIndex { _ => Err(ValueError::CannotIndex {
value: self.clone(), value: self.clone(),
index: index_value.clone(), index: index_value.clone(),
@ -354,7 +386,7 @@ impl Value {
Value::Mutable(data) => &data.read().unwrap(), Value::Mutable(data) => &data.read().unwrap(),
}; };
let new_data = left let new_data = left
.add(&right) .add(right)
.ok_or_else(|| ValueError::CannotAdd(self.clone(), other.clone()))?; .ok_or_else(|| ValueError::CannotAdd(self.clone(), other.clone()))?;
*left = new_data; *left = new_data;
@ -392,7 +424,7 @@ impl Value {
Value::Mutable(data) => &data.read().unwrap(), Value::Mutable(data) => &data.read().unwrap(),
}; };
let new_data = left let new_data = left
.subtract(&right) .subtract(right)
.ok_or_else(|| ValueError::CannotSubtract(self.clone(), other.clone()))?; .ok_or_else(|| ValueError::CannotSubtract(self.clone(), other.clone()))?;
*left = new_data; *left = new_data;
@ -430,7 +462,7 @@ impl Value {
Value::Mutable(data) => &data.read().unwrap(), Value::Mutable(data) => &data.read().unwrap(),
}; };
let new_data = left let new_data = left
.multiply(&right) .multiply(right)
.ok_or_else(|| ValueError::CannotMultiply(self.clone(), other.clone()))?; .ok_or_else(|| ValueError::CannotMultiply(self.clone(), other.clone()))?;
*left = new_data; *left = new_data;
@ -468,7 +500,7 @@ impl Value {
Value::Mutable(data) => &data.read().unwrap(), Value::Mutable(data) => &data.read().unwrap(),
}; };
let new_data = left let new_data = left
.divide(&right) .divide(right)
.ok_or_else(|| ValueError::CannotDivide(self.clone(), other.clone()))?; .ok_or_else(|| ValueError::CannotDivide(self.clone(), other.clone()))?;
*left = new_data; *left = new_data;
@ -506,7 +538,7 @@ impl Value {
Value::Mutable(data) => &data.read().unwrap(), Value::Mutable(data) => &data.read().unwrap(),
}; };
let new_data = left let new_data = left
.modulo(&right) .modulo(right)
.ok_or_else(|| ValueError::CannotModulo(self.clone(), other.clone()))?; .ok_or_else(|| ValueError::CannotModulo(self.clone(), other.clone()))?;
*left = new_data; *left = new_data;
@ -709,14 +741,18 @@ impl Eq for Value {}
impl PartialEq for Value { impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { let left = match self {
(Value::Raw(left), Value::Raw(right)) => left == right, Value::Raw(data) => data,
(Value::Reference(left), Value::Reference(right)) => left == right, Value::Reference(data) => data,
(Value::Mutable(left), Value::Mutable(right)) => { Value::Mutable(data) => &data.read().unwrap(),
*left.read().unwrap() == *right.read().unwrap() };
} let right = match other {
_ => false, Value::Raw(data) => data,
} Value::Reference(data) => data,
Value::Mutable(data) => &data.read().unwrap(),
};
left == right
} }
} }
@ -834,8 +870,7 @@ pub enum ValueData {
Integer(i64), Integer(i64),
List(Vec<Value>), List(Vec<Value>),
Map(HashMap<Identifier, Value>), Map(HashMap<Identifier, Value>),
Range(Range<Rangeable>), Range(RangeValue),
RangeInclusive(RangeInclusive<Rangeable>),
String(String), String(String),
Struct(Struct), Struct(Struct),
Tuple(Vec<Value>), Tuple(Vec<Value>),
@ -875,16 +910,7 @@ impl ValueData {
Type::Map { pairs } Type::Map { pairs }
} }
ValueData::Range(range) => Type::Range { ValueData::Range(range) => range.r#type(),
r#type: range.start.r#type(),
},
ValueData::RangeInclusive(range_inclusive) => {
let rangeable_type = range_inclusive.start().r#type();
Type::Range {
r#type: rangeable_type,
}
}
ValueData::String(string) => Type::String { ValueData::String(string) => Type::String {
length: Some(string.len()), length: Some(string.len()),
}, },
@ -919,13 +945,13 @@ impl ValueData {
} }
pub fn is_rangeable(&self) -> bool { pub fn is_rangeable(&self) -> bool {
match self { matches!(
self,
ValueData::Integer(_) ValueData::Integer(_)
| ValueData::Float(_) | ValueData::Float(_)
| ValueData::Character(_) | ValueData::Character(_)
| ValueData::Byte(_) => true, | ValueData::Byte(_)
_ => false, )
}
} }
pub fn add(&self, other: &ValueData) -> Option<ValueData> { pub fn add(&self, other: &ValueData) -> Option<ValueData> {
@ -1174,14 +1200,8 @@ impl Display for ValueData {
write!(f, "]") write!(f, "]")
} }
ValueData::Range(Range { start, end }) => { ValueData::Range(range_value) => {
write!(f, "{start}..{end}") write!(f, "{range_value}")
}
ValueData::RangeInclusive(inclusive) => {
let start = inclusive.start();
let end = inclusive.end();
write!(f, "{start}..={end}")
} }
ValueData::String(string) => write!(f, "{string}"), ValueData::String(string) => write!(f, "{string}"),
ValueData::Struct(r#struct) => write!(f, "{struct}"), ValueData::Struct(r#struct) => write!(f, "{struct}"),
@ -1216,7 +1236,6 @@ impl PartialEq for ValueData {
(ValueData::List(left), ValueData::List(right)) => left == right, (ValueData::List(left), ValueData::List(right)) => left == right,
(ValueData::Map(left), ValueData::Map(right)) => left == right, (ValueData::Map(left), ValueData::Map(right)) => left == right,
(ValueData::Range(left), ValueData::Range(right)) => left == right, (ValueData::Range(left), ValueData::Range(right)) => left == right,
(ValueData::RangeInclusive(left), ValueData::RangeInclusive(right)) => left == right,
(ValueData::String(left), ValueData::String(right)) => left == right, (ValueData::String(left), ValueData::String(right)) => left == right,
(ValueData::Struct(left), ValueData::Struct(right)) => left == right, (ValueData::Struct(left), ValueData::Struct(right)) => left == right,
(ValueData::Tuple(left), ValueData::Tuple(right)) => left == right, (ValueData::Tuple(left), ValueData::Tuple(right)) => left == right,
@ -1248,26 +1267,8 @@ impl Ord for ValueData {
(ValueData::Integer(_), _) => Ordering::Greater, (ValueData::Integer(_), _) => Ordering::Greater,
(ValueData::List(left), ValueData::List(right)) => left.cmp(right), (ValueData::List(left), ValueData::List(right)) => left.cmp(right),
(ValueData::List(_), _) => Ordering::Greater, (ValueData::List(_), _) => Ordering::Greater,
(ValueData::Range(left), ValueData::Range(right)) => { (ValueData::Range(left), ValueData::Range(right)) => left.cmp(right),
let start_cmp = left.start.cmp(&right.start);
if start_cmp.is_eq() {
left.end.cmp(&right.end)
} else {
start_cmp
}
}
(ValueData::Range(_), _) => Ordering::Greater, (ValueData::Range(_), _) => Ordering::Greater,
(ValueData::RangeInclusive(left), ValueData::RangeInclusive(right)) => {
let start_cmp = left.start().cmp(right.start());
if start_cmp.is_eq() {
left.end().cmp(right.end())
} else {
start_cmp
}
}
(ValueData::RangeInclusive(_), _) => Ordering::Greater,
(ValueData::String(left), ValueData::String(right)) => left.cmp(right), (ValueData::String(left), ValueData::String(right)) => left.cmp(right),
(ValueData::String(_), _) => Ordering::Greater, (ValueData::String(_), _) => Ordering::Greater,
(ValueData::Struct(left), ValueData::Struct(right)) => left.cmp(right), (ValueData::Struct(left), ValueData::Struct(right)) => left.cmp(right),
@ -1302,7 +1303,6 @@ impl Serialize for ValueData {
ser.end() ser.end()
} }
ValueData::Range(range) => range.serialize(serializer), ValueData::Range(range) => range.serialize(serializer),
ValueData::RangeInclusive(inclusive) => inclusive.serialize(serializer),
ValueData::String(string) => serializer.serialize_str(string), ValueData::String(string) => serializer.serialize_str(string),
ValueData::Struct(r#struct) => r#struct.serialize(serializer), ValueData::Struct(r#struct) => r#struct.serialize(serializer),
ValueData::Tuple(tuple) => tuple.serialize(serializer), ValueData::Tuple(tuple) => tuple.serialize(serializer),
@ -1561,84 +1561,212 @@ impl Display for Struct {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Rangeable { pub enum RangeValue {
Byte(u8), ByteRange(Range<u8>),
Character(char), ByteRangeInclusive(RangeInclusive<u8>),
Float(f64), CharacterRange(Range<char>),
Integer(i64), CharacterRangeInclusive(RangeInclusive<char>),
FloatRange(Range<f64>),
FloatRangeInclusive(RangeInclusive<f64>),
IntegerRange(Range<i64>),
IntegerRangeInclusive(RangeInclusive<i64>),
} }
impl From<u8> for Rangeable { impl RangeValue {
fn from(value: u8) -> Self { pub fn r#type(&self) -> Type {
Rangeable::Byte(value) let inner_type = match self {
RangeValue::ByteRange(_) => RangeableType::Byte,
RangeValue::ByteRangeInclusive(_) => RangeableType::Byte,
RangeValue::CharacterRange(_) => RangeableType::Character,
RangeValue::CharacterRangeInclusive(_) => RangeableType::Character,
RangeValue::FloatRange(_) => RangeableType::Float,
RangeValue::FloatRangeInclusive(_) => RangeableType::Float,
RangeValue::IntegerRange(_) => RangeableType::Integer,
RangeValue::IntegerRangeInclusive(_) => RangeableType::Integer,
};
Type::Range { r#type: inner_type }
} }
} }
impl From<char> for Rangeable { impl From<Range<u8>> for RangeValue {
fn from(value: char) -> Self { fn from(range: Range<u8>) -> Self {
Rangeable::Character(value) RangeValue::ByteRange(range)
} }
} }
impl From<f64> for Rangeable { impl From<RangeInclusive<u8>> for RangeValue {
fn from(value: f64) -> Self { fn from(range: RangeInclusive<u8>) -> Self {
Rangeable::Float(value) RangeValue::ByteRangeInclusive(range)
} }
} }
impl From<i32> for Rangeable { impl From<Range<char>> for RangeValue {
fn from(value: i32) -> Self { fn from(range: Range<char>) -> Self {
Rangeable::Integer(value as i64) RangeValue::CharacterRange(range)
} }
} }
impl From<i64> for Rangeable { impl From<RangeInclusive<char>> for RangeValue {
fn from(value: i64) -> Self { fn from(range: RangeInclusive<char>) -> Self {
Rangeable::Integer(value) RangeValue::CharacterRangeInclusive(range)
} }
} }
impl Rangeable { impl From<Range<f64>> for RangeValue {
fn r#type(&self) -> RangeableType { fn from(range: Range<f64>) -> Self {
match self { RangeValue::FloatRange(range)
Rangeable::Byte(_) => RangeableType::Byte,
Rangeable::Character(_) => RangeableType::Character,
Rangeable::Float(_) => RangeableType::Float,
Rangeable::Integer(_) => RangeableType::Integer,
}
} }
} }
impl Display for Rangeable { impl From<RangeInclusive<f64>> for RangeValue {
fn from(range: RangeInclusive<f64>) -> Self {
RangeValue::FloatRangeInclusive(range)
}
}
impl From<Range<i32>> for RangeValue {
fn from(range: Range<i32>) -> Self {
RangeValue::IntegerRange(range.start as i64..range.end as i64)
}
}
impl From<RangeInclusive<i32>> for RangeValue {
fn from(range: RangeInclusive<i32>) -> Self {
RangeValue::IntegerRangeInclusive(*range.start() as i64..=*range.end() as i64)
}
}
impl From<Range<i64>> for RangeValue {
fn from(range: Range<i64>) -> Self {
RangeValue::IntegerRange(range)
}
}
impl From<RangeInclusive<i64>> for RangeValue {
fn from(range: RangeInclusive<i64>) -> Self {
RangeValue::IntegerRangeInclusive(range)
}
}
impl Display for RangeValue {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Rangeable::Byte(byte) => write!(f, "{byte}"), RangeValue::ByteRange(range) => write!(f, "{}..{}", range.start, range.end),
Rangeable::Character(character) => write!(f, "{character}"), RangeValue::ByteRangeInclusive(range) => {
Rangeable::Float(float) => write!(f, "{float}"), write!(f, "{}..={}", range.start(), range.end())
Rangeable::Integer(integer) => write!(f, "{integer}"), }
RangeValue::CharacterRange(range) => write!(f, "{}..{}", range.start, range.end),
RangeValue::CharacterRangeInclusive(range) => {
write!(f, "{}..={}", range.start(), range.end())
}
RangeValue::FloatRange(range) => write!(f, "{}..{}", range.start, range.end),
RangeValue::FloatRangeInclusive(range) => {
write!(f, "{}..={}", range.start(), range.end())
}
RangeValue::IntegerRange(range) => write!(f, "{}..{}", range.start, range.end),
RangeValue::IntegerRangeInclusive(range) => {
write!(f, "{}..={}", range.start(), range.end())
}
} }
} }
} }
impl Eq for Rangeable {} impl Eq for RangeValue {}
impl PartialOrd for Rangeable { impl PartialOrd for RangeValue {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Ord for Rangeable { impl Ord for RangeValue {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
match (self, other) { match (self, other) {
(Rangeable::Byte(left), Rangeable::Byte(right)) => left.cmp(right), (RangeValue::ByteRange(left), RangeValue::ByteRange(right)) => {
(Rangeable::Character(left), Rangeable::Character(right)) => left.cmp(right), let start_cmp = left.start.cmp(&right.start);
(Rangeable::Float(left), Rangeable::Float(right)) => {
left.to_bits().cmp(&right.to_bits()) if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end.cmp(&right.end)
} }
(Rangeable::Integer(left), Rangeable::Integer(right)) => left.cmp(right), }
_ => unreachable!(), (RangeValue::ByteRange(_), _) => Ordering::Greater,
(RangeValue::ByteRangeInclusive(left), RangeValue::ByteRangeInclusive(right)) => {
let start_cmp = left.start().cmp(right.start());
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end().cmp(right.end())
}
}
(RangeValue::ByteRangeInclusive(_), _) => Ordering::Greater,
(RangeValue::CharacterRange(left), RangeValue::CharacterRange(right)) => {
let start_cmp = left.start.cmp(&right.start);
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end.cmp(&right.end)
}
}
(RangeValue::CharacterRange(_), _) => Ordering::Greater,
(
RangeValue::CharacterRangeInclusive(left),
RangeValue::CharacterRangeInclusive(right),
) => {
let start_cmp = left.start().cmp(right.start());
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end().cmp(right.end())
}
}
(RangeValue::CharacterRangeInclusive(_), _) => Ordering::Greater,
(RangeValue::FloatRange(left), RangeValue::FloatRange(right)) => {
let start_cmp = left.start.to_bits().cmp(&right.start.to_bits());
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end.to_bits().cmp(&right.end.to_bits())
}
}
(RangeValue::FloatRange(_), _) => Ordering::Greater,
(RangeValue::FloatRangeInclusive(left), RangeValue::FloatRangeInclusive(right)) => {
let start_cmp = left.start().to_bits().cmp(&right.start().to_bits());
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end().to_bits().cmp(&right.end().to_bits())
}
}
(RangeValue::FloatRangeInclusive(_), _) => Ordering::Greater,
(RangeValue::IntegerRange(left), RangeValue::IntegerRange(right)) => {
let start_cmp = left.start.cmp(&right.start);
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end.cmp(&right.end)
}
}
(RangeValue::IntegerRange(_), _) => Ordering::Greater,
(RangeValue::IntegerRangeInclusive(left), RangeValue::IntegerRangeInclusive(right)) => {
let start_cmp = left.start().cmp(right.start());
if start_cmp != Ordering::Equal {
start_cmp
} else {
left.end().cmp(right.end())
}
}
(RangeValue::IntegerRangeInclusive(_), _) => Ordering::Greater,
} }
} }
} }
@ -1745,6 +1873,10 @@ impl Display for ValueError {
"Failed to make mutable value because the value has an immutable reference to it" "Failed to make mutable value because the value has an immutable reference to it"
), ),
ValueError::CannotMutate(value) => write!(f, "Cannot mutate {}", value), ValueError::CannotMutate(value) => write!(f, "Cannot mutate {}", value),
ValueError::CannotNegate(value) => write!(f, "Cannot negate {}", value),
ValueError::CannotNot(value) => {
write!(f, "Cannot use logical not operation on {}", value)
}
ValueError::CannotSubtract(left, right) => { ValueError::CannotSubtract(left, right) => {
write!(f, "Cannot subtract {} and {}", left, right) write!(f, "Cannot subtract {} and {}", left, right)
} }

View File

@ -386,16 +386,16 @@ impl Vm {
match (start_data, end_data) { match (start_data, end_data) {
(ValueData::Byte(start), ValueData::Byte(end)) => { (ValueData::Byte(start), ValueData::Byte(end)) => {
Ok(Evaluation::Return(Some(Value::range(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..end))))
} }
(ValueData::Character(start), ValueData::Character(end)) => { (ValueData::Character(start), ValueData::Character(end)) => {
Ok(Evaluation::Return(Some(Value::range(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..end))))
} }
(ValueData::Float(start), ValueData::Float(end)) => { (ValueData::Float(start), ValueData::Float(end)) => {
Ok(Evaluation::Return(Some(Value::range(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..end))))
} }
(ValueData::Integer(start), ValueData::Integer(end)) => { (ValueData::Integer(start), ValueData::Integer(end)) => {
Ok(Evaluation::Return(Some(Value::range(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..end))))
} }
_ => Err(RuntimeError::InvalidRange { _ => Err(RuntimeError::InvalidRange {
start_position, start_position,
@ -426,16 +426,16 @@ impl Vm {
match (start_data, end_data) { match (start_data, end_data) {
(ValueData::Byte(start), ValueData::Byte(end)) => { (ValueData::Byte(start), ValueData::Byte(end)) => {
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..=end))))
} }
(ValueData::Character(start), ValueData::Character(end)) => { (ValueData::Character(start), ValueData::Character(end)) => {
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..=end))))
} }
(ValueData::Float(start), ValueData::Float(end)) => { (ValueData::Float(start), ValueData::Float(end)) => {
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..=end))))
} }
(ValueData::Integer(start), ValueData::Integer(end)) => { (ValueData::Integer(start), ValueData::Integer(end)) => {
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end)))) Ok(Evaluation::Return(Some(Value::range(start..=end))))
} }
_ => Err(RuntimeError::InvalidRange { _ => Err(RuntimeError::InvalidRange {
start_position, start_position,
@ -1404,14 +1404,14 @@ mod tests {
fn break_loop() { fn break_loop() {
let input = "let mut x = 0; loop { x += 1; if x == 10 { break; } } x"; let input = "let mut x = 0; loop { x += 1; if x == 10 { break; } } x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(10))))); assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(10)))));
} }
#[test] #[test]
fn string_index() { fn string_index() {
let input = "'foo'[0]"; let input = "'foo'[0]";
assert_eq!(run(input), Ok(Some(Value::Character('f')))); assert_eq!(run(input), Ok(Some(Value::character('f'))));
} }
#[test] #[test]
@ -1421,8 +1421,8 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::map([ Ok(Some(Value::map([
(Identifier::new("foo"), Value::Integer(42)), (Identifier::new("foo"), Value::integer(42)),
(Identifier::new("bar"), Value::Float(4.2)) (Identifier::new("bar"), Value::float(4.2))
]))) ])))
); );
} }
@ -1431,7 +1431,7 @@ mod tests {
fn async_block() { fn async_block() {
let input = "let mut x = 1; async { x += 1; x -= 1; } x"; let input = "let mut x = 1; async { x += 1; x -= 1; } x";
assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(1))))); assert_eq!(run(input), Ok(Some(Value::mutable(Value::integer(1)))));
} }
#[test] #[test]
@ -1440,11 +1440,11 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Fields { Ok(Some(Value::r#struct(Struct::Fields {
name: Identifier::new("Foo"), name: Identifier::new("Foo"),
fields: HashMap::from([ fields: HashMap::from([
(Identifier::new("bar"), Value::Integer(42)), (Identifier::new("bar"), Value::integer(42)),
(Identifier::new("baz"), Value::Float(4.0)) (Identifier::new("baz"), Value::float(4.0))
]) ])
}))) })))
); );
@ -1460,9 +1460,9 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Tuple { Ok(Some(Value::r#struct(Struct::Tuple {
name: Identifier::new("Foo"), name: Identifier::new("Foo"),
fields: vec![Value::Integer(42)] fields: vec![Value::integer(42)]
}))) })))
) )
} }
@ -1473,9 +1473,9 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Tuple { Ok(Some(Value::r#struct(Struct::Tuple {
name: Identifier::new("Foo"), name: Identifier::new("Foo"),
fields: vec![Value::Integer(42)] fields: vec![Value::integer(42)]
}))) })))
); );
} }
@ -1490,7 +1490,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Unit { Ok(Some(Value::r#struct(Struct::Unit {
name: Identifier::new("Foo") name: Identifier::new("Foo")
}))) })))
) )
@ -1502,7 +1502,7 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::Struct(Struct::Unit { Ok(Some(Value::r#struct(Struct::Unit {
name: Identifier::new("Foo") name: Identifier::new("Foo")
}))) })))
); );
@ -1512,7 +1512,7 @@ mod tests {
fn list_index_nested() { fn list_index_nested() {
let input = "[[1, 2], [42, 4], [5, 6]][1][0]"; let input = "[[1, 2], [42, 4], [5, 6]][1][0]";
assert_eq!(run(input), Ok(Some(Value::Integer(42)))); assert_eq!(run(input), Ok(Some(Value::integer(42))));
} }
#[test] #[test]
@ -1521,9 +1521,9 @@ mod tests {
assert_eq!( assert_eq!(
run(input), run(input),
Ok(Some(Value::List(vec![ Ok(Some(Value::list(vec![
Value::Integer(2), Value::integer(2),
Value::Integer(3) Value::integer(3)
]))) ])))
); );
} }
@ -1532,35 +1532,35 @@ mod tests {
fn range() { fn range() {
let input = "1..5"; let input = "1..5";
assert_eq!(run(input), Ok(Some(Value::range(1, 5)))); assert_eq!(run(input), Ok(Some(Value::range(1..5))));
} }
#[test] #[test]
fn negate_expression() { fn negate_expression() {
let input = "let x = -42; -x"; let input = "let x = -42; -x";
assert_eq!(run(input), Ok(Some(Value::Integer(42)))); assert_eq!(run(input), Ok(Some(Value::integer(42))));
} }
#[test] #[test]
fn not_expression() { fn not_expression() {
let input = "!(1 == 2 || 3 == 4 || 5 == 6)"; let input = "!(1 == 2 || 3 == 4 || 5 == 6)";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn list_index() { fn list_index() {
let input = "[1, 42, 3][1]"; let input = "[1, 42, 3][1]";
assert_eq!(run(input), Ok(Some(Value::Integer(42)))); assert_eq!(run(input), Ok(Some(Value::integer(42))));
} }
#[test] #[test]
fn map_property_access() { fn map_property_access() {
let input = "map { a = 42 }.a"; let input = "map { a = 42 }.a";
assert_eq!(run(input), Ok(Some(Value::Integer(42)))); assert_eq!(run(input), Ok(Some(Value::integer(42))));
} }
#[test] #[test]
@ -1588,7 +1588,7 @@ mod tests {
fn if_else() { fn if_else() {
let input = "let x = if false { 1 } else { 2 }; x"; let input = "let x = if false { 1 } else { 2 }; x";
assert_eq!(run(input), Ok(Some(Value::Integer(2)))); assert_eq!(run(input), Ok(Some(Value::integer(2))));
} }
#[test] #[test]
@ -1602,167 +1602,167 @@ mod tests {
fn if_else_if_else() { fn if_else_if_else() {
let input = "if false { 1 } else if false { 2 } else { 3 }"; let input = "if false { 1 } else if false { 2 } else { 3 }";
assert_eq!(run(input), Ok(Some(Value::Integer(3)))); assert_eq!(run(input), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn while_loop() { fn while_loop() {
let input = "let mut x = 0; while x < 5 { x += 1 } x"; let input = "let mut x = 0; while x < 5 { x += 1 } x";
assert_eq!(run(input), Ok(Some(Value::mutable_from(5)))); assert_eq!(run(input), Ok(Some(Value::integer(5))));
} }
#[test] #[test]
fn subtract_assign() { fn subtract_assign() {
let input = "let mut x = 1; x -= 1; x"; let input = "let mut x = 1; x -= 1; x";
assert_eq!(run(input), Ok(Some(Value::mutable_from(0)))); assert_eq!(run(input), Ok(Some(Value::integer(0))));
} }
#[test] #[test]
fn add_assign() { fn add_assign() {
let input = "let mut x = 1; x += 1; x"; let input = "let mut x = 1; x += 1; x";
assert_eq!(run(input), Ok(Some(Value::mutable_from(2)))); assert_eq!(run(input), Ok(Some(Value::integer(2))));
} }
#[test] #[test]
fn and() { fn and() {
let input = "true && true"; let input = "true && true";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn or() { fn or() {
let input = "true || false"; let input = "true || false";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn integer_equal() { fn integer_equal() {
let input = "42 == 42"; let input = "42 == 42";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn modulo() { fn modulo() {
let input = "42 % 2"; let input = "42 % 2";
assert_eq!(run(input), Ok(Some(Value::Integer(0)))); assert_eq!(run(input), Ok(Some(Value::integer(0))));
} }
#[test] #[test]
fn divide() { fn divide() {
let input = "42 / 2"; let input = "42 / 2";
assert_eq!(run(input), Ok(Some(Value::Integer(21)))); assert_eq!(run(input), Ok(Some(Value::integer(21))));
} }
#[test] #[test]
fn less_than() { fn less_than() {
let input = "2 < 3"; let input = "2 < 3";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn less_than_or_equal() { fn less_than_or_equal() {
let input = "42 <= 42"; let input = "42 <= 42";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn greater_than() { fn greater_than() {
let input = "2 > 3"; let input = "2 > 3";
assert_eq!(run(input), Ok(Some(Value::Boolean(false)))); assert_eq!(run(input), Ok(Some(Value::boolean(false))));
} }
#[test] #[test]
fn greater_than_or_equal() { fn greater_than_or_equal() {
let input = "42 >= 42"; let input = "42 >= 42";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn integer_saturating_add() { fn integer_saturating_add() {
let input = "9223372036854775807 + 1"; let input = "9223372036854775807 + 1";
assert_eq!(run(input), Ok(Some(Value::Integer(i64::MAX)))); assert_eq!(run(input), Ok(Some(Value::integer(i64::MAX))));
} }
#[test] #[test]
fn integer_saturating_sub() { fn integer_saturating_sub() {
let input = "-9223372036854775808 - 1"; let input = "-9223372036854775808 - 1";
assert_eq!(run(input), Ok(Some(Value::Integer(i64::MIN)))); assert_eq!(run(input), Ok(Some(Value::integer(i64::MIN))));
} }
#[test] #[test]
fn multiply() { fn multiply() {
let input = "2 * 3"; let input = "2 * 3";
assert_eq!(run(input), Ok(Some(Value::Integer(6)))); assert_eq!(run(input), Ok(Some(Value::integer(6))));
} }
#[test] #[test]
fn boolean() { fn boolean() {
let input = "true"; let input = "true";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn is_even() { fn is_even() {
let input = "42.is_even"; let input = "42.is_even";
assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); assert_eq!(run(input), Ok(Some(Value::boolean(true))));
} }
#[test] #[test]
fn is_odd() { fn is_odd() {
let input = "42.is_odd"; let input = "42.is_odd";
assert_eq!(run(input), Ok(Some(Value::Boolean(false)))); assert_eq!(run(input), Ok(Some(Value::boolean(false))));
} }
#[test] #[test]
fn list_length() { fn list_length() {
let input = "[1, 2, 3].length"; let input = "[1, 2, 3].length";
assert_eq!(run(input), Ok(Some(Value::Integer(3)))); assert_eq!(run(input), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn string_length() { fn string_length() {
let input = "\"hello\".length"; let input = "\"hello\".length";
assert_eq!(run(input), Ok(Some(Value::Integer(5)))); assert_eq!(run(input), Ok(Some(Value::integer(5))));
} }
#[test] #[test]
fn map_length() { fn map_length() {
let input = "map { a = 42, b = 4.0 }.length"; let input = "map { a = 42, b = 4.0 }.length";
assert_eq!(run(input), Ok(Some(Value::Integer(2)))); assert_eq!(run(input), Ok(Some(Value::integer(2))));
} }
#[test] #[test]
fn add() { fn add() {
let input = "1 + 2"; let input = "1 + 2";
assert_eq!(run(input), Ok(Some(Value::Integer(3)))); assert_eq!(run(input), Ok(Some(Value::integer(3))));
} }
#[test] #[test]
fn add_multiple() { fn add_multiple() {
let input = "1 + 2 + 3"; let input = "1 + 2 + 3";
assert_eq!(run(input), Ok(Some(Value::Integer(6)))); assert_eq!(run(input), Ok(Some(Value::integer(6))));
} }
} }