Complete value overhaul
This commit is contained in:
parent
87bced9719
commit
23782c37a3
@ -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.
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
|
@ -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);
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
(RangeValue::ByteRange(_), _) => Ordering::Greater,
|
||||||
_ => unreachable!(),
|
(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)
|
||||||
}
|
}
|
||||||
|
@ -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))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user