|
|
|
@ -18,9 +18,11 @@ use renderer::Truthiness;
|
|
|
|
|
use renderer::WalkError;
|
|
|
|
|
use renderer::Walkable;
|
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
use std::convert::TryInto;
|
|
|
|
|
use std::env;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::io::{self, Read};
|
|
|
|
|
use std::ops::Add;
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
|
|
mod parser;
|
|
|
|
@ -391,11 +393,9 @@ impl CompareContextElement for serde_json::Value {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn math_add<'a>(&self, other: &dyn ContextElement) -> Option<IceResult<'a>> {
|
|
|
|
|
match (
|
|
|
|
|
self,
|
|
|
|
|
other.to_any().downcast_ref::<Self>(),
|
|
|
|
|
other.to_any().downcast_ref::<OwnedLiteral>(),
|
|
|
|
|
) {
|
|
|
|
|
let other_json = other.to_any().downcast_ref::<Self>();
|
|
|
|
|
let other_literal = other.to_any().downcast_ref::<OwnedLiteral>();
|
|
|
|
|
match (self, other_json, other_literal) {
|
|
|
|
|
// If its neither of those types, then it is unimplemented
|
|
|
|
|
(_, None, None) => panic!("Math operation on unimplemented type"),
|
|
|
|
|
// Since this is specifically for the math helper, non-primitives are not supported
|
|
|
|
@ -408,45 +408,13 @@ impl CompareContextElement for serde_json::Value {
|
|
|
|
|
| (_, Some(serde_json::Value::String(_)), _)
|
|
|
|
|
| (_, _, Some(OwnedLiteral::LString(_))) => None,
|
|
|
|
|
// Handle other serde_json::Value
|
|
|
|
|
(
|
|
|
|
|
serde_json::Value::Number(self_num),
|
|
|
|
|
Some(serde_json::Value::Number(other_num)),
|
|
|
|
|
_,
|
|
|
|
|
) => {
|
|
|
|
|
match (
|
|
|
|
|
self_num.as_u64(),
|
|
|
|
|
other_num.as_u64(),
|
|
|
|
|
self_num.as_i64(),
|
|
|
|
|
other_num.as_i64(),
|
|
|
|
|
self_num.as_f64(),
|
|
|
|
|
other_num.as_f64(),
|
|
|
|
|
) {
|
|
|
|
|
// If both numbers are integers, we can pass them into math_ints
|
|
|
|
|
(Some(self_num), Some(other_num), _, _, _, _) => {
|
|
|
|
|
math_ints(self_num, other_num, std::ops::Add::add)
|
|
|
|
|
.map(IceResult::from_owned)
|
|
|
|
|
}
|
|
|
|
|
(_, _, Some(self_num), Some(other_num), _, _) => {
|
|
|
|
|
math_ints(self_num, other_num, std::ops::Add::add)
|
|
|
|
|
.map(IceResult::from_owned)
|
|
|
|
|
}
|
|
|
|
|
(Some(self_num), _, _, Some(other_num), _, _) => {
|
|
|
|
|
math_ints(self_num, other_num, std::ops::Add::add)
|
|
|
|
|
.map(IceResult::from_owned)
|
|
|
|
|
}
|
|
|
|
|
(_, Some(other_num), Some(self_num), _, _, _) => {
|
|
|
|
|
math_ints(self_num, other_num, std::ops::Add::add)
|
|
|
|
|
.map(IceResult::from_owned)
|
|
|
|
|
}
|
|
|
|
|
// Otherwise they'll be floats and we can just do the math directly
|
|
|
|
|
(_, _, _, _, Some(self_num), Some(other_num)) => Some(IceResult::from_owned(
|
|
|
|
|
OwnedLiteral::LFloat(self_num + other_num),
|
|
|
|
|
)),
|
|
|
|
|
_ => panic!("Unhandled operation, some integer must not have cast to a float."),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(_, Some(other_json_value), _) => (std::convert::Into::<MathNumber>::into(self)
|
|
|
|
|
+ std::convert::Into::<MathNumber>::into(other_json_value))
|
|
|
|
|
.map(IceResult::from_owned),
|
|
|
|
|
// Handle literals
|
|
|
|
|
_ => todo!(),
|
|
|
|
|
(_, _, Some(other_literal)) => (std::convert::Into::<MathNumber>::into(self)
|
|
|
|
|
+ std::convert::Into::<MathNumber>::into(other_literal))
|
|
|
|
|
.map(IceResult::from_owned),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -593,6 +561,91 @@ where
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
enum MathNumber {
|
|
|
|
|
Integer(i128),
|
|
|
|
|
Decimal(f64),
|
|
|
|
|
Failure,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<&serde_json::Value> for MathNumber {
|
|
|
|
|
fn from(original: &serde_json::Value) -> Self {
|
|
|
|
|
match original {
|
|
|
|
|
serde_json::Value::Null => MathNumber::Integer(0),
|
|
|
|
|
serde_json::Value::Bool(boolean) => {
|
|
|
|
|
if *boolean {
|
|
|
|
|
MathNumber::Integer(1)
|
|
|
|
|
} else {
|
|
|
|
|
MathNumber::Integer(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
serde_json::Value::Number(num) => num.into(),
|
|
|
|
|
serde_json::Value::String(text) => {
|
|
|
|
|
panic!("Strings should not be cast to numbers for math")
|
|
|
|
|
}
|
|
|
|
|
serde_json::Value::Array(_) => {
|
|
|
|
|
panic!("Only primitives should be cast to numbers for comparisons")
|
|
|
|
|
}
|
|
|
|
|
serde_json::Value::Object(_) => {
|
|
|
|
|
panic!("Only primitives should be cast to numbers for comparisons")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<&serde_json::Number> for MathNumber {
|
|
|
|
|
fn from(original: &serde_json::Number) -> Self {
|
|
|
|
|
match original.as_u64() {
|
|
|
|
|
Some(num) => return MathNumber::Integer(num.try_into().unwrap()),
|
|
|
|
|
None => (),
|
|
|
|
|
};
|
|
|
|
|
match original.as_i64() {
|
|
|
|
|
Some(num) => return MathNumber::Integer(num.into()),
|
|
|
|
|
None => (),
|
|
|
|
|
};
|
|
|
|
|
match original.as_f64() {
|
|
|
|
|
Some(num) => return MathNumber::Decimal(num),
|
|
|
|
|
None => (),
|
|
|
|
|
};
|
|
|
|
|
MathNumber::Failure
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<&OwnedLiteral> for MathNumber {
|
|
|
|
|
fn from(original: &OwnedLiteral) -> Self {
|
|
|
|
|
match original {
|
|
|
|
|
OwnedLiteral::LString(_) => panic!("Strings should not be cast to numbers for math"),
|
|
|
|
|
OwnedLiteral::LPositiveInteger(num) => {
|
|
|
|
|
return MathNumber::Integer((*num).try_into().unwrap())
|
|
|
|
|
}
|
|
|
|
|
OwnedLiteral::LNegativeInteger(num) => return MathNumber::Integer((*num).into()),
|
|
|
|
|
OwnedLiteral::LFloat(num) => return MathNumber::Decimal(*num),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Add<MathNumber> for MathNumber {
|
|
|
|
|
type Output = Option<OwnedLiteral>;
|
|
|
|
|
|
|
|
|
|
fn add(self, other: MathNumber) -> Self::Output {
|
|
|
|
|
match (self, other) {
|
|
|
|
|
(MathNumber::Failure, _) | (_, MathNumber::Failure) => None,
|
|
|
|
|
(MathNumber::Integer(self_num), MathNumber::Integer(other_num)) => {
|
|
|
|
|
math_ints(self_num, other_num, std::ops::Add::add)
|
|
|
|
|
}
|
|
|
|
|
(MathNumber::Decimal(self_num), MathNumber::Decimal(other_num)) => {
|
|
|
|
|
Some(OwnedLiteral::LFloat(self_num + other_num))
|
|
|
|
|
}
|
|
|
|
|
(MathNumber::Integer(self_num), MathNumber::Decimal(other_num)) => {
|
|
|
|
|
Some(OwnedLiteral::LFloat((self_num as f64) + other_num))
|
|
|
|
|
}
|
|
|
|
|
(MathNumber::Decimal(self_num), MathNumber::Integer(other_num)) => {
|
|
|
|
|
Some(OwnedLiteral::LFloat(self_num + (other_num as f64)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|