diff --git a/eval/compiler/BUILD b/eval/compiler/BUILD index 8d9a5aa3b..a8fe79b56 100644 --- a/eval/compiler/BUILD +++ b/eval/compiler/BUILD @@ -204,6 +204,11 @@ cc_test( ":cel_expression_builder_flat_impl", ":comprehension_vulnerability_check", ":flat_expr_builder", + "//base:ast", + "//common:source", + "//common:value", + "//common:value_testing", + "//eval/eval:evaluator_core", "//eval/public:activation", "//eval/public:builtin_func_registrar", "//eval/public:cel_attribute", @@ -213,10 +218,15 @@ cc_test( "//eval/public/containers:container_backed_list_impl", "//eval/public/testing:matchers", "//eval/testutil:test_message_cc_proto", + "//extensions:bindings_ext", "//internal:testing", "//parser", + "//parser:parser_interface", + "//runtime:activation", "//runtime:runtime_options", + "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", + "//testutil:test_macros", "@com_google_absl//absl/status", "@com_google_absl//absl/strings", "@com_google_cel_spec//proto/cel/expr:syntax_cc_proto", diff --git a/eval/compiler/constant_folding.cc b/eval/compiler/constant_folding.cc index fb58d7d48..4a8d55c31 100644 --- a/eval/compiler/constant_folding.cc +++ b/eval/compiler/constant_folding.cc @@ -75,8 +75,9 @@ class ConstantFoldingExtension : public ProgramOptimizer { const TypeProvider& type_provider) : shared_arena_(std::move(shared_arena)), shared_message_factory_(std::move(shared_message_factory)), - state_(kDefaultStackLimit, kComprehensionSlotCount, type_provider, - descriptor_pool, message_factory, arena) {} + state_(kDefaultStackLimit, kComprehensionSlotCount, + /*iterator_stack_size=*/0, type_provider, descriptor_pool, + message_factory, arena) {} absl::Status OnPreVisit(google::api::expr::runtime::PlannerContext& context, const Expr& node) override; diff --git a/eval/compiler/flat_expr_builder.cc b/eval/compiler/flat_expr_builder.cc index f0920bf18..8228764a4 100644 --- a/eval/compiler/flat_expr_builder.cc +++ b/eval/compiler/flat_expr_builder.cc @@ -105,7 +105,12 @@ class FlatExprVisitor; // Helper for bookkeeping variables mapped to indexes. class IndexManager { public: - IndexManager() : next_free_slot_(0), max_slot_count_(0) {} + IndexManager() + : next_free_slot_(0), + max_slot_count_(0), + iter_stack_count_(0), + max_iter_stack_count_(0), + lazy_iter_stack_count_(0) {} size_t ReserveSlots(size_t n) { size_t result = next_free_slot_; @@ -121,11 +126,30 @@ class IndexManager { return next_free_slot_; } + void ReserveIterStack() { + ++iter_stack_count_; + max_iter_stack_count_ = std::max(max_iter_stack_count_, iter_stack_count_); + } + void ReleaseIterStack() { --iter_stack_count_; } + void AddLazyIterStack() { ++lazy_iter_stack_count_; } + size_t max_slot_count() const { return max_slot_count_; } + // Returns the maximum number of iterator stack slots required to evaluate the + // expression by tracking the maximum comprehension nesting in the main + // expression and dedicating a slot for any comprehensions evaluated lazily. + // This is not as tight as possible, but is a correct upper bound estimate and + // is tight for small expressions. + size_t IterStackRequirement() const { + return max_iter_stack_count_ + lazy_iter_stack_count_; + } + private: size_t next_free_slot_; size_t max_slot_count_; + size_t iter_stack_count_; + size_t max_iter_stack_count_; + size_t lazy_iter_stack_count_; }; // Helper for computing jump offsets. @@ -1145,21 +1169,36 @@ class FlatExprVisitor : public cel::AstVisitor { slot_count = 0; } } + // If this is in the scope of an optimized bind accu-init, account the slots // to the outermost bind-init scope. // // The init expression is effectively inlined at the first usage in the // critical path (which is unknown at plan time), so the used slots need to // be dedicated for the entire scope of that bind. + bool in_bind_init = false; for (ComprehensionStackRecord& record : comprehension_stack_) { if (record.in_accu_init && record.is_optimizable_bind) { record.slot_count += slot_count; slot_count = 0; + in_bind_init = true; break; } // If no bind init subexpression, account normally. } + // Iterator frames are releasable if not in a bind (no iterator push), and + // not in a lazy subexpression (which may evaluate in different implicit + // scopes). + const bool is_stack_releasable = + !is_bind && !in_bind_init && (!block_.has_value() || !block_->in); + + if (is_stack_releasable) { + index_manager_.ReserveIterStack(); + } else if (!is_bind) { + index_manager_.AddLazyIterStack(); + } + comprehension_stack_.push_back( {&expr, &comprehension, iter_slot, iter2_slot, accu_slot, slot_count, /*subexpression=*/-1, @@ -1172,6 +1211,7 @@ class FlatExprVisitor : public cel::AstVisitor { options_.enable_comprehension_mutable_map, options_.short_circuiting), /*.is_optimizable_bind=*/is_bind, + /*.is_stack_releasable=*/is_stack_releasable, /*.iter_var_in_scope=*/false, /*.iter_var2_in_scope=*/false, /*.accu_var_in_scope=*/false, @@ -1198,6 +1238,10 @@ class FlatExprVisitor : public cel::AstVisitor { record.visitor->PostVisit(&expr); index_manager_.ReleaseSlots(record.slot_count); + if (record.is_stack_releasable) { + ABSL_DCHECK(!record.is_optimizable_bind); + index_manager_.ReleaseIterStack(); + } comprehension_stack_.pop_back(); } @@ -1499,6 +1543,10 @@ class FlatExprVisitor : public cel::AstVisitor { size_t slot_count() const { return index_manager_.max_slot_count(); } + size_t iter_stack_count() const { + return index_manager_.IterStackRequirement(); + } + void AddOptimizer(std::unique_ptr optimizer) { program_optimizers_.push_back(std::move(optimizer)); } @@ -1530,6 +1578,7 @@ class FlatExprVisitor : public cel::AstVisitor { bool is_optimizable_list_append; bool is_optimizable_map_insert; bool is_optimizable_bind; + bool is_stack_releasable; bool iter_var_in_scope; bool iter_var2_in_scope; bool accu_var_in_scope; @@ -2298,8 +2347,8 @@ absl::StatusOr FlatExprBuilder::CreateExpressionImpl( FlattenExpressionTable(program_builder, execution_path); return FlatExpression(std::move(execution_path), std::move(subexpressions), - visitor.slot_count(), GetTypeProvider(), options_, - std::move(arena)); + visitor.slot_count(), visitor.iter_stack_count(), + GetTypeProvider(), options_, std::move(arena)); } const cel::TypeProvider& FlatExprBuilder::GetTypeProvider() const { return use_legacy_type_provider_ diff --git a/eval/compiler/flat_expr_builder_comprehensions_test.cc b/eval/compiler/flat_expr_builder_comprehensions_test.cc index ed0f67912..df60a456d 100644 --- a/eval/compiler/flat_expr_builder_comprehensions_test.cc +++ b/eval/compiler/flat_expr_builder_comprehensions_test.cc @@ -14,15 +14,22 @@ * limitations under the License. */ +#include +#include #include #include "cel/expr/syntax.pb.h" #include "google/protobuf/field_mask.pb.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" +#include "base/ast.h" +#include "common/source.h" +#include "common/value.h" +#include "common/value_testing.h" #include "eval/compiler/cel_expression_builder_flat_impl.h" #include "eval/compiler/comprehension_vulnerability_check.h" #include "eval/compiler/flat_expr_builder.h" +#include "eval/eval/evaluator_core.h" #include "eval/public/activation.h" #include "eval/public/builtin_func_registrar.h" #include "eval/public/cel_attribute.h" @@ -32,10 +39,15 @@ #include "eval/public/containers/container_backed_list_impl.h" #include "eval/public/testing/matchers.h" #include "eval/testutil/test_message.pb.h" +#include "extensions/bindings_ext.h" #include "internal/testing.h" #include "parser/parser.h" +#include "parser/parser_interface.h" +#include "runtime/activation.h" +#include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" #include "runtime/runtime_options.h" +#include "testutil/test_macros.h" #include "google/protobuf/arena.h" #include "google/protobuf/text_format.h" @@ -623,6 +635,119 @@ TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("Unexpected iter_var access in trivial comprehension"))); } +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, + BindInsideComprehensionWithComprehensionInInitIterStackCount) { + std::unique_ptr parser_builder = cel::NewParserBuilder(); + ASSERT_THAT( + parser_builder->AddLibrary(cel::extensions::BindingsParserLibrary()), + IsOk()); + ASSERT_OK_AND_ASSIGN(std::unique_ptr parser, + parser_builder->Build()); + + ASSERT_OK_AND_ASSIGN( + std::unique_ptr source, + parser->PrepareSource( + "[[1, 2], [3, 4]].map(l, cel.bind(filtered, l.filter(x, x > 1), " + "size(filtered) > 0 ? filtered[0] : 0)) == [2, 3]")); + ASSERT_OK_AND_ASSIGN(std::unique_ptr ast, parser->Parse(*source)); + + cel::RuntimeOptions options = GetRuntimeOptions(); + std::shared_ptr env = + NewTestingRuntimeEnv(); + CelExpressionBuilderFlatImpl builder(env, options); + ASSERT_THAT(RegisterBuiltinFunctions(builder.GetRegistry()), IsOk()); + + ASSERT_OK_AND_ASSIGN( + FlatExpression flat_expr, + builder.flat_expr_builder().CreateExpressionImpl(std::move(ast), + /*issues=*/nullptr)); + EXPECT_EQ(flat_expr.iterator_stack_size(), 2); + + cel::Activation activation; + google::protobuf::Arena arena; + FlatExpressionEvaluatorState state = flat_expr.MakeEvaluatorState( + env->descriptor_pool.get(), env->MutableMessageFactory(), &arena); + ASSERT_OK_AND_ASSIGN( + cel::Value result, + flat_expr.EvaluateWithCallback(activation, /*embedder_context=*/nullptr, + EvaluationListener(), state)); + EXPECT_THAT(result, cel::test::BoolValueIs(true)); +} + +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, + BlockWithComprehensionInBindingAndBodyIterStackCount) { + std::unique_ptr parser_builder = cel::NewParserBuilder(); + ASSERT_THAT(parser_builder->AddLibrary(cel::test::TestMacrosParserLibrary()), + IsOk()); + ASSERT_OK_AND_ASSIGN(std::unique_ptr parser, + parser_builder->Build()); + + ASSERT_OK_AND_ASSIGN( + std::unique_ptr source, + parser->PrepareSource( + "cel.block([[1, 2, 3].filter(x, x > 1), [1, 2, 3].filter(x, x < 3)], " + "[1, 2].map(y, y in cel.index(0) || y in cel.index(1))) == [true, " + "true]")); + ASSERT_OK_AND_ASSIGN(std::unique_ptr ast, parser->Parse(*source)); + + cel::RuntimeOptions options = GetRuntimeOptions(); + std::shared_ptr env = + NewTestingRuntimeEnv(); + CelExpressionBuilderFlatImpl builder(env, options); + ASSERT_THAT(RegisterBuiltinFunctions(builder.GetRegistry()), IsOk()); + + ASSERT_OK_AND_ASSIGN( + FlatExpression flat_expr, + builder.flat_expr_builder().CreateExpressionImpl(std::move(ast), + /*issues=*/nullptr)); + EXPECT_EQ(flat_expr.iterator_stack_size(), 3); + + cel::Activation activation; + google::protobuf::Arena arena; + FlatExpressionEvaluatorState state = flat_expr.MakeEvaluatorState( + env->descriptor_pool.get(), env->MutableMessageFactory(), &arena); + ASSERT_OK_AND_ASSIGN( + cel::Value result, + flat_expr.EvaluateWithCallback(activation, /*embedder_context=*/nullptr, + EvaluationListener(), state)); + EXPECT_THAT(result, cel::test::BoolValueIs(true)); +} + +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, + NonNestedComprehensionsIterStackCount) { + std::unique_ptr parser_builder = cel::NewParserBuilder(); + ASSERT_OK_AND_ASSIGN(std::unique_ptr parser, + parser_builder->Build()); + + ASSERT_OK_AND_ASSIGN( + std::unique_ptr source, + parser->PrepareSource( + "[1, 2].map(x, x + 1) + [3, 4].filter(y, y > 3) == [2, 3, 4]")); + ASSERT_OK_AND_ASSIGN(std::unique_ptr ast, parser->Parse(*source)); + + cel::RuntimeOptions options = GetRuntimeOptions(); + std::shared_ptr env = + NewTestingRuntimeEnv(); + CelExpressionBuilderFlatImpl builder(env, options); + ASSERT_THAT(RegisterBuiltinFunctions(builder.GetRegistry()), IsOk()); + + ASSERT_OK_AND_ASSIGN( + FlatExpression flat_expr, + builder.flat_expr_builder().CreateExpressionImpl(std::move(ast), + /*issues=*/nullptr)); + EXPECT_EQ(flat_expr.iterator_stack_size(), 1); + + cel::Activation activation; + google::protobuf::Arena arena; + FlatExpressionEvaluatorState state = flat_expr.MakeEvaluatorState( + env->descriptor_pool.get(), env->MutableMessageFactory(), &arena); + ASSERT_OK_AND_ASSIGN( + cel::Value result, + flat_expr.EvaluateWithCallback(activation, /*embedder_context=*/nullptr, + EvaluationListener(), state)); + EXPECT_THAT(result, cel::test::BoolValueIs(true)); +} + } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/BUILD b/eval/eval/BUILD index 4bb06c7b8..b477b35f7 100644 --- a/eval/eval/BUILD +++ b/eval/eval/BUILD @@ -927,6 +927,7 @@ cc_library( deps = [ "//common:value", "@com_google_absl//absl/base:nullability", + "@com_google_absl//absl/container:inlined_vector", "@com_google_absl//absl/log:absl_check", ], ) diff --git a/eval/eval/equality_steps_test.cc b/eval/eval/equality_steps_test.cc index 4ebfe10ef..50970ca44 100644 --- a/eval/eval/equality_steps_test.cc +++ b/eval/eval/equality_steps_test.cc @@ -81,7 +81,7 @@ TEST(IterativeTest, PartialAttrUnknown) { FlatExpressionEvaluatorState state( /*value_stack_size=*/5, - /*comprehension_slot_count=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); @@ -113,7 +113,7 @@ TEST(IterativeTest, PartialAttrUnknownDisabled) { FlatExpressionEvaluatorState state( /*value_stack_size=*/5, - /*comprehension_slot_count=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); @@ -183,7 +183,7 @@ TEST_P(EqualsTest, Iterative) { FlatExpressionEvaluatorState state( /*value_stack_size=*/5, - /*comprehension_slot_count=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); @@ -328,7 +328,7 @@ TEST_P(InTest, Iterative) { FlatExpressionEvaluatorState state( /*value_stack_size=*/5, - /*comprehension_slot_count=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); diff --git a/eval/eval/evaluator_core.cc b/eval/eval/evaluator_core.cc index cbc47d136..2fc6eda93 100644 --- a/eval/eval/evaluator_core.cc +++ b/eval/eval/evaluator_core.cc @@ -222,16 +222,16 @@ FlatExpressionEvaluatorState FlatExpression::MakeEvaluatorState( google::protobuf::MessageFactory* absl_nonnull message_factory, google::protobuf::Arena* absl_nonnull arena) const { return FlatExpressionEvaluatorState(path_.size(), comprehension_slots_size_, - type_provider_, descriptor_pool, - message_factory, arena); + iterator_stack_size_, type_provider_, + descriptor_pool, message_factory, arena); } FlatExpressionEvaluatorState FlatExpression::MakeEvaluatorState( const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, google::protobuf::MessageFactory* absl_nullable message_factory) const { return FlatExpressionEvaluatorState(path_.size(), comprehension_slots_size_, - type_provider_, descriptor_pool, - message_factory); + iterator_stack_size_, type_provider_, + descriptor_pool, message_factory); } absl::StatusOr FlatExpression::EvaluateWithCallback( diff --git a/eval/eval/evaluator_core.h b/eval/eval/evaluator_core.h index e415487c3..b389c38a6 100644 --- a/eval/eval/evaluator_core.h +++ b/eval/eval/evaluator_core.h @@ -450,14 +450,11 @@ class FlatExpressionEvaluatorState { public: FlatExpressionEvaluatorState( size_t value_stack_size, size_t comprehension_slot_count, - const cel::TypeProvider& type_provider, + size_t iterator_stack_size, const cel::TypeProvider& type_provider, const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, google::protobuf::MessageFactory* absl_nullable message_factory = nullptr) : value_stack_(value_stack_size), - // We currently use comprehension_slot_count because it is less of an - // over estimate than value_stack_size. In future we should just - // calculate the correct capacity. - iterator_stack_(comprehension_slot_count), + iterator_stack_(iterator_stack_size), comprehension_slots_(comprehension_slot_count), type_provider_(type_provider), descriptor_pool_(descriptor_pool), @@ -465,15 +462,12 @@ class FlatExpressionEvaluatorState { FlatExpressionEvaluatorState( size_t value_stack_size, size_t comprehension_slot_count, - const cel::TypeProvider& type_provider, + size_t iterator_stack_size, const cel::TypeProvider& type_provider, const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, google::protobuf::MessageFactory* absl_nonnull message_factory, google::protobuf::Arena* absl_nonnull arena) : value_stack_(value_stack_size), - // We currently use comprehension_slot_count because it is less of an - // over estimate than value_stack_size. In future we should just - // calculate the correct capacity. - iterator_stack_(comprehension_slot_count), + iterator_stack_(iterator_stack_size), comprehension_slots_(comprehension_slot_count), type_provider_(type_provider), descriptor_pool_(descriptor_pool), @@ -879,19 +873,21 @@ class FlatExpression { : path_(std::move(path)), subexpressions_({path_}), comprehension_slots_size_(comprehension_slots_size), + iterator_stack_size_(comprehension_slots_size), type_provider_(type_provider), options_(options), arena_(std::move(arena)) {} FlatExpression(ExecutionPath path, std::vector subexpressions, - size_t comprehension_slots_size, + size_t comprehension_slots_size, size_t iterator_stack_size, const cel::TypeProvider& type_provider, const cel::RuntimeOptions& options, absl_nullable std::shared_ptr arena = nullptr) : path_(std::move(path)), subexpressions_(std::move(subexpressions)), comprehension_slots_size_(comprehension_slots_size), + iterator_stack_size_(iterator_stack_size), type_provider_(type_provider), options_(options), arena_(std::move(arena)) {} @@ -934,12 +930,15 @@ class FlatExpression { size_t comprehension_slots_size() const { return comprehension_slots_size_; } + size_t iterator_stack_size() const { return iterator_stack_size_; } + const cel::TypeProvider& type_provider() const { return type_provider_; } private: ExecutionPath path_; std::vector subexpressions_; size_t comprehension_slots_size_; + size_t iterator_stack_size_; const cel::TypeProvider& type_provider_; cel::RuntimeOptions options_; // Arena used during planning phase, may hold constant values so should be diff --git a/eval/eval/evaluator_core_test.cc b/eval/eval/evaluator_core_test.cc index c67dc8b58..1f43f3f35 100644 --- a/eval/eval/evaluator_core_test.cc +++ b/eval/eval/evaluator_core_test.cc @@ -84,7 +84,7 @@ TEST(EvaluatorCoreTest, ExecutionFrameNext) { cel::Activation activation; FlatExpressionEvaluatorState state( path.size(), - /*comprehension_slots_size=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); ExecutionFrame frame(path, activation, options, state); @@ -111,7 +111,7 @@ TEST(EvaluatorCoreTest, JumpOutOfRangeAborts) { cel::Activation activation; FlatExpressionEvaluatorState state( path.size(), - /*comprehension_slots_size=*/0, type_provider, + /*comprehension_slot_count=*/0, /*iterator_stack_size=*/0, type_provider, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena); ExecutionFrame frame(path, activation, options, state); diff --git a/eval/eval/iterator_stack.h b/eval/eval/iterator_stack.h index 0b0de14aa..ccb377dd3 100644 --- a/eval/eval/iterator_stack.h +++ b/eval/eval/iterator_stack.h @@ -20,6 +20,7 @@ #include #include "absl/base/nullability.h" +#include "absl/container/inlined_vector.h" #include "absl/log/absl_check.h" #include "common/value.h" @@ -92,7 +93,7 @@ class IteratorStack final { } private: - std::vector entries_; + absl::InlinedVector entries_; size_t max_size_; }; diff --git a/eval/eval/lazy_init_step_test.cc b/eval/eval/lazy_init_step_test.cc index 3b5282d21..d7211e597 100644 --- a/eval/eval/lazy_init_step_test.cc +++ b/eval/eval/lazy_init_step_test.cc @@ -46,7 +46,8 @@ class LazyInitStepTest : public testing::Test { public: LazyInitStepTest() : type_provider_(cel::internal::GetTestingDescriptorPool()), - evaluator_state_(kValueStack, kComprehensionSlotCount, type_provider_, + evaluator_state_(kValueStack, kComprehensionSlotCount, + /*iterator_stack_size=*/0, type_provider_, cel::internal::GetTestingDescriptorPool(), cel::internal::GetTestingMessageFactory(), &arena_) {} diff --git a/extensions/bindings_ext.cc b/extensions/bindings_ext.cc index 4823c077c..b9a80d493 100644 --- a/extensions/bindings_ext.cc +++ b/extensions/bindings_ext.cc @@ -100,4 +100,8 @@ CheckerLibrary BindingsCheckerLibrary(int version) { }}; } +ParserLibrary BindingsParserLibrary() { + return ParserLibrary{"cel.lib.ext.bindings", &ConfigureParser}; +} + } // namespace cel::extensions diff --git a/extensions/bindings_ext.h b/extensions/bindings_ext.h index 40b83a37f..5f54abf25 100644 --- a/extensions/bindings_ext.h +++ b/extensions/bindings_ext.h @@ -22,6 +22,7 @@ #include "parser/macro.h" #include "parser/macro_registry.h" #include "parser/options.h" +#include "parser/parser_interface.h" namespace cel::extensions { @@ -41,6 +42,9 @@ CompilerLibrary BindingsCompilerLibrary(int version = kBindingsVersionLatest); // Declarations for the bindings extension library. CheckerLibrary BindingsCheckerLibrary(int version = kBindingsVersionLatest); +// Macros for the bindings extension library. +ParserLibrary BindingsParserLibrary(); + } // namespace cel::extensions #endif // THIRD_PARTY_CEL_CPP_EXTENSIONS_BINDINGS_EXT_H_ diff --git a/testutil/BUILD b/testutil/BUILD index a8bc214c9..6574db5d5 100644 --- a/testutil/BUILD +++ b/testutil/BUILD @@ -42,6 +42,7 @@ cc_library( "//parser:macro", "//parser:macro_expr_factory", "//parser:macro_registry", + "//parser:parser_interface", "@com_google_absl//absl/base:no_destructor", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/status", diff --git a/testutil/test_macros.cc b/testutil/test_macros.cc index 19e9a4844..30b94280d 100644 --- a/testutil/test_macros.cc +++ b/testutil/test_macros.cc @@ -15,19 +15,20 @@ #include "testutil/test_macros.h" #include +#include #include #include "absl/base/no_destructor.h" #include "absl/log/absl_check.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" -#include "absl/types/optional.h" #include "absl/types/span.h" #include "common/expr.h" #include "internal/status_macros.h" #include "parser/macro.h" #include "parser/macro_expr_factory.h" #include "parser/macro_registry.h" +#include "parser/parser_interface.h" namespace cel::test { @@ -170,4 +171,17 @@ absl::Status RegisterTestMacros(MacroRegistry& registry) { return absl::OkStatus(); } +ParserLibrary TestMacrosParserLibrary() { + return ParserLibrary{ + "cel.test.test_macros", + [](ParserBuilder& builder) -> absl::Status { + CEL_RETURN_IF_ERROR(builder.AddMacro(CelBlockMacro())); + CEL_RETURN_IF_ERROR(builder.AddMacro(CelIndexMacro())); + CEL_RETURN_IF_ERROR(builder.AddMacro(CelIterVarMacro())); + CEL_RETURN_IF_ERROR(builder.AddMacro(CelAccuVarMacro())); + return absl::OkStatus(); + }, + }; +} + } // namespace cel::test diff --git a/testutil/test_macros.h b/testutil/test_macros.h index cad897999..cc988ceb1 100644 --- a/testutil/test_macros.h +++ b/testutil/test_macros.h @@ -18,6 +18,7 @@ #include "absl/status/status.h" #include "parser/macro.h" #include "parser/macro_registry.h" +#include "parser/parser_interface.h" namespace cel::test { @@ -28,6 +29,8 @@ const Macro& CelAccuVarMacro(); absl::Status RegisterTestMacros(MacroRegistry& registry); +ParserLibrary TestMacrosParserLibrary(); + } // namespace cel::test #endif // THIRD_PARTY_CEL_CPP_TESTUTIL_TEST_MACROS_H_