allow null to compare

This commit is contained in:
fengcen 2017-12-07 07:24:12 +08:00
parent 1b690b634c
commit daf3f5bd4a
3 changed files with 125 additions and 56 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@
*-test
target/
Cargo.lock
.vscode

View File

@ -202,8 +202,10 @@ mod tests {
#[test]
fn test_min_brackets() {
assert_eq!(eval("(min(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
Ok(to_value(100)));
assert_eq!(
eval("(min(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
Ok(to_value(100))
);
}
#[test]
@ -218,8 +220,10 @@ mod tests {
#[test]
fn test_max_brackets() {
assert_eq!(eval("(max(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
Ok(to_value(2500)));
assert_eq!(
eval("(max(30, 5, 245, 20) * 10 + (5 + 5) * 5)"),
Ok(to_value(2500))
);
}
#[test]
@ -232,6 +236,12 @@ mod tests {
assert_eq!(eval("len(array(2, 3, 4, 5, 6))"), Ok(to_value(5)));
}
#[test]
fn test_null_and_number() {
assert_eq!(eval("hos != 0"), Ok(to_value(true)));
assert_eq!(eval("hos > 0"), Ok(to_value(false)));
}
#[test]
fn test_len_string() {
assert_eq!(eval("len('Hello world!')"), Ok(to_value(12)));
@ -243,10 +253,10 @@ mod tests {
object.insert("field1", "value1");
object.insert("field2", "value2");
object.insert("field3", "value3");
assert_eq!(Expr::new("len(object)")
.value("object", object)
.exec(),
Ok(to_value(3)));
assert_eq!(
Expr::new("len(object)").value("object", object).exec(),
Ok(to_value(3))
);
}
#[test]
@ -333,14 +343,18 @@ mod tests {
#[test]
fn test_single_and_double_quote() {
assert_eq!(eval(r#"' """" ' + ' """" '"#),
Ok(to_value(r#" """" """" "#)));
assert_eq!(
eval(r#"' """" ' + ' """" '"#),
Ok(to_value(r#" """" """" "#))
);
}
#[test]
fn test_double_and_single_quote() {
assert_eq!(eval(r#"" '''' " + " '''' ""#),
Ok(to_value(r#" '''' '''' "#)));
assert_eq!(
eval(r#"" '''' " + " '''' ""#),
Ok(to_value(r#" '''' '''' "#))
);
}
#[test]
@ -432,10 +446,12 @@ mod tests {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object.foo == 'Foo, hello world!'")
assert_eq!(
Expr::new("object.foo == 'Foo, hello world!'")
.value("object", object)
.exec(),
Ok(to_value(true)));
Ok(to_value(true))
);
}
#[test]
@ -443,10 +459,12 @@ mod tests {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object['foo'] == 'Foo, hello world!'")
assert_eq!(
Expr::new("object['foo'] == 'Foo, hello world!'")
.value("object", object)
.exec(),
Ok(to_value(true)));
Ok(to_value(true))
);
}
#[test]
@ -454,11 +472,13 @@ mod tests {
let mut object = HashMap::new();
object.insert("foo", "Foo, hello world!");
object.insert("bar", "Bar, hello world!");
assert_eq!(Expr::new("object[foo] == 'Foo, hello world!'")
assert_eq!(
Expr::new("object[foo] == 'Foo, hello world!'")
.value("object", object)
.value("foo", "foo")
.exec(),
Ok(to_value(true)));
Ok(to_value(true))
);
}
#[test]
@ -469,40 +489,54 @@ mod tests {
#[test]
fn test_array_access() {
let array = vec!["hello", "world", "!"];
assert_eq!(Expr::new("array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'")
.value("array", array)
assert_eq!(
Expr::new(
"array[1-1] == 'hello' && array[1] == 'world' && array[2] == '!'",
).value("array", array)
.exec(),
Ok(to_value(true)));
Ok(to_value(true))
);
}
#[test]
fn test_builtin_is_empty() {
assert_eq!(Expr::new("is_empty(array)")
assert_eq!(
Expr::new("is_empty(array)")
.value("array", Vec::<String>::new())
.exec(),
Ok(to_value(true)));
Ok(to_value(true))
);
}
#[test]
fn test_builtin_min() {
assert_eq!(Expr::new("min(array)")
assert_eq!(
Expr::new("min(array)")
.value("array", vec![23, 34, 45, 2])
.exec(),
Ok(to_value(2)));
Ok(to_value(2))
);
}
#[test]
fn test_custom_function() {
assert_eq!(Expr::new("output()")
.function("output",
|_| Ok(to_value("This is custom function's output")))
assert_eq!(
Expr::new("output()")
.function(
"output",
|_| Ok(to_value("This is custom function's output")),
)
.exec(),
Ok(to_value("This is custom function's output")));
Ok(to_value("This is custom function's output"))
);
}
#[test]
fn test_error_start_with_non_value_operator() {
let mut tree = Tree { raw: "+ + 5".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "+ + 5".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
@ -512,7 +546,10 @@ mod tests {
#[test]
fn test_error_duplicate_operator() {
let mut tree = Tree { raw: "5 + + 5".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "5 + + 5".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
@ -522,7 +559,10 @@ mod tests {
#[test]
fn test_error_duplicate_value() {
let mut tree = Tree { raw: "2 + 6 5".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "2 + 6 5".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
@ -532,7 +572,10 @@ mod tests {
#[test]
fn test_error_unpaired_brackets() {
let mut tree = Tree { raw: "(2 + 3)) * 5".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "(2 + 3)) * 5".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
@ -541,7 +584,10 @@ mod tests {
#[test]
fn test_error_comma() {
let mut tree = Tree { raw: ", 2 + 5".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: ", 2 + 5".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
@ -564,16 +610,20 @@ mod benches {
#[bench]
fn bench_parse_pos(b: &mut test::Bencher) {
let mut tree =
Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(),
..Default::default()
};
b.iter(|| tree.parse_pos().unwrap());
}
#[bench]
fn bench_parse_operators(b: &mut test::Bencher) {
let mut tree =
Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
b.iter(|| tree.parse_operators().unwrap());
@ -581,8 +631,10 @@ mod benches {
#[bench]
fn bench_parse_nodes(b: &mut test::Bencher) {
let mut tree =
Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
@ -592,8 +644,10 @@ mod benches {
#[bench]
fn bench_compile(b: &mut test::Bencher) {
b.iter(|| {
let mut tree =
Tree { raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(), ..Default::default() };
let mut tree = Tree {
raw: "(2 + (3 + 4) + (6 + (6 + 7)) + 5)".to_owned(),
..Default::default()
};
tree.parse_pos().unwrap();
tree.parse_operators().unwrap();
tree.parse_node().unwrap();
@ -603,7 +657,9 @@ mod benches {
#[bench]
fn bench_exec(b: &mut test::Bencher) {
let expr = Expr::new("(2 + (3 + 4) + (6 + (6 + 7)) + 5)").compile().unwrap();
let expr = Expr::new("(2 + (3 + 4) + (6 + (6 + 7)) + 5)")
.compile()
.unwrap();
b.iter(|| expr.exec().unwrap())
}

View File

@ -101,6 +101,9 @@ impl Math for Value {
}
fn gt(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() > value.get_f64()))
} else {
@ -109,6 +112,9 @@ impl Math for Value {
}
fn lt(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() < value.get_f64()))
} else {
@ -117,6 +123,9 @@ impl Math for Value {
}
fn ge(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() >= value.get_f64()))
} else {
@ -125,6 +134,9 @@ impl Math for Value {
}
fn le(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() <= value.get_f64()))
} else {