Complete value overhaul
This commit is contained in:
parent
87bced9719
commit
23782c37a3
@ -17,8 +17,8 @@ use crate::{
|
||||
PrimitiveValueExpression, RangeExpression, Span, Statement, StructDefinition,
|
||||
StructExpression, TupleAccessExpression,
|
||||
},
|
||||
core_library, parse, Context, ContextError, DustError, Expression, Identifier, Rangeable,
|
||||
RangeableType, StructType, Type,
|
||||
core_library, parse, Context, ContextError, DustError, Expression, Identifier, RangeableType,
|
||||
StructType, Type,
|
||||
};
|
||||
|
||||
/// Analyzes the abstract syntax tree for errors.
|
||||
|
@ -31,7 +31,7 @@ pub struct UnitConstructor {
|
||||
|
||||
impl UnitConstructor {
|
||||
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 {
|
||||
pub fn construct(self, fields: Vec<Value>) -> Value {
|
||||
Value::Struct(Struct::Tuple {
|
||||
Value::r#struct(Struct::Tuple {
|
||||
name: self.name,
|
||||
fields,
|
||||
})
|
||||
@ -56,7 +56,7 @@ pub struct FieldsConstructor {
|
||||
|
||||
impl FieldsConstructor {
|
||||
pub fn construct(self, fields: HashMap<Identifier, Value>) -> Value {
|
||||
Value::Struct(Struct::Fields {
|
||||
Value::r#struct(Struct::Fields {
|
||||
name: self.name,
|
||||
fields,
|
||||
})
|
||||
|
@ -347,7 +347,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run_with_context(source, context.clone()),
|
||||
Ok(Some(Value::Integer(15)))
|
||||
Ok(Some(Value::integer(15)))
|
||||
);
|
||||
|
||||
assert_eq!(context.association_count().unwrap(), 0);
|
||||
|
@ -10,7 +10,7 @@ pub fn core_library<'a>() -> &'a Context {
|
||||
(
|
||||
Identifier::new("to_string"),
|
||||
(
|
||||
ContextData::VariableValue(Value::Function(Function::BuiltIn(
|
||||
ContextData::VariableValue(Value::function(Function::BuiltIn(
|
||||
BuiltInFunction::ToString,
|
||||
))),
|
||||
(0, 0),
|
||||
@ -19,7 +19,7 @@ pub fn core_library<'a>() -> &'a Context {
|
||||
(
|
||||
Identifier::new("read_line"),
|
||||
(
|
||||
ContextData::VariableValue(Value::Function(Function::BuiltIn(
|
||||
ContextData::VariableValue(Value::function(Function::BuiltIn(
|
||||
BuiltInFunction::ReadLine,
|
||||
))),
|
||||
(0, 0),
|
||||
@ -28,7 +28,7 @@ pub fn core_library<'a>() -> &'a Context {
|
||||
(
|
||||
Identifier::new("write_line"),
|
||||
(
|
||||
ContextData::VariableValue(Value::Function(Function::BuiltIn(
|
||||
ContextData::VariableValue(Value::function(Function::BuiltIn(
|
||||
BuiltInFunction::WriteLine,
|
||||
))),
|
||||
(0, 0),
|
||||
|
@ -5,12 +5,11 @@ use std::{
|
||||
error::Error,
|
||||
fmt::{self, Display, Formatter},
|
||||
ops::{Range, RangeInclusive},
|
||||
ptr::read,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use serde::{
|
||||
de::{self, EnumAccess, MapAccess, SeqAccess, Visitor},
|
||||
de::{self, MapAccess, SeqAccess, Visitor},
|
||||
ser::SerializeMap,
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
};
|
||||
@ -25,30 +24,29 @@ use crate::{
|
||||
/// Each type of value has a corresponding constructor, here are some simple examples:
|
||||
///
|
||||
/// ```
|
||||
/// # use dust_lang::ValueData;
|
||||
/// let boolean = ValueData::boolean(true);
|
||||
/// let float = ValueData::float(3.14);
|
||||
/// let integer = ValueData::integer(42);
|
||||
/// let string = ValueData::string("Hello, world!");
|
||||
/// # use dust_lang::Value;
|
||||
/// let boolean = Value::boolean(true);
|
||||
/// let float = Value::float(3.14);
|
||||
/// let integer = Value::integer(42);
|
||||
/// let string = Value::string("Hello, world!");
|
||||
/// ```
|
||||
///
|
||||
/// Values can be combined into more complex values:
|
||||
///
|
||||
/// ```
|
||||
/// # use dust_lang::ValueData;
|
||||
/// let list = ValueData::list(vec![
|
||||
/// ValueData::integer(1),
|
||||
/// ValueData::integer(2),
|
||||
/// ValueData::integer(3),
|
||||
/// # use dust_lang::Value;
|
||||
/// let list = Value::list(vec![
|
||||
/// Value::integer(1),
|
||||
/// Value::integer(2),
|
||||
/// Value::integer(3),
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// Values have a type, which can be retrieved using the `type` method:
|
||||
///
|
||||
/// ```
|
||||
/// # use std::collections::HashMap;
|
||||
/// # use dust_lang::*;
|
||||
/// let value = ValueData::integer(42);
|
||||
/// let value = Value::integer(42);
|
||||
///
|
||||
/// assert_eq!(value.r#type(), Type::Integer);
|
||||
/// ```
|
||||
@ -76,8 +74,8 @@ impl Value {
|
||||
Value::Raw(ValueData::Float(value))
|
||||
}
|
||||
|
||||
pub fn integer(value: i64) -> Self {
|
||||
Value::Raw(ValueData::Integer(value))
|
||||
pub fn integer<T: Into<i64>>(into_i64: T) -> Self {
|
||||
Value::Raw(ValueData::Integer(into_i64.into()))
|
||||
}
|
||||
|
||||
pub fn string<T: ToString>(to_string: T) -> Self {
|
||||
@ -88,8 +86,8 @@ impl Value {
|
||||
Value::Raw(ValueData::List(value))
|
||||
}
|
||||
|
||||
pub fn map(value: HashMap<Identifier, Value>) -> Self {
|
||||
Value::Raw(ValueData::Map(value))
|
||||
pub fn map<T: Into<HashMap<Identifier, Value>>>(into_map: T) -> Self {
|
||||
Value::Raw(ValueData::Map(into_map.into()))
|
||||
}
|
||||
|
||||
pub fn mutable(value: Value) -> Self {
|
||||
@ -104,12 +102,12 @@ impl Value {
|
||||
Value::Raw(ValueData::Function(value))
|
||||
}
|
||||
|
||||
pub fn range<T: Into<Rangeable>>(start: T, end: T) -> Self {
|
||||
Value::Raw(ValueData::Range(start.into()..end.into()))
|
||||
pub fn range<T: Into<RangeValue>>(range: T) -> Self {
|
||||
Value::Raw(ValueData::Range(range.into()))
|
||||
}
|
||||
|
||||
pub fn range_inclusive<T: Into<Rangeable>>(start: T, end: T) -> Self {
|
||||
Value::Raw(ValueData::RangeInclusive(start.into()..=end.into()))
|
||||
pub fn r#struct(value: Struct) -> Self {
|
||||
Value::Raw(ValueData::Struct(value))
|
||||
}
|
||||
|
||||
pub fn reference(value: Value) -> Self {
|
||||
@ -282,6 +280,40 @@ impl Value {
|
||||
value: self.clone(),
|
||||
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 {
|
||||
value: self.clone(),
|
||||
index: index_value.clone(),
|
||||
@ -354,7 +386,7 @@ impl Value {
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let new_data = left
|
||||
.add(&right)
|
||||
.add(right)
|
||||
.ok_or_else(|| ValueError::CannotAdd(self.clone(), other.clone()))?;
|
||||
|
||||
*left = new_data;
|
||||
@ -392,7 +424,7 @@ impl Value {
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let new_data = left
|
||||
.subtract(&right)
|
||||
.subtract(right)
|
||||
.ok_or_else(|| ValueError::CannotSubtract(self.clone(), other.clone()))?;
|
||||
|
||||
*left = new_data;
|
||||
@ -430,7 +462,7 @@ impl Value {
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let new_data = left
|
||||
.multiply(&right)
|
||||
.multiply(right)
|
||||
.ok_or_else(|| ValueError::CannotMultiply(self.clone(), other.clone()))?;
|
||||
|
||||
*left = new_data;
|
||||
@ -468,7 +500,7 @@ impl Value {
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let new_data = left
|
||||
.divide(&right)
|
||||
.divide(right)
|
||||
.ok_or_else(|| ValueError::CannotDivide(self.clone(), other.clone()))?;
|
||||
|
||||
*left = new_data;
|
||||
@ -506,7 +538,7 @@ impl Value {
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let new_data = left
|
||||
.modulo(&right)
|
||||
.modulo(right)
|
||||
.ok_or_else(|| ValueError::CannotModulo(self.clone(), other.clone()))?;
|
||||
|
||||
*left = new_data;
|
||||
@ -709,14 +741,18 @@ impl Eq for Value {}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Value::Raw(left), Value::Raw(right)) => left == right,
|
||||
(Value::Reference(left), Value::Reference(right)) => left == right,
|
||||
(Value::Mutable(left), Value::Mutable(right)) => {
|
||||
*left.read().unwrap() == *right.read().unwrap()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
let left = match self {
|
||||
Value::Raw(data) => data,
|
||||
Value::Reference(data) => data,
|
||||
Value::Mutable(data) => &data.read().unwrap(),
|
||||
};
|
||||
let right = match other {
|
||||
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),
|
||||
List(Vec<Value>),
|
||||
Map(HashMap<Identifier, Value>),
|
||||
Range(Range<Rangeable>),
|
||||
RangeInclusive(RangeInclusive<Rangeable>),
|
||||
Range(RangeValue),
|
||||
String(String),
|
||||
Struct(Struct),
|
||||
Tuple(Vec<Value>),
|
||||
@ -875,16 +910,7 @@ impl ValueData {
|
||||
|
||||
Type::Map { pairs }
|
||||
}
|
||||
ValueData::Range(range) => Type::Range {
|
||||
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::Range(range) => range.r#type(),
|
||||
ValueData::String(string) => Type::String {
|
||||
length: Some(string.len()),
|
||||
},
|
||||
@ -919,13 +945,13 @@ impl ValueData {
|
||||
}
|
||||
|
||||
pub fn is_rangeable(&self) -> bool {
|
||||
match self {
|
||||
matches!(
|
||||
self,
|
||||
ValueData::Integer(_)
|
||||
| ValueData::Float(_)
|
||||
| ValueData::Character(_)
|
||||
| ValueData::Byte(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
| ValueData::Byte(_)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add(&self, other: &ValueData) -> Option<ValueData> {
|
||||
@ -1174,14 +1200,8 @@ impl Display for ValueData {
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
ValueData::Range(Range { start, end }) => {
|
||||
write!(f, "{start}..{end}")
|
||||
}
|
||||
ValueData::RangeInclusive(inclusive) => {
|
||||
let start = inclusive.start();
|
||||
let end = inclusive.end();
|
||||
|
||||
write!(f, "{start}..={end}")
|
||||
ValueData::Range(range_value) => {
|
||||
write!(f, "{range_value}")
|
||||
}
|
||||
ValueData::String(string) => write!(f, "{string}"),
|
||||
ValueData::Struct(r#struct) => write!(f, "{struct}"),
|
||||
@ -1216,7 +1236,6 @@ impl PartialEq for ValueData {
|
||||
(ValueData::List(left), ValueData::List(right)) => left == right,
|
||||
(ValueData::Map(left), ValueData::Map(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::Struct(left), ValueData::Struct(right)) => left == right,
|
||||
(ValueData::Tuple(left), ValueData::Tuple(right)) => left == right,
|
||||
@ -1248,26 +1267,8 @@ impl Ord for ValueData {
|
||||
(ValueData::Integer(_), _) => Ordering::Greater,
|
||||
(ValueData::List(left), ValueData::List(right)) => left.cmp(right),
|
||||
(ValueData::List(_), _) => Ordering::Greater,
|
||||
(ValueData::Range(left), ValueData::Range(right)) => {
|
||||
let start_cmp = left.start.cmp(&right.start);
|
||||
|
||||
if start_cmp.is_eq() {
|
||||
left.end.cmp(&right.end)
|
||||
} else {
|
||||
start_cmp
|
||||
}
|
||||
}
|
||||
(ValueData::Range(left), ValueData::Range(right)) => left.cmp(right),
|
||||
(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(_), _) => Ordering::Greater,
|
||||
(ValueData::Struct(left), ValueData::Struct(right)) => left.cmp(right),
|
||||
@ -1302,7 +1303,6 @@ impl Serialize for ValueData {
|
||||
ser.end()
|
||||
}
|
||||
ValueData::Range(range) => range.serialize(serializer),
|
||||
ValueData::RangeInclusive(inclusive) => inclusive.serialize(serializer),
|
||||
ValueData::String(string) => serializer.serialize_str(string),
|
||||
ValueData::Struct(r#struct) => r#struct.serialize(serializer),
|
||||
ValueData::Tuple(tuple) => tuple.serialize(serializer),
|
||||
@ -1561,84 +1561,212 @@ impl Display for Struct {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Rangeable {
|
||||
Byte(u8),
|
||||
Character(char),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum RangeValue {
|
||||
ByteRange(Range<u8>),
|
||||
ByteRangeInclusive(RangeInclusive<u8>),
|
||||
CharacterRange(Range<char>),
|
||||
CharacterRangeInclusive(RangeInclusive<char>),
|
||||
FloatRange(Range<f64>),
|
||||
FloatRangeInclusive(RangeInclusive<f64>),
|
||||
IntegerRange(Range<i64>),
|
||||
IntegerRangeInclusive(RangeInclusive<i64>),
|
||||
}
|
||||
|
||||
impl From<u8> for Rangeable {
|
||||
fn from(value: u8) -> Self {
|
||||
Rangeable::Byte(value)
|
||||
impl RangeValue {
|
||||
pub fn r#type(&self) -> Type {
|
||||
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 {
|
||||
fn from(value: char) -> Self {
|
||||
Rangeable::Character(value)
|
||||
impl From<Range<u8>> for RangeValue {
|
||||
fn from(range: Range<u8>) -> Self {
|
||||
RangeValue::ByteRange(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for Rangeable {
|
||||
fn from(value: f64) -> Self {
|
||||
Rangeable::Float(value)
|
||||
impl From<RangeInclusive<u8>> for RangeValue {
|
||||
fn from(range: RangeInclusive<u8>) -> Self {
|
||||
RangeValue::ByteRangeInclusive(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Rangeable {
|
||||
fn from(value: i32) -> Self {
|
||||
Rangeable::Integer(value as i64)
|
||||
impl From<Range<char>> for RangeValue {
|
||||
fn from(range: Range<char>) -> Self {
|
||||
RangeValue::CharacterRange(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for Rangeable {
|
||||
fn from(value: i64) -> Self {
|
||||
Rangeable::Integer(value)
|
||||
impl From<RangeInclusive<char>> for RangeValue {
|
||||
fn from(range: RangeInclusive<char>) -> Self {
|
||||
RangeValue::CharacterRangeInclusive(range)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rangeable {
|
||||
fn r#type(&self) -> RangeableType {
|
||||
match self {
|
||||
Rangeable::Byte(_) => RangeableType::Byte,
|
||||
Rangeable::Character(_) => RangeableType::Character,
|
||||
Rangeable::Float(_) => RangeableType::Float,
|
||||
Rangeable::Integer(_) => RangeableType::Integer,
|
||||
}
|
||||
impl From<Range<f64>> for RangeValue {
|
||||
fn from(range: Range<f64>) -> Self {
|
||||
RangeValue::FloatRange(range)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
match self {
|
||||
Rangeable::Byte(byte) => write!(f, "{byte}"),
|
||||
Rangeable::Character(character) => write!(f, "{character}"),
|
||||
Rangeable::Float(float) => write!(f, "{float}"),
|
||||
Rangeable::Integer(integer) => write!(f, "{integer}"),
|
||||
RangeValue::ByteRange(range) => write!(f, "{}..{}", range.start, range.end),
|
||||
RangeValue::ByteRangeInclusive(range) => {
|
||||
write!(f, "{}..={}", range.start(), range.end())
|
||||
}
|
||||
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> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Rangeable {
|
||||
impl Ord for RangeValue {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(Rangeable::Byte(left), Rangeable::Byte(right)) => left.cmp(right),
|
||||
(Rangeable::Character(left), Rangeable::Character(right)) => left.cmp(right),
|
||||
(Rangeable::Float(left), Rangeable::Float(right)) => {
|
||||
left.to_bits().cmp(&right.to_bits())
|
||||
(RangeValue::ByteRange(left), RangeValue::ByteRange(right)) => {
|
||||
let start_cmp = left.start.cmp(&right.start);
|
||||
|
||||
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"
|
||||
),
|
||||
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) => {
|
||||
write!(f, "Cannot subtract {} and {}", left, right)
|
||||
}
|
||||
|
@ -386,16 +386,16 @@ impl Vm {
|
||||
|
||||
match (start_data, end_data) {
|
||||
(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)) => {
|
||||
Ok(Evaluation::Return(Some(Value::range(start, end))))
|
||||
Ok(Evaluation::Return(Some(Value::range(start..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)) => {
|
||||
Ok(Evaluation::Return(Some(Value::range(start, end))))
|
||||
Ok(Evaluation::Return(Some(Value::range(start..end))))
|
||||
}
|
||||
_ => Err(RuntimeError::InvalidRange {
|
||||
start_position,
|
||||
@ -426,16 +426,16 @@ impl Vm {
|
||||
|
||||
match (start_data, end_data) {
|
||||
(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)) => {
|
||||
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end))))
|
||||
Ok(Evaluation::Return(Some(Value::range(start..=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)) => {
|
||||
Ok(Evaluation::Return(Some(Value::range_inclusive(start, end))))
|
||||
Ok(Evaluation::Return(Some(Value::range(start..=end))))
|
||||
}
|
||||
_ => Err(RuntimeError::InvalidRange {
|
||||
start_position,
|
||||
@ -1404,14 +1404,14 @@ mod tests {
|
||||
fn break_loop() {
|
||||
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]
|
||||
fn string_index() {
|
||||
let input = "'foo'[0]";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Character('f'))));
|
||||
assert_eq!(run(input), Ok(Some(Value::character('f'))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1421,8 +1421,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::map([
|
||||
(Identifier::new("foo"), Value::Integer(42)),
|
||||
(Identifier::new("bar"), Value::Float(4.2))
|
||||
(Identifier::new("foo"), Value::integer(42)),
|
||||
(Identifier::new("bar"), Value::float(4.2))
|
||||
])))
|
||||
);
|
||||
}
|
||||
@ -1431,7 +1431,7 @@ mod tests {
|
||||
fn async_block() {
|
||||
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]
|
||||
@ -1440,11 +1440,11 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::Struct(Struct::Fields {
|
||||
Ok(Some(Value::r#struct(Struct::Fields {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: HashMap::from([
|
||||
(Identifier::new("bar"), Value::Integer(42)),
|
||||
(Identifier::new("baz"), Value::Float(4.0))
|
||||
(Identifier::new("bar"), Value::integer(42)),
|
||||
(Identifier::new("baz"), Value::float(4.0))
|
||||
])
|
||||
})))
|
||||
);
|
||||
@ -1460,9 +1460,9 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::Struct(Struct::Tuple {
|
||||
Ok(Some(Value::r#struct(Struct::Tuple {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: vec![Value::Integer(42)]
|
||||
fields: vec![Value::integer(42)]
|
||||
})))
|
||||
)
|
||||
}
|
||||
@ -1473,9 +1473,9 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::Struct(Struct::Tuple {
|
||||
Ok(Some(Value::r#struct(Struct::Tuple {
|
||||
name: Identifier::new("Foo"),
|
||||
fields: vec![Value::Integer(42)]
|
||||
fields: vec![Value::integer(42)]
|
||||
})))
|
||||
);
|
||||
}
|
||||
@ -1490,7 +1490,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::Struct(Struct::Unit {
|
||||
Ok(Some(Value::r#struct(Struct::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
})))
|
||||
)
|
||||
@ -1502,7 +1502,7 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::Struct(Struct::Unit {
|
||||
Ok(Some(Value::r#struct(Struct::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
})))
|
||||
);
|
||||
@ -1512,7 +1512,7 @@ mod tests {
|
||||
fn list_index_nested() {
|
||||
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]
|
||||
@ -1521,9 +1521,9 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::List(vec![
|
||||
Value::Integer(2),
|
||||
Value::Integer(3)
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(2),
|
||||
Value::integer(3)
|
||||
])))
|
||||
);
|
||||
}
|
||||
@ -1532,35 +1532,35 @@ mod tests {
|
||||
fn range() {
|
||||
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]
|
||||
fn negate_expression() {
|
||||
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]
|
||||
fn not_expression() {
|
||||
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]
|
||||
fn list_index() {
|
||||
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]
|
||||
fn map_property_access() {
|
||||
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]
|
||||
@ -1588,7 +1588,7 @@ mod tests {
|
||||
fn if_else() {
|
||||
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]
|
||||
@ -1602,167 +1602,167 @@ mod tests {
|
||||
fn if_else_if_else() {
|
||||
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]
|
||||
fn while_loop() {
|
||||
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]
|
||||
fn subtract_assign() {
|
||||
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]
|
||||
fn add_assign() {
|
||||
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]
|
||||
fn and() {
|
||||
let input = "true && true";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or() {
|
||||
let input = "true || false";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_equal() {
|
||||
let input = "42 == 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulo() {
|
||||
let input = "42 % 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(0))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide() {
|
||||
let input = "42 / 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(21))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(21))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than() {
|
||||
let input = "2 < 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than_or_equal() {
|
||||
let input = "42 <= 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than() {
|
||||
let input = "2 > 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(false))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_or_equal() {
|
||||
let input = "42 >= 42";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_saturating_add() {
|
||||
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]
|
||||
fn integer_saturating_sub() {
|
||||
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]
|
||||
fn multiply() {
|
||||
let input = "2 * 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(6))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boolean() {
|
||||
let input = "true";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Boolean(true))));
|
||||
assert_eq!(run(input), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn 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]
|
||||
fn 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]
|
||||
fn list_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]
|
||||
fn string_length() {
|
||||
let input = "\"hello\".length";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(5))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(5))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn map_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]
|
||||
fn add() {
|
||||
let input = "1 + 2";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(3))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_multiple() {
|
||||
let input = "1 + 2 + 3";
|
||||
|
||||
assert_eq!(run(input), Ok(Some(Value::Integer(6))));
|
||||
assert_eq!(run(input), Ok(Some(Value::integer(6))));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user