diff --git a/src/commands/where_.rs b/src/commands/where_.rs index 07e7da6949..3db7e5fa8b 100644 --- a/src/commands/where_.rs +++ b/src/commands/where_.rs @@ -15,16 +15,21 @@ impl crate::Command for Where { let field: Result = args.args[0].as_string(); let field = field?; - let op: Result = args.args[1].as_string(); - let op = op?; + match args.args[1] { + Value::Primitive(Primitive::Operator(ref operator)) => { + let objects = args + .input + .iter() + .filter(|item| find(&item, &field, operator, &args.args[2])) + .map(|item| ReturnValue::Value(item.copy())) + .collect(); - let objects = args - .input - .iter() - .filter(|item| find(&item, &field, &op, &args.args[2])) - .map(|item| ReturnValue::Value(item.copy())) - .collect(); - - Ok(objects) + Ok(objects) + } + ref x => { + println!("{:?}", x); + Err(ShellError::string("expected a comparison operator")) + } + } } } diff --git a/src/object/base.rs b/src/object/base.rs index 0912a14938..66c591971f 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -5,6 +5,7 @@ use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use ordered_float::OrderedFloat; use std::time::SystemTime; +use crate::parser::parse::Operator; type OF64 = OrderedFloat; @@ -18,6 +19,7 @@ pub enum Primitive { String(String), Boolean(bool), Date(DateTime), + Operator(Operator), } impl Primitive { @@ -48,6 +50,7 @@ impl Primitive { (false, Some(_)) => format!(""), }, 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 } -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(); match descs.iter().find(|d| d.name == *field) { None => false, Some(desc) => { let v = obj.get_data(desc).borrow().copy(); - //println!("'{:?}' '{}' '{:?}'", v, op, rhs); + //println!("'{:?}' '{:?}' '{:?}'", v, op, rhs); match v { Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) { - ("-eq", Value::Primitive(Primitive::Boolean(b2))) => b == *b2, - ("-ne", Value::Primitive(Primitive::Boolean(b2))) => b != *b2, + (Operator::Equal, Value::Primitive(Primitive::Boolean(b2))) => b == *b2, + (Operator::NotEqual, Value::Primitive(Primitive::Boolean(b2))) => b != *b2, _ => false, }, Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) { - ("-lt", Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128), - ("-gt", Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128), - ("-le", Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128), - ("-ge", Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128), - ("-eq", Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128), - ("-ne", Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128), + (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u128), + (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > (*i2 as u128), + (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= (*i2 as u128), + (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= (*i2 as u128), + (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u128), + (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u128), _ => false, }, Value::Primitive(Primitive::Int(i)) => match (op, rhs) { - ("-lt", Value::Primitive(Primitive::Int(i2))) => i < *i2, - ("-gt", Value::Primitive(Primitive::Int(i2))) => i > *i2, - ("-le", Value::Primitive(Primitive::Int(i2))) => i <= *i2, - ("-ge", Value::Primitive(Primitive::Int(i2))) => i >= *i2, - ("-eq", Value::Primitive(Primitive::Int(i2))) => i == *i2, - ("-ne", Value::Primitive(Primitive::Int(i2))) => i != *i2, + (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < *i2, + (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > *i2, + (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= *i2, + (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i >= *i2, + (Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == *i2, + (Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2, _ => false, }, Value::Primitive(Primitive::Float(i)) => match (op, rhs) { - ("-lt", Value::Primitive(Primitive::Float(i2))) => i < *i2, - ("-gt", Value::Primitive(Primitive::Float(i2))) => i > *i2, - ("-le", Value::Primitive(Primitive::Float(i2))) => i <= *i2, - ("-ge", Value::Primitive(Primitive::Float(i2))) => i >= *i2, - ("-eq", Value::Primitive(Primitive::Float(i2))) => i == *i2, - ("-ne", Value::Primitive(Primitive::Float(i2))) => i != *i2, - ("-lt", Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64, - ("-gt", Value::Primitive(Primitive::Int(i2))) => i.into_inner() > *i2 as f64, - ("-le", Value::Primitive(Primitive::Int(i2))) => i.into_inner() <= *i2 as f64, - ("-ge", Value::Primitive(Primitive::Int(i2))) => i.into_inner() >= *i2 as f64, - ("-eq", Value::Primitive(Primitive::Int(i2))) => i.into_inner() == *i2 as f64, - ("-ne", Value::Primitive(Primitive::Int(i2))) => i.into_inner() != *i2 as f64, + (Operator::LessThan, Value::Primitive(Primitive::Float(i2))) => i < *i2, + (Operator::GreaterThan, Value::Primitive(Primitive::Float(i2))) => i > *i2, + (Operator::LessThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i <= *i2, + (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i >= *i2, + (Operator::Equal, Value::Primitive(Primitive::Float(i2))) => i == *i2, + (Operator::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2, + (Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => (i.into_inner()) < *i2 as f64, + (Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i.into_inner() > *i2 as f64, + (Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() <= *i2 as f64, + (Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i.into_inner() >= *i2 as f64, + (Operator::Equal, 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, }, Value::Primitive(Primitive::String(s)) => match (op, rhs) { - ("-eq", Value::Primitive(Primitive::String(s2))) => s == *s2, - ("-ne", Value::Primitive(Primitive::String(s2))) => s != *s2, + (Operator::Equal, Value::Primitive(Primitive::String(s2))) => s == *s2, + (Operator::NotEqual, Value::Primitive(Primitive::String(s2))) => s != *s2, _ => false, }, _ => false, diff --git a/src/parser/parse.rs b/src/parser/parse.rs index 276c057a39..fc001263e0 100644 --- a/src/parser/parse.rs +++ b/src/parser/parse.rs @@ -14,6 +14,45 @@ pub enum Item { Bare(String), Int(i64), 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::Err> { + match input { + "==" => Ok(Operator::Equal), + "!=" => Ok(Operator::NotEqual), + "<" => Ok(Operator::LessThan), + ">" => Ok(Operator::GreaterThan), + "<=" => Ok(Operator::LessThanOrEqual), + ">=" => Ok(Operator::GreaterThanOrEqual), + _ => Err(()), + } + } } impl Item { @@ -23,6 +62,7 @@ impl Item { Item::Bare(s) => Value::Primitive(Primitive::String(s.clone())), Item::Int(i) => Value::Primitive(Primitive::Int(*i)), 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::Int(i) => format!("{:?}", i), Item::Boolean(b) => format!("{:?}", b), + Item::Operator(o) => o.print(), }); itertools::join(formatted, " ") @@ -45,6 +86,10 @@ impl Item { Item::Bare(s) => Ok(s), 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::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()))) } +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> { 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> { - alt((boolean, int, quoted, unquoted))(s) + alt((boolean, int, operator, quoted, unquoted))(s) } fn command_args(s: &str) -> IResult<&str, Vec> {