Add support for real comparison operators

This commit is contained in:
Jonathan Turner 2019-05-17 18:27:31 -07:00
parent 52716d0c24
commit 76c295995d
3 changed files with 106 additions and 41 deletions

View File

@ -15,16 +15,21 @@ impl crate::Command for Where {
let field: Result<String, _> = args.args[0].as_string(); let field: Result<String, _> = args.args[0].as_string();
let field = field?; let field = field?;
let op: Result<String, _> = args.args[1].as_string(); match args.args[1] {
let op = op?; Value::Primitive(Primitive::Operator(ref operator)) => {
let objects = args let objects = args
.input .input
.iter() .iter()
.filter(|item| find(&item, &field, &op, &args.args[2])) .filter(|item| find(&item, &field, operator, &args.args[2]))
.map(|item| ReturnValue::Value(item.copy())) .map(|item| ReturnValue::Value(item.copy()))
.collect(); .collect();
Ok(objects) Ok(objects)
} }
ref x => {
println!("{:?}", x);
Err(ShellError::string("expected a comparison operator"))
}
}
}
} }

View File

@ -5,6 +5,7 @@ use chrono::{DateTime, Utc};
use chrono_humanize::Humanize; use chrono_humanize::Humanize;
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use std::time::SystemTime; use std::time::SystemTime;
use crate::parser::parse::Operator;
type OF64 = OrderedFloat<f64>; type OF64 = OrderedFloat<f64>;
@ -18,6 +19,7 @@ pub enum Primitive {
String(String), String(String),
Boolean(bool), Boolean(bool),
Date(DateTime<Utc>), Date(DateTime<Utc>),
Operator(Operator),
} }
impl Primitive { impl Primitive {
@ -48,6 +50,7 @@ impl Primitive {
(false, Some(_)) => format!(""), (false, Some(_)) => format!(""),
}, },
Primitive::Date(d) => format!("{}", d.humanize()), Primitive::Date(d) => format!("{}", d.humanize()),
Primitive::Operator(o) => o.print()
} }
} }
} }
@ -224,57 +227,57 @@ crate fn reject(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
out out
} }
crate fn find(obj: &Value, field: &str, op: &str, rhs: &Value) -> bool { crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
let descs = obj.data_descriptors(); let descs = obj.data_descriptors();
match descs.iter().find(|d| d.name == *field) { match descs.iter().find(|d| d.name == *field) {
None => false, None => false,
Some(desc) => { Some(desc) => {
let v = obj.get_data(desc).borrow().copy(); let v = obj.get_data(desc).borrow().copy();
//println!("'{:?}' '{}' '{:?}'", v, op, rhs); //println!("'{:?}' '{:?}' '{:?}'", v, op, rhs);
match v { match v {
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) { Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
("-eq", Value::Primitive(Primitive::Boolean(b2))) => b == *b2, (Operator::Equal, Value::Primitive(Primitive::Boolean(b2))) => b == *b2,
("-ne", Value::Primitive(Primitive::Boolean(b2))) => b != *b2, (Operator::NotEqual, Value::Primitive(Primitive::Boolean(b2))) => b != *b2,
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) { Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) {
("-lt", Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128), (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128),
("-gt", Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128), (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128),
("-le", Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128), (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128),
("-ge", Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128), (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128),
("-eq", Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128), (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128),
("-ne", Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128), (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128),
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Int(i)) => match (op, rhs) { Value::Primitive(Primitive::Int(i)) => match (op, rhs) {
("-lt", Value::Primitive(Primitive::Int(i2))) => i < *i2, (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < *i2,
("-gt", Value::Primitive(Primitive::Int(i2))) => i > *i2, (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > *i2,
("-le", Value::Primitive(Primitive::Int(i2))) => i <= *i2, (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= *i2,
("-ge", Value::Primitive(Primitive::Int(i2))) => i >= *i2, (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= *i2,
("-eq", Value::Primitive(Primitive::Int(i2))) => i == *i2, (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == *i2,
("-ne", Value::Primitive(Primitive::Int(i2))) => i != *i2, (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2,
_ => false, _ => false,
}, },
Value::Primitive(Primitive::Float(i)) => match (op, rhs) { Value::Primitive(Primitive::Float(i)) => match (op, rhs) {
("-lt", Value::Primitive(Primitive::Float(i2))) => i < *i2, (Operator::LessThan, Value::Primitive(Primitive::Float(i2))) => i < *i2,
("-gt", Value::Primitive(Primitive::Float(i2))) => i > *i2, (Operator::GreaterThan, Value::Primitive(Primitive::Float(i2))) => i > *i2,
("-le", Value::Primitive(Primitive::Float(i2))) => i <= *i2, (Operator::LessThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i <= *i2,
("-ge", Value::Primitive(Primitive::Float(i2))) => i >= *i2, (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i >= *i2,
("-eq", Value::Primitive(Primitive::Float(i2))) => i == *i2, (Operator::Equal, Value::Primitive(Primitive::Float(i2))) => i == *i2,
("-ne", Value::Primitive(Primitive::Float(i2))) => i != *i2, (Operator::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2,
("-lt", Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64, (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64,
("-gt", Value::Primitive(Primitive::Int(i2))) => i.into_inner() > *i2 as f64, (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i.into_inner() > *i2 as f64,
("-le", Value::Primitive(Primitive::Int(i2))) => i.into_inner() <= *i2 as f64, (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() <= *i2 as f64,
("-ge", Value::Primitive(Primitive::Int(i2))) => i.into_inner() >= *i2 as f64, (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() >= *i2 as f64,
("-eq", Value::Primitive(Primitive::Int(i2))) => i.into_inner() == *i2 as f64, (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i.into_inner() == *i2 as f64,
("-ne", Value::Primitive(Primitive::Int(i2))) => i.into_inner() != *i2 as f64, (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() != *i2 as f64,
_ => false, _ => false,
}, },
Value::Primitive(Primitive::String(s)) => match (op, rhs) { Value::Primitive(Primitive::String(s)) => match (op, rhs) {
("-eq", Value::Primitive(Primitive::String(s2))) => s == *s2, (Operator::Equal, Value::Primitive(Primitive::String(s2))) => s == *s2,
("-ne", Value::Primitive(Primitive::String(s2))) => s != *s2, (Operator::NotEqual, Value::Primitive(Primitive::String(s2))) => s != *s2,
_ => false, _ => false,
}, },
_ => false, _ => false,

View File

@ -14,6 +14,45 @@ pub enum Item {
Bare(String), Bare(String),
Int(i64), Int(i64),
Boolean(bool), Boolean(bool),
Operator(Operator),
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Operator {
Equal,
NotEqual,
LessThan,
GreaterThan,
LessThanOrEqual,
GreaterThanOrEqual,
}
impl Operator {
pub fn print(&self) -> String {
match *self {
Operator::Equal => "==".to_string(),
Operator::NotEqual => "!=".to_string(),
Operator::LessThan => "<".to_string(),
Operator::GreaterThan => ">".to_string(),
Operator::LessThanOrEqual => "<=".to_string(),
Operator::GreaterThanOrEqual => ">=".to_string(),
}
}
}
impl FromStr for Operator {
type Err = ();
fn from_str(input: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
match input {
"==" => Ok(Operator::Equal),
"!=" => Ok(Operator::NotEqual),
"<" => Ok(Operator::LessThan),
">" => Ok(Operator::GreaterThan),
"<=" => Ok(Operator::LessThanOrEqual),
">=" => Ok(Operator::GreaterThanOrEqual),
_ => Err(()),
}
}
} }
impl Item { impl Item {
@ -23,6 +62,7 @@ impl Item {
Item::Bare(s) => Value::Primitive(Primitive::String(s.clone())), Item::Bare(s) => Value::Primitive(Primitive::String(s.clone())),
Item::Int(i) => Value::Primitive(Primitive::Int(*i)), Item::Int(i) => Value::Primitive(Primitive::Int(*i)),
Item::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)), Item::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)),
Item::Operator(o) => Value::Primitive(Primitive::Operator(o.clone())),
} }
} }
} }
@ -33,6 +73,7 @@ crate fn print_items(items: &[Item]) -> String {
Item::Quoted(s) => format!("{:?}", s), Item::Quoted(s) => format!("{:?}", s),
Item::Int(i) => format!("{:?}", i), Item::Int(i) => format!("{:?}", i),
Item::Boolean(b) => format!("{:?}", b), Item::Boolean(b) => format!("{:?}", b),
Item::Operator(o) => o.print(),
}); });
itertools::join(formatted, " ") itertools::join(formatted, " ")
@ -45,6 +86,10 @@ impl Item {
Item::Bare(s) => Ok(s), Item::Bare(s) => Ok(s),
Item::Boolean(i) => Err(ShellError::string(format!("{} is not a valid command", i))), Item::Boolean(i) => Err(ShellError::string(format!("{} is not a valid command", i))),
Item::Int(i) => Err(ShellError::string(format!("{} is not a valid command", i))), Item::Int(i) => Err(ShellError::string(format!("{} is not a valid command", i))),
Item::Operator(x) => Err(ShellError::string(format!(
"{:?} is not a valid command",
x
))),
} }
} }
} }
@ -62,6 +107,18 @@ fn unquoted(s: &str) -> IResult<&str, Item> {
is_not(" |")(s).map(|(a, b)| (a, Item::Bare(b.to_string()))) is_not(" |")(s).map(|(a, b)| (a, Item::Bare(b.to_string())))
} }
fn operator(s: &str) -> IResult<&str, Item> {
alt((
tag("=="),
tag("!="),
tag("<"),
tag(">"),
tag("<="),
tag(">="),
))(s)
.map(|(a, b)| (a, Item::Operator(FromStr::from_str(b).unwrap())))
}
fn int(s: &str) -> IResult<&str, Item> { fn int(s: &str) -> IResult<&str, Item> {
is_a("1234567890")(s).map(|(a, b)| (a, Item::Int(FromStr::from_str(b).unwrap()))) is_a("1234567890")(s).map(|(a, b)| (a, Item::Int(FromStr::from_str(b).unwrap())))
} }
@ -72,7 +129,7 @@ fn boolean(s: &str) -> IResult<&str, Item> {
} }
fn command_token(s: &str) -> IResult<&str, Item> { fn command_token(s: &str) -> IResult<&str, Item> {
alt((boolean, int, quoted, unquoted))(s) alt((boolean, int, operator, quoted, unquoted))(s)
} }
fn command_args(s: &str) -> IResult<&str, Vec<Item>> { fn command_args(s: &str) -> IResult<&str, Vec<Item>> {