use std::{
collections::{BTreeMap, HashMap},
rc::Rc,
};
use crate::RuntimeErrorKind;
use super::Expression;
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign};
impl Add for Expression {
type Output = Result<Self, RuntimeErrorKind>;
fn add(self, other: Self) -> Result<Self, RuntimeErrorKind> {
match (self, other) {
(Self::Integer(m), Self::Integer(n)) => m
.checked_add(n)
.map(Self::Integer)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{m} + {n}"))),
(Self::Integer(m), Self::Float(n)) => Ok(Self::Float(m as f64 + n)),
(Self::Float(m), Self::Integer(n)) => Ok(Self::Float(m + n as f64)),
(Self::Float(m), Self::Float(n)) => Ok(Self::Float(m + n)),
(Self::Integer(m), Self::String(n)) => {
match n.parse::<i64>() {
Ok(n) => Ok(Self::Integer(m + n)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"+".into(),
format!("Cannot convert string `{n}` to integer"),
)), }
}
(Self::Float(m), Self::String(n)) => {
match n.parse::<f64>() {
Ok(n) => Ok(Self::Float(m + n)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"+".into(),
format!("Cannot convert string `{n}` to integer"),
)), }
}
(Self::Integer(m), Self::List(b)) => {
let sum: i64 = b
.as_ref()
.iter()
.filter_map(|x| {
if let Self::Integer(n) = x {
Some(*n)
} else {
None }
})
.sum();
Ok(Self::Integer(m + sum))
}
(Self::Float(m), Self::List(b)) => {
let sum: f64 = b
.as_ref()
.iter()
.filter_map(|x| {
if let Self::Float(n) = x {
Some(*n)
} else if let Self::Integer(n) = x {
Some(*n as f64)
} else {
None }
})
.sum();
Ok(Self::Float(m + sum))
}
(Self::String(m), Self::String(n)) => Ok(Self::String(m + &n)),
(Self::String(m), Self::Integer(n)) => Ok(Self::String(m + &n.to_string())),
(Self::String(m), Self::Float(n)) => Ok(Self::String(m + &n.to_string())),
(Self::String(m), Self::List(b)) => {
let concatenated: String = b
.as_ref()
.iter()
.filter_map(|x| {
if let Self::String(n) = x {
Some(n.clone())
} else {
None }
})
.collect();
Ok(Self::String(m + &concatenated))
}
(Self::Range(a, step), Self::Integer(b)) if b >= 0 => {
let end = a
.end
.checked_add(b)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{} + {b}", a.end)))?;
Ok(Expression::Range(a.start..end, step))
}
(Self::Range(a, step), Self::Integer(b)) => {
let start = a
.start
.checked_add(b)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{} + {b}", a.start)))?;
Ok(Expression::Range(start..a.end, step))
}
(Self::List(a), Self::List(b)) => {
let mut new_vec = Vec::with_capacity(a.len() + b.len());
new_vec.extend_from_slice(&a);
new_vec.extend_from_slice(&b);
Ok(Self::List(Rc::new(new_vec)))
}
(Self::List(a), other) => {
let mut new_vec = Vec::with_capacity(a.len() + 1);
new_vec.extend_from_slice(&a);
new_vec.push(other);
Ok(Self::List(Rc::new(new_vec)))
}
(Self::BSet(a), Self::BSet(b)) => {
let mut new_set = a.as_ref().clone();
new_set.extend(b.as_ref().iter().cloned());
Ok(Self::BSet(Rc::new(new_set)))
}
(Self::BSet(a), other) => {
let mut new_set = a.as_ref().clone();
new_set.insert(other);
Ok(Self::BSet(Rc::new(new_set)))
}
(Self::HMap(a), Self::HMap(b)) => {
let mut new_map = HashMap::new();
new_map.extend(a.iter().map(|(k, v)| (k.clone(), v.clone())));
new_map.extend(b.iter().map(|(k, v)| (k.clone(), v.clone())));
Ok(Self::HMap(Rc::new(new_map)))
}
(Self::HMap(a), other) => {
let mut new_map = HashMap::new();
new_map.extend(a.iter().map(|(k, v)| (k.clone(), v.clone())));
new_map.insert(other.to_string(), other);
Ok(Self::from(new_map))
}
(Self::Map(a), Self::Map(b)) => {
let mut new_map = BTreeMap::new();
new_map.extend(a.iter().map(|(k, v)| (k.clone(), v.clone())));
new_map.extend(b.iter().map(|(k, v)| (k.clone(), v.clone())));
Ok(Self::Map(Rc::new(new_map)))
}
(Self::Map(a), other) => {
let mut new_map = BTreeMap::new();
new_map.extend(a.iter().map(|(k, v)| (k.clone(), v.clone())));
new_map.insert(other.to_string(), other);
Ok(Self::Map(Rc::new(new_map)))
}
(Self::Bytes(mut a), Self::Bytes(b)) => {
a.extend(b);
Ok(Self::Bytes(a))
}
(Self::Bytes(mut a), Self::String(n)) => {
a.extend(n.into_bytes());
Ok(Self::Bytes(a))
}
(Self::Bytes(mut a), Self::Integer(n)) => {
a.push(n as u8);
Ok(Self::Bytes(a))
}
(Self::String(m), Self::Bytes(n)) => {
let result = format!("{}{}", m, String::from_utf8_lossy(n.as_ref()));
Ok(Self::String(result))
}
(m, n) => Err(RuntimeErrorKind::CommandFailed2(
"+".into(),
format!(
"Cannot add {}:{} and {}:{}",
m,
m.type_name(),
n,
n.type_name()
),
)),
}
}
}
impl Sub for Expression {
type Output = Result<Self, RuntimeErrorKind>;
fn sub(self, other: Self) -> Result<Self, RuntimeErrorKind> {
match (self, other) {
(Self::Integer(m), Self::Integer(n)) => m
.checked_sub(n)
.map(Self::Integer)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{m} - {n}"))),
(Self::Integer(m), Self::Float(n)) => Ok(Self::Float(m as f64 - n)),
(Self::Float(m), Self::Integer(n)) => Ok(Self::Float(m - n as f64)),
(Self::Float(m), Self::Float(n)) => Ok(Self::Float(m - n)),
(Self::Integer(m), Self::String(n)) => {
match n.parse::<i64>() {
Ok(n) => Ok(Self::Integer(m - n)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"-".into(),
format!("Cannot convert string `{n}` to integer"),
)), }
}
(Self::Float(m), Self::String(n)) => {
match n.parse::<f64>() {
Ok(n) => Ok(Self::Float(m - n)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"-".into(),
format!("Cannot convert string `{n}` to integer"),
)), }
}
(Self::String(m), Self::String(n)) => {
if let Some(pos) = m.find(&n) {
let new_string = m[..pos].to_string() + &m[pos + n.len()..];
Ok(Self::String(new_string))
} else {
Ok(Self::String(m))
}
}
(Self::String(m), Self::Integer(n)) => {
if n >= 0 {
if m.len() >= n as usize {
let l = m.len() - n as usize;
Ok(Self::String(m[..l].to_string()))
} else {
Ok(Self::String("".to_owned()))
}
} else {
let l = n
.checked_neg()
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("-{n}")))?
as usize;
if l <= m.len() {
Ok(Self::String(m[l..].to_string()))
} else {
Ok(Self::String("".to_owned()))
}
}
}
(Self::String(m), Self::Float(n)) => {
let n_str = n.to_string();
if let Some(pos) = m.find(&n_str) {
let new_string = m[..pos].to_string() + &m[pos + n_str.len()..];
Ok(Self::String(new_string))
} else {
Ok(Self::String(m))
}
}
(Self::Range(a, step), Self::Integer(b)) if b >= 0 => {
let end = a
.end
.checked_sub(b)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{} - {b}", a.end)))?;
Ok(Expression::Range(a.start..end, step))
}
(Self::Range(a, step), Self::Integer(b)) => {
let start = a
.start
.checked_add(b)
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("{} - {b}", a.start)))?;
Ok(Expression::Range(start..a.end, step))
}
(Self::List(a), Self::List(b)) => {
if Rc::ptr_eq(&a, &b) {
Ok(Self::List(Rc::new(Vec::new()))) } else {
let mut a_items = a.as_ref().to_vec(); let b_items = b.as_ref().to_vec(); a_items.retain(|x| !b_items.contains(x)); Ok(Self::List(Rc::new(a_items)))
}
}
(Self::List(a), value) => {
let pos = a.as_ref().iter().position(|x| *x == value);
if let Some(pos) = pos {
let mut a_items: Vec<_> = a.as_ref().to_vec();
a_items.remove(pos);
Ok(Self::List(Rc::new(a_items)))
} else {
Ok(Self::List(a))
}
}
(Self::BSet(a), Self::BSet(b)) => {
let mut new_set = a.as_ref().clone();
for item in b.as_ref().iter() {
new_set.remove(item);
}
Ok(Self::BSet(Rc::new(new_set)))
}
(Self::BSet(a), value) => {
let mut new_set = a.as_ref().clone();
new_set.remove(&value);
Ok(Self::BSet(Rc::new(new_set)))
}
(Self::HMap(a), Self::HMap(b)) => {
if Rc::ptr_eq(&a, &b) {
return Ok(Self::HMap(Rc::new(HashMap::new())));
}
let mut a_map = a.as_ref().clone(); for key in b.as_ref().keys() {
a_map.remove(key); }
Ok(Self::from(a_map))
}
(Self::HMap(a), Self::Symbol(key) | Self::String(key)) => {
let mut new_map = a.as_ref().clone();
new_map.remove(&key);
Ok(Self::from(new_map))
}
(Self::Map(a), Self::Map(b)) => {
if Rc::ptr_eq(&a, &b) {
return Ok(Self::Map(Rc::new(BTreeMap::new())));
}
let mut a_map = a.as_ref().clone(); for key in b.as_ref().keys() {
a_map.remove(key); }
Ok(Self::from(a_map))
}
(Self::Map(a), Self::Symbol(key) | Self::String(key)) => {
let mut new_map = a.as_ref().clone();
new_map.remove(&key);
Ok(Self::from(new_map))
}
(Self::DateTime(a), Self::DateTime(b)) => {
let d = a - b;
Ok(Self::from(d.num_milliseconds()))
}
(Self::Bytes(m), Self::Bytes(n)) => {
if let Some(pos) = subslice(&m, &n) {
let mut result = m[..pos].to_vec();
result.extend_from_slice(&m[pos + n.len()..]);
Ok(Self::Bytes(result))
} else {
Ok(Self::Bytes(m))
}
}
(Self::Bytes(m), Self::String(n)) => {
let n_bytes = n.into_bytes();
if let Some(pos) = subslice(&m, &n_bytes) {
let mut result = m[..pos].to_vec();
result.extend_from_slice(&m[pos + n_bytes.len()..]);
Ok(Self::Bytes(result))
} else {
Ok(Self::Bytes(m))
}
}
(Self::Bytes(m), Self::Integer(n)) => {
if n >= 0 {
let n = n as usize;
if m.len() >= n {
Ok(Self::Bytes(m[..m.len() - n].to_vec()))
} else {
Ok(Self::Bytes(Vec::new()))
}
} else {
let n = n
.checked_neg()
.ok_or_else(|| RuntimeErrorKind::Overflow(format!("-{n}")))?
as usize;
if n <= m.len() {
Ok(Self::Bytes(m[n..].to_vec()))
} else {
Ok(Self::Bytes(Vec::new()))
}
}
}
(n, m) => Err(RuntimeErrorKind::CommandFailed2(
"-".into(),
format!(
"Cannot subtract {}:{} from {}:{}",
m,
m.type_name(),
n,
n.type_name()
),
)),
}
}
}
fn subslice(haystack: &[u8], needle: &[u8]) -> Option<usize> {
if needle.is_empty() {
return Some(0);
}
haystack.windows(needle.len()).position(|w| w == needle)
}
impl Mul for Expression {
type Output = Result<Self, RuntimeErrorKind>;
fn mul(self, other: Self) -> Result<Self, RuntimeErrorKind> {
match (self, other) {
(Self::Integer(m), Self::Integer(n)) => match m.checked_mul(n) {
Some(result) => Ok(Self::Integer(result)),
None => Err(RuntimeErrorKind::Overflow(format!(
"Integer overflow when multiplying {m} and {n}"
))),
},
(Self::Integer(m), Self::Float(n)) => Ok(Self::Float(m as f64 * n)),
(Self::Float(m), Self::Integer(n)) => Ok(Self::Float(m * n as f64)),
(Self::Float(m), Self::Float(n)) => Ok(Self::Float(m * n)),
(Self::Integer(n), Self::String(m)) => {
match m.parse::<i64>() {
Ok(num) => Ok(Self::Integer(n * num)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!("Cannot convert string `{m}` to integer"),
)),
}
}
(Self::Float(n), Self::String(m)) => {
match m.parse::<f64>() {
Ok(num) => Ok(Self::Float(n * num)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!("Cannot convert string `{m}` to float"),
)),
}
}
(Self::String(m), Self::Integer(n)) => {
if n == 0 {
Ok(Self::String(String::new()))
} else if n < 0 {
Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!("Cannot multiply string by negative number {n}"),
))
} else {
Ok(Self::String(m.repeat(n as usize)))
}
}
(Self::List(a), Self::List(b)) => {
let a_rows = a.as_ref().len();
let a_cols = if a_rows > 0 {
match &a.as_ref()[0] {
Self::List(inner) => inner.as_ref().len(),
_ => 0,
}
} else {
0
};
let b_cols = if !b.as_ref().is_empty() {
match &b.as_ref()[0] {
Self::List(inner) => inner.as_ref().len(),
_ => 0,
}
} else {
0
};
if a_cols != b.as_ref().len() {
return Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!(
"Matrix dimensions do not match for multiplication: {}x{} and {}x{}",
a_rows,
a_cols,
b.as_ref().len(),
b_cols
),
));
}
let mut result = Vec::new();
for i in 0..a_rows {
let mut row_result = Vec::new();
for j in 0..b_cols {
let mut sum = 0.0; for k in 0..a_cols {
let a_value = match &a.as_ref()[i] {
Self::List(inner) => match inner.as_ref().get(k) {
Some(val) => match val {
Self::Integer(v) => *v as f64,
Self::Float(v) => *v,
_ => 0.0,
},
None => 0.0,
},
_ => 0.0,
};
let b_value = match &b.as_ref()[k] {
Self::List(inner) => match inner.as_ref().get(j) {
Some(val) => match val {
Self::Integer(v) => *v as f64,
Self::Float(v) => *v,
_ => 0.0,
},
None => 0.0,
},
_ => 0.0,
};
sum += a_value * b_value;
}
row_result.push(Self::Float(sum));
}
result.push(Self::from(row_result));
}
Ok(Self::from(result))
}
(Self::List(a), value) => {
let mut new_list = Vec::new();
let n = match value {
Self::Integer(n) => n as f64, Self::Float(n) => n,
_ => {
return Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!("Cannot multiply by non-numeric value {value:?}"),
));
}
};
for element in a.as_ref().iter() {
match element {
Self::Integer(val) => new_list.push(Self::Float(*val as f64 * n)),
Self::Float(val) => new_list.push(Self::Float(val * n)),
_ => {
return Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!("Cannot multiply non-numeric element {element:?}"),
));
}
}
}
Ok(Self::from(new_list))
}
(Self::BSet(a), Self::BSet(b)) => {
let new_set = a.as_ref().intersection(b.as_ref()).cloned().collect();
Ok(Self::BSet(Rc::new(new_set)))
}
(Self::Bytes(m), Self::Integer(n)) => {
let n = n as usize;
if n > 0 && n < usize::MAX {
Ok(Self::Bytes(m.repeat(n)))
} else {
Ok(Self::None)
}
}
(m, n) => Err(RuntimeErrorKind::CommandFailed2(
"*".into(),
format!(
"Cannot multiply {}:{} and {}:{}",
m,
m.type_name(),
n,
n.type_name()
),
)),
}
}
}
impl Div for Expression {
type Output = Result<Self, RuntimeErrorKind>;
fn div(self, other: Self) -> Result<Self, RuntimeErrorKind> {
match (self, other) {
(l, Self::Integer(0) | Self::Float(0.0)) => Err(RuntimeErrorKind::CustomError(
format!("can't divide {l} by zero").into(),
)),
(l, Self::String(s)) if s == "0" || s == "0.0" => Err(RuntimeErrorKind::CustomError(
format!("can't divide {l} by zero").into(),
)),
(Self::Integer(m), Self::Integer(n)) => Ok(Self::Integer(m / n)),
(Self::Integer(m), Self::Float(n)) => Ok(Self::Float(m as f64 / n)),
(Self::Float(m), Self::Integer(n)) => Ok(Self::Float(m / n as f64)),
(Self::Float(m), Self::Float(n)) => Ok(Self::Float(m / n)),
(Self::Integer(n), Self::String(m)) => {
match m.parse::<i64>() {
Ok(num) => Ok(Self::Integer(n / num)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"/".into(),
format!("Cannot convert string `{m}` to integer"),
)),
}
}
(Self::Float(n), Self::String(m)) => {
match m.parse::<f64>() {
Ok(num) => Ok(Self::Float(n / num)),
Err(_) => Err(RuntimeErrorKind::CommandFailed2(
"/".into(),
format!("Cannot convert string `{m}` to float"),
)),
}
}
(Self::List(a), value) => {
let divisor = match value {
Self::Integer(n) => n as f64,
Self::Float(n) => n,
_ => {
return Err(RuntimeErrorKind::CommandFailed2(
"/".into(),
format!("Cannot divide by non-numeric value {value:?}"),
));
}
};
let new_list: Result<Vec<Self>, RuntimeErrorKind> = a
.as_ref()
.iter()
.map(|element| match element {
Self::Integer(val) => Ok(Self::Float(*val as f64 / divisor)),
Self::Float(val) => Ok(Self::Float(val / divisor)),
_ => Err(RuntimeErrorKind::CommandFailed2(
"/".into(),
format!("Cannot divide non-numeric element {element:?}"),
)),
})
.collect();
new_list.map(Self::from) }
(m, n) => Err(RuntimeErrorKind::CommandFailed2(
"/".into(),
format!(
"Cannot divide {}:{} by {}:{}",
m,
m.type_name(),
n,
n.type_name()
),
)),
}
}
}
impl Neg for Expression {
type Output = Expression;
#[inline]
fn neg(self) -> Self::Output {
match self {
Self::Integer(n) => Self::Integer(-n),
Self::Float(n) => Self::Float(-n),
Self::Boolean(b) => Self::Boolean(!b),
_ => Self::None,
}
}
}
impl AddAssign for Expression {
fn add_assign(&mut self, other: Self) {
*self = match (&self, other) {
(Self::Integer(m), Self::Integer(n)) => Self::Integer(m.wrapping_add(n)),
(Self::Integer(m), Self::Float(n)) => Self::Float(*m as f64 + n),
(Self::Float(m), Self::Integer(n)) => Self::Float(*m + n as f64),
(Self::Float(m), Self::Float(n)) => Self::Float(*m + n),
_ => return,
}
}
}
impl SubAssign for Expression {
fn sub_assign(&mut self, other: Self) {
*self = match (&self, other) {
(Self::Integer(m), Self::Integer(n)) => Self::Integer(m.wrapping_sub(n)),
(Self::Integer(m), Self::Float(n)) => Self::Float(*m as f64 - n),
(Self::Float(m), Self::Integer(n)) => Self::Float(*m - n as f64),
(Self::Float(m), Self::Float(n)) => Self::Float(*m - n),
_ => return,
}
}
}
impl MulAssign for Expression {
fn mul_assign(&mut self, other: Self) {
*self = match (&self, other) {
(Self::Integer(m), Self::Integer(n)) => Self::Integer(m.wrapping_mul(n)),
(Self::Integer(m), Self::Float(n)) => Self::Float(*m as f64 * n),
(Self::Float(m), Self::Integer(n)) => Self::Float(*m * n as f64),
(Self::Float(m), Self::Float(n)) => Self::Float(*m * n),
_ => return,
}
}
}
impl DivAssign for Expression {
fn div_assign(&mut self, other: Self) {
*self = match (&self, other) {
(_, Self::Integer(0)) => Self::None,
(_, Self::Float(0.0)) => Self::None,
(Self::Integer(m), Self::Integer(n)) => Self::Integer(*m / n),
(Self::Integer(m), Self::Float(n)) => Self::Float(*m as f64 / n),
(Self::Float(m), Self::Integer(n)) => Self::Float(*m / n as f64),
(Self::Float(m), Self::Float(n)) => Self::Float(*m / n),
_ => return,
}
}
}
impl Rem for Expression {
type Output = Self;
fn rem(self, other: Self) -> Self {
match (self, other) {
(Self::Integer(m), Self::Integer(n)) => Self::Integer(m % n),
(Self::Float(m), Self::Integer(n)) => Self::Float(m % n as f64),
(Self::Integer(m), Self::Float(n)) => Self::Float(m as f64 % n),
(Self::Float(m), Self::Float(n)) => Self::Float(m % n),
_ => Self::None,
}
}
}