From 0b393285e23c555d17afa3010f6cc48c4ff6d5be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Tue, 9 Apr 2024 07:56:50 +0200 Subject: [PATCH 1/5] FIX use constructor in Parser --- jexl-parser/src/lib.rs | 51 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/jexl-parser/src/lib.rs b/jexl-parser/src/lib.rs index 86114bd..69335f8 100644 --- a/jexl-parser/src/lib.rs +++ b/jexl-parser/src/lib.rs @@ -10,11 +10,20 @@ pub use lalrpop_util::ParseError; pub use crate::parser::Token; -pub struct Parser {} +pub struct Parser { + parser: parser::ExpressionParser +} impl Parser { - pub fn parse(input: &str) -> Result> { - Ok(*parser::ExpressionParser::new().parse(input)?) + + pub fn new() -> Self { + Parser { + parser: parser::ExpressionParser::new() + } + } + + pub fn parse(&self, input: &str) -> Result> { + Ok(self.parser.parse(input)?) } } @@ -25,13 +34,15 @@ mod tests { #[test] fn literal() { - assert_eq!(Parser::parse("1"), Ok(Expression::Number(1.0))); + let parser = Parser::new(); + assert_eq!(parser.parse("1"), Ok(Expression::Number(1.0))); } #[test] fn binary_expression() { + let parser = Parser::new(); assert_eq!( - Parser::parse("1+2"), + parser.parse("1+2"), Ok(Expression::BinaryOperation { operation: OpCode::Add, left: Box::new(Expression::Number(1.0)), @@ -42,13 +53,15 @@ mod tests { #[test] fn binary_expression_whitespace() { - assert_eq!(Parser::parse("1 + 2 "), Parser::parse("1+2"),); + let parser = Parser::new(); + assert_eq!(parser.parse("1 + 2 "), parser.parse("1+2"),); } #[test] fn transform_simple_no_args() { + let parser = Parser::new(); let exp = "'T_T'|lower"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::Transform { @@ -61,8 +74,9 @@ mod tests { #[test] fn transform_multiple_args() { + let parser = Parser::new(); let exp = "'John Doe'|split(' ')"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::Transform { @@ -75,8 +89,9 @@ mod tests { #[test] fn trasform_way_too_many_args() { + let parser = Parser::new(); let exp = "123456|math(12, 35, 100, 31, 90)"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::Transform { @@ -95,8 +110,9 @@ mod tests { #[test] fn test_index_op_ident() { + let parser = Parser::new(); let exp = "foo[0]"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::IndexOperation { @@ -108,8 +124,9 @@ mod tests { #[test] fn test_index_op_array_literal() { + let parser = Parser::new(); let exp = "[1, 2, 3][0]"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::IndexOperation { @@ -125,8 +142,9 @@ mod tests { #[test] fn test_dot_op_ident() { + let parser = Parser::new(); let exp = "foo.bar"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::DotOperation { @@ -138,8 +156,9 @@ mod tests { #[test] fn test_dot_op_equality_with_null() { + let parser = Parser::new(); let exp = "foo.bar == null"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::BinaryOperation { @@ -155,8 +174,9 @@ mod tests { #[test] fn test_dot_op_object_literal() { + let parser = Parser::new(); let exp = "{'foo': 1}.foo"; - let parsed = Parser::parse(exp).unwrap(); + let parsed = parser.parse(exp).unwrap(); assert_eq!( parsed, Expression::DotOperation { @@ -171,6 +191,7 @@ mod tests { #[test] fn test_parsing_null() { - assert_eq!(Parser::parse("null"), Ok(Expression::Null)); + let parser = Parser::new(); + assert_eq!(parser.parse("null"), Ok(Expression::Null)); } } From ba8ab3ef5f9cbddd292cc11307c8fb588fedf826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Tue, 9 Apr 2024 12:23:54 +0200 Subject: [PATCH 2/5] FIX expected Expression, found Box error --- jexl-parser/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jexl-parser/src/lib.rs b/jexl-parser/src/lib.rs index 69335f8..193539b 100644 --- a/jexl-parser/src/lib.rs +++ b/jexl-parser/src/lib.rs @@ -22,8 +22,8 @@ impl Parser { } } - pub fn parse(&self, input: &str) -> Result> { - Ok(self.parser.parse(input)?) + pub fn parse<'a>(&'a self, input: &'a str) -> Result> { + Ok(*self.parser.parse(input)?) } } From a30df95d1e586bec97e9705ab86bf9170b659115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Tue, 9 Apr 2024 17:42:37 +0200 Subject: [PATCH 3/5] FIX tyring to use new Parser in Evaluator --- jexl-eval/src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jexl-eval/src/lib.rs b/jexl-eval/src/lib.rs index 7312acb..4df8ea6 100644 --- a/jexl-eval/src/lib.rs +++ b/jexl-eval/src/lib.rs @@ -146,7 +146,9 @@ impl<'a> Evaluator<'a> { input: &'b str, context: T, ) -> Result<'b, Value> { - let tree = Parser::parse(input)?; + // FIXME: just testing... + let parser = Parser::new(); + let tree = parser.parse(input)?; let context = serde_json::to_value(context)?; if !context.is_object() { return Err(EvaluationError::InvalidContext); From 0f87dec31f84ed4196609ec100aaeb408fb2ded8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Thu, 11 Apr 2024 09:13:14 +0200 Subject: [PATCH 4/5] FIX parser function signature --- jexl-parser/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jexl-parser/src/lib.rs b/jexl-parser/src/lib.rs index 193539b..9150aad 100644 --- a/jexl-parser/src/lib.rs +++ b/jexl-parser/src/lib.rs @@ -22,7 +22,7 @@ impl Parser { } } - pub fn parse<'a>(&'a self, input: &'a str) -> Result> { + pub fn parse<'a>(& self, input: &'a str) -> Result, &'static str>> { Ok(*self.parser.parse(input)?) } } From d017065cbdfce3e58318eba0a8d3a8d38ca8fee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Thu, 11 Apr 2024 09:51:59 +0200 Subject: [PATCH 5/5] FIX add parser argument in eval_in_context() method --- jexl-eval/src/lib.rs | 49 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/jexl-eval/src/lib.rs b/jexl-eval/src/lib.rs index 4df8ea6..b25ad22 100644 --- a/jexl-eval/src/lib.rs +++ b/jexl-eval/src/lib.rs @@ -26,10 +26,12 @@ //! For example: //! ```rust //! use jexl_eval::Evaluator; +//! use jexl_parser::Parser; //! use serde_json::json as value; +//! let parser = Parser::new(); //! let context = value!({"a": {"b": 2.0}}); //! let evaluator = Evaluator::new(); -//! assert_eq!(evaluator.eval_in_context("a.b", context).unwrap(), value!(2.0)); +//! assert_eq!(evaluator.eval_in_context(&parser, "a.b", context).unwrap(), value!(2.0)); //! ``` //! @@ -138,16 +140,18 @@ impl<'a> Evaluator<'a> { pub fn eval<'b>(&self, input: &'b str) -> Result<'b, Value> { let context = value!({}); - self.eval_in_context(input, &context) + // FIXME: we create the parser internally in eval() to minimize changes in function signatures, tests, etc. + // For our use case we don't use this function, but maybe makes sense to move this to function parameter + let parser = Parser::new(); + self.eval_in_context(&parser, input, &context) } pub fn eval_in_context<'b, T: serde::Serialize>( &self, + parser: &Parser, input: &'b str, context: T, ) -> Result<'b, Value> { - // FIXME: just testing... - let parser = Parser::new(); let tree = parser.parse(input)?; let context = serde_json::to_value(context)?; if !context.is_object() { @@ -437,24 +441,27 @@ mod tests { #[test] fn test_identifier() { + let parser = Parser::new(); let context = value!({"a": 1.0}); assert_eq!( - Evaluator::new().eval_in_context("a", context).unwrap(), + Evaluator::new().eval_in_context(&parser, "a", context).unwrap(), value!(1.0) ); } #[test] fn test_identifier_chain() { + let parser = Parser::new(); let context = value!({"a": {"b": 2.0}}); assert_eq!( - Evaluator::new().eval_in_context("a.b", context).unwrap(), + Evaluator::new().eval_in_context(&parser, "a.b", context).unwrap(), value!(2.0) ); } #[test] fn test_context_filter_arrays() { + let parser = Parser::new(); let context = value!({ "foo": { "bar": [ @@ -466,7 +473,7 @@ mod tests { }); assert_eq!( Evaluator::new() - .eval_in_context("foo.bar[.tek == 'baz']", &context) + .eval_in_context(&parser, "foo.bar[.tek == 'baz']", &context) .unwrap(), value!([{"tek": "baz"}]) ); @@ -474,6 +481,7 @@ mod tests { #[test] fn test_context_array_index() { + let parser = Parser::new(); let context = value!({ "foo": { "bar": [ @@ -485,7 +493,7 @@ mod tests { }); assert_eq!( Evaluator::new() - .eval_in_context("foo.bar[1].tek", context) + .eval_in_context(&parser, "foo.bar[1].tek", context) .unwrap(), value!("baz") ); @@ -493,10 +501,11 @@ mod tests { #[test] fn test_object_expression_properties() { + let parser = Parser::new(); let context = value!({"foo": {"baz": {"bar": "tek"}}}); assert_eq!( Evaluator::new() - .eval_in_context("foo['ba' + 'z'].bar", &context) + .eval_in_context(&parser, "foo['ba' + 'z'].bar", &context) .unwrap(), value!("tek") ); @@ -686,7 +695,8 @@ mod tests { }); let test = |expr: &str, is_ok: bool, exp: Value| { - let obs = evaluator.eval_in_context(&expr, context.clone()); + let parser = Parser::new(); + let obs = evaluator.eval_in_context(&parser, &expr, context.clone()); if !is_ok { assert!(obs.is_err()); assert!(matches!( @@ -791,6 +801,7 @@ mod tests { #[test] fn test_filter_collections_many_returned() { let evaluator = Evaluator::new(); + let parser = Parser::new(); let context = value!({ "foo": [ {"bobo": 50, "fofo": 100}, @@ -801,7 +812,7 @@ mod tests { }); let exp = "foo[.bobo >= 50]"; assert_eq!( - evaluator.eval_in_context(exp, context).unwrap(), + evaluator.eval_in_context(&parser, exp, context).unwrap(), value!([{"bobo": 50, "fofo": 100}, {"bobo": 60, "baz": 90}]) ); } @@ -809,6 +820,7 @@ mod tests { #[test] fn test_binary_op_eq_ne() { let evaluator = Evaluator::new(); + let parser = Parser::new(); let context = value!({ "NULL": null, "STRING": "string", @@ -821,13 +833,13 @@ mod tests { let test = |l: &str, r: &str, exp: bool| { let expr = format!("{} == {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(exp) ); let expr = format!("{} != {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(!exp) ); }; @@ -887,6 +899,7 @@ mod tests { #[test] fn test_binary_op_string_gt_lt_gte_lte() { let evaluator = Evaluator::new(); + let parser = Parser::new(); let context = value!({ "A": "A string", "B": "B string", @@ -895,20 +908,20 @@ mod tests { let test = |l: &str, r: &str, is_gt: bool| { let expr = format!("{} > {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(is_gt) ); let expr = format!("{} <= {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(!is_gt) ); // we test equality in another test let expr = format!("{} == {}", l, r); let is_eq = evaluator - .eval_in_context(&expr, context.clone()) + .eval_in_context(&parser, &expr, context.clone()) .unwrap() .as_bool() .unwrap(); @@ -916,13 +929,13 @@ mod tests { if is_eq { let expr = format!("{} >= {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(true) ); } else { let expr = format!("{} < {}", l, r); assert_eq!( - evaluator.eval_in_context(&expr, context.clone()).unwrap(), + evaluator.eval_in_context(&parser, &expr, context.clone()).unwrap(), value!(!is_gt) ); }