diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index fe0b1fa..ac52999 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -1,3 +1,5 @@ +use std::ops::AddAssign; + use serde::{Deserialize, Serialize}; use crate::{ @@ -129,13 +131,12 @@ impl AbstractTree for Assignment { } fn run(&self, source: &str, context: &Context) -> Result { - let value = self.statement.run(source, context)?; + let right = self.statement.run(source, context)?; let new_value = match self.operator { AssignmentOperator::PlusEqual => { - if let Some(mut previous_value) = context.get_value(&self.identifier)? { - previous_value += value; - previous_value + if let Some(left) = context.get_value(&self.identifier)? { + left.add_assign(right)? } else { return Err(RuntimeError::VariableIdentifierNotFound( self.identifier.clone(), @@ -143,16 +144,15 @@ impl AbstractTree for Assignment { } } AssignmentOperator::MinusEqual => { - if let Some(mut previous_value) = context.get_value(&self.identifier)? { - previous_value -= value; - previous_value + if let Some(mut left) = context.get_value(&self.identifier)? { + left.sub_assign(right)? } else { return Err(RuntimeError::VariableIdentifierNotFound( self.identifier.clone(), )); } } - AssignmentOperator::Equal => value, + AssignmentOperator::Equal => right, }; context.set_value(self.identifier.clone(), new_value)?; diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index e2295c8..d82e6ae 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -108,12 +108,12 @@ impl AbstractTree for For { if let Value::List(list) = &expression_run { if self.is_async { - list.items().par_iter().try_for_each(|value| { + list.items()?.par_iter().try_for_each(|value| { self.context.set_value(key.clone(), value.clone())?; self.block.run(source, &self.context).map(|_value| ()) })?; } else { - for value in list.items().iter() { + for value in list.items()?.iter() { self.context.set_value(key.clone(), value.clone())?; self.block.run(source, &self.context)?; } diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index c0a4cea..ec9a9cc 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -55,7 +55,7 @@ impl AbstractTree for Index { match value { Value::List(list) => { let index = self.index.run(source, context)?.as_integer()? as usize; - let item = list.items().get(index).cloned().unwrap_or_default(); + let item = list.items()?.get(index).cloned().unwrap_or_default(); Ok(item) } diff --git a/src/abstract_tree/math.rs b/src/abstract_tree/math.rs index aa315f5..7069d6d 100644 --- a/src/abstract_tree/math.rs +++ b/src/abstract_tree/math.rs @@ -49,12 +49,12 @@ impl AbstractTree for Math { let left = self.left.run(source, context)?; let right = self.right.run(source, context)?; let value = match self.operator { - MathOperator::Add => left + right, - MathOperator::Subtract => left - right, - MathOperator::Multiply => left * right, - MathOperator::Divide => left / right, - MathOperator::Modulo => left % right, - }?; + MathOperator::Add => left.add_assign(right)?, + MathOperator::Subtract => todo!(), + MathOperator::Multiply => todo!(), + MathOperator::Divide => todo!(), + MathOperator::Modulo => todo!(), + }; Ok(value) } diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 833dbdc..8a603c6 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -125,7 +125,7 @@ impl Callable for BuiltInFunction { let value = arguments.first().unwrap(); let length = if let Ok(list) = value.as_list() { - list.items().len() + list.items()?.len() } else if let Ok(map) = value.as_map() { map.inner().len() } else if let Ok(str) = value.as_string() { @@ -163,7 +163,7 @@ impl Callable for BuiltInFunction { let value = arguments.first().unwrap(); if let Ok(list) = value.as_list() { - let items = list.items(); + let items = list.items()?; if items.len() == 0 { Ok(Value::none()) diff --git a/src/built_in_functions/str.rs b/src/built_in_functions/str.rs index 08d215a..54fce79 100644 --- a/src/built_in_functions/str.rs +++ b/src/built_in_functions/str.rs @@ -334,7 +334,7 @@ impl Callable for StrFunction { RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?; let mut string = arguments.first().unwrap().as_string()?.clone(); - let range = arguments.get(1).unwrap().as_list()?.items(); + let range = arguments.get(1).unwrap().as_list()?.items()?; let start = range[0].as_integer()? as usize; let end = range[1].as_integer()? as usize; let pattern = arguments.get(2).unwrap().as_string()?; diff --git a/src/context.rs b/src/context.rs index 9d25c24..f8f749c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -117,7 +117,7 @@ impl Context { Ok(()) } - /// Modify a context to take the functions and type definitions of another. + /// Modify a context to take all the information of another. /// /// In the case of the conflict, the inherited value will override the previous /// value. @@ -173,7 +173,7 @@ impl Context { pub fn get_type(&self, identifier: &Identifier) -> Result, RwLockError> { if let Some(value_data) = self.inner.read()?.get(identifier) { match value_data { - ValueData::Value { inner, .. } => return Ok(Some(inner.r#type())), + ValueData::Value { inner, .. } => return Ok(Some(inner.r#type()?)), ValueData::TypeHint { inner, .. } => return Ok(Some(inner.clone())), ValueData::TypeDefinition(_) => todo!(), } @@ -181,7 +181,7 @@ impl Context { for built_in_value in all_built_in_values() { if built_in_value.name() == identifier.inner().as_ref() { - return Ok(Some(built_in_value.get().r#type())); + return Ok(Some(built_in_value.get().r#type()?)); } } diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs index 8137af7..b60f493 100644 --- a/src/error/runtime_error.rs +++ b/src/error/runtime_error.rs @@ -136,6 +136,12 @@ impl RuntimeError { } } +impl From for RuntimeError { + fn from(error: ValidationError) -> Self { + RuntimeError::ValidationFailure(error) + } +} + impl From for RuntimeError { fn from(error: csv::Error) -> Self { RuntimeError::Csv(error.to_string()) @@ -184,12 +190,6 @@ impl From for RuntimeError { } } -impl Display for RuntimeError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{self:?}") - } -} - impl From for RuntimeError { fn from(error: RwLockError) -> Self { RuntimeError::RwLock(error) @@ -201,3 +201,9 @@ impl From> for RuntimeError { RuntimeError::RwLock(RwLockError) } } + +impl Display for RuntimeError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{self:?}") + } +} diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs index 25a9876..c4d32f5 100644 --- a/src/error/validation_error.rs +++ b/src/error/validation_error.rs @@ -18,6 +18,18 @@ pub enum ValidationError { /// The 'assert' macro did not resolve successfully. AssertFailed { position: SourcePosition }, + /// Two value are incompatible for addition. + CannotAdd { left: Value, right: Value }, + + /// Two value are incompatible for subtraction. + CannotSubtract { left: Value, right: Value }, + + /// Two value are incompatible for multiplication. + CannotMultiply { left: Value, right: Value }, + + /// Two value are incompatible for dividing. + CannotDivide { left: Value, right: Value }, + /// The attempted conversion is impossible. ConversionImpossible { initial_type: Type, diff --git a/src/value/list.rs b/src/value/list.rs index ee15f56..6213366 100644 --- a/src/value/list.rs +++ b/src/value/list.rs @@ -1,4 +1,8 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + cmp::Ordering, + fmt::{self, Display, Formatter}, + sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}, +}; use stanza::{ renderer::{console::Console, Renderer}, @@ -6,10 +10,10 @@ use stanza::{ table::{Cell, Content, Row, Table}, }; -use crate::Value; +use crate::{error::rw_lock_error::RwLockError, Value}; -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] -pub struct List(Vec); +#[derive(Debug, Clone)] +pub struct List(Arc>>); impl Default for List { fn default() -> Self { @@ -19,28 +23,29 @@ impl Default for List { impl List { pub fn new() -> Self { - List(Vec::new()) + List(Arc::new(RwLock::new(Vec::new()))) } pub fn with_capacity(capacity: usize) -> Self { - List(Vec::with_capacity(capacity)) + List(Arc::new(RwLock::new(Vec::with_capacity(capacity)))) } pub fn with_items(items: Vec) -> Self { - List(items) + List(Arc::new(RwLock::new(items))) } - pub fn items(&self) -> &Vec { - &self.0 + pub fn items(&self) -> Result>, RwLockError> { + Ok(self.0.read()?) } - pub fn items_mut(&mut self) -> &mut Vec { - &mut self.0 + pub fn items_mut(&self) -> Result>, RwLockError> { + Ok(self.0.write()?) } pub fn as_text_table(&self) -> Table { let cells: Vec = self .items() + .unwrap() .iter() .map(|value| { if let Value::List(list) = value { @@ -76,3 +81,43 @@ impl Display for List { f.write_str(&renderer.render(&self.as_text_table())) } } + +impl Eq for List {} + +impl PartialEq for List { + fn eq(&self, other: &Self) -> bool { + if let Ok(left) = self.items() { + if let Ok(right) = other.items() { + if left.len() != right.len() { + return false; + } else { + for (i, j) in left.iter().zip(right.iter()) { + if i != j { + return false; + } + } + } + } + } + + false + } +} + +impl PartialOrd for List { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for List { + fn cmp(&self, other: &Self) -> Ordering { + if let Ok(left) = self.items() { + if let Ok(right) = other.items() { + return left.cmp(&right); + } + } + + Ordering::Equal + } +} diff --git a/src/value/mod.rs b/src/value/mod.rs index 7249521..92f6bb4 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,6 +1,8 @@ //! Types that represent runtime values. use crate::{ - built_in_values::BuiltInValue, error::RuntimeError, Identifier, Type, TypeSpecification, + built_in_values::BuiltInValue, + error::{rw_lock_error::RwLockError, RuntimeError, ValidationError}, + Identifier, Type, TypeSpecification, }; use serde::{ @@ -68,17 +70,17 @@ impl Value { Value::Range(start..=end) } - pub fn r#type(&self) -> Type { - match self { + pub fn r#type(&self) -> Result { + let r#type = match self { Value::List(list) => { let mut previous_type = None; - for value in list.items().iter() { + for value in list.items()?.iter() { let value_type = value.r#type(); if let Some(previous) = &previous_type { if &value_type != previous { - return Type::List(Box::new(Type::Any)); + return Ok(Type::List(Box::new(Type::Any))); } } @@ -86,7 +88,7 @@ impl Value { } if let Some(previous) = previous_type { - Type::List(Box::new(previous)) + Type::List(Box::new(previous?)) } else { Type::List(Box::new(Type::Any)) } @@ -97,7 +99,7 @@ impl Value { for (key, value) in map.inner() { identifier_types.push(( Identifier::new(key.inner()), - TypeSpecification::new(value.r#type()), + TypeSpecification::new(value.r#type()?), )); } @@ -111,7 +113,9 @@ impl Value { Value::Range(_) => todo!(), Value::Struct(_) => todo!(), Value::Enum(_) => todo!(), - } + }; + + Ok(r#type) } pub fn is_string(&self) -> bool { @@ -150,7 +154,8 @@ impl Value { self == &Value::none() } - /// Borrows the value stored in `self` as `&String`, or returns `Err` if `self` is not a `Value::String`. + /// Borrows the value stored in `self` as `&String`, or returns `Err` if + /// `self` is not a `Value::String`. pub fn as_string(&self) -> Result<&String, RuntimeError> { match self { Value::String(string) => Ok(string), @@ -160,7 +165,8 @@ impl Value { } } - /// Copies the value stored in `self` as `i64`, or returns `Err` if `self` is not a `Value::Int` + /// Copies the value stored in `self` as `i64`, or returns `Err` if `self` + /// is not a `Value::Int` pub fn as_integer(&self) -> Result { match self { Value::Integer(i) => Ok(*i), @@ -170,7 +176,8 @@ impl Value { } } - /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float`. + /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` + /// is not a `Primitive::Float`. pub fn as_float(&self) -> Result { match self { Value::Float(f) => Ok(*f), @@ -180,8 +187,11 @@ impl Value { } } - /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` is not a `Primitive::Float` or `Value::Int`. - /// Note that this method silently converts `i64` to `f64`, if `self` is a `Value::Int`. + /// Copies the value stored in `self` as `f64`, or returns `Err` if `self` + /// is not a `Primitive::Float` or `Value::Int`. + /// + /// Note that this method silently converts `i64` to `f64`, if `self` is + /// a `Value::Int`. pub fn as_number(&self) -> Result { match self { Value::Float(f) => Ok(*f), @@ -192,7 +202,8 @@ impl Value { } } - /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` is not a `Primitive::Boolean`. + /// Copies the value stored in `self` as `bool`, or returns `Err` if `self` + /// is not a `Primitive::Boolean`. pub fn as_boolean(&self) -> Result { match self { Value::Boolean(boolean) => Ok(*boolean), @@ -202,7 +213,8 @@ impl Value { } } - /// Borrows the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::List`. + /// Borrows the value stored in `self` as `Vec`, or returns `Err` if + /// `self` is not a `Value::List`. pub fn as_list(&self) -> Result<&List, RuntimeError> { match self { Value::List(list) => Ok(list), @@ -212,7 +224,8 @@ impl Value { } } - /// Takes ownership of the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::List`. + /// Takes ownership of the value stored in `self` as `Vec`, or + /// returns `Err` if `self` is not a `Value::List`. pub fn into_inner_list(self) -> Result { match self { Value::List(list) => Ok(list), @@ -222,7 +235,8 @@ impl Value { } } - /// Borrows the value stored in `self` as `Vec`, or returns `Err` if `self` is not a `Value::Map`. + /// Borrows the value stored in `self` as `Vec`, or returns `Err` if + /// `self` is not a `Value::Map`. pub fn as_map(&self) -> Result<&Map, RuntimeError> { match self { Value::Map(map) => Ok(map), @@ -242,6 +256,35 @@ impl Value { }), } } + + pub fn add_assign(self, other: Self) -> Result { + match (self, other) { + (Value::Float(_), Value::Float(_)) => todo!(), + (Value::Float(_), Value::Integer(_)) => todo!(), + (Value::Integer(left), Value::Float(right)) => Ok(Value::Float((left as f64) + right)), + (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)), + (Value::List(list), value) | (value, Value::List(list)) => { + list.items_mut()?.push(value); + + Ok(Value::List(list)) + } + (Value::Map(_), _) | (_, Value::Map(_)) => todo!(), + (Value::String(_), Value::String(_)) => todo!(), + (left, right) => Err(ValidationError::CannotAdd { left, right }), + } + } + + pub fn sub_assign(self, other: Self) -> Result { + match (self, other) { + (Value::Float(_), Value::Float(_)) => todo!(), + (Value::Float(_), Value::Integer(_)) => todo!(), + (Value::Integer(left), Value::Float(right)) => Ok(Value::Float((left as f64) + right)), + (Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)), + (Value::Map(_), _) | (_, Value::Map(_)) => todo!(), + (Value::String(_), Value::String(_)) => todo!(), + (left, right) => Err(ValidationError::CannotSubtract { left, right }), + } + } } impl Default for Value { @@ -360,7 +403,6 @@ impl AddAssign for Value { (Value::Float(left), Value::Float(right)) => *left += right, (Value::Float(left), Value::Integer(right)) => *left += right as f64, (Value::String(left), Value::String(right)) => *left += &right, - (Value::List(list), value) => list.items_mut().push(value), _ => {} } } @@ -372,17 +414,6 @@ impl SubAssign for Value { (Value::Integer(left), Value::Integer(right)) => *left -= right, (Value::Float(left), Value::Float(right)) => *left -= right, (Value::Float(left), Value::Integer(right)) => *left -= right as f64, - (Value::List(list), value) => { - let index_to_remove = list - .items() - .iter() - .enumerate() - .find_map(|(i, list_value)| if list_value == &value { Some(i) } else { None }); - - if let Some(index) = index_to_remove { - list.items_mut().remove(index); - } - } _ => {} } } @@ -465,7 +496,12 @@ impl Serialize for Value { Value::Integer(inner) => serializer.serialize_i64(*inner), Value::Boolean(inner) => serializer.serialize_bool(*inner), Value::List(inner) => { - let items = inner.items(); + let items = if let Ok(items) = inner.items() { + items + } else { + return Err(serde::ser::Error::custom("failed to obtain a read lock")); + }; + let mut list = serializer.serialize_tuple(items.len())?; for value in items.iter() { diff --git a/src/value/struct_instance.rs b/src/value/struct_instance.rs index e7bc9dc..24239a0 100644 --- a/src/value/struct_instance.rs +++ b/src/value/struct_instance.rs @@ -21,7 +21,7 @@ impl Display for StructInstance { writeln!(f, "{{")?; for (key, value) in self.map.inner() { - writeln!(f, " {key} <{}> = {value}", value.r#type())?; + writeln!(f, " {key} <{}> = {value}", value.r#type().unwrap())?; } write!(f, "}}") diff --git a/tests/for_loop.rs b/tests/for_loop.rs index dbe200f..b712136 100644 --- a/tests/for_loop.rs +++ b/tests/for_loop.rs @@ -42,12 +42,12 @@ fn modify_list() { ); assert_eq!( + result, Ok(Value::List(List::with_items(vec![ Value::Integer(1), Value::Integer(2), Value::Integer(3), ]))), - result ); } @@ -74,7 +74,7 @@ fn modify_map() { } #[test] -fn do_not_modify_list_values() { +fn modify_list_values() { let result = interpret( " list = [1 2 3] @@ -84,12 +84,12 @@ fn do_not_modify_list_values() { ); assert_eq!( + result, Ok(Value::List(List::with_items(vec![ - Value::Integer(1), Value::Integer(2), Value::Integer(3), + Value::Integer(4), ]))), - result ); }