diff --git a/dust-lang/src/analyzer.rs b/dust-lang/src/analyzer.rs index 7ce0534..5d65474 100644 --- a/dust-lang/src/analyzer.rs +++ b/dust-lang/src/analyzer.rs @@ -10,7 +10,9 @@ use std::{ }; use crate::{ - ast::{AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement}, + ast::{ + AbstractSyntaxTree, LetStatement, Node, OperatorExpression, Statement, StructDefinition, + }, parse, Context, DustError, Expression, Identifier, Span, Type, }; @@ -89,8 +91,8 @@ impl<'a> Analyzer<'a> { identifier.position, ); } else { - return Err(AnalyzerError::UndefinedVariable { - identifier: identifier.clone(), + return Err(AnalyzerError::ExpectedValue { + actual: statement.clone(), }); } @@ -106,8 +108,8 @@ impl<'a> Analyzer<'a> { identifier.position, ); } else { - return Err(AnalyzerError::UndefinedVariable { - identifier: identifier.clone(), + return Err(AnalyzerError::ExpectedValue { + actual: statement.clone(), }); } @@ -124,7 +126,9 @@ impl<'a> Analyzer<'a> { value, } => todo!(), }, - Statement::StructDefinition(_) => {} + Statement::StructDefinition(_) => { + let StructDefinition { identifier, fields } = statement; + } } Ok(()) diff --git a/dust-lang/src/ast/expression.rs b/dust-lang/src/ast/expression.rs index 9c670d9..00380ae 100644 --- a/dust-lang/src/ast/expression.rs +++ b/dust-lang/src/ast/expression.rs @@ -332,12 +332,12 @@ impl Expression { } Some(Type::Struct(StructType::Fields { - identifier: name.inner.clone(), + name: name.inner.clone(), fields: field_types, })) } StructExpression::Unit { name } => Some(Type::Struct(StructType::Unit { - identifier: name.inner.clone(), + name: name.inner.clone(), })), }, Expression::TupleAccess(tuple_access_expression) => { diff --git a/dust-lang/src/built_in_function.rs b/dust-lang/src/built_in_function.rs index 718ba33..57a3ac4 100644 --- a/dust-lang/src/built_in_function.rs +++ b/dust-lang/src/built_in_function.rs @@ -78,7 +78,7 @@ impl BuiltInFunction { if let Some(value_arguments) = value_arguments { if value_arguments.len() == 1 { if let Some(integer) = value_arguments[0].as_integer() { - Ok(Some(Value::boolean(integer % 2 == 0))) + Ok(Some(Value::Boolean(integer % 2 == 0))) } else { Err(BuiltInFunctionError::ExpectedInteger) } @@ -93,7 +93,7 @@ impl BuiltInFunction { if let Some(value_arguments) = value_arguments { if value_arguments.len() == 1 { if let Some(integer) = value_arguments[0].as_integer() { - Ok(Some(Value::boolean(integer % 2 != 0))) + Ok(Some(Value::Boolean(integer % 2 != 0))) } else { Err(BuiltInFunctionError::ExpectedInteger) } @@ -107,8 +107,8 @@ impl BuiltInFunction { BuiltInFunction::Length => { if let Some(value_arguments) = value_arguments { if value_arguments.len() == 1 { - if let Some(list) = value_arguments[0].as_list() { - Ok(Some(Value::integer(list.len() as i64))) + if let Value::List(list) = &value_arguments[0] { + Ok(Some(Value::Integer(list.len() as i64))) } else { Err(BuiltInFunctionError::ExpectedInteger) } diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index 8f60d46..5f4f9f8 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -332,14 +332,14 @@ impl Display for FunctionType { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum StructType { Unit { - identifier: Identifier, + name: Identifier, }, Tuple { - identifier: Identifier, + name: Identifier, fields: Vec, }, Fields { - identifier: Identifier, + name: Identifier, fields: Vec<(Identifier, Type)>, }, } @@ -362,7 +362,9 @@ impl Display for StructType { write!(f, ")") } StructType::Fields { - identifier, fields, .. + name: identifier, + fields, + .. } => { write!(f, "{identifier} {{ ")?; diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index ddc2e1b..27d244e 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -1,17 +1,15 @@ //! Dust value representation use std::{ cmp::Ordering, - collections::BTreeMap, error::Error, fmt::{self, Display, Formatter}, ops::{Range, RangeInclusive}, - ptr, - sync::{Arc, RwLock, RwLockWriteGuard}, + sync::{Arc, RwLock}, }; use serde::{ - de::{self, MapAccess, SeqAccess, Visitor}, - ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple}, + de::{self, MapAccess, Visitor}, + ser::{SerializeStruct, SerializeStructVariant}, Deserialize, Deserializer, Serialize, Serializer, }; @@ -58,7 +56,7 @@ pub enum Value { Character(char), Enum { name: Identifier, r#type: EnumType }, Float(f64), - Function(Arc), + Function(Function), Integer(i64), List(Vec), Mutable(Arc>), @@ -70,22 +68,93 @@ pub enum Value { } impl Value { + pub fn mutable(value: Value) -> Value { + Value::Mutable(Arc::new(RwLock::new(value))) + } + pub fn byte_range(start: u8, end: u8) -> Value { Value::Range(Rangeable::Byte(start)..Rangeable::Byte(end)) } + pub fn byte_range_inclusive(start: u8, end: u8) -> Value { + Value::RangeInclusive(Rangeable::Byte(start)..=Rangeable::Byte(end)) + } + pub fn character_range(start: char, end: char) -> Value { Value::Range(Rangeable::Character(start)..Rangeable::Character(end)) } + pub fn character_range_inclusive(start: char, end: char) -> Value { + Value::RangeInclusive(Rangeable::Character(start)..=Rangeable::Character(end)) + } + pub fn float_range(start: f64, end: f64) -> Value { Value::Range(Rangeable::Float(start)..Rangeable::Float(end)) } + pub fn float_range_inclusive(start: f64, end: f64) -> Value { + Value::RangeInclusive(Rangeable::Float(start)..=Rangeable::Float(end)) + } + pub fn integer_range(start: i64, end: i64) -> Value { Value::Range(Rangeable::Integer(start)..Rangeable::Integer(end)) } + pub fn integer_range_inclusive(start: i64, end: i64) -> Value { + Value::RangeInclusive(Rangeable::Integer(start)..=Rangeable::Integer(end)) + } + + pub fn string(to_string: T) -> Value { + Value::String(to_string.to_string()) + } + + pub fn as_boolean(&self) -> Option { + match self { + Value::Boolean(value) => Some(*value), + Value::Mutable(locked) => locked.read().unwrap().as_boolean(), + _ => None, + } + } + + pub fn as_byte(&self) -> Option { + match self { + Value::Byte(value) => Some(*value), + Value::Mutable(locked) => locked.read().unwrap().as_byte(), + _ => None, + } + } + + pub fn as_character(&self) -> Option { + match self { + Value::Character(value) => Some(*value), + Value::Mutable(locked) => locked.read().unwrap().as_character(), + _ => None, + } + } + + pub fn as_float(&self) -> Option { + match self { + Value::Float(value) => Some(*value), + Value::Mutable(locked) => locked.read().unwrap().as_float(), + _ => None, + } + } + + pub fn as_integer(&self) -> Option { + match self { + Value::Integer(value) => Some(*value), + Value::Mutable(locked) => locked.read().unwrap().as_integer(), + _ => None, + } + } + + pub fn as_mutable(&self) -> Result<&Arc>, ValueError> { + match self { + Value::Mutable(inner) => Ok(inner), + _ => Err(ValueError::CannotMutate(self.clone())), + } + } + pub fn into_mutable(self) -> Value { match self { Value::Mutable(_) => self, @@ -97,13 +166,6 @@ impl Value { matches!(self, Value::Mutable(_)) } - pub fn as_mutable(&self) -> Result<&Arc>, ValueError> { - match self { - Value::Mutable(inner) => Ok(inner), - _ => Err(ValueError::CannotMutate(self.clone())), - } - } - pub fn mutate(&self, other: Value) -> Result<(), ValueError> { match self { Value::Mutable(inner) => *inner.write().unwrap() = other, @@ -135,9 +197,9 @@ impl Value { Value::RangeInclusive(_) => Type::Range, Value::String(_) => Type::String, Value::Struct(r#struct) => match r#struct { - Struct::Unit { r#type } => r#type.clone(), - Struct::Tuple { r#type, .. } => r#type.clone(), - Struct::Fields { r#type, .. } => r#type.clone(), + Struct::Unit { r#type } => Type::Struct(r#type.clone()), + Struct::Tuple { r#type, .. } => Type::Struct(r#type.clone()), + Struct::Fields { r#type, .. } => Type::Struct(r#type.clone()), }, Value::Tuple(values) => { let item_types = values.iter().map(Value::r#type).collect(); @@ -149,16 +211,24 @@ impl Value { pub fn get_field(&self, field: &Identifier) -> Option { match self { - Value::Struct(Struct::Fields { fields, .. }) => { - fields.iter().find_map(|(identifier, value)| { + Value::Mutable(inner) => inner.read().unwrap().get_field(field), + Value::Struct(Struct::Fields { + fields, + r#type: + StructType::Fields { + fields: field_types, + .. + }, + }) => field_types + .iter() + .zip(fields.iter()) + .find_map(|((identifier, _), value)| { if identifier == field { Some(value.clone()) } else { None } - }) - } - Value::Mutable(inner) => inner.clone().read().unwrap().get_field(field), + }), _ => None, } } @@ -174,7 +244,9 @@ impl Value { pub fn add(&self, other: &Value) -> Result { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)), - (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)), + (Value::Integer(left), Value::Integer(right)) => { + Ok(Value::Integer(left.saturating_add(*right))) + } (Value::String(left), Value::String(right)) => { Ok(Value::String(format!("{}{}", left, right))) } @@ -231,7 +303,9 @@ impl Value { pub fn subtract(&self, other: &Value) -> Result { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)), - (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)), + (Value::Integer(left), Value::Integer(right)) => { + Ok(Value::Integer(left.saturating_sub(*right))) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); @@ -277,7 +351,9 @@ impl Value { pub fn multiply(&self, other: &Value) -> Result { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Float(left * right)), - (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left * right)), + (Value::Integer(left), Value::Integer(right)) => { + Ok(Value::Integer(left.saturating_mul(*right))) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); @@ -324,7 +400,7 @@ impl Value { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Float(left / right)), (Value::Integer(left), Value::Integer(right)) => { - Ok(Value::Float((*left as f64) / (*right as f64))) + Ok(Value::Integer(left.saturating_div(*right))) } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); @@ -472,12 +548,28 @@ impl Value { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left < right)), (Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left < right)), + (Value::Float(left), Value::Integer(right)) => { + Ok(Value::Boolean(*left < *right as f64)) + } + (Value::Integer(left), Value::Float(right)) => { + Ok(Value::Boolean((*left as f64) < *right)) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); left.less_than(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.less_than(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.less_than(&right) + } _ => Err(ValueError::CannotLessThan(self.clone(), other.clone())), } } @@ -486,12 +578,28 @@ impl Value { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left <= right)), (Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left <= right)), + (Value::Float(left), Value::Integer(right)) => { + Ok(Value::Boolean(*left <= *right as f64)) + } + (Value::Integer(left), Value::Float(right)) => { + Ok(Value::Boolean(*left as f64 <= *right)) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); left.less_than_or_equal(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.less_than_or_equal(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.less_than_or_equal(&right) + } _ => Err(ValueError::CannotLessThanOrEqual( self.clone(), other.clone(), @@ -503,12 +611,28 @@ impl Value { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left > right)), (Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left > right)), + (Value::Float(left), Value::Integer(right)) => { + Ok(Value::Boolean(*left > *right as f64)) + } + (Value::Integer(left), Value::Float(right)) => { + Ok(Value::Boolean(*left as f64 > *right)) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); left.greater_than(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.greater_than(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.greater_than(&right) + } _ => Err(ValueError::CannotGreaterThan(self.clone(), other.clone())), } } @@ -517,12 +641,28 @@ impl Value { match (self, other) { (Value::Float(left), Value::Float(right)) => Ok(Value::Boolean(left >= right)), (Value::Integer(left), Value::Integer(right)) => Ok(Value::Boolean(left >= right)), + (Value::Float(left), Value::Integer(right)) => { + Ok(Value::Boolean(*left >= *right as f64)) + } + (Value::Integer(left), Value::Float(right)) => { + Ok(Value::Boolean(*left as f64 >= *right)) + } (Value::Mutable(left), Value::Mutable(right)) => { let left = left.read().unwrap(); let right = right.read().unwrap(); left.greater_than_or_equal(&right) } + (Value::Mutable(left), right) => { + let left = left.read().unwrap(); + + left.greater_than_or_equal(right) + } + (left, Value::Mutable(right)) => { + let right = right.read().unwrap(); + + left.greater_than_or_equal(&right) + } _ => Err(ValueError::CannotGreaterThanOrEqual( self.clone(), other.clone(), @@ -531,15 +671,15 @@ impl Value { } pub fn and(&self, other: &Value) -> Result { - match (self, other) { - (Value::Boolean(left), Value::Boolean(right)) => Ok(Value::Boolean(*left && *right)), + match (self.as_boolean(), other.as_boolean()) { + (Some(left), Some(right)) => Ok(Value::Boolean(left && right)), _ => Err(ValueError::CannotAnd(self.clone(), other.clone())), } } pub fn or(&self, other: &Value) -> Result { - match (self, other) { - (Value::Boolean(left), Value::Boolean(right)) => Ok(Value::Boolean(*left || *right)), + match (self.as_boolean(), other.as_boolean()) { + (Some(left), Some(right)) => Ok(Value::Boolean(left || right)), _ => Err(ValueError::CannotOr(self.clone(), other.clone())), } } @@ -918,15 +1058,15 @@ impl<'de> Deserialize<'de> for Function { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Struct { Unit { - r#type: Type, + r#type: StructType, }, Tuple { - r#type: Type, + r#type: StructType, fields: Vec, }, Fields { - r#type: Type, - fields: Vec<(Identifier, Value)>, + r#type: StructType, + fields: Vec, }, } @@ -947,24 +1087,34 @@ impl Display for Struct { write!(f, ")") } - Struct::Fields { fields, .. } => { + Struct::Fields { + fields, + r#type: + StructType::Fields { + fields: field_types, + .. + }, + } => { write!(f, "{{ ")?; - for (index, (identifier, r#type)) in fields.iter().enumerate() { + for (index, ((identifier, _), value)) in + field_types.iter().zip(fields.iter()).enumerate() + { if index > 0 { write!(f, ", ")?; } - write!(f, "{}: {}", identifier, r#type)?; + write!(f, "{}: {}", identifier, value)?; } write!(f, " }}") } + _ => Ok(()), } } } -#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] enum Rangeable { Byte(u8), Character(char), @@ -985,6 +1135,12 @@ impl Display for Rangeable { impl Eq for Rangeable {} +impl PartialOrd for Rangeable { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Ord for Rangeable { fn cmp(&self, other: &Self) -> Ordering { match (self, other) { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 08e8121..8c479f6 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -16,10 +16,10 @@ use crate::{ AbstractSyntaxTree, BlockExpression, CallExpression, ComparisonOperator, ElseExpression, FieldAccessExpression, IfExpression, LetStatement, ListExpression, ListIndexExpression, LiteralExpression, LogicOperator, LoopExpression, MathOperator, Node, OperatorExpression, - RangeExpression, Statement, + RangeExpression, Statement, StructDefinition, }, parse, Analyzer, BuiltInFunctionError, Context, DustError, Expression, Identifier, ParseError, - Span, Value, ValueError, + Span, StructType, Type, Value, ValueError, }; /// Run the source code and return the result. @@ -30,7 +30,7 @@ use crate::{ /// # use dust_lang::value::Value; /// let result = run("40 + 2"); /// -/// assert_eq!(result, Ok(Some(Value::integer(42)))); +/// assert_eq!(result, Ok(Some(Value::Integer(42)))); /// ``` pub fn run(source: &str) -> Result, DustError> { let context = Context::new(); @@ -45,12 +45,12 @@ pub fn run(source: &str) -> Result, DustError> { /// # use dust_lang::{Context, Identifier, Value, run_with_context}; /// let context = Context::new(); /// -/// context.set_value(Identifier::new("foo"), Value::integer(40)); +/// context.set_value(Identifier::new("foo"), Value::Integer(40)); /// context.update_last_position(&Identifier::new("foo"), (100, 100)); /// /// let result = run_with_context("foo + 2", context); /// -/// assert_eq!(result, Ok(Some(Value::integer(42)))); +/// assert_eq!(result, Ok(Some(Value::Integer(42)))); /// ``` pub fn run_with_context(source: &str, context: Context) -> Result, DustError> { let abstract_syntax_tree = parse(source)?; @@ -119,7 +119,20 @@ impl Vm { Ok(None) } - Statement::StructDefinition(_) => todo!(), + Statement::StructDefinition(struct_definition) => { + let (name, struct_type) = match struct_definition.inner { + StructDefinition::Unit { name } => { + (name.inner.clone(), StructType::Unit { name: name.inner }) + } + StructDefinition::Tuple { name, items } => todo!(), + StructDefinition::Fields { name, fields } => todo!(), + }; + + self.context + .set_type(name, Type::Struct(struct_type), struct_definition.position); + + Ok(None) + } }; if collect_garbage { @@ -203,20 +216,65 @@ impl Vm { Expression::Operator(operator_expression) => { self.run_operator(*operator_expression.inner, collect_garbage) } - Expression::Range(range_expression) => match range_expression.inner.as_ref() { + Expression::Range(range_expression) => match *range_expression.inner { RangeExpression::Exclusive { start, end } => { let start_position = start.position(); let start = self - .run_expression(*start.inner, collect_garbage)? + .run_expression(start, collect_garbage)? .expect_value(start_position)?; let end_position = end.position(); let end = self - .run_expression(*end.inner, collect_garbage)? + .run_expression(end, collect_garbage)? .expect_value(end_position)?; - Ok(Evaluation::Return(Some(Value::range(start..end)))) + match (start, end) { + (Value::Byte(start), Value::Byte(end)) => { + Ok(Evaluation::Return(Some(Value::byte_range(start, end)))) + } + (Value::Character(start), Value::Character(end)) => { + Ok(Evaluation::Return(Some(Value::character_range(start, end)))) + } + (Value::Float(start), Value::Float(end)) => { + Ok(Evaluation::Return(Some(Value::float_range(start, end)))) + } + (Value::Integer(start), Value::Integer(end)) => { + Ok(Evaluation::Return(Some(Value::integer_range(start, end)))) + } + _ => Err(VmError::InvalidRange { + start_position, + end_position, + }), + } + } + RangeExpression::Inclusive { start, end } => { + let start_position = start.position(); + let start = self + .run_expression(start, collect_garbage)? + .expect_value(start_position)?; + let end_position = end.position(); + let end = self + .run_expression(end, collect_garbage)? + .expect_value(end_position)?; + + match (start, end) { + (Value::Byte(start), Value::Byte(end)) => Ok(Evaluation::Return(Some( + Value::byte_range_inclusive(start, end), + ))), + (Value::Character(start), Value::Character(end)) => Ok(Evaluation::Return( + Some(Value::character_range_inclusive(start, end)), + )), + (Value::Float(start), Value::Float(end)) => Ok(Evaluation::Return(Some( + Value::float_range_inclusive(start, end), + ))), + (Value::Integer(start), Value::Integer(end)) => Ok(Evaluation::Return( + Some(Value::integer_range_inclusive(start, end)), + )), + _ => Err(VmError::InvalidRange { + start_position, + end_position, + }), + } } - RangeExpression::Inclusive { start, end } => todo!(), }, Expression::Struct(_) => todo!(), Expression::TupleAccess(_) => todo!(), @@ -341,7 +399,7 @@ impl Vm { let integer = value .as_integer() .ok_or(VmError::ExpectedBoolean { position })?; - let negated = Value::integer(-integer); + let negated = Value::Integer(-integer); Ok(Evaluation::Return(Some(negated))) } @@ -353,7 +411,7 @@ impl Vm { let boolean = value .as_boolean() .ok_or(VmError::ExpectedBoolean { position })?; - let not = Value::boolean(!boolean); + let not = Value::Boolean(!boolean); Ok(Evaluation::Return(Some(not))) } @@ -442,11 +500,10 @@ impl Vm { fn run_literal(&self, literal: LiteralExpression) -> Result { let value = match literal { - LiteralExpression::Boolean(boolean) => Value::boolean(boolean), - LiteralExpression::Float(float) => Value::float(float), - LiteralExpression::Integer(integer) => Value::integer(integer), - LiteralExpression::String(string) => Value::string(string), - LiteralExpression::Value(value) => value, + LiteralExpression::Boolean(boolean) => Value::Boolean(boolean), + LiteralExpression::Float(float) => Value::Float(float), + LiteralExpression::Integer(integer) => Value::Integer(integer), + LiteralExpression::String(string) => Value::String(string), }; Ok(Evaluation::Return(Some(value))) @@ -499,7 +556,7 @@ impl Vm { }); }; - let function = if let Some(function) = invoker_value.as_function() { + let function = if let Value::Function(function) = invoker_value { function } else { return Err(VmError::ExpectedFunction { @@ -569,7 +626,7 @@ impl Vm { .run_expression(repeat_operand, collect_garbage)? .expect_value(position)?; - Ok(Evaluation::Return(Some(Value::list(vec![ + Ok(Evaluation::Return(Some(Value::List(vec![ value; length as usize ])))) @@ -586,7 +643,7 @@ impl Vm { values.push(value); } - Ok(Evaluation::Return(Some(Value::list(values)))) + Ok(Evaluation::Return(Some(Value::List(values)))) } } } @@ -769,6 +826,10 @@ pub enum VmError { ExpectedValue { position: Span, }, + InvalidRange { + start_position: Span, + end_position: Span, + }, UndefinedVariable { identifier: Identifier, position: Span, @@ -803,6 +864,11 @@ impl VmError { Self::ExpectedFunction { position, .. } => *position, Self::ExpectedList { position } => *position, Self::ExpectedValue { position } => *position, + Self::InvalidRange { + start_position, + end_position, + .. + } => (start_position.0, end_position.1), Self::UndefinedVariable { position, .. } => *position, Self::UndefinedProperty { property_position, .. @@ -891,6 +957,16 @@ impl Display for VmError { Self::ExpectedValue { position } => { write!(f, "Expected a value at position: {:?}", position) } + Self::InvalidRange { + start_position, + end_position, + } => { + write!( + f, + "Invalid range with start position: {:?} and end position: {:?}", + start_position, end_position + ) + } Self::UndefinedVariable { identifier, position, @@ -912,7 +988,7 @@ impl Display for VmError { #[cfg(test)] mod tests { - use crate::Struct; + use crate::{Struct, StructType, Type}; use super::*; @@ -920,7 +996,7 @@ mod tests { fn async_block() { let input = "let mut x = 1; async { x += 1; x -= 1; } x"; - assert!(run(input).unwrap().unwrap().as_integer().is_some()); + assert_eq!(run(input), Ok(Some(Value::Integer(1)))); } #[test] @@ -929,12 +1005,15 @@ mod tests { assert_eq!( run(input), - Ok(Some(Value::r#struct(Struct::Fields { - name: Identifier::new("Foo"), - fields: vec![ - (Identifier::new("bar"), Value::integer(42)), - (Identifier::new("baz"), Value::float(4.0)) - ] + Ok(Some(Value::Struct(Struct::Fields { + r#type: StructType::Fields { + name: Identifier::new("Foo"), + fields: vec![ + (Identifier::new("bar"), Type::Integer), + (Identifier::new("baz"), Type::Float) + ] + }, + fields: vec![Value::Integer(42), Value::Float(4.0)] }))) ); } @@ -949,9 +1028,12 @@ mod tests { assert_eq!( run(input), - Ok(Some(Value::r#struct(Struct::Tuple { - name: Identifier::new("Foo"), - fields: vec![Value::integer(42)] + Ok(Some(Value::Struct(Struct::Tuple { + r#type: StructType::Tuple { + name: Identifier::new("Foo"), + fields: vec![Type::Integer] + }, + fields: vec![Value::Integer(42)] }))) ) } @@ -962,9 +1044,11 @@ mod tests { assert_eq!( run(input), - Ok(Some(Value::r#struct(Struct::Tuple { - name: Identifier::new("Foo"), - fields: vec![Value::integer(42)] + Ok(Some(Value::Struct(Struct::Tuple { + r#type: StructType::Unit { + name: Identifier::new("Foo") + }, + fields: vec![Value::Integer(42)] }))) ); } @@ -979,8 +1063,10 @@ mod tests { assert_eq!( run(input), - Ok(Some(Value::r#struct(Struct::Unit { - name: Identifier::new("Foo") + Ok(Some(Value::Struct(Struct::Unit { + r#type: StructType::Unit { + name: Identifier::new("Foo") + } }))) ) } @@ -991,8 +1077,10 @@ mod tests { assert_eq!( run(input), - Ok(Some(Value::r#struct(Struct::Unit { - name: Identifier::new("Foo") + Ok(Some(Value::Struct(Struct::Unit { + r#type: StructType::Unit { + name: Identifier::new("Foo") + } }))) ); } @@ -1001,7 +1089,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] @@ -1010,9 +1098,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) ]))) ); } @@ -1021,35 +1109,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::integer_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 = "{ a = 42 }.a"; - assert_eq!(run(input), Ok(Some(Value::integer(42)))); + assert_eq!(run(input), Ok(Some(Value::Integer(42)))); } #[test] @@ -1063,7 +1151,7 @@ mod tests { fn to_string() { let input = "to_string(42)"; - assert_eq!(run(input), Ok(Some(Value::string("42".to_string())))); + assert_eq!(run(input), Ok(Some(Value::string("42")))); } #[test] @@ -1077,7 +1165,7 @@ mod tests { fn if_else() { let input = "if false { 1 } else { 2 }"; - assert_eq!(run(input), Ok(Some(Value::integer(2)))); + assert_eq!(run(input), Ok(Some(Value::Integer(2)))); } #[test] @@ -1091,155 +1179,153 @@ 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::integer(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::integer(0)))); + assert_eq!(run(input), Ok(Some(Value::mutable(Value::Integer(0))))); } #[test] fn add_assign() { - env_logger::builder().is_test(true).try_init().ok(); - let input = "let mut x = 1; x += 1; x"; - assert_eq!(run(input), Ok(Some(Value::integer(2)))); + assert_eq!(run(input), Ok(Some(Value::mutable(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 = "is_even(42)"; - assert_eq!(run(input), Ok(Some(Value::boolean(true)))); + assert_eq!(run(input), Ok(Some(Value::Boolean(true)))); } #[test] fn is_odd() { let input = "is_odd(42)"; - assert_eq!(run(input), Ok(Some(Value::boolean(false)))); + assert_eq!(run(input), Ok(Some(Value::Boolean(false)))); } #[test] fn length() { let input = "length([1, 2, 3])"; - assert_eq!(run(input), Ok(Some(Value::integer(3)))); + assert_eq!(run(input), Ok(Some(Value::Integer(3)))); } #[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)))); } }