Add implementation based on MathNumber.
This commit is contained in:
parent
df0ae05648
commit
d9ce011113
139
src/bin.rs
139
src/bin.rs
@ -18,9 +18,11 @@ use renderer::Truthiness;
|
|||||||
use renderer::WalkError;
|
use renderer::WalkError;
|
||||||
use renderer::Walkable;
|
use renderer::Walkable;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
|
use std::ops::Add;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
@ -391,11 +393,9 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn math_add<'a>(&self, other: &dyn ContextElement) -> Option<IceResult<'a>> {
|
fn math_add<'a>(&self, other: &dyn ContextElement) -> Option<IceResult<'a>> {
|
||||||
match (
|
let other_json = other.to_any().downcast_ref::<Self>();
|
||||||
self,
|
let other_literal = other.to_any().downcast_ref::<OwnedLiteral>();
|
||||||
other.to_any().downcast_ref::<Self>(),
|
match (self, other_json, other_literal) {
|
||||||
other.to_any().downcast_ref::<OwnedLiteral>(),
|
|
||||||
) {
|
|
||||||
// If its neither of those types, then it is unimplemented
|
// If its neither of those types, then it is unimplemented
|
||||||
(_, None, None) => panic!("Math operation on unimplemented type"),
|
(_, None, None) => panic!("Math operation on unimplemented type"),
|
||||||
// Since this is specifically for the math helper, non-primitives are not supported
|
// 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(serde_json::Value::String(_)), _)
|
||||||
| (_, _, Some(OwnedLiteral::LString(_))) => None,
|
| (_, _, Some(OwnedLiteral::LString(_))) => None,
|
||||||
// Handle other serde_json::Value
|
// Handle other serde_json::Value
|
||||||
(
|
(_, Some(other_json_value), _) => (std::convert::Into::<MathNumber>::into(self)
|
||||||
serde_json::Value::Number(self_num),
|
+ std::convert::Into::<MathNumber>::into(other_json_value))
|
||||||
Some(serde_json::Value::Number(other_num)),
|
.map(IceResult::from_owned),
|
||||||
_,
|
|
||||||
) => {
|
|
||||||
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."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Handle literals
|
// 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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user