Begin new math implementation for Value; Clean up
This commit is contained in:
parent
d27c98e393
commit
c82f631524
@ -1,3 +1,5 @@
|
|||||||
|
use std::ops::AddAssign;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -129,13 +131,12 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
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 {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(&self.identifier)? {
|
if let Some(left) = context.get_value(&self.identifier)? {
|
||||||
previous_value += value;
|
left.add_assign(right)?
|
||||||
previous_value
|
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||||
self.identifier.clone(),
|
self.identifier.clone(),
|
||||||
@ -143,16 +144,15 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some(mut previous_value) = context.get_value(&self.identifier)? {
|
if let Some(mut left) = context.get_value(&self.identifier)? {
|
||||||
previous_value -= value;
|
left.sub_assign(right)?
|
||||||
previous_value
|
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::VariableIdentifierNotFound(
|
return Err(RuntimeError::VariableIdentifierNotFound(
|
||||||
self.identifier.clone(),
|
self.identifier.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => right,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set_value(self.identifier.clone(), new_value)?;
|
context.set_value(self.identifier.clone(), new_value)?;
|
||||||
|
@ -108,12 +108,12 @@ impl AbstractTree for For {
|
|||||||
|
|
||||||
if let Value::List(list) = &expression_run {
|
if let Value::List(list) = &expression_run {
|
||||||
if self.is_async {
|
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.context.set_value(key.clone(), value.clone())?;
|
||||||
self.block.run(source, &self.context).map(|_value| ())
|
self.block.run(source, &self.context).map(|_value| ())
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
for value in list.items().iter() {
|
for value in list.items()?.iter() {
|
||||||
self.context.set_value(key.clone(), value.clone())?;
|
self.context.set_value(key.clone(), value.clone())?;
|
||||||
self.block.run(source, &self.context)?;
|
self.block.run(source, &self.context)?;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ impl AbstractTree for Index {
|
|||||||
match value {
|
match value {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let index = self.index.run(source, context)?.as_integer()? as usize;
|
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)
|
Ok(item)
|
||||||
}
|
}
|
||||||
|
@ -49,12 +49,12 @@ impl AbstractTree for Math {
|
|||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let value = match self.operator {
|
let value = match self.operator {
|
||||||
MathOperator::Add => left + right,
|
MathOperator::Add => left.add_assign(right)?,
|
||||||
MathOperator::Subtract => left - right,
|
MathOperator::Subtract => todo!(),
|
||||||
MathOperator::Multiply => left * right,
|
MathOperator::Multiply => todo!(),
|
||||||
MathOperator::Divide => left / right,
|
MathOperator::Divide => todo!(),
|
||||||
MathOperator::Modulo => left % right,
|
MathOperator::Modulo => todo!(),
|
||||||
}?;
|
};
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ impl Callable for BuiltInFunction {
|
|||||||
|
|
||||||
let value = arguments.first().unwrap();
|
let value = arguments.first().unwrap();
|
||||||
let length = if let Ok(list) = value.as_list() {
|
let length = if let Ok(list) = value.as_list() {
|
||||||
list.items().len()
|
list.items()?.len()
|
||||||
} else if let Ok(map) = value.as_map() {
|
} else if let Ok(map) = value.as_map() {
|
||||||
map.inner().len()
|
map.inner().len()
|
||||||
} else if let Ok(str) = value.as_string() {
|
} else if let Ok(str) = value.as_string() {
|
||||||
@ -163,7 +163,7 @@ impl Callable for BuiltInFunction {
|
|||||||
let value = arguments.first().unwrap();
|
let value = arguments.first().unwrap();
|
||||||
|
|
||||||
if let Ok(list) = value.as_list() {
|
if let Ok(list) = value.as_list() {
|
||||||
let items = list.items();
|
let items = list.items()?;
|
||||||
|
|
||||||
if items.len() == 0 {
|
if items.len() == 0 {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
|
@ -334,7 +334,7 @@ impl Callable for StrFunction {
|
|||||||
RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?;
|
RuntimeError::expect_argument_amount(self.name(), 3, arguments.len())?;
|
||||||
|
|
||||||
let mut string = arguments.first().unwrap().as_string()?.clone();
|
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 start = range[0].as_integer()? as usize;
|
||||||
let end = range[1].as_integer()? as usize;
|
let end = range[1].as_integer()? as usize;
|
||||||
let pattern = arguments.get(2).unwrap().as_string()?;
|
let pattern = arguments.get(2).unwrap().as_string()?;
|
||||||
|
@ -117,7 +117,7 @@ impl Context {
|
|||||||
Ok(())
|
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
|
/// In the case of the conflict, the inherited value will override the previous
|
||||||
/// value.
|
/// value.
|
||||||
@ -173,7 +173,7 @@ impl Context {
|
|||||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockError> {
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockError> {
|
||||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
||||||
match value_data {
|
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::TypeHint { inner, .. } => return Ok(Some(inner.clone())),
|
||||||
ValueData::TypeDefinition(_) => todo!(),
|
ValueData::TypeDefinition(_) => todo!(),
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ impl Context {
|
|||||||
|
|
||||||
for built_in_value in all_built_in_values() {
|
for built_in_value in all_built_in_values() {
|
||||||
if built_in_value.name() == identifier.inner().as_ref() {
|
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()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
impl From<csv::Error> for RuntimeError {
|
||||||
fn from(error: csv::Error) -> Self {
|
fn from(error: csv::Error) -> Self {
|
||||||
RuntimeError::Csv(error.to_string())
|
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 {
|
impl From<RwLockError> for RuntimeError {
|
||||||
fn from(error: RwLockError) -> Self {
|
fn from(error: RwLockError) -> Self {
|
||||||
RuntimeError::RwLock(error)
|
RuntimeError::RwLock(error)
|
||||||
@ -201,3 +201,9 @@ impl<T> From<PoisonError<T>> for RuntimeError {
|
|||||||
RuntimeError::RwLock(RwLockError)
|
RuntimeError::RwLock(RwLockError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for RuntimeError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{self:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,18 @@ pub enum ValidationError {
|
|||||||
/// The 'assert' macro did not resolve successfully.
|
/// The 'assert' macro did not resolve successfully.
|
||||||
AssertFailed { position: SourcePosition },
|
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.
|
/// The attempted conversion is impossible.
|
||||||
ConversionImpossible {
|
ConversionImpossible {
|
||||||
initial_type: Type,
|
initial_type: Type,
|
||||||
|
@ -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::{
|
use stanza::{
|
||||||
renderer::{console::Console, Renderer},
|
renderer::{console::Console, Renderer},
|
||||||
@ -6,10 +10,10 @@ use stanza::{
|
|||||||
table::{Cell, Content, Row, Table},
|
table::{Cell, Content, Row, Table},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Value;
|
use crate::{error::rw_lock_error::RwLockError, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct List(Vec<Value>);
|
pub struct List(Arc<RwLock<Vec<Value>>>);
|
||||||
|
|
||||||
impl Default for List {
|
impl Default for List {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -19,28 +23,29 @@ impl Default for List {
|
|||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
List(Vec::new())
|
List(Arc::new(RwLock::new(Vec::new())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
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 {
|
pub fn with_items(items: Vec<Value>) -> Self {
|
||||||
List(items)
|
List(Arc::new(RwLock::new(items)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items(&self) -> &Vec<Value> {
|
pub fn items(&self) -> Result<RwLockReadGuard<Vec<Value>>, RwLockError> {
|
||||||
&self.0
|
Ok(self.0.read()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items_mut(&mut self) -> &mut Vec<Value> {
|
pub fn items_mut(&self) -> Result<RwLockWriteGuard<Vec<Value>>, RwLockError> {
|
||||||
&mut self.0
|
Ok(self.0.write()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_text_table(&self) -> Table {
|
pub fn as_text_table(&self) -> Table {
|
||||||
let cells: Vec<Cell> = self
|
let cells: Vec<Cell> = self
|
||||||
.items()
|
.items()
|
||||||
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|value| {
|
.map(|value| {
|
||||||
if let Value::List(list) = value {
|
if let Value::List(list) = value {
|
||||||
@ -76,3 +81,43 @@ impl Display for List {
|
|||||||
f.write_str(&renderer.render(&self.as_text_table()))
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
//! Types that represent runtime values.
|
//! Types that represent runtime values.
|
||||||
use crate::{
|
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::{
|
use serde::{
|
||||||
@ -68,17 +70,17 @@ impl Value {
|
|||||||
Value::Range(start..=end)
|
Value::Range(start..=end)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#type(&self) -> Type {
|
pub fn r#type(&self) -> Result<Type, RwLockError> {
|
||||||
match self {
|
let r#type = match self {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let mut previous_type = None;
|
let mut previous_type = None;
|
||||||
|
|
||||||
for value in list.items().iter() {
|
for value in list.items()?.iter() {
|
||||||
let value_type = value.r#type();
|
let value_type = value.r#type();
|
||||||
|
|
||||||
if let Some(previous) = &previous_type {
|
if let Some(previous) = &previous_type {
|
||||||
if &value_type != previous {
|
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 {
|
if let Some(previous) = previous_type {
|
||||||
Type::List(Box::new(previous))
|
Type::List(Box::new(previous?))
|
||||||
} else {
|
} else {
|
||||||
Type::List(Box::new(Type::Any))
|
Type::List(Box::new(Type::Any))
|
||||||
}
|
}
|
||||||
@ -97,7 +99,7 @@ impl Value {
|
|||||||
for (key, value) in map.inner() {
|
for (key, value) in map.inner() {
|
||||||
identifier_types.push((
|
identifier_types.push((
|
||||||
Identifier::new(key.inner()),
|
Identifier::new(key.inner()),
|
||||||
TypeSpecification::new(value.r#type()),
|
TypeSpecification::new(value.r#type()?),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +113,9 @@ impl Value {
|
|||||||
Value::Range(_) => todo!(),
|
Value::Range(_) => todo!(),
|
||||||
Value::Struct(_) => todo!(),
|
Value::Struct(_) => todo!(),
|
||||||
Value::Enum(_) => todo!(),
|
Value::Enum(_) => todo!(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
Ok(r#type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_string(&self) -> bool {
|
pub fn is_string(&self) -> bool {
|
||||||
@ -150,7 +154,8 @@ impl Value {
|
|||||||
self == &Value::none()
|
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> {
|
pub fn as_string(&self) -> Result<&String, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::String(string) => Ok(string),
|
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> {
|
pub fn as_integer(&self) -> Result<i64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Integer(i) => Ok(*i),
|
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> {
|
pub fn as_float(&self) -> Result<f64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Float(f) => Ok(*f),
|
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`.
|
/// Copies the value stored in `self` as `f64`, or returns `Err` if `self`
|
||||||
/// Note that this method silently converts `i64` to `f64`, if `self` is a `Value::Int`.
|
/// 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> {
|
pub fn as_number(&self) -> Result<f64, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Float(f) => Ok(*f),
|
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> {
|
pub fn as_boolean(&self) -> Result<bool, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Boolean(boolean) => Ok(*boolean),
|
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> {
|
pub fn as_list(&self) -> Result<&List, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::List(list) => Ok(list),
|
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> {
|
pub fn into_inner_list(self) -> Result<List, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::List(list) => Ok(list),
|
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> {
|
pub fn as_map(&self) -> Result<&Map, RuntimeError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Map(map) => Ok(map),
|
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 {
|
impl Default for Value {
|
||||||
@ -360,7 +403,6 @@ impl AddAssign for Value {
|
|||||||
(Value::Float(left), Value::Float(right)) => *left += right,
|
(Value::Float(left), Value::Float(right)) => *left += right,
|
||||||
(Value::Float(left), Value::Integer(right)) => *left += right as f64,
|
(Value::Float(left), Value::Integer(right)) => *left += right as f64,
|
||||||
(Value::String(left), Value::String(right)) => *left += &right,
|
(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::Integer(left), Value::Integer(right)) => *left -= right,
|
||||||
(Value::Float(left), Value::Float(right)) => *left -= right,
|
(Value::Float(left), Value::Float(right)) => *left -= right,
|
||||||
(Value::Float(left), Value::Integer(right)) => *left -= right as f64,
|
(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::Integer(inner) => serializer.serialize_i64(*inner),
|
||||||
Value::Boolean(inner) => serializer.serialize_bool(*inner),
|
Value::Boolean(inner) => serializer.serialize_bool(*inner),
|
||||||
Value::List(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())?;
|
let mut list = serializer.serialize_tuple(items.len())?;
|
||||||
|
|
||||||
for value in items.iter() {
|
for value in items.iter() {
|
||||||
|
@ -21,7 +21,7 @@ impl Display for StructInstance {
|
|||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
|
|
||||||
for (key, value) in self.map.inner() {
|
for (key, value) in self.map.inner() {
|
||||||
writeln!(f, " {key} <{}> = {value}", value.r#type())?;
|
writeln!(f, " {key} <{}> = {value}", value.r#type().unwrap())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
|
@ -42,12 +42,12 @@ fn modify_list() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
result,
|
||||||
Ok(Value::List(List::with_items(vec![
|
Ok(Value::List(List::with_items(vec![
|
||||||
Value::Integer(1),
|
Value::Integer(1),
|
||||||
Value::Integer(2),
|
Value::Integer(2),
|
||||||
Value::Integer(3),
|
Value::Integer(3),
|
||||||
]))),
|
]))),
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ fn modify_map() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn do_not_modify_list_values() {
|
fn modify_list_values() {
|
||||||
let result = interpret(
|
let result = interpret(
|
||||||
"
|
"
|
||||||
list = [1 2 3]
|
list = [1 2 3]
|
||||||
@ -84,12 +84,12 @@ fn do_not_modify_list_values() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
result,
|
||||||
Ok(Value::List(List::with_items(vec![
|
Ok(Value::List(List::with_items(vec![
|
||||||
Value::Integer(1),
|
|
||||||
Value::Integer(2),
|
Value::Integer(2),
|
||||||
Value::Integer(3),
|
Value::Integer(3),
|
||||||
|
Value::Integer(4),
|
||||||
]))),
|
]))),
|
||||||
result
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user