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,
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.

View File

@ -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,
})

View File

@ -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);

View File

@ -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),

View File

@ -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::Float(_)
| ValueData::Character(_)
| 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)
}

View File

@ -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))));
}
}