@@ -615,7 +615,8 @@ class ParserVisitor final : public CelBaseVisitor,
615615 bool add_macro_calls = false ,
616616 bool enable_optional_syntax = false ,
617617 bool enable_quoted_identifiers = false ,
618- bool enable_variadic_logical_operators = false )
618+ bool enable_variadic_logical_operators = false ,
619+ bool fold_unary_operators = false )
619620 : source_(source),
620621 factory_ (source_, max_expression_node_count),
621622 macro_registry_(macro_registry),
@@ -624,7 +625,8 @@ class ParserVisitor final : public CelBaseVisitor,
624625 add_macro_calls_(add_macro_calls),
625626 enable_optional_syntax_(enable_optional_syntax),
626627 enable_quoted_identifiers_(enable_quoted_identifiers),
627- enable_variadic_logical_operators_(enable_variadic_logical_operators) {}
628+ enable_variadic_logical_operators_(enable_variadic_logical_operators),
629+ fold_unary_operators_(fold_unary_operators) {}
628630
629631 ~ParserVisitor () override = default ;
630632
@@ -700,6 +702,9 @@ class ParserVisitor final : public CelBaseVisitor,
700702 const Expr& e);
701703
702704 std::string NormalizeIdentifier (CelParser::EscapeIdentContext* ctx);
705+ std::any VisitUnaryOps (const std::vector<antlr4::Token*>& ops,
706+ CelParser::MemberContext* member,
707+ absl::string_view op_name);
703708 // Attempt to unnest parse context.
704709 //
705710 // Walk the parse tree to the first complex term to reduce recursive depth in
@@ -716,6 +721,7 @@ class ParserVisitor final : public CelBaseVisitor,
716721 const bool enable_optional_syntax_;
717722 const bool enable_quoted_identifiers_;
718723 const bool enable_variadic_logical_operators_;
724+ const bool fold_unary_operators_;
719725};
720726
721727template <typename T, typename = std::enable_if_t <
@@ -989,24 +995,37 @@ std::any ParserVisitor::visitUnary(CelParser::UnaryContext* ctx) {
989995 factory_.NextId (SourceRangeFromParserRuleContext (ctx)), " <<error>>" ));
990996}
991997
992- std::any ParserVisitor::visitLogicalNot (CelParser::LogicalNotContext* ctx) {
993- if (ctx->ops .size () % 2 == 0 ) {
994- return visit (ctx->member ());
998+ std::any ParserVisitor::VisitUnaryOps (const std::vector<antlr4::Token*>& ops,
999+ CelParser::MemberContext* member,
1000+ absl::string_view op_name) {
1001+ if (fold_unary_operators_) {
1002+ if (ops.size () % 2 == 0 ) {
1003+ return visit (member);
1004+ }
1005+ int64_t op_id = factory_.NextId (SourceRangeFromToken (ops[0 ]));
1006+ auto target = ExprFromAny (visit (member));
1007+ return ExprToAny (GlobalCallOrMacro (op_id, op_name, std::move (target)));
9951008 }
996- int64_t op_id = factory_.NextId (SourceRangeFromToken (ctx->ops [0 ]));
997- auto target = ExprFromAny (visit (ctx->member ()));
998- return ExprToAny (
999- GlobalCallOrMacro (op_id, CelOperator::LOGICAL_NOT , std::move (target)));
1009+
1010+ std::vector<int64_t > op_ids;
1011+ op_ids.reserve (ops.size ());
1012+ for (const auto * op : ops) {
1013+ op_ids.push_back (factory_.NextId (SourceRangeFromToken (op)));
1014+ }
1015+
1016+ auto target = ExprFromAny (visit (member));
1017+ for (int i = static_cast <int >(op_ids.size ()) - 1 ; i >= 0 ; --i) {
1018+ target = GlobalCallOrMacro (op_ids[i], op_name, std::move (target));
1019+ }
1020+ return ExprToAny (std::move (target));
1021+ }
1022+
1023+ std::any ParserVisitor::visitLogicalNot (CelParser::LogicalNotContext* ctx) {
1024+ return VisitUnaryOps (ctx->ops , ctx->member (), CelOperator::LOGICAL_NOT );
10001025}
10011026
10021027std::any ParserVisitor::visitNegate (CelParser::NegateContext* ctx) {
1003- if (ctx->ops .size () % 2 == 0 ) {
1004- return visit (ctx->member ());
1005- }
1006- int64_t op_id = factory_.NextId (SourceRangeFromToken (ctx->ops [0 ]));
1007- auto target = ExprFromAny (visit (ctx->member ()));
1008- return ExprToAny (
1009- GlobalCallOrMacro (op_id, CelOperator::NEGATE , std::move (target)));
1028+ return VisitUnaryOps (ctx->ops , ctx->member (), CelOperator::NEGATE );
10101029}
10111030
10121031std::string ParserVisitor::NormalizeIdentifier (
@@ -1684,7 +1703,8 @@ absl::StatusOr<std::unique_ptr<cel::Ast>> AntlrParseImpl(
16841703 source, options.max_recursion_depth , options.expression_node_limit ,
16851704 registry, options.add_macro_calls , options.enable_optional_syntax ,
16861705 options.enable_quoted_identifiers ,
1687- options.enable_variadic_logical_operators );
1706+ options.enable_variadic_logical_operators ,
1707+ options.fold_unary_operators );
16881708
16891709 lexer.removeErrorListeners ();
16901710 parser.removeErrorListeners ();
0 commit comments