From 1920820044c1c395e678b0a7d4a21dd21eb0ae27 Mon Sep 17 00:00:00 2001 From: Alexander Sennikov Date: Fri, 26 Apr 2024 15:11:20 +0200 Subject: [PATCH 1/3] chore: add register_function method --- src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 553a127e..b8f0fdf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,6 +36,10 @@ impl<'a> JsonAta<'a> { self.frame.bind(name, value) } + pub fn register_function(&self, name: &str, arity: usize, implementation: fn(FunctionContext<'a, '_>, &'a Value<'a>) -> Result<&'a Value<'a>>) { + self.frame.bind(name, Value::nativefn(&self.arena, name, arity, implementation)); + } + pub fn evaluate(&self, input: Option<&str>) -> Result<&'a Value<'a>> { self.evaluate_timeboxed(input, None, None) } @@ -106,3 +110,94 @@ impl<'a> JsonAta<'a> { evaluator.evaluate(&self.ast, input, &self.frame) } } + +#[cfg(test)] +mod tests{ + use super::*; + use bumpalo::Bump; + + #[test] + fn register_function() { + let arena = Bump::new(); + let jsonata = JsonAta::new("$test('abc')", &arena).unwrap(); + jsonata.register_function("test", 1, |ctx, _| Ok(Value::number(ctx.arena, 1))); + + let result = jsonata.evaluate(Some(r#"anything"#)); + + println!("{:?}", result); + + assert_eq!(result.unwrap(), Value::number(&arena, 1)); + } +} + + + // fn t(resource: &str) { + // if SKIP.iter().any(|&s| s == resource) { + // return; + // } + + // test_case(resource); + // } + + // fn test_case(resource: &str) { + // let arena = Bump::new(); + // let test_jsonata = JsonAta::new( + // &fs::read_to_string(path::Path::new(resource)).unwrap(), + // &arena, + // ) + // .unwrap(); + // let test = test_jsonata.evaluate(None).unwrap(); + // let test = Value::wrap_in_array_if_needed(&arena, test, ArrayFlags::empty()); + + // for case in test.members() { + // let timelimit = &case["timelimit"]; + // let timelimit = if timelimit.is_integer() { + // Some(timelimit.as_usize()) + // } else { + // None + // }; + + // let depth = &case["depth"]; + // let depth = if depth.is_integer() { + // Some(depth.as_usize()) + // } else { + // None + // }; + + // let expr = &case["expr"]; + // let expr_file = &case["expr-file"]; + + // let expr = if expr.is_string() { + // expr.as_str().to_string() + // } else if expr_file.is_string() { + // fs::read_to_string( + // path::Path::new(resource) + // .parent() + // .unwrap() + // .join(expr_file.as_str().to_string()), + // ) + // .unwrap() + // } else { + // panic!("No expression") + // }; + + // eprintln!("EXPR: {expr}"); + + // let data = &case["data"]; + // let dataset = &case["dataset"]; + + // let data = if dataset.is_string() { + // let dataset = format!("tests/testsuite/datasets/{}.json", dataset.as_str()); + // fs::read_to_string(&dataset).unwrap() + // } else if data.is_undefined() { + // "".to_string() + // } else { + // data.to_string() + // }; + + // let data = JsonAta::new(&data, &arena).unwrap().evaluate(None).unwrap(); + + // let test_jsonata = JsonAta::new(&expr, &arena).unwrap(); + // test_jsonata.assign_var("$", data); + + // let result = test_jsonata.evaluate_timeboxed(None, depth, timel From dff11a7a28bd9ce5923c72dcbd36acdcc05ac7d8 Mon Sep 17 00:00:00 2001 From: Alexander Sennikov Date: Mon, 29 Apr 2024 18:41:07 +0200 Subject: [PATCH 2/3] chore: add tests for register_function --- src/lib.rs | 118 +++++++++++++++++++---------------------------------- 1 file changed, 41 insertions(+), 77 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b8f0fdf7..ed1bbbee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,90 +114,54 @@ impl<'a> JsonAta<'a> { #[cfg(test)] mod tests{ use super::*; - use bumpalo::Bump; #[test] - fn register_function() { + fn register_function_simple() { let arena = Bump::new(); - let jsonata = JsonAta::new("$test('abc')", &arena).unwrap(); - jsonata.register_function("test", 1, |ctx, _| Ok(Value::number(ctx.arena, 1))); + let jsonata = JsonAta::new("$test()", &arena).unwrap(); + jsonata.register_function("test", 0, |ctx, _| Ok(Value::number(ctx.arena, 1))); let result = jsonata.evaluate(Some(r#"anything"#)); - println!("{:?}", result); - assert_eq!(result.unwrap(), Value::number(&arena, 1)); } -} + #[test] + fn register_function_override_now() { + let arena = Bump::new(); + let jsonata = JsonAta::new("$now()", &arena).unwrap(); + jsonata.register_function("now", 0, |ctx, _| Ok(Value::string(ctx.arena, "time for tea"))); + + let result = jsonata.evaluate(Some(r#"anything"#)); + + assert_eq!(result.unwrap(), Value::string(&arena, "time for tea")); + } + + #[test] + fn register_function_map_squareroot() { + let arena = Bump::new(); + let jsonata = JsonAta::new("$map([1,4,9,16], $squareroot)", &arena).unwrap(); + jsonata.register_function("squareroot", 1, |ctx, args| { + let num = &args[0]; + return Ok(Value::number(ctx.arena, (num.as_f64()).sqrt())) + }); + + let result = jsonata.evaluate(Some(r#"anything"#)); + + assert_eq!(result.unwrap().members().map(|v| v.as_f64()).collect::>(), vec![1.0, 2.0, 3.0, 4.0]); + } - // fn t(resource: &str) { - // if SKIP.iter().any(|&s| s == resource) { - // return; - // } - - // test_case(resource); - // } - - // fn test_case(resource: &str) { - // let arena = Bump::new(); - // let test_jsonata = JsonAta::new( - // &fs::read_to_string(path::Path::new(resource)).unwrap(), - // &arena, - // ) - // .unwrap(); - // let test = test_jsonata.evaluate(None).unwrap(); - // let test = Value::wrap_in_array_if_needed(&arena, test, ArrayFlags::empty()); - - // for case in test.members() { - // let timelimit = &case["timelimit"]; - // let timelimit = if timelimit.is_integer() { - // Some(timelimit.as_usize()) - // } else { - // None - // }; - - // let depth = &case["depth"]; - // let depth = if depth.is_integer() { - // Some(depth.as_usize()) - // } else { - // None - // }; - - // let expr = &case["expr"]; - // let expr_file = &case["expr-file"]; - - // let expr = if expr.is_string() { - // expr.as_str().to_string() - // } else if expr_file.is_string() { - // fs::read_to_string( - // path::Path::new(resource) - // .parent() - // .unwrap() - // .join(expr_file.as_str().to_string()), - // ) - // .unwrap() - // } else { - // panic!("No expression") - // }; - - // eprintln!("EXPR: {expr}"); - - // let data = &case["data"]; - // let dataset = &case["dataset"]; - - // let data = if dataset.is_string() { - // let dataset = format!("tests/testsuite/datasets/{}.json", dataset.as_str()); - // fs::read_to_string(&dataset).unwrap() - // } else if data.is_undefined() { - // "".to_string() - // } else { - // data.to_string() - // }; - - // let data = JsonAta::new(&data, &arena).unwrap().evaluate(None).unwrap(); - - // let test_jsonata = JsonAta::new(&expr, &arena).unwrap(); - // test_jsonata.assign_var("$", data); - - // let result = test_jsonata.evaluate_timeboxed(None, depth, timel + #[test] + fn register_function_filter_even() { + let arena = Bump::new(); + let jsonata = JsonAta::new("$filter([1,4,9,16], $even)", &arena).unwrap(); + jsonata.register_function("even", 1, |ctx, args| { + let num = &args[0]; + return Ok(Value::bool(ctx.arena, (num.as_f64()) % 2.0 == 0.0)); + }); + + let result = jsonata.evaluate(Some(r#"anything"#)); + + assert_eq!(result.unwrap().members().map(|v| v.as_f64()).collect::>(), vec![4.0, 16.0]); + } +} From 908a885d91b0b4b775df22e7dc2a58fe87a629c7 Mon Sep 17 00:00:00 2001 From: Alexander Sennikov Date: Mon, 29 Apr 2024 18:44:53 +0200 Subject: [PATCH 3/3] chore: format --- src/lib.rs | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed1bbbee..8a785544 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,8 +36,16 @@ impl<'a> JsonAta<'a> { self.frame.bind(name, value) } - pub fn register_function(&self, name: &str, arity: usize, implementation: fn(FunctionContext<'a, '_>, &'a Value<'a>) -> Result<&'a Value<'a>>) { - self.frame.bind(name, Value::nativefn(&self.arena, name, arity, implementation)); + pub fn register_function( + &self, + name: &str, + arity: usize, + implementation: fn(FunctionContext<'a, '_>, &'a Value<'a>) -> Result<&'a Value<'a>>, + ) { + self.frame.bind( + name, + Value::nativefn(self.arena, name, arity, implementation), + ); } pub fn evaluate(&self, input: Option<&str>) -> Result<&'a Value<'a>> { @@ -112,7 +120,7 @@ impl<'a> JsonAta<'a> { } #[cfg(test)] -mod tests{ +mod tests { use super::*; #[test] @@ -120,7 +128,7 @@ mod tests{ let arena = Bump::new(); let jsonata = JsonAta::new("$test()", &arena).unwrap(); jsonata.register_function("test", 0, |ctx, _| Ok(Value::number(ctx.arena, 1))); - + let result = jsonata.evaluate(Some(r#"anything"#)); assert_eq!(result.unwrap(), Value::number(&arena, 1)); @@ -130,8 +138,10 @@ mod tests{ fn register_function_override_now() { let arena = Bump::new(); let jsonata = JsonAta::new("$now()", &arena).unwrap(); - jsonata.register_function("now", 0, |ctx, _| Ok(Value::string(ctx.arena, "time for tea"))); - + jsonata.register_function("now", 0, |ctx, _| { + Ok(Value::string(ctx.arena, "time for tea")) + }); + let result = jsonata.evaluate(Some(r#"anything"#)); assert_eq!(result.unwrap(), Value::string(&arena, "time for tea")); @@ -143,12 +153,19 @@ mod tests{ let jsonata = JsonAta::new("$map([1,4,9,16], $squareroot)", &arena).unwrap(); jsonata.register_function("squareroot", 1, |ctx, args| { let num = &args[0]; - return Ok(Value::number(ctx.arena, (num.as_f64()).sqrt())) + return Ok(Value::number(ctx.arena, (num.as_f64()).sqrt())); }); - + let result = jsonata.evaluate(Some(r#"anything"#)); - assert_eq!(result.unwrap().members().map(|v| v.as_f64()).collect::>(), vec![1.0, 2.0, 3.0, 4.0]); + assert_eq!( + result + .unwrap() + .members() + .map(|v| v.as_f64()) + .collect::>(), + vec![1.0, 2.0, 3.0, 4.0] + ); } #[test] @@ -159,9 +176,16 @@ mod tests{ let num = &args[0]; return Ok(Value::bool(ctx.arena, (num.as_f64()) % 2.0 == 0.0)); }); - + let result = jsonata.evaluate(Some(r#"anything"#)); - assert_eq!(result.unwrap().members().map(|v| v.as_f64()).collect::>(), vec![4.0, 16.0]); + assert_eq!( + result + .unwrap() + .members() + .map(|v| v.as_f64()) + .collect::>(), + vec![4.0, 16.0] + ); } }