1
0

Begin new math implementation for Value; Clean up

This commit is contained in:
Jeff 2024-02-16 15:07:24 -05:00
parent d27c98e393
commit c82f631524
13 changed files with 174 additions and 75 deletions

View File

@ -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<Value, RuntimeError> {
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)?;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Option<Type>, 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()?));
}
}

View File

@ -136,6 +136,12 @@ impl RuntimeError {
}
}
impl From<ValidationError> for RuntimeError {
fn from(error: ValidationError) -> Self {
RuntimeError::ValidationFailure(error)
}
}
impl From<csv::Error> for RuntimeError {
fn from(error: csv::Error) -> Self {
RuntimeError::Csv(error.to_string())
@ -184,12 +190,6 @@ impl From<FromUtf8Error> for RuntimeError {
}
}
impl Display for RuntimeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl From<RwLockError> for RuntimeError {
fn from(error: RwLockError) -> Self {
RuntimeError::RwLock(error)
@ -201,3 +201,9 @@ impl<T> From<PoisonError<T>> for RuntimeError {
RuntimeError::RwLock(RwLockError)
}
}
impl Display for RuntimeError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}

View File

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

View File

@ -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<Value>);
#[derive(Debug, Clone)]
pub struct List(Arc<RwLock<Vec<Value>>>);
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<Value>) -> Self {
List(items)
List(Arc::new(RwLock::new(items)))
}
pub fn items(&self) -> &Vec<Value> {
&self.0
pub fn items(&self) -> Result<RwLockReadGuard<Vec<Value>>, RwLockError> {
Ok(self.0.read()?)
}
pub fn items_mut(&mut self) -> &mut Vec<Value> {
&mut self.0
pub fn items_mut(&self) -> Result<RwLockWriteGuard<Vec<Value>>, RwLockError> {
Ok(self.0.write()?)
}
pub fn as_text_table(&self) -> Table {
let cells: Vec<Cell> = 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<std::cmp::Ordering> {
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
}
}

View File

@ -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<Type, RwLockError> {
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<i64, RuntimeError> {
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<f64, RuntimeError> {
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<f64, RuntimeError> {
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<bool, RuntimeError> {
match self {
Value::Boolean(boolean) => Ok(*boolean),
@ -202,7 +213,8 @@ impl Value {
}
}
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::List`.
/// Borrows the value stored in `self` as `Vec<Value>`, 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<Value>`, or returns `Err` if `self` is not a `Value::List`.
/// Takes ownership of the value stored in `self` as `Vec<Value>`, or
/// returns `Err` if `self` is not a `Value::List`.
pub fn into_inner_list(self) -> Result<List, RuntimeError> {
match self {
Value::List(list) => Ok(list),
@ -222,7 +235,8 @@ impl Value {
}
}
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::Map`.
/// Borrows the value stored in `self` as `Vec<Value>`, 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<Value, ValidationError> {
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<Value, ValidationError> {
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() {

View File

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

View File

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