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 *-test
target/ target/
Cargo.lock Cargo.lock
.vscode

View File

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

View File

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