use proc_macro::Punct;
use super::eval::{Value, ValueRef};
#[derive(Clone, Copy, Debug)]
pub(crate) enum Comparison {
Lt,
Gt,
Lte,
Gte,
Eq,
Ne,
And,
Or,
None,
}
impl Comparison {
pub(crate) fn compare(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef {
let lhs = lhs.as_value();
let rhs = rhs.as_value();
ValueRef::Boolean(match self {
Comparison::Lt => Self::gt(rhs, lhs),
Comparison::Gt => Self::gt(lhs, rhs),
Comparison::Lte => Self::eq(lhs.clone(), rhs.clone()) || (!Self::gt(lhs, rhs)),
Comparison::Gte => Self::eq(lhs.clone(), rhs.clone()) || Self::gt(lhs, rhs),
Comparison::Eq => Self::eq(lhs, rhs),
Comparison::Ne => !Self::eq(lhs, rhs),
Comparison::And => Self::and(lhs, rhs),
Comparison::Or => Self::or(lhs, rhs),
Comparison::None => false,
})
}
fn eq(lhs: Value, rhs: Value) -> bool {
let lhs_clone = lhs.clone();
let rhs_clone = rhs.clone();
match (lhs, rhs) {
(Value::String(s1), Value::String(s2)) => s1 == s2,
(Value::String(_), Value::Boolean(b)) => lhs_clone.as_bool() == b,
(Value::String(_), Value::Int(i)) => match lhs_clone.as_int() {
Some(i_lhs) => i_lhs == i,
None => false,
},
(Value::Boolean(b), Value::String(_)) => b == rhs_clone.as_bool(),
(Value::Boolean(b1), Value::Boolean(b2)) => b1 == b2,
(Value::Boolean(_), Value::Int(i)) => match lhs_clone.as_int() {
Some(i_lhs) => i_lhs == i,
None => false,
},
(Value::Int(i), Value::String(_)) => match rhs_clone.as_int() {
Some(i_rhs) => i == i_rhs,
None => false,
},
(Value::Int(i), Value::Boolean(_)) => match rhs_clone.as_int() {
Some(i_rhs) => i == i_rhs,
None => false,
},
(Value::Int(i1), Value::Int(i2)) => i1 == i2,
}
}
fn gt(lhs: Value, rhs: Value) -> bool {
let lhs_clone = lhs.clone();
let rhs_clone = rhs.clone();
match (lhs, rhs) {
(Value::String(s1), Value::String(s2)) => s1 > s2,
(Value::String(_), Value::Boolean(b)) => lhs_clone.as_bool() > b,
(Value::String(_), Value::Int(i)) => match lhs_clone.as_int() {
Some(i_lhs) => i_lhs > i,
None => false,
},
(Value::Boolean(b), Value::String(_)) => b > rhs_clone.as_bool(),
(Value::Boolean(b1), Value::Boolean(b2)) => b1 > b2,
(Value::Boolean(_), Value::Int(i)) => match lhs_clone.as_int() {
Some(i_lhs) => i_lhs > i,
None => false,
},
(Value::Int(i), Value::String(_)) => match rhs_clone.as_int() {
Some(i_rhs) => i > i_rhs,
None => false,
},
(Value::Int(i), Value::Boolean(_)) => match rhs_clone.as_int() {
Some(i_rhs) => i > i_rhs,
None => false,
},
(Value::Int(i1), Value::Int(i2)) => i1 > i2,
}
}
fn and(lhs: Value, rhs: Value) -> bool {
lhs.as_bool() && rhs.as_bool()
}
fn or(lhs: Value, rhs: Value) -> bool {
lhs.as_bool() || rhs.as_bool()
}
pub(crate) fn single(p: &Punct) -> Self {
match p.as_char() {
'<' => Self::Lt,
'>' => Self::Gt,
_ => panic!("Operator {} invalid", p.as_char()),
}
}
pub(crate) fn dual(p1: &Punct, p2: &Punct) -> Self {
match (p1.as_char(), p2.as_char()) {
('<', '=') => Self::Lte,
('>', '=') => Self::Gte,
('=', '=') => Self::Eq,
('!', '=') => Self::Ne,
('&', '&') => Self::And,
('|', '|') => Self::Or,
_ => panic!("Operator {}{} invalid", p1.as_char(), p2.as_char()),
}
}
}