From fcad3d5b36e936d6587c0856f717e94debf8cca1 Mon Sep 17 00:00:00 2001 From: Justin King Date: Thu, 8 Oct 2026 15:41:07 -0700 Subject: [PATCH] Remove recursive evaluation PiperOrigin-RevId: 996115495 --- conformance/BUILD | 4 +- conformance/run.bzl | 45 +- conformance/run.cc | 4 - eval/compiler/BUILD | 33 +- .../cel_expression_builder_flat_impl.cc | 15 - .../cel_expression_builder_flat_impl_test.cc | 117 +--- eval/compiler/constant_folding.cc | 14 - eval/compiler/flat_expr_builder.cc | 497 ---------------- .../flat_expr_builder_comprehensions_test.cc | 43 +- eval/compiler/flat_expr_builder_extensions.cc | 105 ---- eval/compiler/flat_expr_builder_extensions.h | 70 +-- .../flat_expr_builder_extensions_test.cc | 58 +- eval/compiler/flat_expr_builder_test.cc | 142 +---- eval/compiler/qualified_reference_resolver.cc | 2 +- .../regex_precompilation_optimization.cc | 37 -- eval/eval/BUILD | 221 +------ eval/eval/cel_expression_flat_impl.cc | 63 -- eval/eval/cel_expression_flat_impl.h | 81 --- eval/eval/compiler_constant_step.cc | 31 - eval/eval/compiler_constant_step.h | 52 -- eval/eval/compiler_constant_step_test.cc | 73 --- eval/eval/comprehension_step.cc | 386 ------------ eval/eval/comprehension_step.h | 14 - eval/eval/comprehension_step_test.cc | 319 ---------- eval/eval/const_value_step.h | 23 - eval/eval/container_access_step.cc | 50 +- eval/eval/container_access_step.h | 9 +- eval/eval/container_access_step_test.cc | 12 +- eval/eval/create_list_step.cc | 124 +--- eval/eval/create_list_step.h | 18 +- eval/eval/create_list_step_test.cc | 302 +--------- eval/eval/create_map_step.cc | 137 +---- eval/eval/create_map_step.h | 19 +- eval/eval/create_map_step_test.cc | 35 +- eval/eval/create_struct_step.cc | 120 +--- eval/eval/create_struct_step.h | 10 +- eval/eval/create_struct_step_test.cc | 40 +- eval/eval/direct_expression_step.cc | 20 - eval/eval/direct_expression_step.h | 82 --- eval/eval/equality_steps.cc | 78 +-- eval/eval/equality_steps.h | 15 - eval/eval/equality_steps_test.cc | 143 +---- eval/eval/evaluator_core.cc | 16 - eval/eval/evaluator_core.h | 21 - eval/eval/function_step.cc | 95 --- eval/eval/function_step.h | 17 - eval/eval/function_step_test.cc | 193 ------ eval/eval/ident_step.cc | 65 --- eval/eval/ident_step.h | 12 - eval/eval/ident_step_test.cc | 114 ---- eval/eval/lazy_init_step.cc | 109 ---- eval/eval/lazy_init_step.h | 21 - eval/eval/logic_step.cc | 274 --------- eval/eval/logic_step.h | 24 - eval/eval/logic_step_test.cc | 379 ------------ eval/eval/optional_or_step.cc | 108 ---- eval/eval/optional_or_step.h | 11 +- eval/eval/optional_or_step_test.cc | 383 ------------ eval/eval/regex_match_step.cc | 45 +- eval/eval/regex_match_step.h | 8 +- eval/eval/regex_match_step_test.cc | 1 - eval/eval/select_step.cc | 121 +--- eval/eval/select_step.h | 10 +- eval/eval/select_step_test.cc | 552 ------------------ eval/eval/shadowable_value_step.cc | 43 +- eval/eval/shadowable_value_step.h | 7 +- eval/eval/shadowable_value_step_test.cc | 6 +- eval/eval/ternary_step.cc | 117 +--- eval/eval/ternary_step.h | 12 +- eval/eval/ternary_step_test.cc | 194 +----- eval/eval/trace_step.h | 73 --- eval/public/BUILD | 3 - eval/public/cel_options.h | 8 +- extensions/BUILD | 2 - extensions/select_optimization.cc | 67 --- runtime/BUILD | 2 - runtime/internal/BUILD | 5 - runtime/internal/runtime_impl.cc | 76 --- runtime/internal/runtime_impl.h | 5 - runtime/optional_types_test.cc | 36 -- runtime/runtime_options.h | 8 +- .../standard_runtime_builder_factory_test.cc | 201 +------ 82 files changed, 108 insertions(+), 6999 deletions(-) delete mode 100644 eval/eval/compiler_constant_step.cc delete mode 100644 eval/eval/compiler_constant_step.h delete mode 100644 eval/eval/compiler_constant_step_test.cc delete mode 100644 eval/eval/const_value_step.h delete mode 100644 eval/eval/direct_expression_step.cc delete mode 100644 eval/eval/direct_expression_step.h delete mode 100644 eval/eval/optional_or_step_test.cc delete mode 100644 eval/eval/trace_step.h diff --git a/conformance/BUILD b/conformance/BUILD index b4ac3718f..a6bf15f6b 100644 --- a/conformance/BUILD +++ b/conformance/BUILD @@ -246,7 +246,7 @@ _TESTS_TO_SKIP_LEGACY_DASHBOARD = [ ] # Generates a bunch of `cc_test` whose names follow the pattern -# `conformance_(...)_{pratt|antlr}_{optimized|unoptimized}_{recursive|iterative}`. +# `conformance_(...)_{pratt|antlr}_{optimized|unoptimized}`. gen_conformance_tests( name = "conformance_parse_only", data = _ALL_TESTS, @@ -315,7 +315,7 @@ gen_conformance_tests( ) # Generates a bunch of `cc_test` whose names follow the pattern -# `conformance_dashboard_..._{pratt|antlr}_{optimized|unoptimized}_{recursive|iterative}`. +# `conformance_dashboard_..._{pratt|antlr}_{optimized|unoptimized}`. gen_conformance_tests( name = "conformance_dashboard_parse_only", dashboard = True, diff --git a/conformance/run.bzl b/conformance/run.bzl index 76b33efb3..9c4b315e5 100644 --- a/conformance/run.bzl +++ b/conformance/run.bzl @@ -47,17 +47,16 @@ def _expand_tests_to_skip(tests_to_skip): result.append(test_to_skip[0:slash] + part) return result -def _conformance_test_name(name, pratt, optimize, recursive): +def _conformance_test_name(name, pratt, optimize): return "_".join( [ name, "pratt" if pratt else "antlr", "optimized" if optimize else "unoptimized", - "recursive" if recursive else "iterative", ], ) -def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt): +def _conformance_test_args(modern, optimize, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt): args = [] if modern: args.append("--modern") @@ -65,8 +64,6 @@ def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, args.append("--opt") if select_opt: args.append("--select_optimization") - if recursive: - args.append("--recursive") if skip_check: args.append("--skip_check") else: @@ -81,10 +78,10 @@ def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, args.append("--noenable_pratt_parser") return args -def _conformance_test(name, data, modern, optimize, recursive, select_opt, skip_check, skip_tests, tags, dashboard, enable_variadic_logical_operators, pratt): +def _conformance_test(name, data, modern, optimize, select_opt, skip_check, skip_tests, tags, dashboard, enable_variadic_logical_operators, pratt): cc_test( - name = _conformance_test_name(name, pratt, optimize, recursive), - args = _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt) + ["$(rlocationpath {})".format(test) for test in data], + name = _conformance_test_name(name, pratt, optimize), + args = _conformance_test_args(modern, optimize, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt) + ["$(rlocationpath {})".format(test) for test in data], env = select( { "@platforms//os:windows": {"CEL_SKIP_TESTS": ",".join(skip_tests + _TESTS_TO_SKIP_WINDOWS)}, @@ -115,23 +112,21 @@ def gen_conformance_tests(name, data, modern = False, checked = False, select_op tests = [] for pratt in (True, False): for optimize in (True, False): - for recursive in (True, False): - test_name = _conformance_test_name(name, pratt, optimize, recursive) - tests.append(test_name) - _conformance_test( - name, - data, - modern = modern, - optimize = optimize, - recursive = recursive, - select_opt = select_opt, - skip_check = skip_check, - skip_tests = _expand_tests_to_skip(skip_tests), - tags = tags, - dashboard = dashboard, - enable_variadic_logical_operators = enable_variadic_logical_operators, - pratt = pratt, - ) + test_name = _conformance_test_name(name, pratt, optimize) + tests.append(test_name) + _conformance_test( + name, + data, + modern = modern, + optimize = optimize, + select_opt = select_opt, + skip_check = skip_check, + skip_tests = _expand_tests_to_skip(skip_tests), + tags = tags, + dashboard = dashboard, + enable_variadic_logical_operators = enable_variadic_logical_operators, + pratt = pratt, + ) native.test_suite( name = name, tests = tests, diff --git a/conformance/run.cc b/conformance/run.cc index 6b7bae071..72eeeb4dd 100644 --- a/conformance/run.cc +++ b/conformance/run.cc @@ -59,9 +59,6 @@ ABSL_FLAG(bool, opt, false, "Enable optimizations (constant folding)"); ABSL_FLAG( bool, modern, false, "Use modern cel::Value APIs implementation of the conformance service."); -ABSL_FLAG(bool, recursive, false, - "Enable recursive plans. Depth limited to slightly more than the " - "default nesting limit."); ABSL_FLAG(std::vector, skip_tests, {}, "Tests to skip"); ABSL_FLAG(bool, dashboard, false, "Dashboard mode, ignore test failures"); ABSL_FLAG(bool, skip_check, true, "Skip type checking the expressions"); @@ -264,7 +261,6 @@ NewConformanceServiceFromFlags() { cel_conformance::ConformanceServiceOptions{ .optimize = absl::GetFlag(FLAGS_opt), .modern = absl::GetFlag(FLAGS_modern), - .recursive = absl::GetFlag(FLAGS_recursive), .select_optimization = absl::GetFlag(FLAGS_select_optimization), .enable_variadic_logical_operators = absl::GetFlag(FLAGS_enable_variadic_logical_operators), diff --git a/eval/compiler/BUILD b/eval/compiler/BUILD index 89677776c..d75e6e50d 100644 --- a/eval/compiler/BUILD +++ b/eval/compiler/BUILD @@ -32,13 +32,9 @@ cc_library( "//base:ast", "//base:data", "//common:expr", - "//common:native_type", "//common:value", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", "//eval/eval:expression_step_logic", - "//eval/eval:trace_step", - "//internal:casts", "//runtime:runtime_options", "//runtime/internal:issue_collector", "//runtime/internal:runtime_env", @@ -51,7 +47,6 @@ cc_library( "@com_google_absl//absl/memory", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:variant", "@com_google_protobuf//:protobuf", ], @@ -64,13 +59,8 @@ cc_test( ":flat_expr_builder_extensions", ":resolver", "//common:expr", - "//common:native_type", - "//common:value", - "//eval/eval:const_value_step", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", - "//eval/eval:function_step", - "//internal:status_macros", + "//eval/eval:expression_step_logic", "//internal:testing", "//runtime:function_registry", "//runtime:runtime_issue", @@ -102,7 +92,6 @@ cc_library( "//base:ast", "//base:builtins", "//base:data", - "//common:allocator", "//common:ast", "//common:ast_traverse", "//common:ast_visitor", @@ -112,22 +101,16 @@ cc_library( "//common:type", "//common:type_spec_resolver", "//common:value", - "//eval/eval:const_value_step", "//eval/eval:container_access_step", "//eval/eval:create_list_step", "//eval/eval:create_map_step", "//eval/eval:create_struct_step", - "//eval/eval:direct_expression_step", - "//eval/eval:equality_steps", "//eval/eval:evaluator_core", "//eval/eval:expression_step_logic", - "//eval/eval:function_step", - "//eval/eval:ident_step", "//eval/eval:optional_or_step", "//eval/eval:select_step", "//eval/eval:shadowable_value_step", "//eval/eval:ternary_step", - "//eval/eval:trace_step", "//internal:status_macros", "//runtime:function_registry", "//runtime:runtime_issue", @@ -137,7 +120,6 @@ cc_library( "//runtime/internal:issue_collector", "//runtime/internal:runtime_env", "@com_google_absl//absl/algorithm:container", - "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", @@ -171,7 +153,6 @@ cc_test( "//eval/public:activation", "//eval/public:builtin_func_registrar", "//eval/public:cel_attribute", - "//eval/public:cel_builtins", "//eval/public:cel_expr_builder_factory", "//eval/public:cel_expression", "//eval/public:cel_function", @@ -197,7 +178,6 @@ cc_test( "//runtime:runtime_options", "//runtime:standard_functions", "//runtime/internal:runtime_env_testing", - "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/status", @@ -255,9 +235,7 @@ cc_library( deps = [ ":flat_expr_builder", "//base:ast", - "//common:native_type", "//eval/eval:cel_expression_flat_impl", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", "//eval/public:cel_expression", "//eval/public:cel_function_registry", @@ -286,9 +264,6 @@ cc_test( ], deps = [ ":cel_expression_builder_flat_impl", - ":constant_folding", - ":regex_precompilation_optimization", - "//eval/eval:cel_expression_flat_impl", "//eval/public:activation", "//eval/public:builtin_func_registrar", "//eval/public:cel_expression", @@ -297,7 +272,6 @@ cc_test( "//eval/public:portable_cel_function_adapter", "//eval/public/containers:container_backed_map_impl", "//eval/public/structs:cel_proto_wrapper", - "//eval/public/structs:protobuf_descriptor_type_provider", "//eval/public/testing:matchers", "//extensions:bindings_ext", "//internal:status_macros", @@ -334,12 +308,10 @@ cc_library( "//common:constant", "//common:expr", "//common:value", - "//eval/eval:const_value_step", "//eval/eval:evaluator_core", "//internal:status_macros", "//runtime:activation", "//runtime/internal:convert_constant", - "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", @@ -407,7 +379,6 @@ cc_library( "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:optional", ], ) @@ -547,8 +518,6 @@ cc_library( "//common:expr", "//common:native_type", "//common:value", - "//eval/eval:compiler_constant_step", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", "//eval/eval:regex_match_step", "//internal:re2_options", diff --git a/eval/compiler/cel_expression_builder_flat_impl.cc b/eval/compiler/cel_expression_builder_flat_impl.cc index 830b5ff1d..f519d9393 100644 --- a/eval/compiler/cel_expression_builder_flat_impl.cc +++ b/eval/compiler/cel_expression_builder_flat_impl.cc @@ -27,9 +27,7 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "base/ast.h" -#include "common/native_type.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/public/cel_expression.h" #include "extensions/protobuf/ast_converters.h" @@ -96,19 +94,6 @@ CelExpressionBuilderFlatImpl::CreateExpressionImpl( warnings->push_back(issue.ToStatus()); } } - if (flat_expr_builder_.options().max_recursion_depth != 0 && - !impl.subexpressions().empty() && - // mainline expression is exactly one recursive step. - impl.subexpressions().front().size() == 1 && - impl.subexpressions().front().front().IsGenericStep() && - impl.subexpressions() - .front() - .front() - .GetGenericStep() - ->GetNativeTypeId() == - cel::NativeTypeId::For()) { - return CelExpressionRecursiveImpl::Create(env_, std::move(impl)); - } return std::make_unique(env_, std::move(impl)); } diff --git a/eval/compiler/cel_expression_builder_flat_impl_test.cc b/eval/compiler/cel_expression_builder_flat_impl_test.cc index 9802d2a05..b48fbd959 100644 --- a/eval/compiler/cel_expression_builder_flat_impl_test.cc +++ b/eval/compiler/cel_expression_builder_flat_impl_test.cc @@ -30,9 +30,6 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" -#include "eval/compiler/constant_folding.h" -#include "eval/compiler/regex_precompilation_optimization.h" -#include "eval/eval/cel_expression_flat_impl.h" #include "eval/public/activation.h" #include "eval/public/builtin_func_registrar.h" #include "eval/public/cel_expression.h" @@ -72,8 +69,6 @@ using ::google::api::expr::parser::ParseWithMacros; using ::testing::_; using ::testing::Contains; using ::testing::HasSubstr; -using ::testing::IsNull; -using ::testing::NotNull; TEST(CelExpressionBuilderFlatImplTest, Error) { Expr expr; @@ -100,14 +95,14 @@ TEST(CelExpressionBuilderFlatImplTest, ParsedExpr) { EXPECT_THAT(result, test::IsCelInt64(3)); } -struct RecursiveTestCase { +struct TestCase { std::string test_name; std::string expr; test::CelValueMatcher matcher; std::string pb_expr; }; -class RecursivePlanTest : public ::testing::TestWithParam { +class PlanTest : public ::testing::TestWithParam { protected: absl::Status SetupBuilder(CelExpressionBuilderFlatImpl& builder) { builder.GetTypeRegistry()->RegisterEnum("TestEnum", @@ -146,7 +141,7 @@ class RecursivePlanTest : public ::testing::TestWithParam { } }; -absl::StatusOr ParseTestCase(const RecursiveTestCase& test_case) { +absl::StatusOr ParseTestCase(const TestCase& test_case) { static const std::vector* kMacros = []() { auto* result = new std::vector(Macro::AllMacros()); absl::c_copy(cel::extensions::bindings_macros(), @@ -166,107 +161,14 @@ absl::StatusOr ParseTestCase(const RecursiveTestCase& test_case) { return absl::InvalidArgumentError("No expression provided"); } -TEST_P(RecursivePlanTest, ParsedExprRecursiveImpl) { - const RecursiveTestCase& test_case = GetParam(); - ASSERT_OK_AND_ASSIGN(ParsedExpr parsed_expr, ParseTestCase(test_case)); - cel::RuntimeOptions options; - options.container = "cel.expr.conformance.proto3"; - google::protobuf::Arena arena; - // Unbounded. - options.max_recursion_depth = -1; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - - ASSERT_OK(SetupBuilder(builder)); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr plan, - builder.CreateExpression(&parsed_expr.expr(), - &parsed_expr.source_info())); - - EXPECT_THAT(dynamic_cast(plan.get()), - NotNull()); - - Activation activation; - - ASSERT_OK(SetupActivation(activation, &arena)); - - ASSERT_OK_AND_ASSIGN(CelValue result, plan->Evaluate(activation, &arena)); - EXPECT_THAT(result, test_case.matcher); -} - -TEST_P(RecursivePlanTest, ParsedExprRecursiveOptimizedImpl) { - const RecursiveTestCase& test_case = GetParam(); - ASSERT_OK_AND_ASSIGN(ParsedExpr parsed_expr, ParseTestCase(test_case)); - cel::RuntimeOptions options; - options.container = "cel.expr.conformance.proto3"; - google::protobuf::Arena arena; - // Unbounded. - options.max_recursion_depth = -1; - options.enable_comprehension_list_append = true; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - - ASSERT_OK(SetupBuilder(builder)); - - builder.flat_expr_builder().AddProgramOptimizer( - cel::runtime_internal::CreateConstantFoldingOptimizer()); - builder.flat_expr_builder().AddProgramOptimizer( - CreateRegexPrecompilationExtension(options.regex_max_program_size)); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr plan, - builder.CreateExpression(&parsed_expr.expr(), - &parsed_expr.source_info())); - - EXPECT_THAT(dynamic_cast(plan.get()), - NotNull()); - - Activation activation; - - ASSERT_OK(SetupActivation(activation, &arena)); - - ASSERT_OK_AND_ASSIGN(CelValue result, plan->Evaluate(activation, &arena)); - EXPECT_THAT(result, test_case.matcher); -} - -TEST_P(RecursivePlanTest, ParsedExprRecursiveTraceSupport) { - const RecursiveTestCase& test_case = GetParam(); - ASSERT_OK_AND_ASSIGN(ParsedExpr parsed_expr, ParseTestCase(test_case)); - cel::RuntimeOptions options; - options.container = "cel.expr.conformance.proto3"; - google::protobuf::Arena arena; - auto cb = [](int64_t id, const CelValue& value, google::protobuf::Arena* arena) { - return absl::OkStatus(); - }; - // Unbounded. - options.max_recursion_depth = -1; - options.enable_recursive_tracing = true; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - - ASSERT_OK(SetupBuilder(builder)); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr plan, - builder.CreateExpression(&parsed_expr.expr(), - &parsed_expr.source_info())); - - EXPECT_THAT(dynamic_cast(plan.get()), - NotNull()); - - Activation activation; - - ASSERT_OK(SetupActivation(activation, &arena)); - - ASSERT_OK_AND_ASSIGN(CelValue result, plan->Trace(activation, &arena, cb)); - EXPECT_THAT(result, test_case.matcher); -} - -TEST_P(RecursivePlanTest, Disabled) { +TEST_P(PlanTest, Basic) { google::protobuf::LinkMessageReflection(); - const RecursiveTestCase& test_case = GetParam(); + const TestCase& test_case = GetParam(); ASSERT_OK_AND_ASSIGN(ParsedExpr parsed_expr, ParseTestCase(test_case)); cel::RuntimeOptions options; options.container = "cel.expr.conformance.proto3"; google::protobuf::Arena arena; - // disabled. - options.max_recursion_depth = 0; CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); ASSERT_OK(SetupBuilder(builder)); @@ -275,9 +177,6 @@ TEST_P(RecursivePlanTest, Disabled) { builder.CreateExpression(&parsed_expr.expr(), &parsed_expr.source_info())); - EXPECT_THAT(dynamic_cast(plan.get()), - IsNull()); - Activation activation; ASSERT_OK(SetupActivation(activation, &arena)); @@ -287,8 +186,8 @@ TEST_P(RecursivePlanTest, Disabled) { } INSTANTIATE_TEST_SUITE_P( - RecursivePlanTest, RecursivePlanTest, - testing::ValuesIn(std::vector{ + PlanTest, PlanTest, + testing::ValuesIn(std::vector{ {"constant", "'abc'", test::IsCelString("abc")}, {"call", "1 + 2", test::IsCelInt64(3)}, {"nested_call", "1 + 1 + 1 + 1", test::IsCelInt64(4)}, @@ -545,7 +444,7 @@ INSTANTIATE_TEST_SUITE_P( } })pb"}}), - [](const testing::TestParamInfo& info) -> std::string { + [](const testing::TestParamInfo& info) -> std::string { return info.param.test_name; }); diff --git a/eval/compiler/constant_folding.cc b/eval/compiler/constant_folding.cc index 071f16186..fb58d7d48 100644 --- a/eval/compiler/constant_folding.cc +++ b/eval/compiler/constant_folding.cc @@ -19,7 +19,6 @@ #include #include -#include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/status/status.h" #include "absl/status/statusor.h" @@ -31,7 +30,6 @@ #include "common/value.h" #include "eval/compiler/flat_expr_builder_extensions.h" #include "eval/compiler/resolver.h" -#include "eval/eval/const_value_step.h" #include "eval/eval/evaluator_core.h" #include "internal/status_macros.h" #include "runtime/activation.h" @@ -49,7 +47,6 @@ using ::cel::builtin::kAnd; using ::cel::builtin::kOr; using ::cel::builtin::kTernary; using ::cel::runtime_internal::ConvertConstant; -using ::google::api::expr::runtime::CreateConstValueDirectStep; using ::google::api::expr::runtime::EvaluationListener; using ::google::api::expr::runtime::ExecutionFrame; using ::google::api::expr::runtime::ExecutionPath; @@ -229,17 +226,6 @@ absl::Status ConstantFoldingExtension::OnPostVisit(PlannerContext& context, } } - // If recursive planning enabled (recursion limit unbounded or at least 1), - // use a recursive (direct) step for the folded constant. - // - // Constant folding is applied leaf to root based on the program plan so far, - // so the planner will have an opportunity to validate that the recursion - // limit is being followed when visiting parent nodes in the AST. - if (context.options().max_recursion_depth != 0) { - return context.ReplaceSubplan( - node, CreateConstValueDirectStep(std::move(value), node.id()), 1); - } - // Otherwise make a stack machine plan. ExecutionPath new_plan; new_plan.push_back(ExpressionStep::MakeConstant(value, node.id())); diff --git a/eval/compiler/flat_expr_builder.cc b/eval/compiler/flat_expr_builder.cc index 5c8d7c36a..a305dec17 100644 --- a/eval/compiler/flat_expr_builder.cc +++ b/eval/compiler/flat_expr_builder.cc @@ -50,7 +50,6 @@ #include "base/ast.h" #include "base/builtins.h" #include "base/type_provider.h" -#include "common/allocator.h" #include "common/ast.h" #include "common/ast_traverse.h" #include "common/ast_visitor.h" @@ -64,24 +63,17 @@ #include "eval/compiler/flat_expr_builder_extensions.h" #include "eval/compiler/resolver.h" #include "eval/eval/comprehension_step.h" -#include "eval/eval/const_value_step.h" #include "eval/eval/container_access_step.h" #include "eval/eval/create_list_step.h" #include "eval/eval/create_map_step.h" #include "eval/eval/create_struct_step.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/equality_steps.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_logic.h" #include "eval/eval/function_step.h" -#include "eval/eval/ident_step.h" -#include "eval/eval/lazy_init_step.h" -#include "eval/eval/logic_step.h" #include "eval/eval/optional_or_step.h" #include "eval/eval/select_step.h" #include "eval/eval/shadowable_value_step.h" #include "eval/eval/ternary_step.h" -#include "eval/eval/trace_step.h" #include "internal/status_macros.h" #include "runtime/internal/convert_constant.h" #include "runtime/internal/issue_collector.h" @@ -97,7 +89,6 @@ namespace { using ::cel::Ast; using ::cel::AstTraverse; using ::cel::RuntimeIssue; -using ::cel::StringValue; using ::cel::Value; using ::cel::runtime_internal::ConvertConstant; using ::cel::runtime_internal::GetLegacyRuntimeTypeProvider; @@ -111,13 +102,6 @@ constexpr absl::string_view kBlock = "cel.@block"; // Forward declare to resolve circular dependency for short_circuiting visitors. class FlatExprVisitor; -// Error code for failed recursive program building. Generally indicates an -// optimization doesn't support recursive programs. -absl::Status FailedRecursivePlanning() { - return absl::InternalError( - "failed to build recursive program. check for unsupported optimizations"); -} - // Helper for bookkeeping variables mapped to indexes. class IndexManager { public: @@ -466,17 +450,6 @@ class ComprehensionVisitor { size_t accu_slot_; }; -absl::flat_hash_set MakeOptionalIndicesSet( - const cel::ListExpr& create_list_expr) { - absl::flat_hash_set optional_indices; - for (size_t i = 0; i < create_list_expr.elements().size(); ++i) { - if (create_list_expr.elements()[i].optional()) { - optional_indices.insert(static_cast(i)); - } - } - return optional_indices; -} - absl::flat_hash_set MakeOptionalIndicesSet( const cel::StructExpr& create_struct_expr) { absl::flat_hash_set optional_indices; @@ -590,12 +563,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } - void SetMaxRecursionDepth(int max_recursion_depth) { - max_recursion_depth_ = max_recursion_depth; - } - - bool PlanRecursiveProgram() const { return max_recursion_depth_ > 0; } - void SetResolvedType(const cel::Expr& expr, cel::Type type) { resolved_types_[&expr] = std::move(type); } @@ -667,14 +634,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } - auto* subexpression = program_builder_.current(); - if (subexpression != nullptr && options_.enable_recursive_tracing && - subexpression->IsRecursive()) { - auto program = subexpression->ExtractRecursiveProgram(); - subexpression->set_recursive_program( - std::make_unique(std::move(program.step)), program.depth); - } - program_builder_.ExitSubexpression(&expr); if (!comprehension_stack_.empty() && @@ -713,13 +672,6 @@ class FlatExprVisitor : public cel::AstVisitor { return; } - if (options_.max_recursion_depth > 0 || options_.max_recursion_depth < 0) { - SetRecursiveStep(CreateConstValueDirectStep( - std::move(converted_value).value(), expr.id()), - 1); - return; - } - AddStep(ExpressionStep::MakeConstant(std::move(converted_value).value(), expr.id())); } @@ -838,25 +790,12 @@ class FlatExprVisitor : public cel::AstVisitor { absl::InternalError("bad subexpression reference")); return; } - if (subexpression->IsRecursive()) { - const auto& program = subexpression->recursive_program(); - SetRecursiveStep( - CreateDirectLazyInitStep(slot.slot, program.step.get(), expr.id()), - program.depth + 1); - } else { // Off by one since mainline expression will be index 0. AddStep(ExpressionStep::MakeLazyInitStep( slot.slot, slot.subexpression + 1, expr.id())); - } return; } else if (slot.slot >= 0) { - if (options_.max_recursion_depth != 0) { - SetRecursiveStep( - CreateDirectSlotIdentStep(ident_expr.name(), slot.slot, expr.id()), - 1); - } else { AddStep(ExpressionStep::MakeReadSlotStep(slot.slot, expr.id())); - } return; } @@ -900,24 +839,13 @@ class FlatExprVisitor : public cel::AstVisitor { if (const_value) { // If the path starts with a dot, strip it. absl::string_view name = absl::StripPrefix(path, "."); - if (options_.max_recursion_depth != 0) { - SetRecursiveStep( - CreateDirectShadowableValueStep( - name, std::move(const_value).value(), select_root_id), - 1); - return; - } AddStep(CreateShadowableValueStep(name, std::move(const_value).value()), select_root_id); return; } absl::string_view ident_name = absl::StripPrefix(ident_expr.name(), "."); - if (options_.max_recursion_depth != 0) { - SetRecursiveStep(CreateDirectIdentStep(ident_name, expr.id()), 1); - } else { AddStep(ExpressionStep::MakeIdentifierStep(ident_name, expr.id())); - } } void PreVisitSelect(const cel::Expr& expr, @@ -1003,22 +931,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto deps = ExtractRecursiveDependencies(); - if (deps.size() != 1) { - SetProgressStatusIfError(absl::InternalError( - "unexpected number of dependencies for select operation.")); - return; - } - - SetRecursiveStep( - CreateDirectSelectStep(std::move(deps[0]), std::move(field), - select_expr.test_only(), expr.id(), - options_.enable_empty_wrapper_null_unboxing, - enable_optional_types_), - *depth + 1); - return; - } if (field_type.has_value()) { AddStep( @@ -1124,196 +1036,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } - // Returns the maximum recursion depth of the current program if it is - // eligible for recursion, or nullopt if it is not. - std::optional RecursionEligible() { - if (!PlanRecursiveProgram() || program_builder_.current() == nullptr) { - return std::nullopt; - } - return program_builder_.current()->RecursiveDependencyDepth(); - } - - std::vector> - ExtractRecursiveDependencies() { - // Must check recursion eligibility before calling. - ABSL_DCHECK(program_builder_.current() != nullptr); - - return program_builder_.current()->ExtractRecursiveDependencies(); - } - - void MakeTernaryRecursive(const cel::Expr* expr) { - if (expr->call_expr().args().size() != 3) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin ternary")); - return; - } - - const cel::Expr* condition_expr = &expr->call_expr().args()[0]; - const cel::Expr* left_expr = &expr->call_expr().args()[1]; - const cel::Expr* right_expr = &expr->call_expr().args()[2]; - - auto* condition_plan = program_builder_.GetSubexpression(condition_expr); - auto* left_plan = program_builder_.GetSubexpression(left_expr); - auto* right_plan = program_builder_.GetSubexpression(right_expr); - - if (condition_plan == nullptr || !condition_plan->IsRecursive() || - left_plan == nullptr || !left_plan->IsRecursive() || - right_plan == nullptr || !right_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - - int max_depth = std::max({0, condition_plan->recursive_program().depth, - left_plan->recursive_program().depth, - right_plan->recursive_program().depth}); - - SetRecursiveStep( - CreateDirectTernaryStep(condition_plan->ExtractRecursiveProgram().step, - left_plan->ExtractRecursiveProgram().step, - right_plan->ExtractRecursiveProgram().step, - expr->id(), options_.short_circuiting), - max_depth + 1); - } - - void MakeShortcircuitRecursive(const cel::Expr* expr, bool is_or) { - int args_size = expr->call_expr().args().size(); - if (args_size < 2) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin boolean operator &&/||")); - return; - } - - auto* current_plan = - program_builder_.GetSubexpression(&expr->call_expr().args()[0]); - if (current_plan == nullptr || !current_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - int current_depth = current_plan->recursive_program().depth; - std::unique_ptr current_step = - current_plan->ExtractRecursiveProgram().step; - - for (int i = 1; i < args_size; ++i) { - auto* next_plan = - program_builder_.GetSubexpression(&expr->call_expr().args()[i]); - if (next_plan == nullptr || !next_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - current_depth = - std::max(current_depth, next_plan->recursive_program().depth); - std::unique_ptr next_step = - next_plan->ExtractRecursiveProgram().step; - if (is_or) { - current_step = - CreateDirectOrStep(std::move(current_step), std::move(next_step), - expr->id(), options_.short_circuiting); - } else { - current_step = - CreateDirectAndStep(std::move(current_step), std::move(next_step), - expr->id(), options_.short_circuiting); - } - current_depth++; - } - SetRecursiveStep(std::move(current_step), current_depth); - } - - void MakeOptionalShortcircuit(const cel::Expr* expr, bool is_or_value) { - if (!expr->call_expr().has_target() || - expr->call_expr().args().size() != 1) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for optional.or{Value}")); - return; - } - const cel::Expr* left_expr = &expr->call_expr().target(); - const cel::Expr* right_expr = &expr->call_expr().args()[0]; - - auto* left_plan = program_builder_.GetSubexpression(left_expr); - auto* right_plan = program_builder_.GetSubexpression(right_expr); - - if (left_plan == nullptr || !left_plan->IsRecursive() || - right_plan == nullptr || !right_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - int max_depth = std::max({0, left_plan->recursive_program().depth, - right_plan->recursive_program().depth}); - - SetRecursiveStep(CreateDirectOptionalOrStep( - expr->id(), left_plan->ExtractRecursiveProgram().step, - right_plan->ExtractRecursiveProgram().step, - is_or_value, options_.short_circuiting), - max_depth + 1); - } - - void MaybeMakeBindRecursive(const cel::Expr* expr, - const cel::ComprehensionExpr* comprehension, - size_t accu_slot) { - if (!PlanRecursiveProgram()) { - return; - } - - auto* result_plan = - program_builder_.GetSubexpression(&comprehension->result()); - - if (result_plan == nullptr || !result_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - - int result_depth = result_plan->recursive_program().depth; - - auto program = result_plan->ExtractRecursiveProgram(); - SetRecursiveStep( - CreateDirectBindStep(accu_slot, std::move(program.step), expr->id()), - result_depth + 1); - } - - void MaybeMakeComprehensionRecursive( - const cel::Expr* expr, const cel::ComprehensionExpr* comprehension, - size_t iter_slot, size_t iter2_slot, size_t accu_slot) { - if (!PlanRecursiveProgram()) { - return; - } - - auto* accu_plan = - program_builder_.GetSubexpression(&comprehension->accu_init()); - auto* range_plan = - program_builder_.GetSubexpression(&comprehension->iter_range()); - auto* loop_plan = - program_builder_.GetSubexpression(&comprehension->loop_step()); - auto* condition_plan = - program_builder_.GetSubexpression(&comprehension->loop_condition()); - auto* result_plan = - program_builder_.GetSubexpression(&comprehension->result()); - if (accu_plan == nullptr || !accu_plan->IsRecursive() || - range_plan == nullptr || !range_plan->IsRecursive() || - loop_plan == nullptr || !loop_plan->IsRecursive() || - condition_plan == nullptr || !condition_plan->IsRecursive() || - result_plan == nullptr || !result_plan->IsRecursive()) { - SetProgressStatusIfError(FailedRecursivePlanning()); - return; - } - - int max_depth = 0; - max_depth = std::max(max_depth, accu_plan->recursive_program().depth); - max_depth = std::max(max_depth, range_plan->recursive_program().depth); - max_depth = std::max(max_depth, loop_plan->recursive_program().depth); - max_depth = std::max(max_depth, condition_plan->recursive_program().depth); - max_depth = std::max(max_depth, result_plan->recursive_program().depth); - - auto step = CreateDirectComprehensionStep( - iter_slot, iter2_slot, accu_slot, - range_plan->ExtractRecursiveProgram().step, - accu_plan->ExtractRecursiveProgram().step, - loop_plan->ExtractRecursiveProgram().step, - condition_plan->ExtractRecursiveProgram().step, - result_plan->ExtractRecursiveProgram().step, options_.short_circuiting, - expr->id()); - - SetRecursiveStep(std::move(step), max_depth + 1); - } - // Invoked after all child nodes are processed. void PostVisitCall(const cel::Expr& expr, const cel::CallExpr& call_expr) override { @@ -1564,10 +1286,6 @@ class FlatExprVisitor : public cel::AstVisitor { comprehension_stack_.back(); if (comprehension.is_optimizable_list_append) { if (&(comprehension.comprehension->accu_init()) == &expr) { - if (PlanRecursiveProgram()) { - SetRecursiveStep(CreateDirectMutableListStep(expr.id()), 1); - return; - } AddStep(ExpressionStep::MakeNewMutableListStep(expr.id())); return; } @@ -1578,18 +1296,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } } - if (std::optional depth = RecursionEligible(); depth.has_value()) { - auto deps = ExtractRecursiveDependencies(); - if (deps.size() != list_expr.elements().size()) { - SetProgressStatusIfError(absl::InternalError( - "Unexpected number of plan elements for CreateList expr")); - return; - } - auto step = CreateDirectListStep( - std::move(deps), MakeOptionalIndicesSet(list_expr), expr.id()); - SetRecursiveStep(std::move(step), *depth + 1); - return; - } AddStep(CreateCreateListStep(list_expr), expr.id()); } @@ -1612,20 +1318,6 @@ class FlatExprVisitor : public cel::AstVisitor { std::vector fields = std::move(status_or_resolved_fields.value().second); - if (auto depth = RecursionEligible(); depth.has_value()) { - auto deps = ExtractRecursiveDependencies(); - if (deps.size() != struct_expr.fields().size()) { - SetProgressStatusIfError(absl::InternalError( - "Unexpected number of plan elements for CreateStruct expr")); - return; - } - auto step = CreateDirectCreateStructStep( - std::move(resolved_name), std::move(fields), std::move(deps), - MakeOptionalIndicesSet(struct_expr), expr.id()); - SetRecursiveStep(std::move(step), *depth + 1); - return; - } - AddStep(CreateCreateStructStep(std::move(resolved_name), std::move(fields), MakeOptionalIndicesSet(struct_expr)), expr.id()); @@ -1643,28 +1335,12 @@ class FlatExprVisitor : public cel::AstVisitor { comprehension_stack_.back(); if (comprehension.is_optimizable_map_insert) { if (&(comprehension.comprehension->accu_init()) == &expr) { - if (PlanRecursiveProgram()) { - SetRecursiveStep(CreateDirectMutableMapStep(expr.id()), 1); - return; - } AddStep(CreateMutableMapStep(), expr.id()); return; } } } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto deps = ExtractRecursiveDependencies(); - if (deps.size() != 2 * map_expr.entries().size()) { - SetProgressStatusIfError(absl::InternalError( - "Unexpected number of plan elements for CreateStruct expr")); - return; - } - auto step = CreateDirectCreateMapStep( - std::move(deps), MakeOptionalIndicesSet(map_expr), expr.id()); - SetRecursiveStep(std::move(step), *depth + 1); - return; - } AddStep(CreateCreateStructStepForMap(map_expr.entries().size(), MakeOptionalIndicesSet(map_expr)), expr.id()); @@ -1692,14 +1368,6 @@ class FlatExprVisitor : public cel::AstVisitor { auto lazy_overloads = resolver_.FindLazyOverloads( function, call_expr->has_target(), num_args, expr->id()); if (!lazy_overloads.empty()) { - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = program_builder_.current()->ExtractRecursiveDependencies(); - SetRecursiveStep(CreateDirectLazyFunctionStep( - expr->id(), *call_expr, std::move(args), - std::move(lazy_overloads)), - *depth + 1); - return; - } AddStep(ExpressionStep::MakeLazyFunctionStep( CreateLazyFunctionStep(*call_expr, expr->id(), std::move(lazy_overloads)), @@ -1725,18 +1393,6 @@ class FlatExprVisitor : public cel::AstVisitor { } } - if (auto recursion_depth = RecursionEligible(); - recursion_depth.has_value()) { - // Nonnull while active -- nullptr indicates logic error elsewhere in the - // builder. - ABSL_DCHECK(program_builder_.current() != nullptr); - auto args = program_builder_.current()->ExtractRecursiveDependencies(); - SetRecursiveStep( - CreateDirectFunctionStep(expr->id(), *call_expr, std::move(args), - std::move(overloads)), - *recursion_depth + 1); - return; - } AddStep(ExpressionStep::MakeEagerFunctionStep( CreateFunctionStep(*call_expr, expr->id(), std::move(overloads)), expr->id())); @@ -1778,23 +1434,6 @@ class FlatExprVisitor : public cel::AstVisitor { return nullptr; } - void SetRecursiveStep(std::unique_ptr step, int depth) { - if (!progress_status_.ok() || PlanningSuppressed()) { - return; - } - if (program_builder_.current() == nullptr) { - SetProgressStatusIfError(absl::InternalError( - "CEL AST traversal out of order in flat_expr_builder.")); - return; - } - program_builder_.current()->set_recursive_program(std::move(step), depth); - if (depth > max_recursion_depth_) { - SetProgressStatusIfError(absl::InvalidArgumentError( - absl::StrCat("Maximum recursion depth of ", - options_.max_recursion_depth, " exceeded"))); - } - } - void SetProgressStatusIfError(const absl::Status& status) { if (progress_status_.ok() && !status.ok()) { progress_status_ = status; @@ -2005,7 +1644,6 @@ class FlatExprVisitor : public cel::AstVisitor { bool enable_optional_types_; std::optional block_; - int max_recursion_depth_ = 0; }; FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleIndex( @@ -2020,19 +1658,6 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleIndex( return CallHandlerResult::kIntercepted; } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = ExtractRecursiveDependencies(); - if (args.size() != 2) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin index operator")); - return CallHandlerResult::kIntercepted; - } - SetRecursiveStep( - CreateDirectContainerAccessStep(std::move(args[0]), std::move(args[1]), - enable_optional_types_, expr.id()), - *depth + 1); - return CallHandlerResult::kIntercepted; - } AddStep(CreateContainerAccessStep(call_expr, enable_optional_types_), expr.id()); return CallHandlerResult::kIntercepted; @@ -2047,17 +1672,6 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleNot( return CallHandlerResult::kIntercepted; } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = ExtractRecursiveDependencies(); - if (args.size() != 1) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin not operator")); - return CallHandlerResult::kIntercepted; - } - SetRecursiveStep(CreateDirectNotStep(std::move(args[0]), expr.id()), - *depth + 1); - return CallHandlerResult::kIntercepted; - } AddStep(ExpressionStep::MakeBooleanNotStep(expr.id())); return CallHandlerResult::kIntercepted; } @@ -2070,19 +1684,6 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleNotStrictlyFalse( return CallHandlerResult::kIntercepted; } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = ExtractRecursiveDependencies(); - if (args.size() != 1) { - SetProgressStatusIfError( - absl::InvalidArgumentError("unexpected number of args for builtin " - "@not_strictly_false operator")); - return CallHandlerResult::kIntercepted; - } - SetRecursiveStep( - CreateDirectNotStrictlyFalseStep(std::move(args[0]), expr.id()), - *depth + 1); - return CallHandlerResult::kIntercepted; - } AddStep(ExpressionStep::MakeNotStrictlyFalseStep(expr.id())); return CallHandlerResult::kIntercepted; } @@ -2101,28 +1702,6 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleBlock( block.in = false; index_manager().ReleaseSlots(block.slot_count); - // Check if eligible for recursion and update the plan if so. - // - // The first argument to @block is the list of initializers. These don't - // generate a plan in the main program (they are tracked separately to support - // lazy evaluation) so we only need to extract the second argument -- the body - // of the block that uses the initializers. - ProgramBuilder::Subexpression* body_subexpression = - program_builder_.GetSubexpression(&call_expr.args()[1]); - - if (options_.max_recursion_depth != 0 && body_subexpression != nullptr && - body_subexpression->IsRecursive() && - (options_.max_recursion_depth < 0 || - body_subexpression->recursive_program().depth < - options_.max_recursion_depth)) { - auto recursive_program = body_subexpression->ExtractRecursiveProgram(); - SetRecursiveStep( - CreateDirectBlockStep(block.index, block.slot_count, - std::move(recursive_program.step), expr.id()), - recursive_program.depth + 1); - return CallHandlerResult::kIntercepted; - } - // Otherwise, iterative plan. if (block.slot_count > 0) { AddStep(ExpressionStep::MakeClearSlotsStep(block.index, block.slot_count, @@ -2158,12 +1737,7 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleListAppend( loop_step.call_expr().args().size() == 3 && &(loop_step.call_expr().args()[1]) == &expr; if (is_map_loop_step || is_filter_loop_step) { - if (RecursionEligible().has_value()) { - AddResolvedFunctionStep(&call_expr, &expr, - cel::builtin::kRuntimeListAppend); - } else { AddStep(ExpressionStep::MakeMutableListAppendStep(expr.id())); - } return CallHandlerResult::kIntercepted; } } @@ -2179,19 +1753,6 @@ FlatExprVisitor::CallHandlerResult FlatExprVisitor::HandleHeterogeneousEquality( return CallHandlerResult::kIntercepted; } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = ExtractRecursiveDependencies(); - if (args.size() != 2) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin equality operator")); - return CallHandlerResult::kIntercepted; - } - SetRecursiveStep( - CreateDirectEqualityStep(std::move(args[0]), std::move(args[1]), - inequality, expr.id()), - *depth + 1); - return CallHandlerResult::kIntercepted; - } AddStep(inequality ? ExpressionStep::MakeFastNotEqualStep(expr.id()) : ExpressionStep::MakeFastEqualStep(expr.id())); return CallHandlerResult::kIntercepted; @@ -2205,19 +1766,6 @@ FlatExprVisitor::HandleHeterogeneousEqualityIn(const cel::Expr& expr, return CallHandlerResult::kIntercepted; } - if (auto depth = RecursionEligible(); depth.has_value()) { - auto args = ExtractRecursiveDependencies(); - if (args.size() != 2) { - SetProgressStatusIfError(absl::InvalidArgumentError( - "unexpected number of args for builtin 'in' operator")); - return CallHandlerResult::kIntercepted; - } - SetRecursiveStep( - CreateDirectInStep(std::move(args[0]), std::move(args[1]), expr.id()), - *depth + 1); - return CallHandlerResult::kIntercepted; - } - AddStep(ExpressionStep::MakeFastInStep(expr.id())); return CallHandlerResult::kIntercepted; } @@ -2246,9 +1794,6 @@ void LogicalCondVisitor::PreVisit(const cel::Expr* expr) { } void LogicalCondVisitor::PostVisitArg(int arg_num, const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - return; - } const int last_arg_index = expr->call_expr().args().size() - 1; const size_t num_args = expr->call_expr().args().size(); if (arg_num == last_arg_index) { @@ -2288,9 +1833,6 @@ void LogicalCondVisitor::PostVisitArg(int arg_num, const cel::Expr* expr) { } void LogicalCondVisitor::PostVisit(const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - visitor_->MakeShortcircuitRecursive(expr, is_or_); - } } void OptionalOrCondVisitor::PreVisit(const cel::Expr* expr) { @@ -2300,9 +1842,6 @@ void OptionalOrCondVisitor::PreVisit(const cel::Expr* expr) { } void OptionalOrCondVisitor::PostVisitTarget(const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - return; - } if (!short_circuiting_) { return; } @@ -2314,11 +1853,6 @@ void OptionalOrCondVisitor::PostVisitTarget(const cel::Expr* expr) { } void OptionalOrCondVisitor::PostVisit(const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - visitor_->MakeOptionalShortcircuit(expr, is_or_value_); - return; - } - visitor_->AddStep(CreateOptionalOrStep(is_or_value_), expr->id()); if (!short_circuiting_) { return; @@ -2343,9 +1877,6 @@ void TernaryCondVisitor::PreVisit(const cel::Expr* expr) { } void TernaryCondVisitor::PostVisitArg(int arg_num, const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - return; - } // Ternary operator "_?_:_" requires a special handing. // In contrary to regular function call, its execution affects the control // flow of the overall CEL expression. @@ -2395,10 +1926,6 @@ void TernaryCondVisitor::PostVisitArg(int arg_num, const cel::Expr* expr) { } void TernaryCondVisitor::PostVisit(const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - visitor_->MakeTernaryRecursive(expr); - return; - } // Determine and set jump offset in jump instruction. ExpressionStep* cond_step = cond_jump_pos_.has_value() @@ -2445,10 +1972,6 @@ void ExhaustiveTernaryCondVisitor::PreVisit(const cel::Expr* expr) { } void ExhaustiveTernaryCondVisitor::PostVisit(const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - visitor_->MakeTernaryRecursive(expr); - return; - } visitor_->AddStep(CreateTernaryStep(), expr->id()); } @@ -2486,9 +2009,6 @@ ComprehensionNextStep* absl_nullable ComprehensionVisitor::GetNextStep() { absl::Status ComprehensionVisitor::PostVisitArgDefault( cel::ComprehensionArg arg_num, const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - return absl::OkStatus(); - } switch (arg_num) { case cel::ITER_RANGE: { init_step_pos_ = visitor_->GetCurrentIndex(); @@ -2592,9 +2112,6 @@ absl::Status ComprehensionVisitor::PostVisitArgDefault( void ComprehensionVisitor::PostVisitArgTrivial(cel::ComprehensionArg arg_num, const cel::Expr* expr) { - if (visitor_->PlanRecursiveProgram()) { - return; - } switch (arg_num) { case cel::ITER_RANGE: { break; @@ -2620,13 +2137,6 @@ void ComprehensionVisitor::PostVisitArgTrivial(cel::ComprehensionArg arg_num, } void ComprehensionVisitor::PostVisit(const cel::Expr* expr) { - if (is_trivial_) { - visitor_->MaybeMakeBindRecursive(expr, &expr->comprehension_expr(), - accu_slot_); - return; - } - visitor_->MaybeMakeComprehensionRecursive( - expr, &expr->comprehension_expr(), iter_slot_, iter2_slot_, accu_slot_); } // Flattens the expression table into the end of the mainline expression vector @@ -2726,13 +2236,6 @@ absl::StatusOr FlatExprBuilder::CreateExpressionImpl( program_builder, extension_context, enable_optional_types_); - if (options_.max_recursion_depth == -1 || options_.max_recursion_depth > 0) { - int depth_limit = options_.max_recursion_depth == -1 - ? std::numeric_limits::max() - : options_.max_recursion_depth; - visitor.SetMaxRecursionDepth(depth_limit); - } - cel::TraversalOptions opts; opts.use_comprehension_callbacks = true; AstTraverse(ast->root_expr(), visitor, opts); diff --git a/eval/compiler/flat_expr_builder_comprehensions_test.cc b/eval/compiler/flat_expr_builder_comprehensions_test.cc index ecea6058c..ed0f67912 100644 --- a/eval/compiler/flat_expr_builder_comprehensions_test.cc +++ b/eval/compiler/flat_expr_builder_comprehensions_test.cc @@ -50,24 +50,18 @@ using ::cel::expr::CheckedExpr; using ::cel::expr::ParsedExpr; using ::testing::HasSubstr; -class CelExpressionBuilderFlatImplComprehensionsTest - : public testing::TestWithParam { +class CelExpressionBuilderFlatImplComprehensionsTest : public testing::Test { public: CelExpressionBuilderFlatImplComprehensionsTest() = default; - bool enable_recursive_planning() { return GetParam(); } - cel::RuntimeOptions GetRuntimeOptions() { cel::RuntimeOptions options; - if (enable_recursive_planning()) { - options.max_recursion_depth = -1; - } options.enable_comprehension_list_append = true; return options; } }; -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, NestedComp) { +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, NestedComp) { cel::RuntimeOptions options = GetRuntimeOptions(); CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); @@ -85,7 +79,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, NestedComp) { EXPECT_THAT(*result.ListOrDie(), testing::SizeIs(2)); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, MapComp) { +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, MapComp) { cel::RuntimeOptions options = GetRuntimeOptions(); CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); @@ -106,7 +100,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, MapComp) { test::EqualsCelValue(CelValue::CreateInt64(4))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneTrue) { +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneTrue) { cel::RuntimeOptions options = GetRuntimeOptions(); CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); @@ -123,7 +117,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneTrue) { EXPECT_THAT(result, test::IsCelBool(true)); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneFalse) { +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneFalse) { cel::RuntimeOptions options = GetRuntimeOptions(); CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); @@ -140,7 +134,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ExistsOneFalse) { EXPECT_THAT(result, test::IsCelBool(false)); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ListCompWithUnknowns) { +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ListCompWithUnknowns) { cel::RuntimeOptions options = GetRuntimeOptions(); options.unknown_processing = UnknownProcessingOptions::kAttributeAndFunction; CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); @@ -179,7 +173,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, ListCompWithUnknowns) { testing::Eq(1)); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, InvalidComprehensionWithRewrite) { CheckedExpr expr; // The rewrite step which occurs when an identifier gets a more qualified name @@ -216,7 +210,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("Invalid empty expression")))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithConcatVulernability) { CheckedExpr expr; // The comprehension loop step performs an unsafe concatenation of the @@ -270,7 +264,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithListVulernability) { CheckedExpr expr; // The comprehension @@ -314,7 +308,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithStructVulernability) { CheckedExpr expr; // The comprehension loop step builds a deeply nested struct which expands @@ -371,7 +365,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithNestedComprehensionResultVulernability) { CheckedExpr expr; // The nested comprehension performs an unsafe concatenation on the parent @@ -439,7 +433,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithNestedComprehensionLoopStepVulernability) { CheckedExpr expr; // The nested comprehension performs an unsafe concatenation on the parent @@ -486,7 +480,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithNestedComprehensionLoopStepVulernabilityResult) { CheckedExpr expr; // The nested comprehension performs an unsafe concatenation on the parent @@ -538,7 +532,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, ComprehensionWithNestedComprehensionLoopStepIterRangeVulnerability) { CheckedExpr expr; // The nested comprehension unsafely modifies the parent accumulator @@ -585,7 +579,7 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("memory exhaustion vulnerability"))); } -TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, +TEST_F(CelExpressionBuilderFlatImplComprehensionsTest, InvalidBindComprehension) { ParsedExpr expr; // Trivial comprehensions (such as cel.bind), are optimized by skipping the @@ -629,13 +623,6 @@ TEST_P(CelExpressionBuilderFlatImplComprehensionsTest, HasSubstr("Unexpected iter_var access in trivial comprehension"))); } -INSTANTIATE_TEST_SUITE_P(TestSuite, - CelExpressionBuilderFlatImplComprehensionsTest, - testing::Bool(), - [](const testing::TestParamInfo& info) { - return info.param ? "recursive" : "default"; - }); - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/compiler/flat_expr_builder_extensions.cc b/eval/compiler/flat_expr_builder_extensions.cc index 7e1417eb7..3f308125a 100644 --- a/eval/compiler/flat_expr_builder_extensions.cc +++ b/eval/compiler/flat_expr_builder_extensions.cc @@ -13,7 +13,6 @@ // limitations under the License. #include "eval/compiler/flat_expr_builder_extensions.h" -#include #include #include #include @@ -27,10 +26,8 @@ #include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/types/optional.h" #include "absl/types/variant.h" #include "common/expr.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" namespace google::api::expr::runtime { @@ -39,31 +36,6 @@ namespace { using Subexpression = google::api::expr::runtime::ProgramBuilder::Subexpression; -// Remap a recursive program to its parent if the parent is a transparent -// wrapper. -void MaybeReassignChildRecursiveProgram(Subexpression* parent) { - if (parent->IsFlattened() || parent->IsRecursive()) { - return; - } - if (parent->elements().size() != 1) { - return; - } - auto* child_alternative = - absl::get_if(&parent->elements()[0]); - if (child_alternative == nullptr) { - return; - } - - auto& child_subexpression = *child_alternative; - if (!child_subexpression->IsRecursive()) { - return; - } - - auto child_program = child_subexpression->ExtractRecursiveProgram(); - parent->set_recursive_program(std::move(child_program.step), - child_program.depth); -} - } // namespace Subexpression::Subexpression(const cel::Expr* self, ProgramBuilder* owner) @@ -72,8 +44,6 @@ Subexpression::Subexpression(const cel::Expr* self, ProgramBuilder* owner) size_t Subexpression::ComputeSize() const { if (IsFlattened()) { return flattened_elements().size(); - } else if (IsRecursive()) { - return 1; } std::vector to_expand{this}; size_t size = 0; @@ -83,9 +53,6 @@ size_t Subexpression::ComputeSize() const { if (expr->IsFlattened()) { size += expr->flattened_elements().size(); continue; - } else if (expr->IsRecursive()) { - size += 1; - continue; } for (const auto& elem : expr->elements()) { if (auto* child = absl::get_if(&elem); child != nullptr) { @@ -98,45 +65,6 @@ size_t Subexpression::ComputeSize() const { return size; } -std::optional Subexpression::RecursiveDependencyDepth() const { - auto* tree = absl::get_if(&program_); - int depth = 0; - if (tree == nullptr) { - return std::nullopt; - } - for (const auto& element : *tree) { - auto* subexpression = absl::get_if(&element); - if (subexpression == nullptr) { - return std::nullopt; - } - if (!(*subexpression)->IsRecursive()) { - return std::nullopt; - } - depth = std::max(depth, (*subexpression)->recursive_program().depth); - } - return depth; -} - -std::vector> -Subexpression::ExtractRecursiveDependencies() const { - auto* tree = absl::get_if(&program_); - std::vector> dependencies; - if (tree == nullptr) { - return {}; - } - for (const auto& element : *tree) { - auto* subexpression = absl::get_if(&element); - if (subexpression == nullptr) { - return {}; - } - if (!(*subexpression)->IsRecursive()) { - return {}; - } - dependencies.push_back((*subexpression)->ExtractRecursiveProgram().step); - } - return dependencies; -} - Subexpression* absl_nullable Subexpression::ExtractChild(Subexpression* child) { ABSL_DCHECK(child != nullptr); if (IsFlattened()) { @@ -161,7 +89,6 @@ Subexpression* absl_nullable Subexpression::ExtractChild(Subexpression* child) { // target step. int Subexpression::CalculateOffset(int base, int target) const { ABSL_DCHECK(!IsFlattened()); - ABSL_DCHECK(!IsRecursive()); int sign = 1; int start = base + 1; @@ -220,13 +147,6 @@ void Subexpression::Flatten() { absl::c_move(elements, std::back_inserter(flat)); elements.clear(); continue; - } else if (subexpr->IsRecursive()) { - flat.push_back(ExpressionStep::MakeGenericStep( - std::make_unique( - std::move(subexpr->ExtractRecursiveProgram().step), - subexpr->self_->id()), - subexpr->self_->id())); - continue; } auto& elements = subexpr->elements(); size_t size = elements.size(); @@ -253,13 +173,6 @@ void Subexpression::Flatten() { program_ = std::move(flat); } -Subexpression::RecursiveProgram Subexpression::ExtractRecursiveProgram() { - ABSL_DCHECK(IsRecursive()); - auto result = std::move(absl::get(program_)); - program_.emplace>(); - return result; -} - bool Subexpression::ExtractTo(ExecutionPath& out) { if (!IsFlattened()) { return false; @@ -328,8 +241,6 @@ Subexpression* absl_nullable ProgramBuilder::ExitSubexpression( ABSL_DCHECK(expr == current_->self_); ABSL_DCHECK(GetSubexpression(expr) == current_); - MaybeReassignChildRecursiveProgram(current_); - Subexpression* result = GetSubexpression(current_->parent_); ABSL_DCHECK(result != nullptr || current_ == root_); current_ = result; @@ -350,9 +261,6 @@ ExpressionStep* absl_nullable ProgramBuilder::AddStep(ExpressionStep step) { if (current_ == nullptr) { return nullptr; } - if (current_->IsRecursive()) { - return nullptr; - } if (current_->IsFlattened()) { current_->flattened_elements().push_back(std::move(step)); return ¤t_->flattened_elements().back(); @@ -449,19 +357,6 @@ void ProgramBuilder::Reset() { subprogram_map_.clear(); } -absl::Status PlannerContext::ReplaceSubplan( - const cel::Expr& node, std::unique_ptr step, - int depth) { - auto* subexpression = program_builder_.GetSubexpression(&node); - if (subexpression == nullptr) { - return absl::InternalError( - "attempted to update program step for untracked expr node"); - } - - subexpression->set_recursive_program(std::move(step), depth); - return absl::OkStatus(); -} - absl::Status PlannerContext::AddSubplanStep(const cel::Expr& node, ExpressionStep step) { auto* subexpression = program_builder_.GetSubexpression(&node); diff --git a/eval/compiler/flat_expr_builder_extensions.h b/eval/compiler/flat_expr_builder_extensions.h index e85f337f9..66b80d215 100644 --- a/eval/compiler/flat_expr_builder_extensions.h +++ b/eval/compiler/flat_expr_builder_extensions.h @@ -36,19 +36,14 @@ #include "absl/log/absl_check.h" #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/types/optional.h" #include "absl/types/variant.h" #include "base/ast.h" #include "base/type_provider.h" #include "common/expr.h" -#include "common/native_type.h" #include "common/type_reflector.h" #include "eval/compiler/resolver.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_logic.h" -#include "eval/eval/trace_step.h" -#include "internal/casts.h" #include "runtime/internal/issue_collector.h" #include "runtime/internal/runtime_env.h" #include "runtime/runtime_options.h" @@ -93,11 +88,6 @@ class ProgramBuilder { using FlattenedPlan = ExecutionPath; public: - struct RecursiveProgram { - std::unique_ptr step; - int depth; - }; - ~Subexpression() = default; // Not copyable or movable. @@ -108,10 +98,6 @@ class ProgramBuilder { // Add a program step at the current end of the subexpression. bool AddStep(ExpressionStep step) { - if (IsRecursive()) { - return false; - } - if (IsFlattened()) { flattened_elements().push_back(std::move(step)); return true; @@ -160,27 +146,6 @@ class ProgramBuilder { return absl::get(program_); } - void set_recursive_program(std::unique_ptr step, - int depth) { - program_ = RecursiveProgram{std::move(step), depth}; - } - - const RecursiveProgram& recursive_program() const { - ABSL_DCHECK(IsRecursive()); - return absl::get(program_); - } - - absl::optional RecursiveDependencyDepth() const; - - std::vector> - ExtractRecursiveDependencies() const; - - RecursiveProgram ExtractRecursiveProgram(); - - bool IsRecursive() const { - return absl::holds_alternative(program_); - } - // Compute the current number of program steps in this subexpression and // its dependencies. size_t ComputeSize() const; @@ -221,7 +186,7 @@ class ProgramBuilder { // // This adds complexity, but supports swapping to a flat representation as // needed. - absl::variant program_; + absl::variant program_; const cel::Expr* self_; const cel::Expr* absl_nullable parent_; @@ -314,31 +279,6 @@ class ProgramBuilder { SubprogramMap subprogram_map_; }; -// Attempt to downcast a specific type of recursive step. -template -const Subclass* TryDowncastDirectStep(const DirectExpressionStep* step) { - if (step == nullptr) { - return nullptr; - } - - auto type_id = step->GetNativeTypeId(); - if (type_id == cel::NativeTypeId::For()) { - const auto* trace_step = cel::internal::down_cast(step); - auto deps = trace_step->GetDependencies(); - if (!deps.has_value() || deps->size() != 1) { - return nullptr; - } - step = deps->at(0); - type_id = step->GetNativeTypeId(); - } - - if (type_id == cel::NativeTypeId::For()) { - return cel::internal::down_cast(step); - } - - return nullptr; -} - // Class representing FlatExpr internals exposed to extensions. class PlannerContext { public: @@ -387,14 +327,6 @@ class PlannerContext { // expr->program mapping for any descendants. absl::Status ReplaceSubplan(const cel::Expr& node, ExecutionPath path); - // Replace the subplan associated with node with a new recursive subplan. - // - // This operation clears any existing plan to which removes the - // expr->program mapping for any descendants. - absl::Status ReplaceSubplan(const cel::Expr& node, - std::unique_ptr step, - int depth); - // Extend the current subplan with the given expression step. absl::Status AddSubplanStep(const cel::Expr& node, ExpressionStep step); absl::Status AddSubplanStep(const cel::Expr& node, diff --git a/eval/compiler/flat_expr_builder_extensions_test.cc b/eval/compiler/flat_expr_builder_extensions_test.cc index 2eae196af..07a6cfbe6 100644 --- a/eval/compiler/flat_expr_builder_extensions_test.cc +++ b/eval/compiler/flat_expr_builder_extensions_test.cc @@ -15,21 +15,16 @@ #include #include -#include #include "absl/base/nullability.h" #include "absl/status/status.h" #include "absl/status/status_matchers.h" #include "absl/status/statusor.h" #include "common/expr.h" -#include "common/native_type.h" -#include "common/value.h" #include "eval/compiler/resolver.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" #include "eval/eval/function_step.h" -#include "internal/status_macros.h" #include "internal/testing.h" #include "runtime/function_registry.h" #include "runtime/internal/issue_collector.h" @@ -53,7 +48,6 @@ using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; using ::testing::ElementsAre; using ::testing::IsEmpty; -using ::testing::Optional; class TestStepLogic : public ExpressionStepLogic { public: @@ -526,55 +520,5 @@ TEST_F(ProgramBuilderTest, ExtractToRequiresFlatten) { UniquePtrHolds(step_ptrs.a))); } -TEST_F(ProgramBuilderTest, Recursive) { - Expr a; - Expr b; - Expr c; - - ProgramBuilder program_builder; - - program_builder.EnterSubexpression(&a); - program_builder.EnterSubexpression(&b); - program_builder.current()->set_recursive_program( - CreateConstValueDirectStep(cel::NullValue()), 1); - program_builder.ExitSubexpression(&b); - program_builder.EnterSubexpression(&c); - program_builder.current()->set_recursive_program( - CreateConstValueDirectStep(cel::NullValue()), 1); - program_builder.ExitSubexpression(&c); - - ASSERT_FALSE(program_builder.current()->IsFlattened()); - ASSERT_FALSE(program_builder.current()->IsRecursive()); - ASSERT_TRUE(program_builder.GetSubexpression(&b)->IsRecursive()); - ASSERT_TRUE(program_builder.GetSubexpression(&c)->IsRecursive()); - - EXPECT_EQ(program_builder.GetSubexpression(&b)->recursive_program().depth, 1); - EXPECT_EQ(program_builder.GetSubexpression(&c)->recursive_program().depth, 1); - - cel::CallExpr call_expr; - call_expr.set_function("_==_"); - call_expr.mutable_args().emplace_back(); - call_expr.mutable_args().emplace_back(); - - auto max_depth = program_builder.current()->RecursiveDependencyDepth(); - - EXPECT_THAT(max_depth, Optional(1)); - - auto deps = program_builder.current()->ExtractRecursiveDependencies(); - - program_builder.current()->set_recursive_program( - CreateDirectFunctionStep(-1, call_expr, std::move(deps), {}), - *max_depth + 1); - - program_builder.ExitSubexpression(&a); - - auto path = program_builder.FlattenMain(); - - ASSERT_THAT(path, testing::SizeIs(1)); - EXPECT_TRUE(path[0].IsGenericStep() && - path[0].GetGenericStep()->GetNativeTypeId() == - cel::NativeTypeId::For()); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/compiler/flat_expr_builder_test.cc b/eval/compiler/flat_expr_builder_test.cc index f7cde337b..8611de388 100644 --- a/eval/compiler/flat_expr_builder_test.cc +++ b/eval/compiler/flat_expr_builder_test.cc @@ -25,7 +25,6 @@ #include "cel/expr/syntax.pb.h" #include "google/protobuf/field_mask.pb.h" #include "google/protobuf/descriptor.pb.h" -#include "absl/base/nullability.h" #include "absl/container/flat_hash_map.h" #include "absl/log/absl_check.h" #include "absl/status/status.h" @@ -45,7 +44,6 @@ #include "eval/public/activation.h" #include "eval/public/builtin_func_registrar.h" #include "eval/public/cel_attribute.h" -#include "eval/public/cel_builtins.h" #include "eval/public/cel_expr_builder_factory.h" #include "eval/public/cel_expression.h" #include "eval/public/cel_function.h" @@ -256,7 +254,7 @@ TEST(FlatExprBuilderTest, BinaryCallTooManyArguments) { CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv()); auto* call = expr.mutable_call_expr(); - call->set_function(builtin::kAnd); + call->set_function(cel::builtin::kAnd); call->mutable_target()->mutable_const_expr()->set_string_value("random"); call->add_args()->mutable_const_expr()->set_bool_value(false); call->add_args()->mutable_const_expr()->set_bool_value(true); @@ -270,7 +268,7 @@ TEST(FlatExprBuilderTest, TernaryCallTooManyArguments) { Expr expr; SourceInfo source_info; auto* call = expr.mutable_call_expr(); - call->set_function(builtin::kTernary); + call->set_function(cel::builtin::kTernary); call->mutable_target()->mutable_const_expr()->set_string_value("random"); call->add_args()->mutable_const_expr()->set_bool_value(false); call->add_args()->mutable_const_expr()->set_int64_value(1); @@ -1813,7 +1811,7 @@ absl::Status RunTernaryExpression(CelValue selector, CelValue value1, Expr expr; SourceInfo source_info; auto call_expr = expr.mutable_call_expr(); - call_expr->set_function(builtin::kTernary); + call_expr->set_function(cel::builtin::kTernary); auto arg0 = call_expr->add_args(); arg0->mutable_ident_expr()->set_name("selector"); @@ -1842,7 +1840,7 @@ TEST(FlatExprBuilderTest, Ternary) { Expr expr; SourceInfo source_info; auto call_expr = expr.mutable_call_expr(); - call_expr->set_function(builtin::kTernary); + call_expr->set_function(cel::builtin::kTernary); auto arg0 = call_expr->add_args(); arg0->mutable_ident_expr()->set_name("selector"); @@ -3018,138 +3016,6 @@ INSTANTIATE_TEST_SUITE_P( VariadicLogicalEvalTestCase{"All_Unknown", "[a, b, c].all(x, x)", "true", "unknown1", "true", "unknown"})); -struct RecursionDepthTestCase { - std::string label; - std::string expr; - int max_recursion_depth; - absl::StatusCode expected_status_code; - std::string expected_error_msg; -}; - -class FlatExprBuilderRecursionDepthTest - : public testing::TestWithParam {}; - -TEST_P(FlatExprBuilderRecursionDepthTest, CheckRecursionLimit) { - const auto& test_case = GetParam(); - ASSERT_OK_AND_ASSIGN(ParsedExpr parsed_expr, parser::Parse(test_case.expr)); - - cel::RuntimeOptions options; - options.max_recursion_depth = test_case.max_recursion_depth; - options.fail_on_warnings = false; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - - auto result = - builder.CreateExpression(&parsed_expr.expr(), &parsed_expr.source_info()); - if (test_case.expected_status_code == absl::StatusCode::kOk) { - EXPECT_THAT(result, IsOk()); - } else { - EXPECT_THAT(result, StatusIs(test_case.expected_status_code, - HasSubstr(test_case.expected_error_msg))); - } -} - -INSTANTIATE_TEST_SUITE_P( - FlatExprBuilderRecursionDepthTest, FlatExprBuilderRecursionDepthTest, - testing::Values( - RecursionDepthTestCase{"AndChildLimitExceeded", "(1 + 1) && true", 1, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 1 exceeded"}, - RecursionDepthTestCase{"AndParentLimitExceeded", "(1 + 1) && true", 2, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 2 exceeded"}, - RecursionDepthTestCase{"AndLimitSuccess", "(1 + 1) && true", 3, - absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"AndLimitSuccessGenerous", "(1 + 1) && true", 10, - absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"AndLimitSuccessUnlimited", "(1 + 1) && true", - -1, absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"OrChildLimitExceeded", "(1 + 1) || true", 1, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 1 exceeded"}, - RecursionDepthTestCase{"OrParentLimitExceeded", "(1 + 1) || true", 2, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 2 exceeded"}, - RecursionDepthTestCase{"OrLimitSuccess", "(1 + 1) || true", 3, - absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"OrLimitSuccessGenerous", - "(1 + 1) || false || false || false || false || " - "(true && true && true && true && false)", - 10, absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"OrLimitSuccessUnlimited", "(1 + 1) || true", -1, - absl::StatusCode::kOk, ""}, - RecursionDepthTestCase{"AndDepthUpdateFromSubsequentArg", - "true && (1 + 1 + 1 + 1)", 4, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 4 exceeded"}, - RecursionDepthTestCase{"OrDepthUpdateFromSubsequentArg", - "true || (1 + 1 + 1 + 1)", 4, - absl::StatusCode::kInvalidArgument, - "Maximum recursion depth of 4 exceeded"})); - -TEST(FlatExprBuilderTest, NonRecursiveChildBlockAndError) { - ParsedExpr parsed_expr; - ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString( - R"pb( - expr: { - call_expr: { - function: "_&&_" - args { const_expr: { bool_value: true } } - args { - call_expr: { - function: "cel.@block" - args { - list_expr { elements { const_expr: { int64_value: 1 } } } - } - args { ident_expr: { name: "@index0" } } - } - } - } - } - )pb", - &parsed_expr)); - - cel::RuntimeOptions options; - options.max_recursion_depth = 2; - options.fail_on_warnings = false; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - EXPECT_THAT( - builder.CreateExpression(&parsed_expr.expr(), &parsed_expr.source_info()), - StatusIs(absl::StatusCode::kInternal, - HasSubstr("failed to build recursive program"))); -} - -TEST(FlatExprBuilderTest, NonRecursiveChildBlockOrError) { - ParsedExpr parsed_expr; - ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString( - R"pb( - expr: { - call_expr: { - function: "_||_" - args { const_expr: { bool_value: true } } - args { - call_expr: { - function: "cel.@block" - args { - list_expr { elements { const_expr: { int64_value: 1 } } } - } - args { ident_expr: { name: "@index0" } } - } - } - } - } - )pb", - &parsed_expr)); - - cel::RuntimeOptions options; - options.max_recursion_depth = 2; - options.fail_on_warnings = false; - CelExpressionBuilderFlatImpl builder(NewTestingRuntimeEnv(), options); - EXPECT_THAT( - builder.CreateExpression(&parsed_expr.expr(), &parsed_expr.source_info()), - StatusIs(absl::StatusCode::kInternal, - HasSubstr("failed to build recursive program"))); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/compiler/qualified_reference_resolver.cc b/eval/compiler/qualified_reference_resolver.cc index 158e492be..a46034298 100644 --- a/eval/compiler/qualified_reference_resolver.cc +++ b/eval/compiler/qualified_reference_resolver.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "base/ast.h" #include "base/builtins.h" #include "common/ast.h" diff --git a/eval/compiler/regex_precompilation_optimization.cc b/eval/compiler/regex_precompilation_optimization.cc index bd3a841ed..f4275ebd3 100644 --- a/eval/compiler/regex_precompilation_optimization.cc +++ b/eval/compiler/regex_precompilation_optimization.cc @@ -33,8 +33,6 @@ #include "common/native_type.h" #include "common/value.h" #include "eval/compiler/flat_expr_builder_extensions.h" -#include "eval/eval/compiler_constant_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/regex_match_step.h" #include "internal/re2_options.h" @@ -175,17 +173,6 @@ class RegexPrecompilationOptimization : public ProgramOptimizer { return std::nullopt; } std::optional constant; - if (subexpression->IsRecursive()) { - const auto& program = subexpression->recursive_program(); - auto deps = program.step->GetDependencies(); - if (deps.has_value() && deps->size() == 2) { - const auto* re_plan = - TryDowncastDirectStep(deps->at(1)); - if (re_plan != nullptr) { - constant = re_plan->value(); - } - } - } else { // otherwise stack-machine program. ExecutionPathView re_plan = context.GetSubplan(re_expr); if (re_plan.size() == 1) { @@ -194,7 +181,6 @@ class RegexPrecompilationOptimization : public ProgramOptimizer { constant = std::move(val); } } - } if (constant.has_value() && constant->IsString()) { return constant->GetString().ToString(); @@ -208,33 +194,10 @@ class RegexPrecompilationOptimization : public ProgramOptimizer { ProgramBuilder::Subexpression* absl_nonnull subexpression, const Expr& call, const Expr& subject, std::shared_ptr regex_program) { - if (subexpression->IsRecursive()) { - return RewriteRecursivePlan(subexpression, call, subject, - std::move(regex_program)); - } return RewriteStackMachinePlan(context, call, subject, std::move(regex_program)); } - absl::Status RewriteRecursivePlan( - ProgramBuilder::Subexpression* absl_nonnull subexpression, - const Expr& call, const Expr& subject, - std::shared_ptr regex_program) { - auto program = subexpression->ExtractRecursiveProgram(); - auto deps = program.step->ExtractDependencies(); - if (!deps.has_value() || deps->size() != 2) { - // Possibly already const-folded, put the plan back. - subexpression->set_recursive_program(std::move(program.step), - program.depth); - return absl::OkStatus(); - } - subexpression->set_recursive_program( - CreateDirectRegexMatchStep(call.id(), std::move(deps->at(0)), - std::move(regex_program)), - program.depth); - return absl::OkStatus(); - } - absl::Status RewriteStackMachinePlan( PlannerContext& context, const Expr& call, const Expr& subject, std::shared_ptr regex_program) { diff --git a/eval/eval/BUILD b/eval/eval/BUILD index ded2492ca..37b88db94 100644 --- a/eval/eval/BUILD +++ b/eval/eval/BUILD @@ -56,7 +56,6 @@ cc_library( ":attribute_trail", ":attribute_utility", ":comprehension_slots", - ":direct_expression_step", ":evaluator_stack", ":expression_step_logic", ":iterator_stack", @@ -66,7 +65,6 @@ cc_library( "//common:expr", "//common:function_descriptor", "//common:kind", - "//common:native_type", "//common:value", "//common:value_kind", "//eval/internal:errors", @@ -85,7 +83,6 @@ cc_library( "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:nullability", - "@com_google_absl//absl/container:inlined_vector", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/log:absl_log", "@com_google_absl//absl/status", @@ -107,11 +104,7 @@ cc_library( "cel_expression_flat_impl.h", ], deps = [ - ":attribute_trail", - ":comprehension_slots", - ":direct_expression_step", ":evaluator_core", - "//common:native_type", "//common:value", "//eval/internal:adapter_activation_impl", "//eval/internal:interop", @@ -123,10 +116,8 @@ cc_library( "//runtime/internal:runtime_env", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/log:absl_check", - "@com_google_absl//absl/memory", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", - "@com_google_absl//absl/strings", "@com_google_protobuf//:protobuf", ], ) @@ -206,10 +197,7 @@ cc_library( hdrs = [ "expression_step_logic.h", ], - deps = [ - "//common:native_type", - "@com_google_absl//absl/status", - ], + deps = ["//common:native_type"], ) cc_library( @@ -217,23 +205,7 @@ cc_library( hdrs = [ "expression_step_base.h", ], - deps = [ - ":evaluator_core", - ":expression_step_logic", - ], -) - -cc_library( - name = "const_value_step", - hdrs = [ - "const_value_step.h", - ], - deps = [ - ":compiler_constant_step", - ":direct_expression_step", - "//common:value", - "@com_google_absl//absl/status:statusor", - ], + deps = [":expression_step_logic"], ) cc_library( @@ -247,9 +219,9 @@ cc_library( deps = [ ":attribute_trail", ":attribute_utility", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//base:attributes", "//common:expr", "//common:kind", @@ -257,7 +229,6 @@ cc_library( "//common:value_kind", "//eval/internal:errors", "//internal:number", - "//internal:status_macros", "//runtime/internal:errors", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/status", @@ -273,12 +244,10 @@ cc_library( srcs = ["regex_match_step.cc"], hdrs = ["regex_match_step.h"], deps = [ - ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:value", - "//internal:status_macros", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings:cord", @@ -311,9 +280,9 @@ cc_library( ], deps = [ ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:memory", "//common:type", "//common:value", @@ -342,11 +311,10 @@ cc_library( "create_list_step.h", ], deps = [ - ":attribute_trail", ":attribute_utility", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:expr", "//common:value", "//internal:status_macros", @@ -366,10 +334,9 @@ cc_library( "create_struct_step.h", ], deps = [ - ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:value", "//internal:status_macros", "@com_google_absl//absl/container:flat_hash_set", @@ -389,10 +356,9 @@ cc_library( "create_map_step.h", ], deps = [ - ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:value", "//internal:status_macros", "@com_google_absl//absl/container:flat_hash_set", @@ -417,8 +383,8 @@ cc_test( ], deps = [ ":attribute_trail", - ":direct_expression_step", ":evaluator_core", + ":expression_step_logic", "//base:attributes", "//common:value", "//common:value_kind", @@ -444,31 +410,19 @@ cc_test( "comprehension_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", - ":comprehension_slots", - ":const_value_step", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", "//base:data", "//common:expr", - "//common:value", - "//common:value_testing", "//eval/public:activation", "//eval/public:cel_attribute", "//eval/public:cel_value", "//eval/public/structs:cel_proto_wrapper", - "//internal:status_macros", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", "@com_google_cel_spec//proto/cel/expr:syntax_cc_proto", "@com_google_protobuf//:protobuf", @@ -514,7 +468,6 @@ cc_test( deps = [ ":cel_expression_flat_impl", ":container_access_step", - ":direct_expression_step", ":evaluator_core", "//base:builtins", "//base:data", @@ -533,6 +486,7 @@ cc_test( "//eval/public/testing:matchers", "//internal:testing", "//parser", + "//runtime:runtime_options", "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", "@com_google_absl//absl/base:nullability", @@ -559,7 +513,6 @@ cc_test( "//internal:testing", "//parser", "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", "@com_google_cel_spec//proto/cel/expr:checked_cc_proto", "@com_google_cel_spec//proto/cel/expr:syntax_cc_proto", "@com_google_protobuf//:protobuf", @@ -573,22 +526,16 @@ cc_test( "ident_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", ":evaluator_core", "//base:data", "//common:memory", - "//common:value", "//eval/public:activation", "//eval/public:cel_attribute", "//eval/public:cel_value", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/status", "@com_google_protobuf//:protobuf", ], @@ -602,10 +549,7 @@ cc_test( ], deps = [ ":cel_expression_flat_impl", - ":const_value_step", - ":direct_expression_step", ":evaluator_core", - "//base:builtins", "//base:data", "//common:constant", "//common:expr", @@ -623,13 +567,9 @@ cc_test( "//eval/public/testing:matchers", "//eval/testutil:test_message_cc_proto", "//internal:testing", - "//runtime:function_overload_reference", - "//runtime:function_registry", "//runtime:runtime_options", - "//runtime:standard_functions", "//runtime/internal:runtime_env_testing", "@com_google_absl//absl/status", - "@com_google_absl//absl/status:status_macros", "@com_google_absl//absl/status:status_matchers", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", @@ -645,16 +585,11 @@ cc_test( "logic_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", - ":const_value_step", - ":direct_expression_step", ":evaluator_core", "//base:attributes", "//base:data", "//common:expr", - "//common:unknown", - "//common:value", "//eval/public:activation", "//eval/public:cel_attribute", "//eval/public:cel_value", @@ -662,17 +597,12 @@ cc_test( "//eval/public:unknown_set", "//internal:status_macros", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/status", "@com_google_absl//absl/status:status_matchers", - "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:string_view", "@com_google_protobuf//:protobuf", ], @@ -685,9 +615,7 @@ cc_test( "select_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", - ":const_value_step", ":evaluator_core", ":select_step", "//base:attributes", @@ -696,7 +624,6 @@ cc_test( "//common:legacy_value", "//common:type", "//common:value", - "//common:value_testing", "//eval/public:activation", "//eval/public:cel_attribute", "//eval/public:cel_value", @@ -707,19 +634,13 @@ cc_test( "//eval/public/structs:trivial_legacy_type_info", "//eval/testutil:test_extensions_cc_proto", "//eval/testutil:test_message_cc_proto", - "//extensions/protobuf:value", "//internal:proto_matchers", "//internal:status_macros", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/base:nullability", - "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/status", "@com_google_absl//absl/status:status_matchers", "@com_google_absl//absl/status:statusor", @@ -739,17 +660,13 @@ cc_test( "create_list_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", - ":const_value_step", ":create_list_step", - ":direct_expression_step", ":evaluator_core", "//base:attributes", "//base:data", "//common:expr", "//common:value", - "//common:value_testing", "//eval/internal:interop", "//eval/public:activation", "//eval/public:cel_attribute", @@ -758,13 +675,9 @@ cc_test( "//eval/public/testing:matchers", "//internal:status_macros", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/status", "@com_google_absl//absl/status:status_matchers", @@ -783,11 +696,8 @@ cc_test( deps = [ ":cel_expression_flat_impl", ":create_struct_step", - ":direct_expression_step", ":evaluator_core", - ":ident_step", "//base:data", - "//common:expr", "//eval/public:activation", "//eval/public:cel_type_registry", "//eval/public:cel_value", @@ -822,9 +732,7 @@ cc_test( deps = [ ":cel_expression_flat_impl", ":create_map_step", - ":direct_expression_step", ":evaluator_core", - ":ident_step", "//base:data", "//common:expr", "//eval/public:activation", @@ -928,16 +836,13 @@ cc_library( "ternary_step.h", ], deps = [ - ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//base:builtins", "//common:value", "//eval/internal:errors", - "//internal:status_macros", "@com_google_absl//absl/status", - "@com_google_absl//absl/status:statusor", ], ) @@ -948,28 +853,21 @@ cc_test( "ternary_step_test.cc", ], deps = [ - ":attribute_trail", ":cel_expression_flat_impl", - ":const_value_step", - ":direct_expression_step", ":evaluator_core", ":ternary_step", "//base:attributes", "//base:data", "//common:expr", - "//common:value", "//eval/public:activation", + "//eval/public:cel_attribute", "//eval/public:cel_value", "//eval/public:unknown_attribute_set", "//eval/public:unknown_set", "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", "//runtime:runtime_options", "//runtime/internal:runtime_env", "//runtime/internal:runtime_env_testing", - "//runtime/internal:runtime_type_provider", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/status", "@com_google_protobuf//:protobuf", @@ -981,13 +879,10 @@ cc_library( srcs = ["shadowable_value_step.cc"], hdrs = ["shadowable_value_step.h"], deps = [ - ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", + ":expression_step_logic", "//common:value", - "//internal:status_macros", - "@com_google_absl//absl/memory", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings:string_view", @@ -1014,39 +909,7 @@ cc_test( "//runtime/internal:runtime_env_testing", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/status:statusor", - ], -) - -cc_library( - name = "compiler_constant_step", - srcs = ["compiler_constant_step.cc"], - hdrs = ["compiler_constant_step.h"], - deps = [ - ":attribute_trail", - ":direct_expression_step", - ":evaluator_core", - "//common:native_type", - "//common:value", - "@com_google_absl//absl/status", - ], -) - -cc_test( - name = "compiler_constant_step_test", - srcs = ["compiler_constant_step_test.cc"], - deps = [ - ":attribute_trail", - ":compiler_constant_step", - ":direct_expression_step", - ":evaluator_core", - "//common:native_type", - "//common:value", - "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", - "//runtime:runtime_options", - "//runtime/internal:runtime_type_provider", + "@com_google_absl//absl/strings:string_view", "@com_google_protobuf//:protobuf", ], ) @@ -1056,7 +919,6 @@ cc_test( srcs = ["lazy_init_step_test.cc"], deps = [ ":comprehension_slots", - ":const_value_step", ":evaluator_core", "//base:data", "//common:value", @@ -1070,46 +932,16 @@ cc_test( ], ) -cc_library( - name = "direct_expression_step", - srcs = ["direct_expression_step.cc"], - hdrs = ["direct_expression_step.h"], - deps = [ - ":attribute_trail", - "//common:native_type", - "//common:value", - "@com_google_absl//absl/status", - "@com_google_absl//absl/types:optional", - ], -) - -cc_library( - name = "trace_step", - hdrs = ["trace_step.h"], - deps = [ - ":attribute_trail", - ":direct_expression_step", - ":evaluator_core", - "//common:native_type", - "//common:value", - "//internal:status_macros", - "@com_google_absl//absl/status", - "@com_google_absl//absl/types:optional", - ], -) - cc_library( name = "optional_or_step", srcs = ["optional_or_step.cc"], hdrs = ["optional_or_step.h"], deps = [ ":attribute_trail", - ":direct_expression_step", ":evaluator_core", ":expression_step_base", ":expression_step_logic", "//common:value", - "//internal:status_macros", "//runtime/internal:errors", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/status", @@ -1118,31 +950,6 @@ cc_library( ], ) -cc_test( - name = "optional_or_step_test", - srcs = ["optional_or_step_test.cc"], - deps = [ - ":attribute_trail", - ":const_value_step", - ":direct_expression_step", - ":evaluator_core", - ":optional_or_step", - "//common:value", - "//common:value_kind", - "//common:value_testing", - "//internal:testing", - "//internal:testing_descriptor_pool", - "//internal:testing_message_factory", - "//runtime:activation", - "//runtime:runtime_options", - "//runtime/internal:errors", - "//runtime/internal:runtime_type_provider", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/status", - "@com_google_protobuf//:protobuf", - ], -) - cc_library( name = "iterator_stack", hdrs = ["iterator_stack.h"], diff --git a/eval/eval/cel_expression_flat_impl.cc b/eval/eval/cel_expression_flat_impl.cc index c0f0b5e71..56b4d32a2 100644 --- a/eval/eval/cel_expression_flat_impl.cc +++ b/eval/eval/cel_expression_flat_impl.cc @@ -16,19 +16,12 @@ #include #include -#include #include "absl/base/nullability.h" #include "absl/log/absl_check.h" -#include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/status/statusor.h" -#include "absl/strings/str_cat.h" -#include "common/native_type.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/internal/adapter_activation_impl.h" #include "eval/internal/interop.h" @@ -37,7 +30,6 @@ #include "eval/public/cel_value.h" #include "internal/casts.h" #include "internal/status_macros.h" -#include "runtime/internal/runtime_env.h" #include "google/protobuf/arena.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/message.h" @@ -46,7 +38,6 @@ namespace google::api::expr::runtime { namespace { using ::cel::Value; -using ::cel::runtime_internal::RuntimeEnv; EvaluationListener AdaptListener(const CelEvaluationListener& listener) { if (!listener) return nullptr; @@ -123,58 +114,4 @@ std::unique_ptr CelExpressionFlatImpl::CreateState() const { flat_expression_); } -absl::StatusOr> -CelExpressionRecursiveImpl::Create( - absl_nonnull std::shared_ptr env, - FlatExpression flat_expr) { - const ExpressionStepLogic* logic = nullptr; - if (!flat_expr.path().empty() && flat_expr.path()[0].IsGenericStep()) { - logic = flat_expr.path()[0].GetGenericStep(); - } - if (logic != nullptr && - logic->GetNativeTypeId() != cel::NativeTypeId::For()) { - return absl::InvalidArgumentError(absl::StrCat( - "Expected a recursive program step", flat_expr.path().size())); - } - - auto* instance = - new CelExpressionRecursiveImpl(std::move(env), std::move(flat_expr)); - - return absl::WrapUnique(instance); -} - -absl::StatusOr CelExpressionRecursiveImpl::Trace( - const BaseActivation& activation, google::protobuf::Arena* arena, - CelEvaluationListener callback, CelEvaluationState* state) const { - std::unique_ptr inline_state; - if (state == nullptr) { - inline_state = CreateState(); - state = inline_state.get(); - } - auto derived_state = ::cel::internal::down_cast(state); - if (arena != nullptr) { - derived_state->Rebind(arena); - } else { - arena = derived_state->arena(); - } - if (state != inline_state.get()) { - derived_state->comprehension_slots().Reset(); - } - ABSL_DCHECK(arena != nullptr) - << "arena must be implicitly provided when using InitializeState() or " - "explicitly provided when using CreateState()"; - cel::interop_internal::AdapterActivationImpl modern_activation(activation); - ExecutionFrameBase execution_frame( - modern_activation, AdaptListener(callback), flat_expression_.options(), - flat_expression_.type_provider(), env_->descriptor_pool.get(), - env_->MutableMessageFactory(), arena, - /*embedder_context=*/nullptr, derived_state->comprehension_slots()); - - cel::Value result; - AttributeTrail trail; - CEL_RETURN_IF_ERROR(root_->Evaluate(execution_frame, result, trail)); - - return cel::interop_internal::ModernValueToLegacyValueOrDie(arena, result); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/cel_expression_flat_impl.h b/eval/eval/cel_expression_flat_impl.h index 055147477..5e9320332 100644 --- a/eval/eval/cel_expression_flat_impl.h +++ b/eval/eval/cel_expression_flat_impl.h @@ -15,19 +15,15 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_CEL_EXPRESSION_FLAT_IMPL_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_CEL_EXPRESSION_FLAT_IMPL_H_ -#include #include #include #include "absl/base/nullability.h" #include "absl/status/statusor.h" -#include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/public/base_activation.h" #include "eval/public/cel_expression.h" #include "eval/public/cel_value.h" -#include "internal/casts.h" #include "runtime/internal/runtime_env.h" #include "google/protobuf/arena.h" #include "google/protobuf/descriptor.h" @@ -98,83 +94,6 @@ class CelExpressionFlatImpl : public CelExpression { FlatExpression flat_expression_; }; -// Implementation of the CelExpression that evaluates a recursive representation -// of the AST. -// -// This class adapts FlatExpression to implement the CelExpression interface. -// -// Assumes that the flat expression is wrapping a simple recursive program. -class CelExpressionRecursiveImpl : public CelExpression { - private: - class EvaluationState : public CelEvaluationState { - public: - explicit EvaluationState(size_t comprehension_slots) - : EvaluationState(nullptr, comprehension_slots) {} - - EvaluationState(google::protobuf::Arena* arena, size_t comprehension_slots) - : arena_(arena), comprehension_slots_(comprehension_slots) {} - - google::protobuf::Arena* arena() { return arena_; } - - void Rebind(google::protobuf::Arena* arena) { arena_ = arena; } - - ComprehensionSlots& comprehension_slots() { return comprehension_slots_; } - - private: - google::protobuf::Arena* arena_; - ComprehensionSlots comprehension_slots_; - }; - - public: - static absl::StatusOr> Create( - absl_nonnull std::shared_ptr env, - FlatExpression flat_expression); - - // Move-only - CelExpressionRecursiveImpl(const CelExpressionRecursiveImpl&) = delete; - CelExpressionRecursiveImpl& operator=(const CelExpressionRecursiveImpl&) = - delete; - CelExpressionRecursiveImpl(CelExpressionRecursiveImpl&&) = default; - CelExpressionRecursiveImpl& operator=(CelExpressionRecursiveImpl&&) = delete; - - // Implement CelExpression. - std::unique_ptr InitializeState( - google::protobuf::Arena* arena) const override { - return std::make_unique( - arena, flat_expression_.comprehension_slots_size()); - } - - // Implement CelExpression. - std::unique_ptr CreateState() const override { - return std::make_unique( - flat_expression_.comprehension_slots_size()); - } - - absl::StatusOr Trace(const BaseActivation& activation, - google::protobuf::Arena* arena, - CelEvaluationListener callback, - CelEvaluationState* state) const override; - - // Exposed for inspection in tests. - const FlatExpression& flat_expression() const { return flat_expression_; } - - const DirectExpressionStep* root() const { return root_; } - - private: - explicit CelExpressionRecursiveImpl( - absl_nonnull std::shared_ptr env, - FlatExpression flat_expression) - : env_(std::move(env)), - flat_expression_(std::move(flat_expression)), - root_(cel::internal::down_cast( - flat_expression_.path()[0].GetGenericStep()) - ->wrapped()) {} - - absl_nonnull std::shared_ptr env_; - FlatExpression flat_expression_; - const DirectExpressionStep* root_; -}; - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_CEL_EXPRESSION_FLAT_IMPL_H_ diff --git a/eval/eval/compiler_constant_step.cc b/eval/eval/compiler_constant_step.cc deleted file mode 100644 index c1b46b92e..000000000 --- a/eval/eval/compiler_constant_step.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "eval/eval/compiler_constant_step.h" - -#include "absl/status/status.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/evaluator_core.h" - -namespace google::api::expr::runtime { - -using ::cel::Value; - -absl::Status DirectCompilerConstantStep::Evaluate( - ExecutionFrameBase& frame, Value& result, AttributeTrail& attribute) const { - result = value_; - return absl::OkStatus(); -} - -} // namespace google::api::expr::runtime diff --git a/eval/eval/compiler_constant_step.h b/eval/eval/compiler_constant_step.h deleted file mode 100644 index 6708e02de..000000000 --- a/eval/eval/compiler_constant_step.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_COMPILER_CONSTANT_STEP_H_ -#define THIRD_PARTY_CEL_CPP_EVAL_EVAL_COMPILER_CONSTANT_STEP_H_ - -#include -#include - -#include "absl/status/status.h" -#include "common/native_type.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" - -namespace google::api::expr::runtime { - -// DirectExpressionStep implementation that simply assigns a constant value. -// -// Overrides NativeTypeId() allow the FlatExprBuilder and extensions to -// inspect the underlying value. -class DirectCompilerConstantStep : public DirectExpressionStep { - public: - DirectCompilerConstantStep(cel::Value value, int64_t expr_id) - : DirectExpressionStep(expr_id), value_(std::move(value)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute) const override; - - cel::NativeTypeId GetNativeTypeId() const override { - return cel::NativeTypeId::For(); - } - - const cel::Value& value() const { return value_; } - - private: - cel::Value value_; -}; - -} // namespace google::api::expr::runtime - -#endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_COMPILER_CONSTANT_STEP_H_ diff --git a/eval/eval/compiler_constant_step_test.cc b/eval/eval/compiler_constant_step_test.cc deleted file mode 100644 index 181728479..000000000 --- a/eval/eval/compiler_constant_step_test.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "eval/eval/compiler_constant_step.h" - -#include "common/native_type.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" -#include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" -#include "runtime/internal/runtime_type_provider.h" -#include "runtime/runtime_options.h" -#include "google/protobuf/arena.h" - -namespace google::api::expr::runtime { - -namespace { - -class DirectCompilerConstantStepTest : public testing::Test { - public: - DirectCompilerConstantStepTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()) {} - - protected: - google::protobuf::Arena arena_; - cel::runtime_internal::RuntimeTypeProvider type_provider_; - cel::Activation empty_activation_; - cel::RuntimeOptions options_; -}; - -TEST_F(DirectCompilerConstantStepTest, Evaluate) { - ExecutionFrameBase frame(empty_activation_, options_, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - DirectCompilerConstantStep step(cel::IntValue(42), -1); - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step.Evaluate(frame, result, attr), absl_testing::IsOk()); - - EXPECT_EQ(result.GetInt().NativeValue(), 42); -} - -TEST_F(DirectCompilerConstantStepTest, TypeId) { - DirectCompilerConstantStep step(cel::IntValue(42), -1); - - const DirectExpressionStep& abstract_step = step; - EXPECT_EQ(abstract_step.GetNativeTypeId(), - cel::NativeTypeId::For()); -} - -TEST_F(DirectCompilerConstantStepTest, Value) { - DirectCompilerConstantStep step(cel::IntValue(42), -1); - - EXPECT_EQ(step.value().GetInt().NativeValue(), 42); -} - -} // namespace -} // namespace google::api::expr::runtime diff --git a/eval/eval/comprehension_step.cc b/eval/eval/comprehension_step.cc index 661a8f2e4..321e9c213 100644 --- a/eval/eval/comprehension_step.cc +++ b/eval/eval/comprehension_step.cc @@ -1,13 +1,11 @@ #include "eval/eval/comprehension_step.h" #include -#include #include #include #include "absl/base/attributes.h" #include "absl/base/casts.h" -#include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/log/absl_check.h" #include "absl/status/status.h" @@ -17,11 +15,9 @@ #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" #include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/iterator_stack.h" #include "eval/internal/errors.h" -#include "internal/status_macros.h" namespace google::api::expr::runtime { namespace { @@ -34,7 +30,6 @@ enum class IterableKind { using ::cel::AttributeQualifier; using ::cel::UnknownValue; using ::cel::Value; -using ::cel::ValueIterator; using ::cel::ValueIteratorPtr; using ::cel::ValueKind; using ::cel::runtime_internal::CreateNoMatchingOverloadError; @@ -56,373 +51,6 @@ AttributeQualifier AttributeQualifierFromValue(const Value& v) { } } -class ComprehensionDirectStep final : public DirectExpressionStep { - public: - explicit ComprehensionDirectStep( - size_t iter_slot, size_t iter2_slot, size_t accu_slot, - std::unique_ptr range, - std::unique_ptr accu_init, - std::unique_ptr loop_step, - std::unique_ptr condition_step, - std::unique_ptr result_step, bool shortcircuiting, - int64_t expr_id) - : DirectExpressionStep(expr_id), - iter_slot_(iter_slot), - iter2_slot_(iter2_slot), - accu_slot_(accu_slot), - range_(std::move(range)), - accu_init_(std::move(accu_init)), - loop_step_(std::move(loop_step)), - condition_(std::move(condition_step)), - result_step_(std::move(result_step)), - shortcircuiting_(shortcircuiting) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& trail) const override { - return iter_slot_ == iter2_slot_ ? Evaluate1(frame, result, trail) - : Evaluate2(frame, result, trail); - } - - private: - absl::Status Evaluate1(ExecutionFrameBase& frame, Value& result, - AttributeTrail& trail) const; - - absl::StatusOr Evaluate1Unknown( - ExecutionFrameBase& frame, IterableKind range_iter_kind, - const AttributeTrail& range_iter_attr, - ValueIterator* absl_nonnull range_iter, - ComprehensionSlots::Slot* absl_nonnull accu_slot, - ComprehensionSlots::Slot* absl_nonnull iter_slot, Value& result, - AttributeTrail& trail) const; - - absl::StatusOr Evaluate1Known( - ExecutionFrameBase& frame, ValueIterator* absl_nonnull range_iter, - ComprehensionSlots::Slot* absl_nonnull accu_slot, - ComprehensionSlots::Slot* absl_nonnull iter_slot, Value& result, - AttributeTrail& trail) const; - - absl::Status Evaluate2(ExecutionFrameBase& frame, Value& result, - AttributeTrail& trail) const; - - const size_t iter_slot_; - const size_t iter2_slot_; - const size_t accu_slot_; - const std::unique_ptr range_; - const std::unique_ptr accu_init_; - const std::unique_ptr loop_step_; - const std::unique_ptr condition_; - const std::unique_ptr result_step_; - const bool shortcircuiting_; -}; - -absl::Status ComprehensionDirectStep::Evaluate1(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& trail) const { - Value range; - AttributeTrail range_attr; - CEL_RETURN_IF_ERROR(range_->Evaluate(frame, range, range_attr)); - - if (frame.unknown_processing_enabled() && range.IsMap()) { - if (frame.attribute_utility().CheckForUnknownPartial(range_attr)) { - result = - frame.attribute_utility().CreateUnknownSet(range_attr.attribute()); - return absl::OkStatus(); - } - } - - absl_nullability_unknown ValueIteratorPtr range_iter; - IterableKind iterable_kind; - switch (range.kind()) { - case ValueKind::kList: { - CEL_ASSIGN_OR_RETURN(range_iter, range.GetList().NewIterator()); - iterable_kind = IterableKind::kList; - } break; - case ValueKind::kMap: { - CEL_ASSIGN_OR_RETURN(range_iter, range.GetMap().NewIterator()); - iterable_kind = IterableKind::kMap; - } break; - case ValueKind::kError: - ABSL_FALLTHROUGH_INTENDED; - case ValueKind::kUnknown: - result = std::move(range); - return absl::OkStatus(); - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(""), frame.arena()); - return absl::OkStatus(); - } - ABSL_DCHECK(range_iter != nullptr); - - ComprehensionSlots::Slot* accu_slot = - frame.comprehension_slots().Get(accu_slot_); - ABSL_DCHECK(accu_slot != nullptr); - - { - Value accu_init; - AttributeTrail accu_init_attr; - CEL_RETURN_IF_ERROR(accu_init_->Evaluate(frame, accu_init, accu_init_attr)); - accu_slot->Set(std::move(accu_init), std::move(accu_init_attr)); - } - - ComprehensionSlots::Slot* iter_slot = - frame.comprehension_slots().Get(iter_slot_); - ABSL_DCHECK(iter_slot != nullptr); - iter_slot->Set(); - - bool should_skip_result; - if (frame.unknown_processing_enabled()) { - CEL_ASSIGN_OR_RETURN( - should_skip_result, - Evaluate1Unknown(frame, iterable_kind, range_attr, range_iter.get(), - accu_slot, iter_slot, result, trail)); - } else { - CEL_ASSIGN_OR_RETURN(should_skip_result, - Evaluate1Known(frame, range_iter.get(), accu_slot, - iter_slot, result, trail)); - } - - frame.comprehension_slots().ClearSlot(iter_slot_); - if (!should_skip_result) { - CEL_RETURN_IF_ERROR(result_step_->Evaluate(frame, result, trail)); - } - frame.comprehension_slots().ClearSlot(accu_slot_); - return absl::OkStatus(); -} - -absl::StatusOr ComprehensionDirectStep::Evaluate1Unknown( - ExecutionFrameBase& frame, IterableKind range_iter_kind, - const AttributeTrail& range_iter_attr, - ValueIterator* absl_nonnull range_iter, - ComprehensionSlots::Slot* absl_nonnull accu_slot, - ComprehensionSlots::Slot* absl_nonnull iter_slot, Value& result, - AttributeTrail& trail) const { - Value condition; - AttributeTrail condition_attr; - Value key_or_value; - Value* key; - Value* value; - - switch (range_iter_kind) { - case IterableKind::kList: - key = &key_or_value; - value = iter_slot->mutable_value(); - break; - case IterableKind::kMap: - key = iter_slot->mutable_value(); - value = nullptr; - break; - default: - ABSL_UNREACHABLE(); - } - while (true) { - CEL_ASSIGN_OR_RETURN(bool ok, range_iter->Next2(frame.descriptor_pool(), - frame.message_factory(), - frame.arena(), key, value)); - if (!ok) { - break; - } - CEL_RETURN_IF_ERROR(frame.IncrementIterations()); - *iter_slot->mutable_attribute() = - range_iter_attr.Step(AttributeQualifierFromValue(*key)); - if (frame.attribute_utility().CheckForUnknownExact( - iter_slot->attribute())) { - *iter_slot->mutable_value() = frame.attribute_utility().CreateUnknownSet( - iter_slot->attribute().attribute()); - } - - // Evaluate the loop condition. - CEL_RETURN_IF_ERROR(condition_->Evaluate(frame, condition, condition_attr)); - - switch (condition.kind()) { - case ValueKind::kBool: - break; - case ValueKind::kError: - ABSL_FALLTHROUGH_INTENDED; - case ValueKind::kUnknown: - result = std::move(condition); - return true; - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(""), frame.arena()); - return true; - } - - if (shortcircuiting_ && !absl::implicit_cast(condition.GetBool())) { - break; - } - - // Evaluate the loop step. - CEL_RETURN_IF_ERROR(loop_step_->Evaluate(frame, *accu_slot->mutable_value(), - *accu_slot->mutable_attribute())); - } - return false; -} - -absl::StatusOr ComprehensionDirectStep::Evaluate1Known( - ExecutionFrameBase& frame, ValueIterator* absl_nonnull range_iter, - ComprehensionSlots::Slot* absl_nonnull accu_slot, - ComprehensionSlots::Slot* absl_nonnull iter_slot, Value& result, - AttributeTrail& trail) const { - Value condition; - AttributeTrail condition_attr; - - while (true) { - CEL_ASSIGN_OR_RETURN( - bool ok, - range_iter->Next1(frame.descriptor_pool(), frame.message_factory(), - frame.arena(), iter_slot->mutable_value())); - if (!ok) { - break; - } - CEL_RETURN_IF_ERROR(frame.IncrementIterations()); - - // Evaluate the loop condition. - CEL_RETURN_IF_ERROR(condition_->Evaluate(frame, condition, condition_attr)); - - switch (condition.kind()) { - case ValueKind::kBool: - break; - case ValueKind::kError: - ABSL_FALLTHROUGH_INTENDED; - case ValueKind::kUnknown: - result = std::move(condition); - return true; - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(""), frame.arena()); - return true; - } - - if (shortcircuiting_ && !absl::implicit_cast(condition.GetBool())) { - break; - } - - // Evaluate the loop step. - CEL_RETURN_IF_ERROR(loop_step_->Evaluate(frame, *accu_slot->mutable_value(), - *accu_slot->mutable_attribute())); - } - return false; -} - -absl::Status ComprehensionDirectStep::Evaluate2(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& trail) const { - Value range; - AttributeTrail range_attr; - CEL_RETURN_IF_ERROR(range_->Evaluate(frame, range, range_attr)); - - if (frame.unknown_processing_enabled() && range.IsMap()) { - if (frame.attribute_utility().CheckForUnknownPartial(range_attr)) { - result = - frame.attribute_utility().CreateUnknownSet(range_attr.attribute()); - return absl::OkStatus(); - } - } - - absl_nullability_unknown ValueIteratorPtr range_iter; - switch (range.kind()) { - case ValueKind::kList: { - CEL_ASSIGN_OR_RETURN(range_iter, range.GetList().NewIterator()); - } break; - case ValueKind::kMap: { - CEL_ASSIGN_OR_RETURN(range_iter, range.GetMap().NewIterator()); - } break; - case ValueKind::kError: - ABSL_FALLTHROUGH_INTENDED; - case ValueKind::kUnknown: - result = std::move(range); - return absl::OkStatus(); - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(""), frame.arena()); - return absl::OkStatus(); - } - ABSL_DCHECK(range_iter != nullptr); - - ComprehensionSlots::Slot* accu_slot = - frame.comprehension_slots().Get(accu_slot_); - ABSL_DCHECK(accu_slot != nullptr); - - { - Value accu_init; - AttributeTrail accu_init_attr; - CEL_RETURN_IF_ERROR(accu_init_->Evaluate(frame, accu_init, accu_init_attr)); - accu_slot->Set(std::move(accu_init), std::move(accu_init_attr)); - } - - ComprehensionSlots::Slot* iter_slot = - frame.comprehension_slots().Get(iter_slot_); - ABSL_DCHECK(iter_slot != nullptr); - iter_slot->Set(); - - ComprehensionSlots::Slot* iter2_slot = - frame.comprehension_slots().Get(iter2_slot_); - ABSL_DCHECK(iter2_slot != nullptr); - iter2_slot->Set(); - - Value condition; - AttributeTrail condition_attr; - bool should_skip_result = false; - - while (true) { - CEL_ASSIGN_OR_RETURN( - bool ok, - range_iter->Next2(frame.descriptor_pool(), frame.message_factory(), - frame.arena(), iter_slot->mutable_value(), - iter2_slot->mutable_value())); - if (!ok) { - break; - } - CEL_RETURN_IF_ERROR(frame.IncrementIterations()); - if (frame.unknown_processing_enabled()) { - *iter_slot->mutable_attribute() = *iter2_slot->mutable_attribute() = - range_attr.Step(AttributeQualifierFromValue(iter_slot->value())); - if (frame.attribute_utility().CheckForUnknownExact( - iter_slot->attribute())) { - *iter2_slot->mutable_value() = - frame.attribute_utility().CreateUnknownSet( - iter_slot->attribute().attribute()); - } - } - - // Evaluate the loop condition. - CEL_RETURN_IF_ERROR(condition_->Evaluate(frame, condition, condition_attr)); - - switch (condition.kind()) { - case ValueKind::kBool: - break; - case ValueKind::kError: - ABSL_FALLTHROUGH_INTENDED; - case ValueKind::kUnknown: - result = std::move(condition); - should_skip_result = true; - goto finish; - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(""), frame.arena()); - should_skip_result = true; - goto finish; - } - - if (shortcircuiting_ && !absl::implicit_cast(condition.GetBool())) { - break; - } - - // Evaluate the loop step. - CEL_RETURN_IF_ERROR(loop_step_->Evaluate(frame, *accu_slot->mutable_value(), - *accu_slot->mutable_attribute())); - } - -finish: - iter_slot->Clear(); - iter2_slot->Clear(); - if (!should_skip_result) { - CEL_RETURN_IF_ERROR(result_step_->Evaluate(frame, result, trail)); - } - accu_slot->Clear(); - return absl::OkStatus(); -} - } // namespace void ComprehensionInitStep::Evaluate(ExecutionFrame* frame) const { @@ -717,20 +345,6 @@ void ComprehensionCondStep::Evaluate2(ExecutionFrame* frame) const { } } -std::unique_ptr CreateDirectComprehensionStep( - size_t iter_slot, size_t iter2_slot, size_t accu_slot, - std::unique_ptr range, - std::unique_ptr accu_init, - std::unique_ptr loop_step, - std::unique_ptr condition_step, - std::unique_ptr result_step, bool shortcircuiting, - int64_t expr_id) { - return std::make_unique( - iter_slot, iter2_slot, accu_slot, std::move(range), std::move(accu_init), - std::move(loop_step), std::move(condition_step), std::move(result_step), - shortcircuiting, expr_id); -} - void EvaluateComprehensionFinishStep(size_t accu_slot, ExecutionFrame& frame) { if (!frame.value_stack().HasEnough(2)) { frame.Abort( diff --git a/eval/eval/comprehension_step.h b/eval/eval/comprehension_step.h index 8bac8dab3..809b94d13 100644 --- a/eval/eval/comprehension_step.h +++ b/eval/eval/comprehension_step.h @@ -4,12 +4,8 @@ #include #include #include -#include -#include "absl/status/status.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/expression_step_logic.h" -#include "eval/eval/iterator_stack.h" namespace google::api::expr::runtime { @@ -84,16 +80,6 @@ class ComprehensionCondStep final { int32_t error_jump_offset_ = std::numeric_limits::max(); }; -// Creates a step for executing a comprehension. -std::unique_ptr CreateDirectComprehensionStep( - size_t iter_slot, size_t iter2_slot, size_t accu_slot, - std::unique_ptr range, - std::unique_ptr accu_init, - std::unique_ptr loop_step, - std::unique_ptr condition_step, - std::unique_ptr result_step, bool shortcircuiting, - int64_t expr_id); - // Runs a cleanup step for the comprehension. // Removes the comprehension context then pushes the 'result' sub expression to // the top of the stack. diff --git a/eval/eval/comprehension_step_test.cc b/eval/eval/comprehension_step_test.cc index 09c4eb228..5964421ed 100644 --- a/eval/eval/comprehension_step_test.cc +++ b/eval/eval/comprehension_step_test.cc @@ -8,17 +8,10 @@ #include "cel/expr/syntax.pb.h" #include "google/protobuf/struct.pb.h" #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "base/type_provider.h" #include "common/expr.h" -#include "common/value.h" -#include "common/value_testing.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/comprehension_slots.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" #include "eval/eval/ident_step.h" @@ -26,13 +19,8 @@ #include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" #include "eval/public/structs/cel_proto_wrapper.h" -#include "internal/status_macros.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "google/protobuf/arena.h" @@ -40,19 +28,12 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::absl_testing::StatusIs; -using ::cel::BoolValue; using ::cel::Expr; -using ::cel::IntValue; using ::cel::TypeProvider; -using ::cel::Value; using ::cel::runtime_internal::NewTestingRuntimeEnv; -using ::cel::test::BoolValueIs; using ::google::protobuf::Struct; using ::google::protobuf::Arena; -using ::testing::_; using ::testing::Eq; -using ::testing::Return; using ::testing::SizeIs; class ListKeysStepTest : public testing::Test { @@ -184,305 +165,5 @@ TEST_F(ListKeysStepTest, UnknownSetPassedThrough) { EXPECT_THAT(eval_result->UnknownSetOrDie()->unknown_attributes(), SizeIs(1)); } -class MockDirectStep : public DirectExpressionStep { - public: - MockDirectStep() : DirectExpressionStep(-1) {} - - MOCK_METHOD(absl::Status, Evaluate, - (ExecutionFrameBase&, Value&, AttributeTrail&), - (const, override)); -}; - -// Test fixture for comprehensions. -// -// Comprehensions are quite involved so tests here focus on edge cases that are -// hard to exercise normally in functional-style tests for the planner. -class DirectComprehensionTest : public testing::Test { - public: - DirectComprehensionTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()), slots_(2) {} - - // returns a two element list for testing [1, 2]. - absl::StatusOr MakeList() { - auto builder = cel::NewListValueBuilder(&arena_); - - CEL_RETURN_IF_ERROR(builder->Add(IntValue(1))); - CEL_RETURN_IF_ERROR(builder->Add(IntValue(2))); - return std::move(*builder).Build(); - } - - protected: - google::protobuf::Arena arena_; - cel::runtime_internal::RuntimeTypeProvider type_provider_; - ComprehensionSlots slots_; - cel::Activation empty_activation_; -}; - -TEST_F(DirectComprehensionTest, PropagateRangeNonOkStatus) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto range_step = std::make_unique(); - MockDirectStep* mock = range_step.get(); - - ON_CALL(*mock, Evaluate(_, _, _)) - .WillByDefault(Return(absl::InternalError("test range error"))); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/std::move(range_step), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(true)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal, "test range error")); -} - -TEST_F(DirectComprehensionTest, PropagateAccuInitNonOkStatus) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto accu_init = std::make_unique(); - MockDirectStep* mock = accu_init.get(); - - ON_CALL(*mock, Evaluate(_, _, _)) - .WillByDefault(Return(absl::InternalError("test accu init error"))); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/std::move(accu_init), - /*loop_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(true)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal, "test accu init error")); -} - -TEST_F(DirectComprehensionTest, PropagateLoopNonOkStatus) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto loop_step = std::make_unique(); - MockDirectStep* mock = loop_step.get(); - - ON_CALL(*mock, Evaluate(_, _, _)) - .WillByDefault(Return(absl::InternalError("test loop error"))); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/std::move(loop_step), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(true)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal, "test loop error")); -} - -TEST_F(DirectComprehensionTest, PropagateConditionNonOkStatus) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto condition = std::make_unique(); - MockDirectStep* mock = condition.get(); - - ON_CALL(*mock, Evaluate(_, _, _)) - .WillByDefault(Return(absl::InternalError("test condition error"))); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*condition_step=*/std::move(condition), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal, "test condition error")); -} - -TEST_F(DirectComprehensionTest, PropagateResultNonOkStatus) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto result_step = std::make_unique(); - MockDirectStep* mock = result_step.get(); - - ON_CALL(*mock, Evaluate(_, _, _)) - .WillByDefault(Return(absl::InternalError("test result error"))); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(true)), - /*result_step=*/std::move(result_step), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal, "test result error")); -} - -TEST_F(DirectComprehensionTest, Shortcircuit) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto loop_step = std::make_unique(); - MockDirectStep* mock = loop_step.get(); - - EXPECT_CALL(*mock, Evaluate(_, _, _)) - .Times(0) - .WillRepeatedly([](ExecutionFrameBase&, Value& result, AttributeTrail&) { - result = BoolValue(false); - return absl::OkStatus(); - }); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/std::move(loop_step), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - ASSERT_THAT(compre_step->Evaluate(frame, result, trail), IsOk()); - EXPECT_THAT(result, BoolValueIs(false)); -} - -TEST_F(DirectComprehensionTest, IterationLimit) { - cel::RuntimeOptions options; - options.comprehension_max_iterations = 2; - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto loop_step = std::make_unique(); - MockDirectStep* mock = loop_step.get(); - - EXPECT_CALL(*mock, Evaluate(_, _, _)) - .Times(1) - .WillRepeatedly([](ExecutionFrameBase&, Value& result, AttributeTrail&) { - result = BoolValue(false); - return absl::OkStatus(); - }); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/std::move(loop_step), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(true)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/true, -1); - - Value result; - AttributeTrail trail; - EXPECT_THAT(compre_step->Evaluate(frame, result, trail), - StatusIs(absl::StatusCode::kInternal)); -} - -TEST_F(DirectComprehensionTest, Exhaustive) { - cel::RuntimeOptions options; - - ExecutionFrameBase frame(empty_activation_, /*callback=*/nullptr, options, - type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_, - /*embedder_context=*/nullptr, slots_); - - auto loop_step = std::make_unique(); - MockDirectStep* mock = loop_step.get(); - - EXPECT_CALL(*mock, Evaluate(_, _, _)) - .Times(2) - .WillRepeatedly([](ExecutionFrameBase&, Value& result, AttributeTrail&) { - result = BoolValue(false); - return absl::OkStatus(); - }); - - ASSERT_OK_AND_ASSIGN(auto list, MakeList()); - - auto compre_step = CreateDirectComprehensionStep( - 0, 0, 1, - /*range_step=*/CreateConstValueDirectStep(std::move(list)), - /*accu_init=*/CreateConstValueDirectStep(BoolValue(false)), - /*loop_step=*/std::move(loop_step), - /*condition_step=*/CreateConstValueDirectStep(BoolValue(false)), - /*result_step=*/CreateDirectSlotIdentStep("__result__", 1, -1), - /*shortcircuiting=*/false, -1); - - Value result; - AttributeTrail trail; - ASSERT_THAT(compre_step->Evaluate(frame, result, trail), IsOk()); - EXPECT_THAT(result, BoolValueIs(false)); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/const_value_step.h b/eval/eval/const_value_step.h deleted file mode 100644 index 55425ceab..000000000 --- a/eval/eval/const_value_step.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONST_VALUE_STEP_H_ -#define THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONST_VALUE_STEP_H_ - -#include -#include -#include - -#include "absl/status/statusor.h" -#include "common/value.h" -#include "eval/eval/compiler_constant_step.h" -#include "eval/eval/direct_expression_step.h" - -namespace google::api::expr::runtime { - -// Factory method for Constant AST node expression recursive step. -inline std::unique_ptr CreateConstValueDirectStep( - cel::Value value, int64_t id = -1) { - return std::make_unique(std::move(value), id); -} - -} // namespace google::api::expr::runtime - -#endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONST_VALUE_STEP_H_ diff --git a/eval/eval/container_access_step.cc b/eval/eval/container_access_step.cc index dc1efbd12..5f7cf3e2b 100644 --- a/eval/eval/container_access_step.cc +++ b/eval/eval/container_access_step.cc @@ -17,12 +17,11 @@ #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" #include "eval/eval/attribute_utility.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "eval/internal/errors.h" #include "internal/number.h" -#include "internal/status_macros.h" #include "runtime/internal/errors.h" namespace google::api::expr::runtime { @@ -311,55 +310,8 @@ void ContainerAccessStep::Evaluate(ExecutionFrame* frame) const { std::move(result), std::move(result_trail)); } -class DirectContainerAccessStep : public DirectExpressionStep { - public: - DirectContainerAccessStep( - std::unique_ptr container_step, - std::unique_ptr key_step, - bool enable_optional_types, int64_t expr_id) - : DirectExpressionStep(expr_id), - container_step_(std::move(container_step)), - key_step_(std::move(key_step)), - enable_optional_types_(enable_optional_types) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& trail) const override; - - private: - std::unique_ptr container_step_; - std::unique_ptr key_step_; - bool enable_optional_types_; -}; - -absl::Status DirectContainerAccessStep::Evaluate(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& trail) const { - Value container; - Value key; - AttributeTrail container_trail; - AttributeTrail key_trail; - - CEL_RETURN_IF_ERROR( - container_step_->Evaluate(frame, container, container_trail)); - CEL_RETURN_IF_ERROR(key_step_->Evaluate(frame, key, key_trail)); - - PerformLookup(frame, container, key, container_trail, enable_optional_types_, - result, trail); - - return absl::OkStatus(); -} - } // namespace -std::unique_ptr CreateDirectContainerAccessStep( - std::unique_ptr container_step, - std::unique_ptr key_step, bool enable_optional_types, - int64_t expr_id) { - return std::make_unique( - std::move(container_step), std::move(key_step), enable_optional_types, - expr_id); -} - // Factory method for Select - based Execution step absl::StatusOr> CreateContainerAccessStep( const cel::CallExpr& call, bool enable_optional_types) { diff --git a/eval/eval/container_access_step.h b/eval/eval/container_access_step.h index 5d5fdde81..38d4b34d4 100644 --- a/eval/eval/container_access_step.h +++ b/eval/eval/container_access_step.h @@ -1,21 +1,14 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONTAINER_ACCESS_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_CONTAINER_ACCESS_STEP_H_ -#include #include #include "absl/status/statusor.h" #include "common/expr.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -std::unique_ptr CreateDirectContainerAccessStep( - std::unique_ptr container_step, - std::unique_ptr key_step, bool enable_optional_types, - int64_t expr_id); - // Factory method for Select - based Execution step absl::StatusOr> CreateContainerAccessStep( const cel::CallExpr& call, bool enable_optional_types = false); diff --git a/eval/eval/container_access_step_test.cc b/eval/eval/container_access_step_test.cc index 612732b43..a298c28e3 100644 --- a/eval/eval/container_access_step_test.cc +++ b/eval/eval/container_access_step_test.cc @@ -16,9 +16,7 @@ #include "common/ast.h" #include "common/expr.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" #include "eval/public/cel_expr_builder_factory.h" @@ -34,6 +32,7 @@ #include "parser/parser.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" +#include "runtime/runtime_options.h" #include "google/protobuf/arena.h" namespace google::api::expr::runtime { @@ -76,19 +75,10 @@ CelValue EvaluateAttributeHelper( container_expr.mutable_ident_expr().set_name("container"); key_expr.mutable_ident_expr().set_name("key"); - if (use_recursive_impl) { - path.push_back(ExpressionStep::MakeGenericStep( - std::make_unique(CreateDirectContainerAccessStep( - CreateDirectIdentStep("container", 1), - CreateDirectIdentStep("key", 2), - /*enable_optional_types=*/false, 3)), - 3)); - } else { path.push_back(ExpressionStep::MakeIdentifierStep("container", 1)); path.push_back(ExpressionStep::MakeIdentifierStep("key", 2)); path.push_back(ExpressionStep::MakeGenericStep( std::move(CreateContainerAccessStep(call).value()), 3)); - } cel::RuntimeOptions options; options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; diff --git a/eval/eval/create_list_step.cc b/eval/eval/create_list_step.cc index 8a7470fa7..1d57fafa7 100644 --- a/eval/eval/create_list_step.cc +++ b/eval/eval/create_list_step.cc @@ -13,11 +13,10 @@ #include "common/expr.h" #include "common/value.h" #include "common/values/list_value_builder.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/attribute_utility.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "internal/status_macros.h" namespace google::api::expr::runtime { @@ -129,124 +128,8 @@ absl::flat_hash_set MakeOptionalIndicesSet( return optional_indices; } -class CreateListDirectStep : public DirectExpressionStep { - public: - CreateListDirectStep( - std::vector> elements, - absl::flat_hash_set optional_indices, int64_t expr_id) - : DirectExpressionStep(expr_id), - elements_(std::move(elements)), - optional_indices_(std::move(optional_indices)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override { - ListValueBuilderPtr builder = NewListValueBuilder(frame.arena()); - builder->Reserve(elements_.size()); - - AttributeUtility::Accumulator unknowns = - frame.attribute_utility().CreateAccumulator(); - AttributeTrail tmp_attr; - - for (size_t i = 0; i < elements_.size(); ++i) { - const auto& element = elements_[i]; - CEL_RETURN_IF_ERROR(element->Evaluate(frame, result, tmp_attr)); - - if (result.IsError()) { - return absl::OkStatus(); - } - - if (frame.attribute_tracking_enabled()) { - if (frame.missing_attribute_errors_enabled()) { - if (frame.attribute_utility().CheckForMissingAttribute(tmp_attr)) { - CEL_ASSIGN_OR_RETURN( - result, frame.attribute_utility().CreateMissingAttributeError( - tmp_attr.attribute(), frame.arena())); - return absl::OkStatus(); - } - } - if (frame.unknown_processing_enabled()) { - if (result.IsUnknown()) { - unknowns.Add(result.GetUnknown()); - } - if (frame.attribute_utility().CheckForUnknown(tmp_attr, - /*use_partial=*/true)) { - unknowns.Add(tmp_attr); - } - } - } - - if (!unknowns.IsEmpty()) { - // We found an unknown, there is no point in attempting to create a - // list. Instead iterate through the remaining elements and look for - // more unknowns. - continue; - } - - // Conditionally add if optional. - if (optional_indices_.contains(static_cast(i))) { - if (auto optional_arg = result.AsOptional(); optional_arg) { - if (!optional_arg->HasValue()) { - continue; - } - Value optional_arg_value; - optional_arg->Value(&optional_arg_value); - if (optional_arg_value.IsError()) { - // Error should never be in optional, but better safe than sorry. - result = std::move(optional_arg_value); - return absl::OkStatus(); - } - CEL_RETURN_IF_ERROR(builder->Add(std::move(optional_arg_value))); - continue; - } - result = cel::TypeConversionError(result.GetTypeName(), "optional_type", - frame.arena()); - return absl::OkStatus(); - } - - // Otherwise just add. - CEL_RETURN_IF_ERROR(builder->Add(std::move(result))); - } - - if (!unknowns.IsEmpty()) { - result = std::move(unknowns).Build(); - return absl::OkStatus(); - } - result = std::move(*builder).Build(); - - return absl::OkStatus(); - } - - private: - std::vector> elements_; - absl::flat_hash_set optional_indices_; -}; - -class DirectMutableListStep : public DirectExpressionStep { - public: - explicit DirectMutableListStep(int64_t expr_id) - : DirectExpressionStep(expr_id) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override; -}; - -absl::Status DirectMutableListStep::Evaluate(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& attribute) const { - result = cel::CustomListValue( - cel::common_internal::NewMutableListValue(frame.arena()), frame.arena()); - return absl::OkStatus(); -} - } // namespace -std::unique_ptr CreateDirectListStep( - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id) { - return std::make_unique( - std::move(deps), std::move(optional_indices), expr_id); -} - absl::StatusOr> CreateCreateListStep( const cel::ListExpr& create_list_expr) { return std::make_unique( @@ -254,9 +137,4 @@ absl::StatusOr> CreateCreateListStep( MakeOptionalIndicesSet(create_list_expr)); } -std::unique_ptr CreateDirectMutableListStep( - int64_t expr_id) { - return std::make_unique(expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/create_list_step.h b/eval/eval/create_list_step.h index 3423febe5..9db49db32 100644 --- a/eval/eval/create_list_step.h +++ b/eval/eval/create_list_step.h @@ -1,34 +1,18 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_CREATE_LIST_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_CREATE_LIST_STEP_H_ -#include #include -#include -#include "absl/container/flat_hash_set.h" #include "absl/status/statusor.h" #include "common/expr.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -// Factory method for CreateList that evaluates recursively. -std::unique_ptr CreateDirectListStep( - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id); - // Factory method for CreateList which constructs an immutable list. absl::StatusOr> CreateCreateListStep( const cel::ListExpr& create_list_expr); -// Factory method for CreateList which constructs a mutable list. -// -// This is intended for the list construction step is generated for a -// list-building comprehension (rather than a user authored expression). -std::unique_ptr CreateDirectMutableListStep( - int64_t expr_id); - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_CREATE_LIST_STEP_H_ diff --git a/eval/eval/create_list_step_test.cc b/eval/eval/create_list_step_test.cc index 96da03ed2..a8f02b5d8 100644 --- a/eval/eval/create_list_step_test.cc +++ b/eval/eval/create_list_step_test.cc @@ -1,5 +1,6 @@ #include "eval/eval/create_list_step.h" +#include #include #include #include @@ -16,13 +17,8 @@ #include "base/type_provider.h" #include "common/expr.h" #include "common/value.h" -#include "common/value_testing.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/internal/interop.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" @@ -31,12 +27,8 @@ #include "eval/public/unknown_attribute_set.h" #include "internal/status_macros.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "google/protobuf/arena.h" @@ -45,24 +37,14 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::absl_testing::IsOkAndHolds; -using ::absl_testing::StatusIs; using ::cel::Attribute; -using ::cel::AttributeQualifier; using ::cel::AttributeSet; -using ::cel::ErrorValue; using ::cel::Expr; -using ::cel::IntValue; using ::cel::TypeProvider; -using ::cel::UnknownValue; -using ::cel::Value; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; -using ::cel::test::IntValueIs; using ::testing::Eq; -using ::testing::HasSubstr; using ::testing::Not; -using ::testing::UnorderedElementsAre; // Helper method. Creates simple pipeline containing Select step and runs it. absl::StatusOr RunExpression( @@ -263,288 +245,6 @@ TEST(CreateListStepTest, CreateListHundredAnd2Unknowns) { EXPECT_THAT(result_set->unknown_attributes().size(), Eq(2)); } -TEST(CreateDirectListStep, Basic) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(IntValue(1), -1)); - deps.push_back(CreateConstValueDirectStep(IntValue(2), -1)); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsList()); - EXPECT_THAT(result.GetList().Size(), IsOkAndHolds(2)); -} - -TEST(CreateDirectListStep, ForwardFirstError) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError("test1"), &arena), -1)); - deps.push_back(CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError("test2"), &arena), -1)); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInternal, "test1")); -} - -std::vector UnknownAttrNames(const UnknownValue& v) { - std::vector names; - names.reserve(v.ToAttributeSet().size()); - - for (const auto& attr : v.ToAttributeSet()) { - EXPECT_THAT(attr.AsString().status(), IsOk()); - names.push_back(attr.AsString().value_or("")); - } - - return names; -} - -TEST(CreateDirectListStep, MergeUnknowns) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - AttributeSet attr_set1({Attribute("var1")}); - AttributeSet attr_set2({Attribute("var2")}); - - std::vector> deps; - deps.push_back( - CreateConstValueDirectStep(cel::common_internal::MakeUnknownValue( - cel::Unknown(std::move(attr_set1))), - -1)); - deps.push_back( - CreateConstValueDirectStep(cel::common_internal::MakeUnknownValue( - cel::Unknown(std::move(attr_set2))), - -1)); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsUnknown()); - EXPECT_THAT(UnknownAttrNames(result.GetUnknown()), - UnorderedElementsAre("var1", "var2")); -} - -TEST(CreateDirectListStep, ErrorBeforeUnknown) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - AttributeSet attr_set1({Attribute("var1")}); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError("test1"), &arena), -1)); - deps.push_back(CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError("test2"), &arena), -1)); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInternal, "test1")); -} - -class SetAttrDirectStep : public DirectExpressionStep { - public: - explicit SetAttrDirectStep(Attribute attr) - : DirectExpressionStep(-1), attr_(std::move(attr)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attr) const override { - result = cel::NullValue(); - attr = AttributeTrail(attr_); - return absl::OkStatus(); - } - - private: - cel::Attribute attr_; -}; - -TEST(CreateDirectListStep, MissingAttribute) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - options.enable_missing_attribute_errors = true; - - ASSERT_THAT( - activation.SetMissingPatterns({cel::AttributePattern( - "var1", {cel::AttributeQualifierPattern::OfString("field1")})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(cel::NullValue(), -1)); - deps.push_back(std::make_unique( - Attribute("var1", {AttributeQualifier::OfString("field1")}))); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT( - result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("var1.field1"))); -} - -TEST(CreateDirectListStep, OptionalPresentSet) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(IntValue(1), -1)); - deps.push_back(CreateConstValueDirectStep( - cel::OptionalValue::Of(IntValue(2), &arena), -1)); - auto step = CreateDirectListStep(std::move(deps), {1}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsList()); - auto list = result.GetList(); - EXPECT_THAT(list.Size(), IsOkAndHolds(2)); - EXPECT_THAT(list.Get(0, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena), - IsOkAndHolds(IntValueIs(1))); - EXPECT_THAT(list.Get(1, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena), - IsOkAndHolds(IntValueIs(2))); -} - -TEST(CreateDirectListStep, OptionalAbsentNotSet) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(IntValue(1), -1)); - deps.push_back(CreateConstValueDirectStep(cel::OptionalValue::None(), -1)); - auto step = CreateDirectListStep(std::move(deps), {1}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsList()); - auto list = result.GetList(); - EXPECT_THAT(list.Size(), IsOkAndHolds(1)); - EXPECT_THAT(list.Get(0, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena), - IsOkAndHolds(IntValueIs(1))); -} - -TEST(CreateDirectListStep, PartialUnknown) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - cel::Activation activation; - cel::RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - ASSERT_THAT( - activation.SetUnknownPatterns({cel::AttributePattern( - "var1", {cel::AttributeQualifierPattern::OfString("field1")})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(cel::IntValue(1), -1)); - deps.push_back(std::make_unique(Attribute("var1", {}))); - auto step = CreateDirectListStep(std::move(deps), {}, -1); - - cel::Value result; - AttributeTrail attr; - - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsUnknown()); - EXPECT_THAT(UnknownAttrNames(result.GetUnknown()), - UnorderedElementsAre("var1")); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/create_map_step.cc b/eval/eval/create_map_step.cc index 15e696782..8283f1ed8 100644 --- a/eval/eval/create_map_step.cc +++ b/eval/eval/create_map_step.cc @@ -18,7 +18,6 @@ #include #include #include -#include #include "absl/container/flat_hash_set.h" #include "absl/status/status.h" @@ -27,18 +26,15 @@ #include "absl/types/optional.h" #include "common/value.h" #include "common/values/map_value_builder.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "internal/status_macros.h" namespace google::api::expr::runtime { namespace { -using ::cel::ErrorValue; -using ::cel::ErrorValueAssign; using ::cel::ErrorValueReturn; using ::cel::MapValueBuilderPtr; using ::cel::UnknownValue; @@ -132,112 +128,6 @@ void CreateStructStepForMap::Evaluate(ExecutionFrame* frame) const { frame->value_stack().PopAndPush(2 * entry_count_, *std::move(result)); } -class DirectCreateMapStep : public DirectExpressionStep { - public: - DirectCreateMapStep(std::vector> deps, - absl::flat_hash_set optional_indices, - int64_t expr_id) - : DirectExpressionStep(expr_id), - deps_(std::move(deps)), - optional_indices_(std::move(optional_indices)), - entry_count_(deps_.size() / 2) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override; - - private: - std::vector> deps_; - absl::flat_hash_set optional_indices_; - size_t entry_count_; -}; - -absl::Status DirectCreateMapStep::Evaluate( - ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const { - auto unknowns = frame.attribute_utility().CreateAccumulator(); - - MapValueBuilderPtr builder = NewMapValueBuilder(frame.arena()); - builder->Reserve(entry_count_); - - for (size_t i = 0; i < entry_count_; i += 1) { - Value key; - Value value; - AttributeTrail tmp_attr; - int map_key_index = 2 * i; - int map_value_index = map_key_index + 1; - CEL_RETURN_IF_ERROR(deps_[map_key_index]->Evaluate(frame, key, tmp_attr)); - - if (key.IsError()) { - result = std::move(key); - return absl::OkStatus(); - } - - if (frame.unknown_processing_enabled()) { - if (key.IsUnknown()) { - unknowns.Add(key.GetUnknown()); - } else if (frame.attribute_utility().CheckForUnknownPartial(tmp_attr)) { - unknowns.Add(tmp_attr); - } - } - - CEL_RETURN_IF_ERROR(cel::CheckMapKey(key)) - .With(ErrorValueAssign(result, frame.arena())); - - CEL_RETURN_IF_ERROR( - deps_[map_value_index]->Evaluate(frame, value, tmp_attr)); - - if (value.IsError()) { - result = std::move(value); - return absl::OkStatus(); - } - - if (frame.unknown_processing_enabled()) { - if (value.IsUnknown()) { - unknowns.Add(value.GetUnknown()); - } else if (frame.attribute_utility().CheckForUnknownPartial(tmp_attr)) { - unknowns.Add(tmp_attr); - } - } - - // Preserve the stack machine behavior of forwarding unknowns before - // errors. - if (!unknowns.IsEmpty()) { - continue; - } - - if (optional_indices_.contains(static_cast(i))) { - if (auto optional_map_value = value.AsOptional(); optional_map_value) { - if (!optional_map_value->HasValue()) { - continue; - } - Value optional_map_value_value; - optional_map_value->Value(&optional_map_value_value); - if (optional_map_value_value.IsError()) { - // Error should never be in optional, but better safe than sorry. - result = optional_map_value_value; - return absl::OkStatus(); - } - CEL_RETURN_IF_ERROR( - builder->Put(std::move(key), std::move(optional_map_value_value))); - continue; - } - result = cel::TypeConversionError(value.DebugString(), "optional_type", - frame.arena()); - return absl::OkStatus(); - } - - CEL_RETURN_IF_ERROR(builder->Put(std::move(key), std::move(value))); - } - - if (!unknowns.IsEmpty()) { - result = std::move(unknowns).Build(); - return absl::OkStatus(); - } - - result = std::move(*builder).Build(); - return absl::OkStatus(); -} - class MutableMapStep final : public ExpressionStepBase { public: MutableMapStep() = default; @@ -248,28 +138,8 @@ class MutableMapStep final : public ExpressionStepBase { } }; -class DirectMutableMapStep final : public DirectExpressionStep { - public: - explicit DirectMutableMapStep(int64_t expr_id) - : DirectExpressionStep(expr_id) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - result = - cel::CustomMapValue(NewMutableMapValue(frame.arena()), frame.arena()); - return absl::OkStatus(); - } -}; - } // namespace -std::unique_ptr CreateDirectCreateMapStep( - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id) { - return std::make_unique( - std::move(deps), std::move(optional_indices), expr_id); -} - absl::StatusOr> CreateCreateStructStepForMap(size_t entry_count, absl::flat_hash_set optional_indices) { @@ -282,9 +152,4 @@ std::unique_ptr CreateMutableMapStep() { return std::make_unique(); } -std::unique_ptr CreateDirectMutableMapStep( - int64_t expr_id) { - return std::make_unique(expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/create_map_step.h b/eval/eval/create_map_step.h index 599a48534..2f9729999 100644 --- a/eval/eval/create_map_step.h +++ b/eval/eval/create_map_step.h @@ -18,23 +18,13 @@ #include #include #include -#include #include "absl/container/flat_hash_set.h" #include "absl/status/statusor.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -// Creates an expression step that evaluates a create map expression. -// -// Deps must have an even number of elements, that alternate key, value pairs. -// (key1, value1, key2, value2...). -std::unique_ptr CreateDirectCreateMapStep( - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id); - // Creates an `ExpressionStep` which performs `CreateStruct` for a map. absl::StatusOr> CreateCreateStructStepForMap(size_t entry_count, @@ -46,13 +36,6 @@ CreateCreateStructStepForMap(size_t entry_count, // map-building comprehension (rather than a user authored expression). std::unique_ptr CreateMutableMapStep(); -// Factory method for CreateMap which constructs a mutable map. -// -// This is intended for the map construction step is generated for a -// map-building comprehension (rather than a user authored expression). -std::unique_ptr CreateDirectMutableMapStep( - int64_t expr_id); - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_CREATE_MAP_STEP_H_ diff --git a/eval/eval/create_map_step_test.cc b/eval/eval/create_map_step_test.cc index d231db211..163fed860 100644 --- a/eval/eval/create_map_step_test.cc +++ b/eval/eval/create_map_step_test.cc @@ -29,9 +29,7 @@ #include "base/type_provider.h" #include "common/expr.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/public/activation.h" #include "eval/public/cel_value.h" #include "eval/public/unknown_set.h" @@ -87,33 +85,6 @@ absl::StatusOr CreateStackMachineProgram( return path; } -absl::StatusOr CreateRecursiveProgram( - const std::vector>& values, - Activation& activation) { - ExecutionPath path; - - int index = 0; - std::vector> deps; - for (const auto& item : values) { - std::string key_name = absl::StrCat("key", index); - std::string value_name = absl::StrCat("value", index); - - deps.push_back(CreateDirectIdentStep(key_name, -1)); - - deps.push_back(CreateDirectIdentStep(value_name, -1)); - - activation.InsertValue(key_name, item.first); - activation.InsertValue(value_name, item.second); - - index++; - } - path.push_back( - ExpressionStep::MakeGenericStep(std::make_unique( - CreateDirectCreateMapStep(std::move(deps), {}, -1)))); - - return path; -} - // Helper method. Creates simple pipeline containing CreateStruct step that // builds Map and runs it. // Equivalent to {key0: value0, ...} @@ -124,11 +95,7 @@ absl::StatusOr RunCreateMapExpression( Activation activation; ExecutionPath path; - if (enable_recursive_program) { - CEL_ASSIGN_OR_RETURN(path, CreateRecursiveProgram(values, activation)); - } else { - CEL_ASSIGN_OR_RETURN(path, CreateStackMachineProgram(values, activation)); - } + CEL_ASSIGN_OR_RETURN(path, CreateStackMachineProgram(values, activation)); cel::RuntimeOptions options; if (enable_unknowns) { options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; diff --git a/eval/eval/create_struct_step.cc b/eval/eval/create_struct_step.cc index 8fcdd3c5a..ef05a08f7 100644 --- a/eval/eval/create_struct_step.cc +++ b/eval/eval/create_struct_step.cc @@ -27,10 +27,9 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "internal/status_macros.h" namespace google::api::expr::runtime { @@ -143,125 +142,8 @@ void CreateStructStepForStruct::Evaluate(ExecutionFrame* frame) const { frame->value_stack().PopAndPush(entries_.size(), *std::move(result)); } -class DirectCreateStructStep : public DirectExpressionStep { - public: - DirectCreateStructStep( - int64_t expr_id, std::string name, std::vector field_keys, - std::vector> deps, - absl::flat_hash_set optional_indices) - : DirectExpressionStep(expr_id), - name_(std::move(name)), - field_keys_(std::move(field_keys)), - deps_(std::move(deps)), - optional_indices_(std::move(optional_indices)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& trail) const override; - - private: - std::string name_; - std::vector field_keys_; - std::vector> deps_; - absl::flat_hash_set optional_indices_; -}; - -absl::Status DirectCreateStructStep::Evaluate(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& trail) const { - Value field_value; - AttributeTrail field_attr; - auto unknowns = frame.attribute_utility().CreateAccumulator(); - - CEL_ASSIGN_OR_RETURN(auto builder, - frame.type_provider().NewValueBuilder( - name_, frame.message_factory(), frame.arena())); - if (builder == nullptr) { - result = cel::ErrorValue::From( - absl::NotFoundError(absl::StrCat("Unable to find builder: ", name_)), - frame.arena()); - return absl::OkStatus(); - } - - for (int i = 0; i < field_keys_.size(); i++) { - CEL_RETURN_IF_ERROR(deps_[i]->Evaluate(frame, field_value, field_attr)); - - // TODO(uncreated-issue/67): if the value is an error, we should be able to return - // early, however some client tests depend on the error message the struct - // impl returns in the stack machine version. - if (field_value.IsError()) { - result = std::move(field_value); - return absl::OkStatus(); - } - - if (frame.unknown_processing_enabled()) { - if (field_value.IsUnknown()) { - unknowns.Add(field_value.GetUnknown()); - } else if (frame.attribute_utility().CheckForUnknownPartial(field_attr)) { - unknowns.Add(field_attr); - } - } - - if (!unknowns.IsEmpty()) { - continue; - } - - if (optional_indices_.contains(static_cast(i))) { - if (auto optional_arg = field_value.AsOptional(); optional_arg) { - if (!optional_arg->HasValue()) { - continue; - } - Value optional_arg_value; - optional_arg->Value(&optional_arg_value); - if (optional_arg_value.IsError()) { - // Error should never be in optional, but better safe than sorry. - result = std::move(optional_arg_value); - return absl::OkStatus(); - } - CEL_ASSIGN_OR_RETURN( - absl::optional error_value, - builder->SetFieldByName(field_keys_[i], - std::move(optional_arg_value))); - if (error_value) { - result = std::move(*error_value); - return absl::OkStatus(); - } - continue; - } else { - result = cel::TypeConversionError(field_value.DebugString(), - "optional_type", frame.arena()); - return absl::OkStatus(); - } - } - - CEL_ASSIGN_OR_RETURN( - absl::optional error_value, - builder->SetFieldByName(field_keys_[i], std::move(field_value))); - if (error_value) { - result = std::move(*error_value); - return absl::OkStatus(); - } - } - - if (!unknowns.IsEmpty()) { - result = std::move(unknowns).Build(); - return absl::OkStatus(); - } - - CEL_ASSIGN_OR_RETURN(result, std::move(*builder).Build()); - return absl::OkStatus(); -} - } // namespace -std::unique_ptr CreateDirectCreateStructStep( - std::string resolved_name, std::vector field_keys, - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id) { - return std::make_unique( - expr_id, std::move(resolved_name), std::move(field_keys), std::move(deps), - std::move(optional_indices)); -} - std::unique_ptr CreateCreateStructStep( std::string name, std::vector field_keys, absl::flat_hash_set optional_indices) { diff --git a/eval/eval/create_struct_step.h b/eval/eval/create_struct_step.h index 11880493a..1dd42273a 100644 --- a/eval/eval/create_struct_step.h +++ b/eval/eval/create_struct_step.h @@ -21,18 +21,10 @@ #include #include "absl/container/flat_hash_set.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -// Creates an `ExpressionStep` which performs `CreateStruct` for a -// message/struct. -std::unique_ptr CreateDirectCreateStructStep( - std::string name, std::vector field_keys, - std::vector> deps, - absl::flat_hash_set optional_indices, int64_t expr_id); - // Creates an `ExpressionStep` which performs `CreateStruct` for a // message/struct. std::unique_ptr CreateCreateStructStep( diff --git a/eval/eval/create_struct_step_test.cc b/eval/eval/create_struct_step_test.cc index 06085c311..e348ecd20 100644 --- a/eval/eval/create_struct_step_test.cc +++ b/eval/eval/create_struct_step_test.cc @@ -29,11 +29,8 @@ #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "base/type_provider.h" -#include "common/expr.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/public/activation.h" #include "eval/public/cel_type_registry.h" #include "eval/public/cel_value.h" @@ -82,25 +79,6 @@ absl::StatusOr MakeStackMachinePath(absl::string_view field) { return path; } -absl::StatusOr MakeRecursivePath(absl::string_view field) { - ExecutionPath path; - - std::vector> deps; - deps.push_back(CreateDirectIdentStep("message", -1)); - - auto step1 = - CreateDirectCreateStructStep("google.api.expr.runtime.TestMessage", - {std::string(field)}, std::move(deps), - /*optional_indices=*/{}, - - /*id=*/-1); - - path.push_back(ExpressionStep::MakeGenericStep( - std::make_unique(std::move(step1)))); - - return path; -} - // Helper method. Creates simple pipeline containing CreateStruct step that // builds message and runs it. absl::StatusOr RunExpression( @@ -122,11 +100,7 @@ absl::StatusOr RunExpression( } ExecutionPath path; - if (enable_recursive_planning) { - CEL_ASSIGN_OR_RETURN(path, MakeRecursivePath(field)); - } else { - CEL_ASSIGN_OR_RETURN(path, MakeStackMachinePath(field)); - } + CEL_ASSIGN_OR_RETURN(path, MakeStackMachinePath(field)); CelExpressionFlatImpl cel_expr( env, @@ -202,21 +176,11 @@ TEST_P(CreateCreateStructStepTest, TestEmptyMessageCreation) { env_->type_registry.GetComposedTypeProvider().FindType( "google.api.expr.runtime.TestMessage")); ASSERT_TRUE(maybe_type.has_value()); - if (enable_recursive_planning()) { - auto step = - CreateDirectCreateStructStep("google.api.expr.runtime.TestMessage", - /*fields=*/{}, - /*deps=*/{}, - /*optional_indices=*/{}, - /*id=*/-1); - path.push_back(ExpressionStep::MakeGenericStep( - std::make_unique(std::move(step)))); - } else { + auto step = CreateCreateStructStep("google.api.expr.runtime.TestMessage", /*fields=*/{}, /*optional_indices=*/{}); path.push_back(ExpressionStep::MakeGenericStep(std::move(step))); - } cel::RuntimeOptions options; if (enable_unknowns(), enable_recursive_planning()) { diff --git a/eval/eval/direct_expression_step.cc b/eval/eval/direct_expression_step.cc deleted file mode 100644 index 36b5ed1f5..000000000 --- a/eval/eval/direct_expression_step.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "eval/eval/direct_expression_step.h" - -namespace google::api::expr::runtime { - -// Intentionally empty. - -} // namespace google::api::expr::runtime diff --git a/eval/eval/direct_expression_step.h b/eval/eval/direct_expression_step.h deleted file mode 100644 index 547adad41..000000000 --- a/eval/eval/direct_expression_step.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_DIRECT_EXPRESSION_STEP_H_ -#define THIRD_PARTY_CEL_CPP_EVAL_EVAL_DIRECT_EXPRESSION_STEP_H_ - -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/types/optional.h" -#include "common/native_type.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" - -namespace google::api::expr::runtime { - -class ExecutionFrameBase; - -// Represents a directly evaluated CEL expression. -// -// Subexpressions assign to values on the C++ program stack and call their -// dependencies directly. -// -// This reduces the setup overhead for evaluation and minimizes value churn -// to / from a heap based value stack managed by the CEL runtime, but can't be -// used for arbitrarily nested expressions. -class DirectExpressionStep { - public: - explicit DirectExpressionStep(int64_t expr_id) : expr_id_(expr_id) {} - DirectExpressionStep() : expr_id_(-1) {} - - virtual ~DirectExpressionStep() = default; - - int64_t expr_id() const { return expr_id_; } - bool comes_from_ast() const { return expr_id_ >= 0; } - - virtual absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute) const = 0; - - // Return a type id for this node. - // - // Users must not make any assumptions about the type if the default value is - // returned. - virtual cel::NativeTypeId GetNativeTypeId() const { - return cel::NativeTypeId(); - } - - // Implementations optionally support inspecting the program tree. - virtual absl::optional> - GetDependencies() const { - return absl::nullopt; - } - - // Implementations optionally support extracting the program tree. - // - // Extract prevents the callee from functioning, and is only intended for use - // when replacing a given expression step. - virtual absl::optional>> - ExtractDependencies() { - return absl::nullopt; - }; - - protected: - int64_t expr_id_; -}; - -} // namespace google::api::expr::runtime - -#endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_DIRECT_EXPRESSION_STEP_H_ diff --git a/eval/eval/equality_steps.cc b/eval/eval/equality_steps.cc index 483b91468..6d8cf5751 100644 --- a/eval/eval/equality_steps.cc +++ b/eval/eval/equality_steps.cc @@ -13,17 +13,15 @@ // limitations under the License. #include "eval/eval/equality_steps.h" -#include -#include #include #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "absl/types/span.h" #include "base/builtins.h" #include "common/value.h" #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "internal/number.h" #include "internal/status_macros.h" @@ -76,36 +74,6 @@ absl::StatusOr EvaluateEquality( return negation ? BoolValue(!*is_equal) : BoolValue(*is_equal); } -class DirectEqualityStep : public DirectExpressionStep { - public: - explicit DirectEqualityStep(std::unique_ptr lhs, - std::unique_ptr rhs, - bool negation, int64_t expr_id) - : DirectExpressionStep(expr_id), - lhs_(std::move(lhs)), - rhs_(std::move(rhs)), - negation_(negation) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override { - AttributeTrail lhs_attr; - CEL_RETURN_IF_ERROR(lhs_->Evaluate(frame, result, lhs_attr)); - - Value rhs_result; - AttributeTrail rhs_attr; - CEL_RETURN_IF_ERROR(rhs_->Evaluate(frame, rhs_result, rhs_attr)); - CEL_ASSIGN_OR_RETURN( - result, EvaluateEquality(frame, result, lhs_attr, rhs_result, rhs_attr, - negation_)); - return absl::OkStatus(); - } - - private: - std::unique_ptr lhs_; - std::unique_ptr rhs_; - bool negation_; -}; - absl::StatusOr EvaluateInMap(ExecutionFrameBase& frame, const Value& item, const MapValue& container) { @@ -193,34 +161,6 @@ absl::StatusOr EvaluateIn(ExecutionFrameBase& frame, const Value& item, frame.arena()); } -class DirectInStep : public DirectExpressionStep { - public: - explicit DirectInStep(std::unique_ptr item, - std::unique_ptr container, - int64_t expr_id) - : DirectExpressionStep(expr_id), - item_(std::move(item)), - container_(std::move(container)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override { - AttributeTrail item_attr; - CEL_RETURN_IF_ERROR(item_->Evaluate(frame, result, item_attr)); - - Value container_result; - AttributeTrail container_attr; - CEL_RETURN_IF_ERROR( - container_->Evaluate(frame, container_result, container_attr)); - CEL_ASSIGN_OR_RETURN(result, EvaluateIn(frame, result, item_attr, - container_result, container_attr)); - return absl::OkStatus(); - } - - private: - std::unique_ptr item_; - std::unique_ptr container_; -}; - } // namespace void EvaluateFastEqualStep(bool negation, ExecutionFrame& frame) { @@ -261,20 +201,4 @@ void EvaluateFastInStep(ExecutionFrame& frame) { frame.value_stack().PopAndPush(2, *std::move(result)); } -// Factory method for recursive _==_ and _!=_ Execution step -std::unique_ptr CreateDirectEqualityStep( - std::unique_ptr lhs, - std::unique_ptr rhs, bool negation, int64_t expr_id) { - return std::make_unique(std::move(lhs), std::move(rhs), - negation, expr_id); -} - -// Factory method for recursive @in Execution step -std::unique_ptr CreateDirectInStep( - std::unique_ptr item, - std::unique_ptr container, int64_t expr_id) { - return std::make_unique(std::move(item), std::move(container), - expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/equality_steps.h b/eval/eval/equality_steps.h index 141e571d1..18b87cc79 100644 --- a/eval/eval/equality_steps.h +++ b/eval/eval/equality_steps.h @@ -15,27 +15,12 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_EQUALITY_STEPS_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_EQUALITY_STEPS_H_ -#include -#include - -#include "eval/eval/direct_expression_step.h" - namespace google::api::expr::runtime { class ExecutionFrame; -// Factory method for recursive _==_/_!=_ Execution step -std::unique_ptr CreateDirectEqualityStep( - std::unique_ptr lhs, - std::unique_ptr rhs, bool negation, int64_t expr_id); - void EvaluateFastEqualStep(bool negation, ExecutionFrame& frame); -// Factory method for recursive @in Execution step -std::unique_ptr CreateDirectInStep( - std::unique_ptr item, - std::unique_ptr container, int64_t expr_id); - void EvaluateFastInStep(ExecutionFrame& frame); } // namespace google::api::expr::runtime diff --git a/eval/eval/equality_steps_test.cc b/eval/eval/equality_steps_test.cc index 660bebeb8..4ebfe10ef 100644 --- a/eval/eval/equality_steps_test.cc +++ b/eval/eval/equality_steps_test.cc @@ -27,8 +27,8 @@ #include "common/value_kind.h" #include "common/value_testing.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" #include "internal/testing.h" #include "internal/testing_descriptor_pool.h" #include "internal/testing_message_factory.h" @@ -51,16 +51,14 @@ using ::cel::ValueKind; using ::cel::test::BoolValueIs; using ::cel::test::ValueKindIs; -class ValueStep : public ExpressionStepLogic, public DirectExpressionStep { +class ValueStep : public ExpressionStepLogic { public: ValueStep(Value value, Attribute attr) : ExpressionStepLogic(), - DirectExpressionStep(-1), value_(std::move(value)), attr_(std::move(attr)) {} explicit ValueStep(Value value) : ExpressionStepLogic(), - DirectExpressionStep(-1), value_(std::move(value)), attr_() {} @@ -68,73 +66,11 @@ class ValueStep : public ExpressionStepLogic, public DirectExpressionStep { frame->value_stack().Push(value_, attr_); } - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override { - result = value_; - attribute_trail = attr_; - return absl::OkStatus(); - } - private: Value value_; AttributeTrail attr_; }; -TEST(RecursiveTest, PartialAttrUnknown) { - cel::Activation activation; - google::protobuf::Arena arena; - cel::RuntimeOptions opts; - opts.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - // A little contrived for simplicity, but this is for cases where e.g. - // `msg == Msg{}` but msg.foo is unknown. - auto plan = CreateDirectEqualityStep( - std::make_unique(IntValue(1), cel::Attribute("foo")), - std::make_unique(IntValue(2)), false, -1); - - ASSERT_THAT(activation.SetUnknownPatterns({cel::AttributePattern( - "foo", {cel::AttributeQualifierPattern::OfString("bar")})}), - IsOk()); - - ExecutionFrameBase frame(activation, opts, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - cel::Value result; - AttributeTrail attribute_trail; - ASSERT_THAT(plan->Evaluate(frame, result, attribute_trail), IsOk()); - - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); -} - -TEST(RecursiveTest, PartialAttrUnknownDisabled) { - cel::Activation activation; - google::protobuf::Arena arena; - cel::RuntimeOptions opts; - opts.unknown_processing = cel::UnknownProcessingOptions::kDisabled; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - auto plan = CreateDirectEqualityStep( - std::make_unique(IntValue(1), cel::Attribute("foo")), - std::make_unique(IntValue(2)), false, -1); - - ASSERT_THAT(activation.SetUnknownPatterns({cel::AttributePattern( - "foo", {cel::AttributeQualifierPattern::OfString("bar")})}), - IsOk()); - ExecutionFrameBase frame(activation, opts, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - cel::Value result; - AttributeTrail attribute_trail; - ASSERT_THAT(plan->Evaluate(frame, result, attribute_trail), IsOk()); - - EXPECT_THAT(result, BoolValueIs(false)); -} - TEST(IterativeTest, PartialAttrUnknown) { cel::Activation activation; google::protobuf::Arena arena; @@ -236,44 +172,6 @@ Value MakeValue(InputType type, google::protobuf::Arena* absl_nonnull arena) { } } -TEST_P(EqualsTest, Recursive) { - const EqualsTestCase& test_case = GetParam(); - cel::Activation activation; - google::protobuf::Arena arena; - cel::RuntimeOptions opts; - opts.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - auto plan = CreateDirectEqualityStep( - std::make_unique(MakeValue(test_case.lhs, &arena)), - std::make_unique(MakeValue(test_case.rhs, &arena)), - test_case.negation, -1); - - ExecutionFrameBase frame(activation, opts, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - cel::Value result; - AttributeTrail attribute_trail; - ASSERT_THAT(plan->Evaluate(frame, result, attribute_trail), IsOk()); - - switch (test_case.expected_result) { - case OutputType::kBoolTrue: - EXPECT_THAT(result, BoolValueIs(true)); - break; - case OutputType::kBoolFalse: - EXPECT_THAT(result, BoolValueIs(false)); - break; - case OutputType::kError: - EXPECT_THAT(result, ValueKindIs(ValueKind::kError)); - break; - case OutputType::kUnknown: - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); - break; - } -} - TEST_P(EqualsTest, Iterative) { const EqualsTestCase& test_case = GetParam(); cel::Activation activation; @@ -419,43 +317,6 @@ struct InTestCase { class InTest : public ::testing::TestWithParam {}; -TEST_P(InTest, Recursive) { - const InTestCase& test_case = GetParam(); - cel::Activation activation; - google::protobuf::Arena arena; - cel::RuntimeOptions opts; - opts.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - - auto plan = CreateDirectInStep( - std::make_unique(MakeValue(test_case.lhs, &arena)), - std::make_unique(MakeValue(test_case.rhs, &arena)), -1); - - ExecutionFrameBase frame(activation, opts, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - - cel::Value result; - AttributeTrail attribute_trail; - ASSERT_THAT(plan->Evaluate(frame, result, attribute_trail), IsOk()); - - switch (test_case.expected_result) { - case OutputType::kBoolTrue: - EXPECT_THAT(result, BoolValueIs(true)); - break; - case OutputType::kBoolFalse: - EXPECT_THAT(result, BoolValueIs(false)); - break; - case OutputType::kError: - EXPECT_THAT(result, ValueKindIs(ValueKind::kError)); - break; - case OutputType::kUnknown: - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); - break; - } -} - TEST_P(InTest, Iterative) { const InTestCase& test_case = GetParam(); cel::Activation activation; diff --git a/eval/eval/evaluator_core.cc b/eval/eval/evaluator_core.cc index 6d31a7b4b..4314f4e38 100644 --- a/eval/eval/evaluator_core.cc +++ b/eval/eval/evaluator_core.cc @@ -17,11 +17,9 @@ #include #include #include -#include #include #include -#include "absl/base/attributes.h" #include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/log/absl_check.h" @@ -33,15 +31,12 @@ #include "common/value.h" #include "common/value_kind.h" #include "common/values/list_value_builder.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/comprehension_slots.h" #include "eval/eval/comprehension_step.h" #include "eval/eval/equality_steps.h" #include "eval/eval/lazy_init_step.h" #include "eval/eval/logic_step.h" -#include "internal/status_macros.h" #include "runtime/activation_interface.h" -#include "runtime/internal/errors.h" #include "google/protobuf/arena.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/message.h" @@ -365,15 +360,4 @@ FixedJumpStepInfo* GetIfFixedJumpStep(ExpressionStep& step) { return nullptr; } -void WrappedDirectStep::Evaluate(ExecutionFrame* frame) const { - cel::Value result; - AttributeTrail attribute_trail; - if (absl::Status status = impl_->Evaluate(*frame, result, attribute_trail); - !status.ok()) { - frame->Abort(std::move(status)); - return; - } - frame->value_stack().Push(std::move(result), std::move(attribute_trail)); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/evaluator_core.h b/eval/eval/evaluator_core.h index 30e2c0087..d23dfd045 100644 --- a/eval/eval/evaluator_core.h +++ b/eval/eval/evaluator_core.h @@ -33,14 +33,12 @@ #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "base/type_provider.h" -#include "common/native_type.h" #include "common/value.h" #include "common/value_kind.h" #include "common/values/list_value_builder.h" #include "eval/eval/attribute_utility.h" #include "eval/eval/comprehension_slots.h" #include "eval/eval/comprehension_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/equality_steps.h" #include "eval/eval/evaluator_stack.h" #include "eval/eval/expression_step_logic.h" @@ -423,25 +421,6 @@ class ExpressionStep { static_assert(sizeof(ExpressionStep) == 16); #endif -// Wrapper for direct steps to work with the stack machine impl. -class WrappedDirectStep : public ExpressionStepLogic { - public: - explicit WrappedDirectStep(std::unique_ptr impl, - int64_t expr_id = -1) - : impl_(std::move(impl)) {} - - void Evaluate(ExecutionFrame* frame) const override; - - cel::NativeTypeId GetNativeTypeId() const override { - return cel::NativeTypeId::For(); - } - - const DirectExpressionStep* wrapped() const { return impl_.get(); } - - private: - std::unique_ptr impl_; -}; - using ExecutionPath = std::vector; using ExecutionPathView = absl::Span; diff --git a/eval/eval/function_step.cc b/eval/eval/function_step.cc index f3d3fb93a..4160072fc 100644 --- a/eval/eval/function_step.cc +++ b/eval/eval/function_step.cc @@ -9,7 +9,6 @@ #include #include -#include "absl/container/inlined_vector.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" @@ -22,7 +21,6 @@ #include "common/value.h" #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_logic.h" #include "eval/internal/errors.h" @@ -303,81 +301,6 @@ class LazyResolver { bool receiver_style_; }; -template -class DirectFunctionStepImpl : public DirectExpressionStep { - public: - DirectFunctionStepImpl( - int64_t expr_id, const std::string& name, - std::vector> arg_steps, - bool receiver_style, Resolver&& resolver) - : DirectExpressionStep(expr_id), - name_(name), - arg_steps_(std::move(arg_steps)), - receiver_style_(receiver_style), - resolver_(std::forward(resolver)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& trail) const override { - absl::InlinedVector args; - absl::InlinedVector arg_trails; - - args.resize(arg_steps_.size()); - arg_trails.resize(arg_steps_.size()); - - for (size_t i = 0; i < arg_steps_.size(); i++) { - CEL_RETURN_IF_ERROR( - arg_steps_[i]->Evaluate(frame, args[i], arg_trails[i])); - } - - if (frame.unknown_processing_enabled()) { - for (size_t i = 0; i < arg_trails.size(); i++) { - if (frame.attribute_utility().CheckForUnknown(arg_trails[i], - /*use_partial=*/true)) { - args[i] = frame.attribute_utility().CreateUnknownSet( - arg_trails[i].attribute()); - } - } - } - - CEL_ASSIGN_OR_RETURN(ResolveResult resolved_function, - resolver_.Resolve(frame, args)); - - if (resolved_function.has_value() && - ShouldAcceptOverload(resolved_function->descriptor, args)) { - CEL_ASSIGN_OR_RETURN(result, - Invoke(*resolved_function, expr_id_, args, frame)); - - return absl::OkStatus(); - } - - result = NoOverloadResult(name_, args, receiver_style_, frame); - - return absl::OkStatus(); - } - - absl::optional> GetDependencies() - const override { - std::vector dependencies; - dependencies.reserve(arg_steps_.size()); - for (const auto& arg_step : arg_steps_) { - dependencies.push_back(arg_step.get()); - } - return dependencies; - } - - absl::optional>> - ExtractDependencies() override { - return std::move(arg_steps_); - } - - private: - friend Resolver; - std::string name_; - std::vector> arg_steps_; - bool receiver_style_; - Resolver resolver_; -}; - } // namespace template @@ -463,24 +386,6 @@ absl::StatusOr LazyFunctionStep::ResolveFunction( return ResolveLazy(input_args, name_, receiver_style_, providers_, frame); } -std::unique_ptr CreateDirectFunctionStep( - int64_t expr_id, const cel::CallExpr& call, - std::vector> deps, - std::vector overloads) { - return std::make_unique>( - expr_id, call.function(), std::move(deps), call.has_target(), - StaticResolver(std::move(overloads))); -} - -std::unique_ptr CreateDirectLazyFunctionStep( - int64_t expr_id, const cel::CallExpr& call, - std::vector> deps, - std::vector providers) { - return std::make_unique>( - expr_id, call.function(), std::move(deps), call.has_target(), - LazyResolver(std::move(providers), call.function(), call.has_target())); -} - std::unique_ptr CreateLazyFunctionStep( const cel::CallExpr& call_expr, int64_t expr_id, std::vector lazy_overloads) { diff --git a/eval/eval/function_step.h b/eval/eval/function_step.h index e0373d670..c5d4893da 100644 --- a/eval/eval/function_step.h +++ b/eval/eval/function_step.h @@ -14,29 +14,12 @@ #include "absl/types/span.h" #include "common/expr.h" #include "common/value.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/expression_step_logic.h" #include "runtime/function_overload_reference.h" #include "runtime/function_registry.h" namespace google::api::expr::runtime { -// Factory method for Call-based execution step where the function has been -// statically resolved from a set of eagerly functions configured in the -// CelFunctionRegistry. -std::unique_ptr CreateDirectFunctionStep( - int64_t expr_id, const cel::CallExpr& call, - std::vector> deps, - std::vector overloads); - -// Factory method for Call-based execution step where the function has been -// statically resolved from a set of lazy functions configured in the -// CelFunctionRegistry. -std::unique_ptr CreateDirectLazyFunctionStep( - int64_t expr_id, const cel::CallExpr& call, - std::vector> deps, - std::vector providers); - class LazyFunctionStep; class EagerFunctionStep; class ExecutionFrameBase; diff --git a/eval/eval/function_step_test.cc b/eval/eval/function_step_test.cc index c6de63d42..9cb338af2 100644 --- a/eval/eval/function_step_test.cc +++ b/eval/eval/function_step_test.cc @@ -8,22 +8,17 @@ #include #include "absl/status/status.h" -#include "absl/status/status_macros.h" #include "absl/status/status_matchers.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" -#include "base/builtins.h" #include "base/type_provider.h" #include "common/constant.h" #include "common/expr.h" #include "common/kind.h" #include "common/value.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/internal/interop.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" @@ -36,11 +31,8 @@ #include "eval/public/testing/matchers.h" #include "eval/testutil/test_message.pb.h" #include "internal/testing.h" -#include "runtime/function_overload_reference.h" -#include "runtime/function_registry.h" #include "runtime/internal/runtime_env_testing.h" #include "runtime/runtime_options.h" -#include "runtime/standard_functions.h" #include "google/protobuf/arena.h" namespace google::api::expr::runtime { @@ -56,7 +48,6 @@ using ::cel::TypeProvider; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::testing::Eq; using ::testing::Not; -using ::testing::Truly; int GetExprId() { static int id = 0; @@ -213,20 +204,6 @@ std::vector ArgumentMatcher(const CallExpr& call) { : call.args().size()); } -std::unique_ptr CreateExpressionImpl( - const cel::RuntimeOptions& options, - std::unique_ptr expr) { - ExecutionPath path; - path.push_back(ExpressionStep::MakeGenericStep( - std::make_unique(std::move(expr)))); - - auto env = NewTestingRuntimeEnv(); - return std::make_unique( - env, - FlatExpression(std::move(path), /*comprehension_slot_count=*/0, - env->type_registry.GetComposedTypeProvider(), options)); -} - absl::StatusOr MakeTestFunctionStep( const CallExpr& call, const CelFunctionRegistry& registry) { auto argument_matcher = ArgumentMatcher(call); @@ -1045,175 +1022,5 @@ TEST(FunctionStepStrictnessTest, IfFunctionNonStrictAndGivenUnknownInvokesIt) { ASSERT_THAT(value, test::IsCelInt64(Eq(0))); } -class DirectFunctionStepTest : public testing::Test { - public: - DirectFunctionStepTest() = default; - - void SetUp() override { - ASSERT_OK(cel::RegisterStandardFunctions(registry_, options_)); - } - - std::vector GetOverloads( - absl::string_view name, int64_t arguments_size) { - std::vector matcher; - matcher.resize(arguments_size, cel::Kind::kAny); - return registry_.FindStaticOverloads(name, false, matcher); - } - - // Helper for shorthand constructing direct expr deps. - // - // Works around copies in init-list construction. - std::vector> MakeDeps( - std::unique_ptr dep, - std::unique_ptr dep2) { - std::vector> result; - result.reserve(2); - result.push_back(std::move(dep)); - result.push_back(std::move(dep2)); - return result; - }; - - protected: - cel::FunctionRegistry registry_; - cel::RuntimeOptions options_; - google::protobuf::Arena arena_; -}; - -TEST_F(DirectFunctionStepTest, SimpleCall) { - cel::IntValue(1); - - CallExpr call; - call.set_function(cel::builtin::kAdd); - call.mutable_args().emplace_back(); - call.mutable_args().emplace_back(); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(cel::IntValue(1))); - deps.push_back(CreateConstValueDirectStep(cel::IntValue(1))); - - auto expr = CreateDirectFunctionStep(-1, call, std::move(deps), - GetOverloads(cel::builtin::kAdd, 2)); - - auto plan = CreateExpressionImpl(options_, std::move(expr)); - - Activation activation; - ASSERT_OK_AND_ASSIGN(auto value, plan->Evaluate(activation, &arena_)); - - EXPECT_THAT(value, test::IsCelInt64(2)); -} - -TEST_F(DirectFunctionStepTest, RecursiveCall) { - cel::IntValue(1); - - CallExpr call; - call.set_function(cel::builtin::kAdd); - call.mutable_args().emplace_back(); - call.mutable_args().emplace_back(); - - auto overloads = GetOverloads(cel::builtin::kAdd, 2); - - auto MakeLeaf = [&]() { - return CreateDirectFunctionStep( - -1, call, - MakeDeps(CreateConstValueDirectStep(cel::IntValue(1)), - CreateConstValueDirectStep(cel::IntValue(1))), - overloads); - }; - - auto expr = CreateDirectFunctionStep( - -1, call, - MakeDeps(CreateDirectFunctionStep( - -1, call, MakeDeps(MakeLeaf(), MakeLeaf()), overloads), - CreateDirectFunctionStep( - -1, call, MakeDeps(MakeLeaf(), MakeLeaf()), overloads)), - overloads); - - auto plan = CreateExpressionImpl(options_, std::move(expr)); - - Activation activation; - ASSERT_OK_AND_ASSIGN(auto value, plan->Evaluate(activation, &arena_)); - - EXPECT_THAT(value, test::IsCelInt64(8)); -} - -TEST_F(DirectFunctionStepTest, ErrorHandlingCall) { - cel::IntValue(1); - - CallExpr add_call; - add_call.set_function(cel::builtin::kAdd); - add_call.mutable_args().emplace_back(); - add_call.mutable_args().emplace_back(); - - CallExpr div_call; - div_call.set_function(cel::builtin::kDivide); - div_call.mutable_args().emplace_back(); - div_call.mutable_args().emplace_back(); - - auto add_overloads = GetOverloads(cel::builtin::kAdd, 2); - auto div_overloads = GetOverloads(cel::builtin::kDivide, 2); - - auto error_expr = CreateDirectFunctionStep( - -1, div_call, - MakeDeps(CreateConstValueDirectStep(cel::IntValue(1)), - CreateConstValueDirectStep(cel::IntValue(0))), - div_overloads); - - auto expr = CreateDirectFunctionStep( - -1, add_call, - MakeDeps(std::move(error_expr), - CreateConstValueDirectStep(cel::IntValue(1))), - add_overloads); - - auto plan = CreateExpressionImpl(options_, std::move(expr)); - - Activation activation; - ASSERT_OK_AND_ASSIGN(auto value, plan->Evaluate(activation, &arena_)); - - EXPECT_THAT(value, - test::IsCelError(StatusIs(absl::StatusCode::kInvalidArgument, - testing::HasSubstr("divide by zero")))); -} - -TEST_F(DirectFunctionStepTest, NoOverload) { - cel::IntValue(1); - - CallExpr call; - call.set_function(cel::builtin::kAdd); - call.mutable_args().emplace_back(); - call.mutable_args().emplace_back(); - - std::vector> deps; - deps.push_back(CreateConstValueDirectStep(cel::IntValue(1))); - deps.push_back(CreateConstValueDirectStep(cel::StringValue::WrapUnsafe("2"))); - - auto expr = CreateDirectFunctionStep(-1, call, std::move(deps), - GetOverloads(cel::builtin::kAdd, 2)); - - auto plan = CreateExpressionImpl(options_, std::move(expr)); - - Activation activation; - ASSERT_OK_AND_ASSIGN(auto value, plan->Evaluate(activation, &arena_)); - - EXPECT_THAT(value, Truly(CheckNoMatchingOverloadError)); -} - -TEST_F(DirectFunctionStepTest, NoOverload0Args) { - cel::IntValue(1); - - CallExpr call; - call.set_function(cel::builtin::kAdd); - - std::vector> deps; - auto expr = CreateDirectFunctionStep(-1, call, std::move(deps), - GetOverloads(cel::builtin::kAdd, 2)); - - auto plan = CreateExpressionImpl(options_, std::move(expr)); - - Activation activation; - ASSERT_OK_AND_ASSIGN(auto value, plan->Evaluate(activation, &arena_)); - - EXPECT_THAT(value, Truly(CheckNoMatchingOverloadError)); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/ident_step.cc b/eval/eval/ident_step.cc index 088e39bbe..0bfbb9211 100644 --- a/eval/eval/ident_step.cc +++ b/eval/eval/ident_step.cc @@ -1,20 +1,13 @@ #include "eval/eval/ident_step.h" -#include -#include -#include #include #include -#include "absl/base/nullability.h" #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "common/value.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_logic.h" #include "eval/internal/errors.h" @@ -63,54 +56,6 @@ absl::Status LookupIdent(absl::string_view name, ExecutionFrameBase& frame, return absl::OkStatus(); } -absl::StatusOr LookupSlot( - absl::string_view name, size_t slot_index, ExecutionFrameBase& frame) { - ComprehensionSlots::Slot* slot = frame.comprehension_slots().Get(slot_index); - if (!slot->Has()) { - return absl::InternalError( - absl::StrCat("Comprehension variable accessed out of scope: ", name)); - } - return slot; -} - -class DirectIdentStep : public DirectExpressionStep { - public: - DirectIdentStep(absl::string_view name, int64_t expr_id) - : DirectExpressionStep(expr_id), name_(name) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - return LookupIdent(name_, frame, result, attribute); - } - - private: - std::string name_; -}; - -class DirectSlotStep : public DirectExpressionStep { - public: - DirectSlotStep(absl::string_view name, size_t slot_index, int64_t expr_id) - : DirectExpressionStep(expr_id), - name_(std::move(name)), - slot_index_(slot_index) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - CEL_ASSIGN_OR_RETURN(const ComprehensionSlots::Slot* slot, - LookupSlot(name_, slot_index_, frame)); - - if (frame.attribute_tracking_enabled()) { - attribute = slot->attribute(); - } - result = slot->value(); - return absl::OkStatus(); - } - - private: - std::string name_; - size_t slot_index_; -}; - } // namespace void EvaluateIdentifierStep(absl::string_view identifier, @@ -125,14 +70,4 @@ void EvaluateIdentifierStep(absl::string_view identifier, } } -std::unique_ptr CreateDirectIdentStep( - absl::string_view identifier, int64_t expr_id) { - return std::make_unique(identifier, expr_id); -} - -std::unique_ptr CreateDirectSlotIdentStep( - absl::string_view identifier, size_t slot_index, int64_t expr_id) { - return std::make_unique(identifier, slot_index, expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/ident_step.h b/eval/eval/ident_step.h index 9bafa77fe..2ce50c58e 100644 --- a/eval/eval/ident_step.h +++ b/eval/eval/ident_step.h @@ -1,24 +1,12 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_IDENT_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_IDENT_STEP_H_ -#include -#include -#include - #include "absl/strings/string_view.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { class ExecutionFrame; -std::unique_ptr CreateDirectIdentStep( - absl::string_view identifier, int64_t expr_id); - -std::unique_ptr CreateDirectSlotIdentStep( - absl::string_view identifier, size_t slot_index, int64_t expr_id); - void EvaluateIdentifierStep(absl::string_view identifier, ExecutionFrame& frame); diff --git a/eval/eval/ident_step_test.cc b/eval/eval/ident_step_test.cc index 91b2cb986..49ef870d6 100644 --- a/eval/eval/ident_step_test.cc +++ b/eval/eval/ident_step_test.cc @@ -8,19 +8,13 @@ #include "absl/status/status.h" #include "base/type_provider.h" #include "common/memory.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" #include "eval/eval/evaluator_core.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "google/protobuf/arena.h" @@ -29,19 +23,12 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::absl_testing::StatusIs; -using ::cel::ErrorValue; -using ::cel::IntValue; using ::cel::MemoryManagerRef; using ::cel::RuntimeOptions; using ::cel::TypeProvider; -using ::cel::UnknownValue; -using ::cel::Value; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::google::protobuf::Arena; using ::testing::Eq; -using ::testing::HasSubstr; -using ::testing::SizeIs; TEST(IdentStepTest, TestIdentStep) { ExecutionPath path; @@ -202,107 +189,6 @@ TEST(IdentStepTest, TestIdentStepUnknownAttribute) { ASSERT_TRUE(result.IsUnknownSet()); } -TEST(DirectIdentStepTest, Basic) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - cel::Activation activation; - RuntimeOptions options; - - activation.InsertOrAssignValue("var1", IntValue(42)); - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - Value result; - AttributeTrail trail; - - auto step = CreateDirectIdentStep("var1", -1); - - ASSERT_THAT(step->Evaluate(frame, result, trail), IsOk()); - - ASSERT_TRUE(result.IsInt()); - EXPECT_THAT(result.GetInt().NativeValue(), Eq(42)); -} - -TEST(DirectIdentStepTest, UnknownAttribute) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - cel::Activation activation; - RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - activation.InsertOrAssignValue("var1", IntValue(42)); - ASSERT_THAT( - activation.SetUnknownPatterns({CreateCelAttributePattern("var1", {})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - Value result; - AttributeTrail trail; - - auto step = CreateDirectIdentStep("var1", -1); - - ASSERT_THAT(step->Evaluate(frame, result, trail), IsOk()); - - ASSERT_TRUE(result.IsUnknown()); - EXPECT_THAT(result.GetUnknown().ToAttributeSet(), SizeIs(1)); -} - -TEST(DirectIdentStepTest, MissingAttribute) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - cel::Activation activation; - RuntimeOptions options; - options.enable_missing_attribute_errors = true; - - activation.InsertOrAssignValue("var1", IntValue(42)); - ASSERT_THAT( - activation.SetMissingPatterns({CreateCelAttributePattern("var1", {})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - Value result; - AttributeTrail trail; - - auto step = CreateDirectIdentStep("var1", -1); - - ASSERT_THAT(step->Evaluate(frame, result, trail), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("var1"))); -} - -TEST(DirectIdentStepTest, NotFound) { - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - cel::Activation activation; - RuntimeOptions options; - - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - Value result; - AttributeTrail trail; - - auto step = CreateDirectIdentStep("var1", -1); - - ASSERT_THAT(step->Evaluate(frame, result, trail), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kUnknown, - HasSubstr("\"var1\" found in Activation"))); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/lazy_init_step.cc b/eval/eval/lazy_init_step.cc index cdb1f9666..03404d048 100644 --- a/eval/eval/lazy_init_step.cc +++ b/eval/eval/lazy_init_step.cc @@ -15,103 +15,14 @@ #include "eval/eval/lazy_init_step.h" #include -#include -#include -#include #include "cel/expr/value.pb.h" -#include "absl/base/nullability.h" #include "absl/status/status.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "internal/status_macros.h" namespace google::api::expr::runtime { -namespace { - -using ::cel::Value; - -class DirectLazyInitStep final : public DirectExpressionStep { - public: - DirectLazyInitStep(size_t slot_index, - const DirectExpressionStep* subexpression, int64_t expr_id) - : DirectExpressionStep(expr_id), - slot_index_(slot_index), - subexpression_(subexpression) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - ComprehensionSlot* slot = frame.comprehension_slots().Get(slot_index_); - if (slot->Has()) { - result = slot->value(); - attribute = slot->attribute(); - } else { - CEL_RETURN_IF_ERROR(subexpression_->Evaluate(frame, result, attribute)); - slot->Set(result, attribute); - } - return absl::OkStatus(); - } - - private: - const size_t slot_index_; - const DirectExpressionStep* absl_nonnull const subexpression_; -}; - -class BindStep : public DirectExpressionStep { - public: - BindStep(size_t slot_index, - std::unique_ptr subexpression, int64_t expr_id) - : DirectExpressionStep(expr_id), - slot_index_(slot_index), - subexpression_(std::move(subexpression)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - CEL_RETURN_IF_ERROR(subexpression_->Evaluate(frame, result, attribute)); - - frame.comprehension_slots().ClearSlot(slot_index_); - - return absl::OkStatus(); - } - - private: - size_t slot_index_; - std::unique_ptr subexpression_; -}; - -class BlockStep : public DirectExpressionStep { - public: - BlockStep(size_t slot_index, size_t slot_count, - std::unique_ptr subexpression, - int64_t expr_id) - : DirectExpressionStep(expr_id), - slot_index_(slot_index), - slot_count_(slot_count), - subexpression_(std::move(subexpression)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - CEL_RETURN_IF_ERROR(subexpression_->Evaluate(frame, result, attribute)); - - for (size_t i = 0; i < slot_count_; ++i) { - frame.comprehension_slots().ClearSlot(slot_index_ + i); - } - - return absl::OkStatus(); - } - - private: - size_t slot_index_; - size_t slot_count_; - std::unique_ptr subexpression_; -}; - -} // namespace - void EvaluateLazyInitStep(const LazyInitStepInfo& step, ExecutionFrame& frame) { ComprehensionSlot* slot = frame.comprehension_slots().Get(step.slot_index); if (slot->Has()) { @@ -138,24 +49,4 @@ void EvaluateClearSlotStep(const ClearSlotStepInfo& step, } } -std::unique_ptr CreateDirectBindStep( - size_t slot_index, std::unique_ptr expression, - int64_t expr_id) { - return std::make_unique(slot_index, std::move(expression), expr_id); -} - -std::unique_ptr CreateDirectBlockStep( - size_t slot_index, size_t slot_count, - std::unique_ptr expression, int64_t expr_id) { - return std::make_unique(slot_index, slot_count, - std::move(expression), expr_id); -} - -std::unique_ptr CreateDirectLazyInitStep( - size_t slot_index, const DirectExpressionStep* absl_nonnull subexpression, - int64_t expr_id) { - return std::make_unique(slot_index, subexpression, - expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/lazy_init_step.h b/eval/eval/lazy_init_step.h index c73c80ee1..a1838c9b3 100644 --- a/eval/eval/lazy_init_step.h +++ b/eval/eval/lazy_init_step.h @@ -38,32 +38,11 @@ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_LAZY_INIT_STEP_H_ #include -#include -#include - -#include "absl/base/nullability.h" -#include "eval/eval/direct_expression_step.h" namespace google::api::expr::runtime { class ExecutionFrame; -// Creates a step representing a Bind expression. -std::unique_ptr CreateDirectBindStep( - size_t slot_index, std::unique_ptr expression, - int64_t expr_id); - -// Creates a step representing a cel.@block expression. -std::unique_ptr CreateDirectBlockStep( - size_t slot_index, size_t slot_count, - std::unique_ptr expression, int64_t expr_id); - -// Creates a direct step representing accessing a lazily evaluated alias from -// a bind or block. -std::unique_ptr CreateDirectLazyInitStep( - size_t slot_index, const DirectExpressionStep* absl_nonnull subexpression, - int64_t expr_id); - struct LazyInitStepInfo { size_t slot_index : 32; size_t subexpression_index : 32; diff --git a/eval/eval/logic_step.cc b/eval/eval/logic_step.cc index d7bab5f8c..3be16e527 100644 --- a/eval/eval/logic_step.cc +++ b/eval/eval/logic_step.cc @@ -1,8 +1,6 @@ #include "eval/eval/logic_step.h" #include -#include -#include #include #include @@ -13,10 +11,8 @@ #include "common/value.h" #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/internal/errors.h" -#include "internal/status_macros.h" #include "runtime/internal/errors.h" namespace google::api::expr::runtime { @@ -30,247 +26,6 @@ using ::cel::Value; using ::cel::ValueKind; using ::cel::runtime_internal::CreateNoMatchingOverloadError; -// Shared logic for the fall through case (we didn't see the shortcircuit -// value). -absl::Status ReturnLogicResult(ExecutionFrameBase& frame, BoolLogicKind op_type, - Value& lhs_result, Value& rhs_result, - AttributeTrail& attribute_trail, - AttributeTrail& rhs_attr) { - ValueKind lhs_kind = lhs_result.kind(); - ValueKind rhs_kind = rhs_result.kind(); - - if (frame.unknown_processing_enabled()) { - if (lhs_kind == ValueKind::kUnknown && rhs_kind == ValueKind::kUnknown) { - lhs_result = frame.attribute_utility().MergeUnknownValues( - lhs_result.GetUnknown(), rhs_result.GetUnknown()); - // Clear attribute trail so this doesn't get re-identified as a new - // unknown and reset the accumulated attributes. - attribute_trail = AttributeTrail(); - return absl::OkStatus(); - } else if (lhs_kind == ValueKind::kUnknown) { - return absl::OkStatus(); - } else if (rhs_kind == ValueKind::kUnknown) { - lhs_result = std::move(rhs_result); - attribute_trail = std::move(rhs_attr); - return absl::OkStatus(); - } - } - - if (lhs_kind == ValueKind::kError) { - return absl::OkStatus(); - } else if (rhs_kind == ValueKind::kError) { - lhs_result = std::move(rhs_result); - attribute_trail = std::move(rhs_attr); - return absl::OkStatus(); - } - - if (lhs_kind == ValueKind::kBool && rhs_kind == ValueKind::kBool) { - return absl::OkStatus(); - } - - // Otherwise, add a no overload error. - attribute_trail = AttributeTrail(); - lhs_result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(op_type == BoolLogicKind::kOr - ? cel::builtin::kOr - : cel::builtin::kAnd), - frame.arena()); - return absl::OkStatus(); -} - -class ExhaustiveDirectLogicStep : public DirectExpressionStep { - public: - explicit ExhaustiveDirectLogicStep(std::unique_ptr lhs, - std::unique_ptr rhs, - BoolLogicKind op_type, int64_t expr_id) - : DirectExpressionStep(expr_id), - lhs_(std::move(lhs)), - rhs_(std::move(rhs)), - op_type_(op_type) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute_trail) const override; - - private: - std::unique_ptr lhs_; - std::unique_ptr rhs_; - BoolLogicKind op_type_; -}; - -absl::Status ExhaustiveDirectLogicStep::Evaluate( - ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute_trail) const { - CEL_RETURN_IF_ERROR(lhs_->Evaluate(frame, result, attribute_trail)); - ValueKind lhs_kind = result.kind(); - - Value rhs_result; - AttributeTrail rhs_attr; - CEL_RETURN_IF_ERROR(rhs_->Evaluate(frame, rhs_result, attribute_trail)); - - ValueKind rhs_kind = rhs_result.kind(); - if (lhs_kind == ValueKind::kBool) { - bool lhs_bool = result.GetBool().NativeValue(); - if ((op_type_ == BoolLogicKind::kOr && lhs_bool) || - (op_type_ == BoolLogicKind::kAnd && !lhs_bool)) { - return absl::OkStatus(); - } - } - - if (rhs_kind == ValueKind::kBool) { - bool rhs_bool = rhs_result.GetBool().NativeValue(); - if ((op_type_ == BoolLogicKind::kOr && rhs_bool) || - (op_type_ == BoolLogicKind::kAnd && !rhs_bool)) { - result = std::move(rhs_result); - attribute_trail = std::move(rhs_attr); - return absl::OkStatus(); - } - } - - return ReturnLogicResult(frame, op_type_, result, rhs_result, attribute_trail, - rhs_attr); -} - -class DirectLogicStep : public DirectExpressionStep { - public: - explicit DirectLogicStep(std::unique_ptr lhs, - std::unique_ptr rhs, - BoolLogicKind op_type, int64_t expr_id) - : DirectExpressionStep(expr_id), - lhs_(std::move(lhs)), - rhs_(std::move(rhs)), - op_type_(op_type) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute_trail) const override; - - private: - std::unique_ptr lhs_; - std::unique_ptr rhs_; - BoolLogicKind op_type_; -}; - -absl::Status DirectLogicStep::Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const { - CEL_RETURN_IF_ERROR(lhs_->Evaluate(frame, result, attribute_trail)); - ValueKind lhs_kind = result.kind(); - if (lhs_kind == ValueKind::kBool) { - bool lhs_bool = result.GetBool().NativeValue(); - if ((op_type_ == BoolLogicKind::kOr && lhs_bool) || - (op_type_ == BoolLogicKind::kAnd && !lhs_bool)) { - return absl::OkStatus(); - } - } - - Value rhs_result; - AttributeTrail rhs_attr; - - CEL_RETURN_IF_ERROR(rhs_->Evaluate(frame, rhs_result, attribute_trail)); - - ValueKind rhs_kind = rhs_result.kind(); - - if (rhs_kind == ValueKind::kBool) { - bool rhs_bool = rhs_result.GetBool().NativeValue(); - if ((op_type_ == BoolLogicKind::kOr && rhs_bool) || - (op_type_ == BoolLogicKind::kAnd && !rhs_bool)) { - result = std::move(rhs_result); - attribute_trail = std::move(rhs_attr); - return absl::OkStatus(); - } - } - - return ReturnLogicResult(frame, op_type_, result, rhs_result, attribute_trail, - rhs_attr); -} - -std::unique_ptr CreateDirectLogicStep( - std::unique_ptr lhs, - std::unique_ptr rhs, int64_t expr_id, - BoolLogicKind op_type, bool shortcircuiting) { - if (shortcircuiting) { - return std::make_unique(std::move(lhs), std::move(rhs), - op_type, expr_id); - } else { - return std::make_unique( - std::move(lhs), std::move(rhs), op_type, expr_id); - } -} - -class DirectNotStep : public DirectExpressionStep { - public: - explicit DirectNotStep(std::unique_ptr operand, - int64_t expr_id) - : DirectExpressionStep(expr_id), operand_(std::move(operand)) {} - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override; - - private: - std::unique_ptr operand_; -}; - -absl::Status DirectNotStep::Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const { - CEL_RETURN_IF_ERROR(operand_->Evaluate(frame, result, attribute_trail)); - - if (frame.unknown_processing_enabled()) { - if (frame.attribute_utility().CheckForUnknownPartial(attribute_trail)) { - result = frame.attribute_utility().CreateUnknownSet( - attribute_trail.attribute()); - return absl::OkStatus(); - } - } - - switch (result.kind()) { - case ValueKind::kBool: - result = BoolValue{!result.GetBool().NativeValue()}; - break; - case ValueKind::kUnknown: - case ValueKind::kError: - // just forward. - break; - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(cel::builtin::kNot), frame.arena()); - break; - } - - return absl::OkStatus(); -} - - -class DirectNotStrictlyFalseStep : public DirectExpressionStep { - public: - explicit DirectNotStrictlyFalseStep( - std::unique_ptr operand, int64_t expr_id) - : DirectExpressionStep(expr_id), operand_(std::move(operand)) {} - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const override; - - private: - std::unique_ptr operand_; -}; - -absl::Status DirectNotStrictlyFalseStep::Evaluate( - ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute_trail) const { - CEL_RETURN_IF_ERROR(operand_->Evaluate(frame, result, attribute_trail)); - - switch (result.kind()) { - case ValueKind::kBool: - // just forward. - break; - case ValueKind::kUnknown: - case ValueKind::kError: - result = BoolValue(true); - break; - default: - result = cel::ErrorValue::From( - CreateNoMatchingOverloadError(cel::builtin::kNot), frame.arena()); - break; - } - - return absl::OkStatus(); -} - } // namespace void EvaluateNotStep(ExecutionFrame& frame) { @@ -388,33 +143,4 @@ void EvaluateBoolLogicStep(BoolLogicKind kind, size_t num_args, frame.value_stack().PopAndPush(num_args, std::move(result)); } -std::unique_ptr CreateDirectAndStep( - std::unique_ptr lhs, - std::unique_ptr rhs, int64_t expr_id, - bool shortcircuiting) { - return CreateDirectLogicStep(std::move(lhs), std::move(rhs), expr_id, - BoolLogicKind::kAnd, shortcircuiting); -} - -std::unique_ptr CreateDirectOrStep( - std::unique_ptr lhs, - std::unique_ptr rhs, int64_t expr_id, - bool shortcircuiting) { - return CreateDirectLogicStep(std::move(lhs), std::move(rhs), expr_id, - BoolLogicKind::kOr, shortcircuiting); -} - -// Factory method for recursive logical not "!" Execution step -std::unique_ptr CreateDirectNotStep( - std::unique_ptr operand, int64_t expr_id) { - return std::make_unique(std::move(operand), expr_id); -} - -// Factory method for recursive logical "@not_strictly_false" Execution step. -std::unique_ptr CreateDirectNotStrictlyFalseStep( - std::unique_ptr operand, int64_t expr_id) { - return std::make_unique(std::move(operand), - expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/logic_step.h b/eval/eval/logic_step.h index 401eaf2ca..fbcfb59ed 100644 --- a/eval/eval/logic_step.h +++ b/eval/eval/logic_step.h @@ -2,10 +2,6 @@ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_LOGIC_STEP_H_ #include -#include -#include - -#include "eval/eval/direct_expression_step.h" namespace google::api::expr::runtime { @@ -23,26 +19,6 @@ enum class BoolLogicKind { void EvaluateBoolLogicStep(BoolLogicKind kind, size_t num_args, ExecutionFrame& frame); -// Factory method for "And" Execution step -std::unique_ptr CreateDirectAndStep( - std::unique_ptr lhs, - std::unique_ptr rhs, int64_t expr_id, - bool shortcircuiting); - -// Factory method for "Or" Execution step -std::unique_ptr CreateDirectOrStep( - std::unique_ptr lhs, - std::unique_ptr rhs, int64_t expr_id, - bool shortcircuiting); - -// Factory method for recursive logical not "!" Execution step -std::unique_ptr CreateDirectNotStep( - std::unique_ptr operand, int64_t expr_id); - -// Factory method for recursive logical "@not_strictly_false" Execution step. -std::unique_ptr CreateDirectNotStrictlyFalseStep( - std::unique_ptr operand, int64_t expr_id); - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_LOGIC_STEP_H_ diff --git a/eval/eval/logic_step_test.cc b/eval/eval/logic_step_test.cc index 04b9fd127..e82c4b7cf 100644 --- a/eval/eval/logic_step_test.cc +++ b/eval/eval/logic_step_test.cc @@ -2,27 +2,19 @@ #include #include -#include #include #include #include "absl/base/nullability.h" #include "absl/status/status.h" #include "absl/status/status_matchers.h" -#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "base/attribute.h" #include "base/attribute_set.h" #include "base/type_provider.h" #include "common/expr.h" -#include "common/unknown.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" @@ -30,12 +22,8 @@ #include "eval/public/unknown_set.h" #include "internal/status_macros.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "google/protobuf/arena.h" @@ -46,12 +34,8 @@ namespace { using ::absl_testing::IsOk; using ::cel::Attribute; using ::cel::AttributeSet; -using ::cel::BoolValue; using ::cel::Expr; -using ::cel::IntValue; using ::cel::TypeProvider; -using ::cel::UnknownValue; -using ::cel::Value; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; using ::google::protobuf::Arena; @@ -318,369 +302,6 @@ TEST_F(LogicStepTest, TestOrLogicUnknownHandling) { INSTANTIATE_TEST_SUITE_P(LogicStepTest, LogicStepTest, testing::Bool()); -enum class BinaryOp { kAnd, kOr }; -enum class UnaryOp { kNot, kNotStrictlyFalse }; - -enum class OpArg { - kTrue, - kFalse, - kUnknown, - kError, - // Arbitrary incorrect type - kInt -}; - -enum class OpResult { - kTrue, - kFalse, - kUnknown, - kError, -}; - -struct BinaryTestCase { - std::string name; - BinaryOp op; - OpArg arg0; - OpArg arg1; - OpResult result; -}; - -UnknownValue MakeUnknownValue(std::string attr) { - std::vector attrs; - attrs.push_back(Attribute(std::move(attr))); - return cel::common_internal::MakeUnknownValue( - cel::Unknown(AttributeSet(attrs))); -} - -std::unique_ptr MakeArgStep(OpArg arg, - absl::string_view name, - google::protobuf::Arena* arena) { - switch (arg) { - case OpArg::kTrue: - return CreateConstValueDirectStep(BoolValue(true)); - case OpArg::kFalse: - return CreateConstValueDirectStep(BoolValue(false)); - case OpArg::kUnknown: - return CreateConstValueDirectStep(MakeUnknownValue(std::string(name))); - case OpArg::kError: - return CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError(name), arena)); - case OpArg::kInt: - return CreateConstValueDirectStep(IntValue(42)); - } -}; - -class DirectBinaryLogicStepTest - : public testing::TestWithParam> { - public: - DirectBinaryLogicStepTest() = default; - - bool ShortcircuitingEnabled() { return std::get<0>(GetParam()); } - const BinaryTestCase& GetTestCase() { return std::get<1>(GetParam()); } - - protected: - Arena arena_; -}; - -TEST_P(DirectBinaryLogicStepTest, TestCases) { - const BinaryTestCase& test_case = GetTestCase(); - - std::unique_ptr lhs = - MakeArgStep(test_case.arg0, "lhs", &arena_); - std::unique_ptr rhs = - MakeArgStep(test_case.arg1, "rhs", &arena_); - - std::unique_ptr op = - (test_case.op == BinaryOp::kAnd) - ? CreateDirectAndStep(std::move(lhs), std::move(rhs), -1, - ShortcircuitingEnabled()) - : CreateDirectOrStep(std::move(lhs), std::move(rhs), -1, - ShortcircuitingEnabled()); - - cel::Activation activation; - cel::RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value value; - AttributeTrail attr; - ASSERT_THAT(op->Evaluate(frame, value, attr), IsOk()); - - switch (test_case.result) { - case OpResult::kTrue: - ASSERT_TRUE(value.IsBool()); - EXPECT_TRUE(value.GetBool().NativeValue()); - break; - case OpResult::kFalse: - ASSERT_TRUE(value.IsBool()); - EXPECT_FALSE(value.GetBool().NativeValue()); - break; - case OpResult::kUnknown: - EXPECT_TRUE(value.IsUnknown()); - break; - case OpResult::kError: - EXPECT_TRUE(value.IsError()); - break; - } -} - -INSTANTIATE_TEST_SUITE_P( - DirectBinaryLogicStepTest, DirectBinaryLogicStepTest, - testing::Combine(testing::Bool(), - testing::ValuesIn>({ - { - "AndFalseFalse", - BinaryOp::kAnd, - OpArg::kFalse, - OpArg::kFalse, - OpResult::kFalse, - }, - { - "AndFalseTrue", - BinaryOp::kAnd, - OpArg::kFalse, - OpArg::kTrue, - OpResult::kFalse, - }, - { - "AndTrueFalse", - BinaryOp::kAnd, - OpArg::kTrue, - OpArg::kFalse, - OpResult::kFalse, - }, - { - "AndTrueTrue", - BinaryOp::kAnd, - OpArg::kTrue, - OpArg::kTrue, - OpResult::kTrue, - }, - - { - "AndTrueError", - BinaryOp::kAnd, - OpArg::kTrue, - OpArg::kError, - OpResult::kError, - }, - { - "AndErrorTrue", - BinaryOp::kAnd, - OpArg::kError, - OpArg::kTrue, - OpResult::kError, - }, - { - "AndFalseError", - BinaryOp::kAnd, - OpArg::kFalse, - OpArg::kError, - OpResult::kFalse, - }, - { - "AndErrorFalse", - BinaryOp::kAnd, - OpArg::kError, - OpArg::kFalse, - OpResult::kFalse, - }, - { - "AndErrorError", - BinaryOp::kAnd, - OpArg::kError, - OpArg::kError, - OpResult::kError, - }, - - { - "AndTrueUnknown", - BinaryOp::kAnd, - OpArg::kTrue, - OpArg::kUnknown, - OpResult::kUnknown, - }, - { - "AndUnknownTrue", - BinaryOp::kAnd, - OpArg::kUnknown, - OpArg::kTrue, - OpResult::kUnknown, - }, - { - "AndFalseUnknown", - BinaryOp::kAnd, - OpArg::kFalse, - OpArg::kUnknown, - OpResult::kFalse, - }, - { - "AndUnknownFalse", - BinaryOp::kAnd, - OpArg::kUnknown, - OpArg::kFalse, - OpResult::kFalse, - }, - { - "AndUnknownUnknown", - BinaryOp::kAnd, - OpArg::kUnknown, - OpArg::kUnknown, - OpResult::kUnknown, - }, - { - "AndUnknownError", - BinaryOp::kAnd, - OpArg::kUnknown, - OpArg::kError, - OpResult::kUnknown, - }, - { - "AndErrorUnknown", - BinaryOp::kAnd, - OpArg::kError, - OpArg::kUnknown, - OpResult::kUnknown, - }, - // Or cases are simplified since the logic generalizes - // and is covered by and cases. - })), - [](const testing::TestParamInfo& info) - -> std::string { - bool shortcircuiting_enabled = std::get<0>(info.param); - absl::string_view name = std::get<1>(info.param).name; - return absl::StrCat( - name, (shortcircuiting_enabled ? "ShortcircuitingEnabled" : "")); - }); - -struct UnaryTestCase { - std::string name; - UnaryOp op; - OpArg arg; - OpResult result; -}; - -class DirectUnaryLogicStepTest : public testing::TestWithParam { - public: - DirectUnaryLogicStepTest() = default; - - const UnaryTestCase& GetTestCase() { return GetParam(); } - - protected: - Arena arena_; -}; - -TEST_P(DirectUnaryLogicStepTest, TestCases) { - const UnaryTestCase& test_case = GetTestCase(); - - std::unique_ptr arg = - MakeArgStep(test_case.arg, "arg", &arena_); - - std::unique_ptr op = - (test_case.op == UnaryOp::kNot) - ? CreateDirectNotStep(std::move(arg), -1) - : CreateDirectNotStrictlyFalseStep(std::move(arg), -1); - - cel::Activation activation; - cel::RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - ExecutionFrameBase frame(activation, options, type_provider, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value value; - AttributeTrail attr; - ASSERT_THAT(op->Evaluate(frame, value, attr), IsOk()); - - switch (test_case.result) { - case OpResult::kTrue: - ASSERT_TRUE(value.IsBool()); - EXPECT_TRUE(value.GetBool().NativeValue()); - break; - case OpResult::kFalse: - ASSERT_TRUE(value.IsBool()); - EXPECT_FALSE(value.GetBool().NativeValue()); - break; - case OpResult::kUnknown: - EXPECT_TRUE(value.IsUnknown()); - break; - case OpResult::kError: - EXPECT_TRUE(value.IsError()); - break; - } -} - -INSTANTIATE_TEST_SUITE_P( - DirectUnaryLogicStepTest, DirectUnaryLogicStepTest, - testing::ValuesIn>( - {UnaryTestCase{"NotTrue", UnaryOp::kNot, OpArg::kTrue, - OpResult::kFalse}, - UnaryTestCase{"NotError", UnaryOp::kNot, OpArg::kError, - OpResult::kError}, - UnaryTestCase{"NotUnknown", UnaryOp::kNot, OpArg::kUnknown, - OpResult::kUnknown}, - UnaryTestCase{"NotInt", UnaryOp::kNot, OpArg::kInt, OpResult::kError}, - UnaryTestCase{"NotFalse", UnaryOp::kNot, OpArg::kFalse, - OpResult::kTrue}, - UnaryTestCase{"NotStrictlyFalseTrue", UnaryOp::kNotStrictlyFalse, - OpArg::kTrue, OpResult::kTrue}, - UnaryTestCase{"NotStrictlyFalseError", UnaryOp::kNotStrictlyFalse, - OpArg::kError, OpResult::kTrue}, - UnaryTestCase{"NotStrictlyFalseUnknown", UnaryOp::kNotStrictlyFalse, - OpArg::kUnknown, OpResult::kTrue}, - UnaryTestCase{"NotStrictlyFalseInt", UnaryOp::kNotStrictlyFalse, - OpArg::kInt, OpResult::kError}, - UnaryTestCase{"NotStrictlyFalseFalse", UnaryOp::kNotStrictlyFalse, - OpArg::kFalse, OpResult::kFalse}}), - [](const testing::TestParamInfo& info) - -> std::string { return info.param.name; }); - -TEST(UnaryLogicStepTest, BooleanNot) { - ExecutionPath path; - path.push_back(ExpressionStep::MakeConstant(cel::BoolValue(true))); - path.push_back(ExpressionStep::MakeBooleanNotStep()); - - google::protobuf::Arena arena; - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - FlatExpressionEvaluatorState state( - 2, 0, type_provider, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - cel::Activation activation; - cel::RuntimeOptions options; - ExecutionFrame frame(path, activation, options, state); - ASSERT_OK_AND_ASSIGN(cel::Value value, frame.Evaluate()); - ASSERT_TRUE(value.IsBool()); - EXPECT_FALSE(value.GetBool().NativeValue()); -} - -TEST(UnaryLogicStepTest, NotStrictlyFalse) { - google::protobuf::Arena arena; - - ExecutionPath path; - path.push_back(ExpressionStep::MakeConstant( - cel::ErrorValue::From(absl::InternalError("error"), &arena))); - path.push_back(ExpressionStep::MakeNotStrictlyFalseStep()); - - cel::runtime_internal::RuntimeTypeProvider type_provider( - cel::internal::GetTestingDescriptorPool()); - FlatExpressionEvaluatorState state( - 2, 0, type_provider, cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena); - cel::Activation activation; - cel::RuntimeOptions options; - ExecutionFrame frame(path, activation, options, state); - ASSERT_OK_AND_ASSIGN(cel::Value value, frame.Evaluate()); - ASSERT_TRUE(value.IsBool()); - EXPECT_TRUE(value.GetBool().NativeValue()); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/optional_or_step.cc b/eval/eval/optional_or_step.cc index 983f229b1..c0b341b4f 100644 --- a/eval/eval/optional_or_step.cc +++ b/eval/eval/optional_or_step.cc @@ -14,7 +14,6 @@ #include "eval/eval/optional_or_step.h" -#include #include #include #include @@ -24,11 +23,9 @@ #include "absl/types/span.h" #include "common/value.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" #include "eval/eval/expression_step_logic.h" -#include "internal/status_macros.h" #include "runtime/internal/errors.h" #include "google/protobuf/arena.h" @@ -130,96 +127,6 @@ void OptionalOrStep::Evaluate(ExecutionFrame* frame) const { frame->value_stack().PopAndPush(2, std::move(result), std::move(result_attr)); } -class ExhaustiveDirectOptionalOrStep : public DirectExpressionStep { - public: - ExhaustiveDirectOptionalOrStep( - int64_t expr_id, std::unique_ptr optional, - std::unique_ptr alternative, OptionalOrKind kind) - - : DirectExpressionStep(expr_id), - kind_(kind), - optional_(std::move(optional)), - alternative_(std::move(alternative)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override; - - private: - OptionalOrKind kind_; - std::unique_ptr optional_; - std::unique_ptr alternative_; -}; - -absl::Status ExhaustiveDirectOptionalOrStep::Evaluate( - ExecutionFrameBase& frame, Value& result, AttributeTrail& attribute) const { - CEL_RETURN_IF_ERROR(optional_->Evaluate(frame, result, attribute)); - Value rhs; - AttributeTrail rhs_attr; - CEL_RETURN_IF_ERROR(alternative_->Evaluate(frame, rhs, rhs_attr)); - CEL_RETURN_IF_ERROR(EvalOptionalOr(kind_, result, rhs, attribute, rhs_attr, - result, attribute, frame.arena())); - return absl::OkStatus(); -} - -class DirectOptionalOrStep : public DirectExpressionStep { - public: - DirectOptionalOrStep(int64_t expr_id, - std::unique_ptr optional, - std::unique_ptr alternative, - OptionalOrKind kind) - - : DirectExpressionStep(expr_id), - kind_(kind), - optional_(std::move(optional)), - alternative_(std::move(alternative)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override; - - private: - OptionalOrKind kind_; - std::unique_ptr optional_; - std::unique_ptr alternative_; -}; - -absl::Status DirectOptionalOrStep::Evaluate(ExecutionFrameBase& frame, - Value& result, - AttributeTrail& attribute) const { - CEL_RETURN_IF_ERROR(optional_->Evaluate(frame, result, attribute)); - - if (result.IsUnknown() || result.IsError()) { - // Forward the lhs error instead of attempting to evaluate the alternative - // (unlike CEL's commutative logic operators). - return absl::OkStatus(); - } - - auto optional_value = result.AsOptional(); - if (!optional_value.has_value()) { - result = MakeNoOverloadError(kind_, frame.arena()); - return absl::OkStatus(); - } - - if (optional_value->HasValue()) { - if (kind_ == OptionalOrKind::kOrValue) { - result = optional_value->Value(); - } - return absl::OkStatus(); - } - - CEL_RETURN_IF_ERROR(alternative_->Evaluate(frame, result, attribute)); - - // If optional.or check that rhs is an optional. - // - // Otherwise, we don't know what type to expect so can't check anything. - if (kind_ == OptionalOrKind::kOrOptional) { - if (!result.IsOptional() && !result.IsError() && !result.IsUnknown()) { - result = MakeNoOverloadError(kind_, frame.arena()); - } - } - - return absl::OkStatus(); -} - } // namespace void OptionalHasValueJumpStep::Evaluate(ExecutionFrame* frame) const { @@ -257,19 +164,4 @@ std::unique_ptr CreateOptionalOrStep(bool is_or_value) { is_or_value ? OptionalOrKind::kOrValue : OptionalOrKind::kOrOptional); } -std::unique_ptr CreateDirectOptionalOrStep( - int64_t expr_id, std::unique_ptr optional, - std::unique_ptr alternative, bool is_or_value, - bool short_circuiting) { - auto kind = - is_or_value ? OptionalOrKind::kOrValue : OptionalOrKind::kOrOptional; - if (short_circuiting) { - return std::make_unique(expr_id, std::move(optional), - std::move(alternative), kind); - } else { - return std::make_unique( - expr_id, std::move(optional), std::move(alternative), kind); - } -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/optional_or_step.h b/eval/eval/optional_or_step.h index f54057fa9..fc55a0ab7 100644 --- a/eval/eval/optional_or_step.h +++ b/eval/eval/optional_or_step.h @@ -15,14 +15,12 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_OPTIONAL_OR_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_OPTIONAL_OR_STEP_H_ -#include #include #include -#include "absl/status/status.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { @@ -54,13 +52,6 @@ std::unique_ptr CreateOptionalHasValueJumpStep( // optional.orValue. std::unique_ptr CreateOptionalOrStep(bool is_or_value); -// Creates a step implementing the short-circuiting optional.or or -// optional.orValue step. -std::unique_ptr CreateDirectOptionalOrStep( - int64_t expr_id, std::unique_ptr optional, - std::unique_ptr alternative, bool is_or_value, - bool short_circuiting); - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_OPTIONAL_OR_STEP_H_ diff --git a/eval/eval/optional_or_step_test.cc b/eval/eval/optional_or_step_test.cc deleted file mode 100644 index f0641ca6c..000000000 --- a/eval/eval/optional_or_step_test.cc +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "eval/eval/optional_or_step.h" - -#include - -#include "absl/memory/memory.h" -#include "absl/status/status.h" -#include "common/value.h" -#include "common/value_kind.h" -#include "common/value_testing.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" -#include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" -#include "runtime/internal/errors.h" -#include "runtime/internal/runtime_type_provider.h" -#include "runtime/runtime_options.h" -#include "google/protobuf/arena.h" - -namespace google::api::expr::runtime { -namespace { - -using ::absl_testing::StatusIs; -using ::cel::Activation; -using ::cel::ErrorValue; -using ::cel::IntValue; -using ::cel::OptionalValue; -using ::cel::RuntimeOptions; -using ::cel::UnknownValue; -using ::cel::Value; -using ::cel::ValueKind; -using ::cel::test::ErrorValueIs; -using ::cel::test::IntValueIs; -using ::cel::test::OptionalValueIs; -using ::cel::test::ValueKindIs; -using ::testing::HasSubstr; -using ::testing::NiceMock; - -class MockDirectStep : public DirectExpressionStep { - public: - MOCK_METHOD(absl::Status, Evaluate, - (ExecutionFrameBase & frame, Value& result, - AttributeTrail& scratch), - (const, override)); -}; - -std::unique_ptr MockNeverCalledDirectStep() { - auto* mock = new NiceMock(); - EXPECT_CALL(*mock, Evaluate).Times(0); - return absl::WrapUnique(mock); -} - -std::unique_ptr MockExpectCallDirectStep() { - auto* mock = new NiceMock(); - EXPECT_CALL(*mock, Evaluate) - .Times(1) - .WillRepeatedly( - [](ExecutionFrameBase& frame, Value& result, AttributeTrail& attr) { - result = ErrorValue::From( - absl::InternalError("expected to be unused"), frame.arena()); - return absl::OkStatus(); - }); - return absl::WrapUnique(mock); -} - -class OptionalOrTest : public testing::Test { - public: - OptionalOrTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()) {} - - protected: - google::protobuf::Arena arena_; - cel::runtime_internal::RuntimeTypeProvider type_provider_; - Activation empty_activation_; -}; - -TEST_F(OptionalOrTest, OptionalOrLeftPresentShortcutRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep(OptionalValue::Of(IntValue(42), &arena_)), - MockNeverCalledDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, OptionalValueIs(IntValueIs(42))); -} - -TEST_F(OptionalOrTest, OptionalOrLeftErrorShortcutsRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep( - ErrorValue::From(absl::InternalError("error"), &arena_)), - MockNeverCalledDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kError)); -} - -TEST_F(OptionalOrTest, OptionalOrLeftErrorExhaustiveRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep( - ErrorValue::From(absl::InternalError("error"), &arena_)), - MockExpectCallDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/false); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kError)); -} - -TEST_F(OptionalOrTest, OptionalOrLeftUnknownShortcutsRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(UnknownValue()), - MockNeverCalledDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); -} - -TEST_F(OptionalOrTest, OptionalOrLeftUnknownExhaustiveRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(UnknownValue()), - MockExpectCallDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/false); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); -} - -TEST_F(OptionalOrTest, OptionalOrLeftAbsentReturnRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(OptionalValue::None()), - CreateConstValueDirectStep(OptionalValue::Of(IntValue(42), &arena_)), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, OptionalValueIs(IntValueIs(42))); -} - -TEST_F(OptionalOrTest, OptionalOrLeftWrongType) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(IntValue(42)), - MockNeverCalledDirectStep(), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, - ErrorValueIs(StatusIs( - absl::StatusCode::kUnknown, - HasSubstr(cel::runtime_internal::kErrNoMatchingOverload)))); -} - -TEST_F(OptionalOrTest, OptionalOrRightWrongType) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(OptionalValue::None()), - CreateConstValueDirectStep(IntValue(42)), - /*is_or_value=*/false, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, - ErrorValueIs(StatusIs( - absl::StatusCode::kUnknown, - HasSubstr(cel::runtime_internal::kErrNoMatchingOverload)))); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftPresentShortcutRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep(OptionalValue::Of(IntValue(42), &arena_)), - MockNeverCalledDirectStep(), - /*is_or_value=*/true, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, IntValueIs(42)); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftPresentExhaustiveRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep(OptionalValue::Of(IntValue(42), &arena_)), - MockExpectCallDirectStep(), - /*is_or_value=*/true, - /*short_circuiting=*/false); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, IntValueIs(42)); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftErrorShortcutsRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, - CreateConstValueDirectStep( - ErrorValue::From(absl::InternalError("error"), &arena_)), - MockNeverCalledDirectStep(), - /*is_or_value=*/true, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kError)); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftUnknownShortcutsRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(UnknownValue()), - MockNeverCalledDirectStep(), true, true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - EXPECT_THAT(result, ValueKindIs(ValueKind::kUnknown)); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftAbsentReturnRight) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(OptionalValue::None()), - CreateConstValueDirectStep(IntValue(42)), - /*is_or_value=*/true, - /*short_circuiting=*/true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, IntValueIs(42)); -} - -TEST_F(OptionalOrTest, OptionalOrValueLeftWrongType) { - RuntimeOptions options; - ExecutionFrameBase frame(empty_activation_, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectOptionalOrStep( - /*expr_id=*/-1, CreateConstValueDirectStep(IntValue(42)), - MockNeverCalledDirectStep(), true, true); - - Value result; - AttributeTrail scratch; - - ASSERT_OK(step->Evaluate(frame, result, scratch)); - - EXPECT_THAT(result, - ErrorValueIs(StatusIs( - absl::StatusCode::kUnknown, - HasSubstr(cel::runtime_internal::kErrNoMatchingOverload)))); -} - -} // namespace -} // namespace google::api::expr::runtime diff --git a/eval/eval/regex_match_step.cc b/eval/eval/regex_match_step.cc index d13e4f651..3c949ee9f 100644 --- a/eval/eval/regex_match_step.cc +++ b/eval/eval/regex_match_step.cc @@ -14,7 +14,6 @@ #include "eval/eval/regex_match_step.h" -#include #include #include #include @@ -24,11 +23,9 @@ #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" -#include "internal/status_macros.h" +#include "eval/eval/expression_step_logic.h" #include "re2/re2.h" namespace google::api::expr::runtime { @@ -37,7 +34,6 @@ namespace { using ::cel::BoolValue; using ::cel::StringValue; -using ::cel::Value; inline constexpr int kNumRegexMatchArguments = 1; inline constexpr size_t kRegexMatchStepSubject = 0; @@ -84,47 +80,8 @@ class RegexMatchStep final : public ExpressionStepBase { const std::shared_ptr re2_; }; -class RegexMatchDirectStep final : public DirectExpressionStep { - public: - RegexMatchDirectStep(int64_t expr_id, - std::unique_ptr subject, - std::shared_ptr re2) - : DirectExpressionStep(expr_id), - subject_(std::move(subject)), - re2_(std::move(re2)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - AttributeTrail subject_attr; - CEL_RETURN_IF_ERROR(subject_->Evaluate(frame, result, subject_attr)); - if (result.IsError() || result.IsUnknown()) { - return absl::OkStatus(); - } - - if (!result.IsString()) { - return absl::Status(absl::StatusCode::kInternal, - "First argument for regular " - "expression match must be a string"); - } - bool match = result.GetString().NativeValue(MatchesVisitor{*re2_}); - result = BoolValue(match); - return absl::OkStatus(); - } - - private: - std::unique_ptr subject_; - const std::shared_ptr re2_; -}; - } // namespace -std::unique_ptr CreateDirectRegexMatchStep( - int64_t expr_id, std::unique_ptr subject, - std::shared_ptr re2) { - return std::make_unique(expr_id, std::move(subject), - std::move(re2)); -} - absl::StatusOr> CreateRegexMatchStep( std::shared_ptr re2) { return std::make_unique(std::move(re2)); diff --git a/eval/eval/regex_match_step.h b/eval/eval/regex_match_step.h index bcbff7bdc..d44559787 100644 --- a/eval/eval/regex_match_step.h +++ b/eval/eval/regex_match_step.h @@ -15,20 +15,14 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_REGEX_MATCH_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_REGEX_MATCH_STEP_H_ -#include #include #include "absl/status/statusor.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" #include "re2/re2.h" namespace google::api::expr::runtime { -std::unique_ptr CreateDirectRegexMatchStep( - int64_t expr_id, std::unique_ptr subject, - std::shared_ptr re2); - absl::StatusOr> CreateRegexMatchStep( std::shared_ptr re2); } diff --git a/eval/eval/regex_match_step_test.cc b/eval/eval/regex_match_step_test.cc index 53b955b25..fa141365e 100644 --- a/eval/eval/regex_match_step_test.cc +++ b/eval/eval/regex_match_step_test.cc @@ -17,7 +17,6 @@ #include "cel/expr/checked.pb.h" #include "cel/expr/syntax.pb.h" #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "eval/public/activation.h" #include "eval/public/builtin_func_registrar.h" #include "eval/public/cel_expr_builder_factory.h" diff --git a/eval/eval/select_step.cc b/eval/eval/select_step.cc index a8f270698..9bfa5fad4 100644 --- a/eval/eval/select_step.cc +++ b/eval/eval/select_step.cc @@ -1,6 +1,5 @@ #include "eval/eval/select_step.h" -#include #include #include #include @@ -19,9 +18,9 @@ #include "common/value.h" #include "common/value_kind.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "eval/public/cel_value.h" #include "eval/public/structs/proto_message_type_adapter.h" #include "internal/status_macros.h" @@ -321,115 +320,6 @@ void SelectStep::Evaluate(ExecutionFrame* frame) const { frame->value_stack().PopAndPush(std::move(result), std::move(result_trail)); } -class DirectSelectStep : public DirectExpressionStep { - public: - DirectSelectStep(int64_t expr_id, - std::unique_ptr operand, - absl::string_view field, bool test_only, - bool enable_wrapper_type_null_unboxing, - bool enable_optional_types) - : DirectExpressionStep(expr_id), - operand_(std::move(operand)), - field_(field), - test_only_(test_only), - unboxing_option_(enable_wrapper_type_null_unboxing - ? ProtoWrapperTypeOptions::kUnsetNull - : ProtoWrapperTypeOptions::kUnsetProtoDefault), - enable_optional_types_(enable_optional_types) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override { - CEL_RETURN_IF_ERROR(operand_->Evaluate(frame, result, attribute)); - - if (result.IsError() || result.IsUnknown()) { - // Just forward. - return absl::OkStatus(); - } - - if (frame.attribute_tracking_enabled()) { - attribute = attribute.Step(&field_); - absl::optional value = CheckForMarkedAttributes(attribute, frame); - if (value.has_value()) { - result = std::move(value).value(); - return absl::OkStatus(); - } - } - - absl::optional optional_arg; - - if (enable_optional_types_ && result.IsOptional()) { - optional_arg = result.GetOptional(); - } - - switch (result.kind()) { - case ValueKind::kStruct: - case ValueKind::kMap: - break; - default: - if (optional_arg) { - break; - } - result = - cel::ErrorValue::From(InvalidSelectTargetError(), frame.arena()); - return absl::OkStatus(); - } - - if (test_only_) { - if (optional_arg) { - if (!optional_arg->HasValue()) { - result = cel::BoolValue{false}; - return absl::OkStatus(); - } - Value value; - optional_arg->Value(&value); - return PerformHas(value, field_, cel::StringValue::WrapUnsafe(field_), - frame.descriptor_pool(), frame.message_factory(), - frame.arena(), result); - } - return PerformHas(result, field_, cel::StringValue::WrapUnsafe(field_), - frame.descriptor_pool(), frame.message_factory(), - frame.arena(), result); - } - - if (optional_arg) { - if (!optional_arg->HasValue()) { - // result is still buffer for the container. just return. - return absl::OkStatus(); - } - Value value; - optional_arg->Value(&value); - auto status = PerformOptionalGet( - value, field_, cel::StringValue::WrapUnsafe(field_), unboxing_option_, - frame.descriptor_pool(), frame.message_factory(), frame.arena(), - frame.options().enable_use_new_field_select_implementation, result); - if (!status.ok()) { - result = ErrorValue::From(std::move(status), frame.arena()); - } - return absl::OkStatus(); - } - - return PerformGet( - result, field_, cel::StringValue::WrapUnsafe(field_), unboxing_option_, - frame.descriptor_pool(), frame.message_factory(), frame.arena(), - frame.options().enable_use_new_field_select_implementation, result); - } - - private: - std::unique_ptr operand_; - - // Field name in formats supported by each of the map and struct field access - // APIs. - // - // ToString or ValueManager::CreateString may force a copy so we do this at - // plan time. - std::string field_; - - // whether this is a has() expression. - bool test_only_; - ProtoWrapperTypeOptions unboxing_option_; - bool enable_optional_types_; -}; - bool CheckAttributeTrail(const std::string& field, ExecutionFrame* frame) { if (!frame->attribute_tracking_enabled()) { return false; @@ -619,15 +509,6 @@ void ProtoHasStep::EvaluateHas( } // namespace -std::unique_ptr CreateDirectSelectStep( - std::unique_ptr operand, absl::string_view field, - bool test_only, int64_t expr_id, bool enable_wrapper_type_null_unboxing, - bool enable_optional_types) { - return std::make_unique( - expr_id, std::move(operand), std::move(field), test_only, - enable_wrapper_type_null_unboxing, enable_optional_types); -} - // Factory method for Select - based Execution step absl::StatusOr> CreateSelectStep( absl::string_view field, bool test_only, diff --git a/eval/eval/select_step.h b/eval/eval/select_step.h index 528e90627..9e5d2967b 100644 --- a/eval/eval/select_step.h +++ b/eval/eval/select_step.h @@ -1,23 +1,15 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_SELECT_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_SELECT_STEP_H_ -#include #include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "common/type.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -// Factory method for recursively evaluated select step. -std::unique_ptr CreateDirectSelectStep( - std::unique_ptr operand, absl::string_view field, - bool test_only, int64_t expr_id, bool enable_wrapper_type_null_unboxing, - bool enable_optional_types = false); - // Factory method for Select stack machine based Execution step absl::StatusOr> CreateSelectStep( absl::string_view field, bool test_only, diff --git a/eval/eval/select_step_test.cc b/eval/eval/select_step_test.cc index 1fca8fa57..68c6f6f50 100644 --- a/eval/eval/select_step_test.cc +++ b/eval/eval/select_step_test.cc @@ -8,7 +8,6 @@ #include "cel/expr/syntax.pb.h" #include "google/protobuf/wrappers.pb.h" #include "absl/base/nullability.h" -#include "absl/log/absl_check.h" #include "absl/status/status.h" #include "absl/status/status_matchers.h" #include "absl/status/statusor.h" @@ -20,13 +19,8 @@ #include "common/expr.h" #include "common/legacy_value.h" #include "common/type.h" -#include "common/value.h" -#include "common/value_testing.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/const_value_step.h" #include "eval/eval/evaluator_core.h" -#include "eval/eval/ident_step.h" #include "eval/public/activation.h" #include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" @@ -37,16 +31,11 @@ #include "eval/public/unknown_set.h" #include "eval/testutil/test_extensions.pb.h" #include "eval/testutil/test_message.pb.h" -#include "extensions/protobuf/value.h" #include "internal/proto_matchers.h" #include "internal/status_macros.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "cel/expr/conformance/proto3/test_all_types.pb.h" #include "google/protobuf/descriptor.h" @@ -58,26 +47,16 @@ namespace { using ::absl_testing::IsOk; using ::absl_testing::StatusIs; using ::cel::Attribute; -using ::cel::AttributeQualifier; using ::cel::AttributeSet; -using ::cel::BoolValue; -using ::cel::ErrorValue; using ::cel::Expr; -using ::cel::IntValue; -using ::cel::OptionalValue; using ::cel::RuntimeOptions; using ::cel::TypeProvider; -using ::cel::UnknownValue; -using ::cel::Value; using ::cel::expr::conformance::proto3::TestAllTypes; -using ::cel::extensions::ProtoMessageToValue; using ::cel::internal::test::EqualsProto; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; -using ::cel::test::IntValueIs; using ::testing::Eq; using ::testing::HasSubstr; -using ::testing::UnorderedElementsAre; struct RunExpressionOptions { bool enable_unknowns = false; @@ -1089,537 +1068,6 @@ TEST_F(SelectStepTest, TypedSelectStepUnknownPatternResolvesToUnknown) { INSTANTIATE_TEST_SUITE_P(UnknownsEnabled, SelectStepConformanceTest, testing::Bool()); -class DirectSelectStepTest : public testing::Test { - public: - DirectSelectStepTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()) {} - - cel::Value TestWrapMessage(const google::protobuf::Message* message) { - CelValue value = CelProtoWrapper::CreateMessage(message, &arena_); - auto result = cel::interop_internal::FromLegacyValue(&arena_, value); - ABSL_DCHECK_OK(result.status()); - return std::move(result).value(); - } - - std::vector AttributeStrings(const UnknownValue& v) { - std::vector result; - for (const Attribute& attr : v.ToAttributeSet()) { - auto attr_str = attr.AsString(); - ABSL_DCHECK_OK(attr_str.status()); - result.push_back(std::move(attr_str).value()); - } - return result; - } - - protected: - google::protobuf::Arena arena_; - cel::runtime_internal::RuntimeTypeProvider type_provider_; -}; - -TEST_F(DirectSelectStepTest, SelectFromMap) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "one", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - auto map_builder = cel::NewMapValueBuilder(&arena_); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("one"), IntValue(1)), - IsOk()); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("two"), IntValue(2)), - IsOk()); - activation.InsertOrAssignValue("map_val", std::move(*map_builder).Build()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsInt()); - - EXPECT_EQ(result.GetInt().NativeValue(), 1); -} - -TEST_F(DirectSelectStepTest, HasMap) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "two", - /*test_only=*/true, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - auto map_builder = cel::NewMapValueBuilder(&arena_); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("one"), IntValue(1)), - IsOk()); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("two"), IntValue(2)), - IsOk()); - activation.InsertOrAssignValue("map_val", std::move(*map_builder).Build()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.GetBool()); - - EXPECT_TRUE(result.GetBool().NativeValue()); -} - -TEST_F(DirectSelectStepTest, SelectFromOptionalMap) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "one", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - auto map_builder = cel::NewMapValueBuilder(&arena_); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("one"), IntValue(1)), - IsOk()); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("two"), IntValue(2)), - IsOk()); - activation.InsertOrAssignValue( - "map_val", OptionalValue::Of(std::move(*map_builder).Build(), &arena_)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsOptional()); - EXPECT_THAT(result.GetOptional().Value(), IntValueIs(1)); -} - -TEST_F(DirectSelectStepTest, SelectFromOptionalMapAbsent) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "three", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - auto map_builder = cel::NewMapValueBuilder(&arena_); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("one"), IntValue(1)), - IsOk()); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("two"), IntValue(2)), - IsOk()); - activation.InsertOrAssignValue( - "map_val", OptionalValue::Of(std::move(*map_builder).Build(), &arena_)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsOptional()); - EXPECT_FALSE(result.GetOptional().HasValue()); -} - -TEST_F(DirectSelectStepTest, SelectFromOptionalStruct) { - cel::Activation activation; - RuntimeOptions options; - - auto step = CreateDirectSelectStep(CreateDirectIdentStep("struct_val", -1), - "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - TestAllTypes message; - message.set_single_int64(1); - - ASSERT_OK_AND_ASSIGN( - Value struct_val, - ProtoMessageToValue(std::move(message), - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_)); - - activation.InsertOrAssignValue("struct_val", - OptionalValue::Of(struct_val, &arena_)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsOptional()); - EXPECT_THAT(result.GetOptional().Value(), IntValueIs(1)); -} - -TEST_F(DirectSelectStepTest, SelectFromOptionalStructFieldNotSet) { - cel::Activation activation; - RuntimeOptions options; - - auto step = CreateDirectSelectStep(CreateDirectIdentStep("struct_val", -1), - "single_string", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - TestAllTypes message; - message.set_single_int64(1); - - ASSERT_OK_AND_ASSIGN( - Value struct_val, - ProtoMessageToValue(std::move(message), - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_)); - - activation.InsertOrAssignValue("struct_val", - OptionalValue::Of(struct_val, &arena_)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsOptional()); - EXPECT_FALSE(result.GetOptional().HasValue()); -} - -TEST_F(DirectSelectStepTest, SelectFromEmptyOptional) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "one", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - activation.InsertOrAssignValue("map_val", OptionalValue::None()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsOptional()); - EXPECT_FALSE(result.GetOptional().HasValue()); -} - -TEST_F(DirectSelectStepTest, HasOptional) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "two", - /*test_only=*/true, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - auto map_builder = cel::NewMapValueBuilder(&arena_); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("one"), IntValue(1)), - IsOk()); - ASSERT_THAT( - map_builder->Put(cel::StringValue::WrapUnsafe("two"), IntValue(2)), - IsOk()); - activation.InsertOrAssignValue( - "map_val", OptionalValue::Of(std::move(*map_builder).Build(), &arena_)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsBool()); - - EXPECT_TRUE(result.GetBool().NativeValue()); -} - -TEST_F(DirectSelectStepTest, HasEmptyOptional) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("map_val", -1), "two", - /*test_only=*/true, -1, - /*enable_wrapper_type_null_unboxing=*/true, - /*enable_optional_types=*/true); - - activation.InsertOrAssignValue("map_val", OptionalValue::None()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsBool()); - - EXPECT_FALSE(result.GetBool().NativeValue()); -} - -TEST_F(DirectSelectStepTest, SelectFromStruct) { - cel::Activation activation; - RuntimeOptions options; - - auto step = CreateDirectSelectStep( - CreateDirectIdentStep("test_all_types", -1), "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsInt()); - - EXPECT_EQ(result.GetInt().NativeValue(), 1); -} - -TEST_F(DirectSelectStepTest, HasStruct) { - cel::Activation activation; - RuntimeOptions options; - - auto step = CreateDirectSelectStep( - CreateDirectIdentStep("test_all_types", -1), "single_string", - /*test_only=*/true, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - - // has(test_all_types.single_string) - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsBool()); - EXPECT_FALSE(result.GetBool().NativeValue()); -} - -TEST_F(DirectSelectStepTest, SelectFromUnsupportedType) { - cel::Activation activation; - RuntimeOptions options; - - auto step = - CreateDirectSelectStep(CreateDirectIdentStep("bool_val", -1), "one", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - activation.InsertOrAssignValue("bool_val", BoolValue(false)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("Applying SELECT to non-message type"))); -} - -TEST_F(DirectSelectStepTest, AttributeUpdatedIfRequested) { - cel::Activation activation; - RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - auto step = CreateDirectSelectStep( - CreateDirectIdentStep("test_all_types", -1), "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsInt()); - EXPECT_EQ(result.GetInt().NativeValue(), 1); - - ASSERT_OK_AND_ASSIGN(std::string attr_str, attr.attribute().AsString()); - EXPECT_EQ(attr_str, "test_all_types.single_int64"); -} - -TEST_F(DirectSelectStepTest, MissingAttributesToErrors) { - cel::Activation activation; - RuntimeOptions options; - options.enable_missing_attribute_errors = true; - - auto step = CreateDirectSelectStep( - CreateDirectIdentStep("test_all_types", -1), "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - ASSERT_THAT(activation.SetMissingPatterns({cel::AttributePattern( - "test_all_types", - {cel::AttributeQualifierPattern::OfString("single_int64")})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("test_all_types.single_int64"))); -} - -TEST_F(DirectSelectStepTest, IdentifiesUnknowns) { - cel::Activation activation; - RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - auto step = CreateDirectSelectStep( - CreateDirectIdentStep("test_all_types", -1), "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - ASSERT_THAT(activation.SetUnknownPatterns({cel::AttributePattern( - "test_all_types", - {cel::AttributeQualifierPattern::OfString("single_int64")})}), - IsOk()); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsUnknown()); - - EXPECT_THAT(AttributeStrings(result.GetUnknown()), - UnorderedElementsAre("test_all_types.single_int64")); -} - -TEST_F(DirectSelectStepTest, ForwardErrorValue) { - cel::Activation activation; - RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - auto step = CreateDirectSelectStep( - CreateConstValueDirectStep( - cel::ErrorValue::From(absl::InternalError("test1"), &arena_), -1), - "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInternal, HasSubstr("test1"))); -} - -TEST_F(DirectSelectStepTest, ForwardUnknownOperand) { - cel::Activation activation; - RuntimeOptions options; - options.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - - AttributeSet attr_set({Attribute("attr", {AttributeQualifier::OfInt(0)})}); - auto step = CreateDirectSelectStep( - CreateConstValueDirectStep(cel::common_internal::MakeUnknownValue( - cel::Unknown(std::move(attr_set))), - -1), - "single_int64", - /*test_only=*/false, -1, - /*enable_wrapper_type_null_unboxing=*/true); - - TestAllTypes message; - message.set_single_int64(1); - activation.InsertOrAssignValue("test_all_types", TestWrapMessage(&message)); - - ExecutionFrameBase frame(activation, options, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - Value result; - AttributeTrail attr; - ASSERT_THAT(step->Evaluate(frame, result, attr), IsOk()); - - ASSERT_TRUE(result.IsUnknown()); - EXPECT_THAT(AttributeStrings(result.GetUnknown()), - UnorderedElementsAre("attr[0]")); -} - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/shadowable_value_step.cc b/eval/eval/shadowable_value_step.cc index b6199ed7e..d257e7514 100644 --- a/eval/eval/shadowable_value_step.cc +++ b/eval/eval/shadowable_value_step.cc @@ -1,20 +1,16 @@ #include "eval/eval/shadowable_value_step.h" -#include #include #include #include -#include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" -#include "internal/status_macros.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { @@ -52,37 +48,6 @@ void ShadowableValueStep::Evaluate(ExecutionFrame* frame) const { } } -class DirectShadowableValueStep : public DirectExpressionStep { - public: - DirectShadowableValueStep(std::string identifier, cel::Value value, - int64_t expr_id) - : DirectExpressionStep(expr_id), - identifier_(std::move(identifier)), - value_(std::move(value)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override; - - private: - std::string identifier_; - Value value_; -}; - -// TODO(uncreated-issue/67): Attribute tracking is skipped for the shadowed case. May -// cause problems for users with unknown tracking and variables named like -// 'list' etc, but follows the current behavior of the stack machine version. -absl::Status DirectShadowableValueStep::Evaluate( - ExecutionFrameBase& frame, Value& result, AttributeTrail& attribute) const { - CEL_ASSIGN_OR_RETURN(auto found, - frame.activation().FindVariable( - identifier_, frame.descriptor_pool(), - frame.message_factory(), frame.arena(), &result)); - if (!found) { - result = value_; - } - return absl::OkStatus(); -} - } // namespace absl::StatusOr> CreateShadowableValueStep( @@ -91,10 +56,4 @@ absl::StatusOr> CreateShadowableValueStep( std::move(value)); } -std::unique_ptr CreateDirectShadowableValueStep( - absl::string_view name, cel::Value value, int64_t expr_id) { - return std::make_unique(std::string(name), - std::move(value), expr_id); -} - } // namespace google::api::expr::runtime diff --git a/eval/eval/shadowable_value_step.h b/eval/eval/shadowable_value_step.h index fae90353b..c6f0a370a 100644 --- a/eval/eval/shadowable_value_step.h +++ b/eval/eval/shadowable_value_step.h @@ -1,14 +1,12 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_SHADOWABLE_VALUE_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_SHADOWABLE_VALUE_STEP_H_ -#include #include #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "common/value.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { @@ -18,9 +16,6 @@ namespace google::api::expr::runtime { absl::StatusOr> CreateShadowableValueStep( absl::string_view name, cel::Value value); -std::unique_ptr CreateDirectShadowableValueStep( - absl::string_view name, cel::Value value, int64_t expr_id); - } // namespace google::api::expr::runtime #endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_SHADOWABLE_VALUE_STEP_H_ diff --git a/eval/eval/shadowable_value_step_test.cc b/eval/eval/shadowable_value_step_test.cc index 83ffd5857..42234b515 100644 --- a/eval/eval/shadowable_value_step_test.cc +++ b/eval/eval/shadowable_value_step_test.cc @@ -6,6 +6,7 @@ #include "absl/base/nullability.h" #include "absl/status/statusor.h" +#include "absl/strings/string_view.h" #include "base/type_provider.h" #include "common/value.h" #include "eval/eval/cel_expression_flat_impl.h" @@ -18,6 +19,7 @@ #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" #include "runtime/runtime_options.h" +#include "google/protobuf/arena.h" namespace google::api::expr::runtime { @@ -32,8 +34,8 @@ using ::testing::Eq; absl::StatusOr RunShadowableExpression( const absl_nonnull std::shared_ptr& env, - std::string identifier, cel::Value value, const Activation& activation, - Arena* arena) { + absl::string_view identifier, cel::Value value, + const Activation& activation, Arena* arena) { CEL_ASSIGN_OR_RETURN(auto step, CreateShadowableValueStep(identifier, std::move(value))); ExecutionPath path; diff --git a/eval/eval/ternary_step.cc b/eval/eval/ternary_step.cc index 0924b915f..d1ed0fd1e 100644 --- a/eval/eval/ternary_step.cc +++ b/eval/eval/ternary_step.cc @@ -1,20 +1,16 @@ #include "eval/eval/ternary_step.h" #include -#include #include #include #include "absl/status/status.h" -#include "absl/status/statusor.h" #include "base/builtins.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" +#include "eval/eval/expression_step_logic.h" #include "eval/internal/errors.h" -#include "internal/status_macros.h" namespace google::api::expr::runtime { @@ -27,102 +23,6 @@ inline constexpr size_t kTernaryStepCondition = 0; inline constexpr size_t kTernaryStepTrue = 1; inline constexpr size_t kTernaryStepFalse = 2; -class ExhaustiveDirectTernaryStep : public DirectExpressionStep { - public: - ExhaustiveDirectTernaryStep(std::unique_ptr condition, - std::unique_ptr left, - std::unique_ptr right, - int64_t expr_id) - : DirectExpressionStep(expr_id), - condition_(std::move(condition)), - left_(std::move(left)), - right_(std::move(right)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute) const override { - cel::Value condition; - cel::Value lhs; - cel::Value rhs; - - AttributeTrail condition_attr; - AttributeTrail lhs_attr; - AttributeTrail rhs_attr; - - CEL_RETURN_IF_ERROR(condition_->Evaluate(frame, condition, condition_attr)); - CEL_RETURN_IF_ERROR(left_->Evaluate(frame, lhs, lhs_attr)); - CEL_RETURN_IF_ERROR(right_->Evaluate(frame, rhs, rhs_attr)); - - if (condition.IsError() || condition.IsUnknown()) { - result = std::move(condition); - attribute = std::move(condition_attr); - return absl::OkStatus(); - } - - if (!condition.IsBool()) { - result = cel::ErrorValue::From(CreateNoMatchingOverloadError(kTernary), - frame.arena()); - return absl::OkStatus(); - } - - if (condition.GetBool().NativeValue()) { - result = std::move(lhs); - attribute = std::move(lhs_attr); - } else { - result = std::move(rhs); - attribute = std::move(rhs_attr); - } - return absl::OkStatus(); - } - - private: - std::unique_ptr condition_; - std::unique_ptr left_; - std::unique_ptr right_; -}; - -class ShortcircuitingDirectTernaryStep : public DirectExpressionStep { - public: - ShortcircuitingDirectTernaryStep( - std::unique_ptr condition, - std::unique_ptr left, - std::unique_ptr right, int64_t expr_id) - : DirectExpressionStep(expr_id), - condition_(std::move(condition)), - left_(std::move(left)), - right_(std::move(right)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& attribute) const override { - cel::Value condition; - - AttributeTrail condition_attr; - - CEL_RETURN_IF_ERROR(condition_->Evaluate(frame, condition, condition_attr)); - - if (condition.IsError() || condition.IsUnknown()) { - result = std::move(condition); - attribute = std::move(condition_attr); - return absl::OkStatus(); - } - - if (!condition.IsBool()) { - result = cel::ErrorValue::From(CreateNoMatchingOverloadError(kTernary), - frame.arena()); - return absl::OkStatus(); - } - - if (condition.GetBool().NativeValue()) { - return left_->Evaluate(frame, result, attribute); - } - return right_->Evaluate(frame, result, attribute); - } - - private: - std::unique_ptr condition_; - std::unique_ptr left_; - std::unique_ptr right_; -}; - class TernaryStep : public ExpressionStepBase { public: // Constructs FunctionStep that uses overloads specified. @@ -173,21 +73,6 @@ void TernaryStep::Evaluate(ExecutionFrame* frame) const { } // namespace -// Factory method for ternary (_?_:_) recursive execution step -std::unique_ptr CreateDirectTernaryStep( - std::unique_ptr condition, - std::unique_ptr left, - std::unique_ptr right, int64_t expr_id, - bool shortcircuiting) { - if (shortcircuiting) { - return std::make_unique( - std::move(condition), std::move(left), std::move(right), expr_id); - } - - return std::make_unique( - std::move(condition), std::move(left), std::move(right), expr_id); -} - std::unique_ptr CreateTernaryStep() { return std::make_unique(); } diff --git a/eval/eval/ternary_step.h b/eval/eval/ternary_step.h index 82491f589..75cf5d315 100644 --- a/eval/eval/ternary_step.h +++ b/eval/eval/ternary_step.h @@ -1,22 +1,12 @@ #ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_TERNARY_STEP_H_ #define THIRD_PARTY_CEL_CPP_EVAL_EVAL_TERNARY_STEP_H_ -#include #include -#include "absl/status/statusor.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" +#include "eval/eval/expression_step_logic.h" namespace google::api::expr::runtime { -// Factory method for ternary (_?_:_) recursive execution step -std::unique_ptr CreateDirectTernaryStep( - std::unique_ptr condition, - std::unique_ptr left, - std::unique_ptr right, int64_t expr_id, - bool shortcircuiting = true); - // Factory method for ternary (_?_:_) execution step std::unique_ptr CreateTernaryStep(); diff --git a/eval/eval/ternary_step_test.cc b/eval/eval/ternary_step_test.cc index 2d49700cc..5d5ac6ae4 100644 --- a/eval/eval/ternary_step_test.cc +++ b/eval/eval/ternary_step_test.cc @@ -7,27 +7,19 @@ #include "absl/base/nullability.h" #include "absl/status/status.h" -#include "base/attribute.h" #include "base/attribute_set.h" #include "base/type_provider.h" #include "common/expr.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" #include "eval/eval/cel_expression_flat_impl.h" -#include "eval/eval/const_value_step.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/public/activation.h" +#include "eval/public/cel_attribute.h" #include "eval/public/cel_value.h" #include "eval/public/unknown_attribute_set.h" #include "eval/public/unknown_set.h" #include "internal/testing.h" -#include "internal/testing_descriptor_pool.h" -#include "internal/testing_message_factory.h" -#include "runtime/activation.h" #include "runtime/internal/runtime_env.h" #include "runtime/internal/runtime_env_testing.h" -#include "runtime/internal/runtime_type_provider.h" #include "runtime/runtime_options.h" #include "google/protobuf/arena.h" @@ -36,21 +28,13 @@ namespace google::api::expr::runtime { namespace { using ::absl_testing::IsOk; -using ::absl_testing::StatusIs; -using ::cel::BoolValue; -using ::cel::ErrorValue; using ::cel::Expr; -using ::cel::IntValue; using ::cel::RuntimeOptions; using ::cel::TypeProvider; -using ::cel::UnknownValue; using ::cel::runtime_internal::NewTestingRuntimeEnv; using ::cel::runtime_internal::RuntimeEnv; using ::google::protobuf::Arena; -using ::testing::ElementsAre; using ::testing::Eq; -using ::testing::HasSubstr; -using ::testing::Truly; class LogicStepTest : public testing::TestWithParam { public: @@ -193,182 +177,6 @@ TEST_F(LogicStepTest, TestUnknownHandling) { INSTANTIATE_TEST_SUITE_P(LogicStepTest, LogicStepTest, testing::Bool()); -class TernaryStepDirectTest : public testing::TestWithParam { - public: - TernaryStepDirectTest() - : type_provider_(cel::internal::GetTestingDescriptorPool()) {} - - bool Shortcircuiting() { return GetParam(); } - - protected: - Arena arena_; - cel::runtime_internal::RuntimeTypeProvider type_provider_; -}; - -TEST_P(TernaryStepDirectTest, ReturnLhs) { - cel::Activation activation; - RuntimeOptions opts; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(BoolValue(true), -1), - CreateConstValueDirectStep(IntValue(1), -1), - CreateConstValueDirectStep(IntValue(2), -1), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - - ASSERT_TRUE(result.IsInt()); - EXPECT_EQ(result.GetInt().NativeValue(), 1); -} - -TEST_P(TernaryStepDirectTest, ReturnRhs) { - cel::Activation activation; - RuntimeOptions opts; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(BoolValue(false), -1), - CreateConstValueDirectStep(IntValue(1), -1), - CreateConstValueDirectStep(IntValue(2), -1), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - - ASSERT_TRUE(result.IsInt()); - EXPECT_EQ(result.GetInt().NativeValue(), 2); -} - -TEST_P(TernaryStepDirectTest, ForwardError) { - cel::Activation activation; - RuntimeOptions opts; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - cel::Value error_value = - cel::ErrorValue::From(absl::InternalError("test error"), &arena_); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(error_value, -1), - CreateConstValueDirectStep(IntValue(1), -1), - CreateConstValueDirectStep(IntValue(2), -1), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kInternal, "test error")); -} - -TEST_P(TernaryStepDirectTest, ForwardUnknown) { - cel::Activation activation; - RuntimeOptions opts; - opts.unknown_processing = cel::UnknownProcessingOptions::kAttributeOnly; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::vector attrs{{cel::Attribute("var")}}; - - cel::UnknownValue unknown_value = cel::common_internal::MakeUnknownValue( - cel::Unknown(cel::AttributeSet(attrs))); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(unknown_value, -1), - CreateConstValueDirectStep(IntValue(2), -1), - CreateConstValueDirectStep(IntValue(3), -1), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - ASSERT_TRUE(result.IsUnknown()); - EXPECT_THAT(result.GetUnknown().ToAttributeSet(), - ElementsAre(Truly([](const cel::Attribute& attr) { - return attr.variable_name() == "var"; - }))); -} - -TEST_P(TernaryStepDirectTest, UnexpectedCondtionKind) { - cel::Activation activation; - RuntimeOptions opts; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(IntValue(-1), -1), - CreateConstValueDirectStep(IntValue(1), -1), - CreateConstValueDirectStep(IntValue(2), -1), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - - ASSERT_TRUE(result.IsError()); - EXPECT_THAT(result.GetError().NativeValue(), - StatusIs(absl::StatusCode::kUnknown, - HasSubstr("No matching overloads found"))); -} - -TEST_P(TernaryStepDirectTest, Shortcircuiting) { - class RecordCallStep : public DirectExpressionStep { - public: - explicit RecordCallStep(bool& was_called) - : DirectExpressionStep(-1), was_called_(&was_called) {} - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& trail) const override { - *was_called_ = true; - result = IntValue(1); - return absl::OkStatus(); - } - - private: - bool* absl_nonnull was_called_; - }; - - bool lhs_was_called = false; - bool rhs_was_called = false; - - cel::Activation activation; - RuntimeOptions opts; - ExecutionFrameBase frame(activation, opts, type_provider_, - cel::internal::GetTestingDescriptorPool(), - cel::internal::GetTestingMessageFactory(), &arena_); - - std::unique_ptr step = CreateDirectTernaryStep( - CreateConstValueDirectStep(BoolValue(false), -1), - std::make_unique(lhs_was_called), - std::make_unique(rhs_was_called), -1, Shortcircuiting()); - - cel::Value result; - AttributeTrail attr_unused; - - ASSERT_THAT(step->Evaluate(frame, result, attr_unused), IsOk()); - - ASSERT_TRUE(result.IsInt()); - EXPECT_THAT(result.GetInt().NativeValue(), Eq(1)); - bool expect_eager_eval = !Shortcircuiting(); - EXPECT_EQ(lhs_was_called, expect_eager_eval); - EXPECT_TRUE(rhs_was_called); -} - -INSTANTIATE_TEST_SUITE_P(TernaryStepDirectTest, TernaryStepDirectTest, - testing::Bool()); - } // namespace } // namespace google::api::expr::runtime diff --git a/eval/eval/trace_step.h b/eval/eval/trace_step.h deleted file mode 100644 index cf4240248..000000000 --- a/eval/eval/trace_step.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2024 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef THIRD_PARTY_CEL_CPP_EVAL_EVAL_TRACE_STEP_H_ -#define THIRD_PARTY_CEL_CPP_EVAL_EVAL_TRACE_STEP_H_ - -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/types/optional.h" -#include "common/native_type.h" -#include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" -#include "eval/eval/evaluator_core.h" -#include "internal/status_macros.h" -namespace google::api::expr::runtime { - -// A decorator that implements tracing for recursively evaluated CEL -// expressions. -// -// Allows inspection for extensions to extract the wrapped expression. -class TraceStep : public DirectExpressionStep { - public: - explicit TraceStep(std::unique_ptr expression) - : DirectExpressionStep(-1), expression_(std::move(expression)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, cel::Value& result, - AttributeTrail& trail) const override { - CEL_RETURN_IF_ERROR(expression_->Evaluate(frame, result, trail)); - if (!frame.callback()) { - return absl::OkStatus(); - } - return frame.callback()(expression_->expr_id(), result, - frame.descriptor_pool(), frame.message_factory(), - frame.arena()); - } - - cel::NativeTypeId GetNativeTypeId() const override { - return cel::NativeTypeId::For(); - } - - absl::optional> GetDependencies() - const override { - return {{expression_.get()}}; - } - - absl::optional>> - ExtractDependencies() override { - std::vector> dependencies; - dependencies.push_back(std::move(expression_)); - return dependencies; - }; - - private: - std::unique_ptr expression_; -}; - -} // namespace google::api::expr::runtime - -#endif // THIRD_PARTY_CEL_CPP_EVAL_EVAL_TRACE_STEP_H_ diff --git a/eval/public/BUILD b/eval/public/BUILD index 39ab6368d..7bb6aac0d 100644 --- a/eval/public/BUILD +++ b/eval/public/BUILD @@ -58,7 +58,6 @@ cc_test( ":message_wrapper", "//eval/public/structs:trivial_legacy_type_info", "//eval/testutil:test_message_cc_proto", - "//internal:casts", "//internal:testing", "@com_google_protobuf//:protobuf", ], @@ -71,9 +70,7 @@ cc_library( ], deps = [ ":message_wrapper", - "//internal:casts", "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/numeric:bits", "@com_google_absl//absl/types:variant", "@com_google_protobuf//:protobuf", ], diff --git a/eval/public/cel_options.h b/eval/public/cel_options.h index d9ebaab13..e7981a226 100644 --- a/eval/public/cel_options.h +++ b/eval/public/cel_options.h @@ -188,18 +188,14 @@ struct InterpreterOptions { // -1 means unbounded. // 0 means disabled (using a heap-based stack machine instead), which is the // default. - ABSL_DEPRECATED( - "The ability to enable recursive planning is being removed in the " - "near future") + ABSL_DEPRECATED("Recursive evaluation has been removed") int max_recursion_depth = 0; // Enable tracing support for recursively planned programs. // // Unlike the stack machine implementation, supporting tracing can affect // performance whether or not tracing is requested for a given evaluation. - ABSL_DEPRECATED( - "The ability to enable recursive planning is being removed in the " - "near future") + ABSL_DEPRECATED("Recursive evaluation has been removed") bool enable_recursive_tracing = false; // Enable fast implementations for some CEL standard functions. diff --git a/extensions/BUILD b/extensions/BUILD index 908cacb18..46fc088ae 100644 --- a/extensions/BUILD +++ b/extensions/BUILD @@ -171,7 +171,6 @@ cc_test( "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/status", "@com_google_absl//absl/status:status_matchers", - "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:string_view", "@com_google_absl//absl/types:optional", "@com_google_absl//absl/types:span", @@ -337,7 +336,6 @@ cc_library( "//eval/compiler:flat_expr_builder", "//eval/compiler:flat_expr_builder_extensions", "//eval/eval:attribute_trail", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", "//eval/eval:expression_step_base", "//eval/public:cel_value", diff --git a/extensions/select_optimization.cc b/extensions/select_optimization.cc index 07e0ae4c0..29cb5d6ff 100644 --- a/extensions/select_optimization.cc +++ b/extensions/select_optimization.cc @@ -51,7 +51,6 @@ #include "eval/compiler/flat_expr_builder.h" #include "eval/compiler/flat_expr_builder_extensions.h" #include "eval/eval/attribute_trail.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" #include "eval/eval/expression_step_base.h" #include "eval/public/cel_value.h" @@ -80,7 +79,6 @@ using ::cel::ExprKind; using ::cel::SelectExpr; using ::google::api::expr::runtime::AttributeTrail; using ::google::api::expr::runtime::CelValue; -using ::google::api::expr::runtime::DirectExpressionStep; using ::google::api::expr::runtime::ExecutionFrame; using ::google::api::expr::runtime::ExecutionFrameBase; using ::google::api::expr::runtime::ExpressionStep; @@ -823,58 +821,6 @@ void StackMachineImpl::Evaluate(ExecutionFrame* frame) const { frame->value_stack().Push(*std::move(result), std::move(attribute_trail)); } -class RecursiveImpl : public DirectExpressionStep { - public: - RecursiveImpl(int64_t expr_id, std::unique_ptr operand, - OptimizedSelectImpl impl) - : DirectExpressionStep(expr_id), - operand_(std::move(operand)), - impl_(std::move(impl)) {} - - absl::Status Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const override; - - private: - // Get the effective attribute for the optimized select expression. - // Assumes the operand is the top of stack if the attribute wasn't known at - // plan time. - AttributeTrail GetAttributeTrail(const AttributeTrail& operand_trail) const; - std::unique_ptr operand_; - OptimizedSelectImpl impl_; -}; - -AttributeTrail RecursiveImpl::GetAttributeTrail( - const AttributeTrail& operand_trail) const { - return impl_.GetAttributeTrail(operand_trail); -} - -absl::Status RecursiveImpl::Evaluate(ExecutionFrameBase& frame, Value& result, - AttributeTrail& attribute) const { - CEL_RETURN_IF_ERROR(operand_->Evaluate(frame, result, attribute)); - - if (result.IsError() || result.IsUnknown()) { - // Just forward. - return absl::OkStatus(); - } - - if (frame.attribute_tracking_enabled()) { - attribute = impl_.GetAttributeTrail(attribute); - CEL_ASSIGN_OR_RETURN(auto value, - CheckForMarkedAttributes(frame, attribute)); - if (value.has_value()) { - result = std::move(value).value(); - return absl::OkStatus(); - } - } - - if (!result.IsStruct()) { - return absl::InvalidArgumentError( - "Expected struct type for select optimization"); - } - CEL_ASSIGN_OR_RETURN(result, impl_.ApplySelect(frame, result.GetStruct())); - return absl::OkStatus(); -} - class SelectOptimizer : public ProgramOptimizer { public: explicit SelectOptimizer(const SelectOptimizationOptions& options) @@ -956,19 +902,6 @@ absl::Status SelectOptimizer::OnPostVisit(PlannerContext& context, OptimizedSelectImpl impl(std::move(instructions), std::move(qualifiers), presence_test, options_); - if (subexpression->IsRecursive()) { - auto program = subexpression->ExtractRecursiveProgram(); - auto deps = program.step->ExtractDependencies(); - if (!deps.has_value() || deps->empty()) { - return absl::InvalidArgumentError("Unexpected cel.@attribute call"); - } - subexpression->set_recursive_program( - std::make_unique(node.id(), std::move(deps->at(0)), - std::move(impl)), - program.depth); - return absl::OkStatus(); - } - google::api::expr::runtime::ExecutionPath path; // else, we need to preserve the original plan for the first argument. diff --git a/runtime/BUILD b/runtime/BUILD index 08e137669..d8ba3eb7d 100644 --- a/runtime/BUILD +++ b/runtime/BUILD @@ -316,7 +316,6 @@ cc_test( "//parser", "//parser:macro_registry", "//parser:standard_macros", - "//runtime/internal:runtime_impl", "@com_google_absl//absl/base:no_destructor", "@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/status", @@ -618,7 +617,6 @@ cc_test( "//internal:testing_descriptor_pool", "//parser", "//parser:options", - "//runtime/internal:runtime_impl", "@com_google_absl//absl/status", "@com_google_absl//absl/status:status_matchers", "@com_google_absl//absl/status:statusor", diff --git a/runtime/internal/BUILD b/runtime/internal/BUILD index 28703ef3b..cbe1fd2fe 100644 --- a/runtime/internal/BUILD +++ b/runtime/internal/BUILD @@ -62,11 +62,7 @@ cc_library( "//common:native_type", "//common:value", "//eval/compiler:flat_expr_builder", - "//eval/eval:attribute_trail", - "//eval/eval:comprehension_slots", - "//eval/eval:direct_expression_step", "//eval/eval:evaluator_core", - "//internal:casts", "//internal:status_macros", "//internal:well_known_types", "//runtime", @@ -220,7 +216,6 @@ cc_library( "//common:descriptor_pool_type_introspector", "//common:type", "//common:value", - "//internal:status_macros", "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/status", diff --git a/runtime/internal/runtime_impl.cc b/runtime/internal/runtime_impl.cc index 3e8eef59a..8d8cda12b 100644 --- a/runtime/internal/runtime_impl.cc +++ b/runtime/internal/runtime_impl.cc @@ -21,13 +21,8 @@ #include "absl/status/statusor.h" #include "base/ast.h" #include "base/type_provider.h" -#include "common/native_type.h" #include "common/value.h" -#include "eval/eval/attribute_trail.h" -#include "eval/eval/comprehension_slots.h" -#include "eval/eval/direct_expression_step.h" #include "eval/eval/evaluator_core.h" -#include "internal/casts.h" #include "internal/status_macros.h" #include "runtime/activation_interface.h" #include "runtime/runtime.h" @@ -36,12 +31,7 @@ namespace cel::runtime_internal { namespace { -using ::google::api::expr::runtime::AttributeTrail; -using ::google::api::expr::runtime::ComprehensionSlots; -using ::google::api::expr::runtime::DirectExpressionStep; -using ::google::api::expr::runtime::ExecutionFrameBase; using ::google::api::expr::runtime::FlatExpression; -using ::google::api::expr::runtime::WrappedDirectStep; class ProgramImpl final : public TraceableProgram { public: @@ -76,46 +66,6 @@ class ProgramImpl final : public TraceableProgram { FlatExpression impl_; }; -class RecursiveProgramImpl final : public TraceableProgram { - public: - using EvaluationListener = TraceableProgram::EvaluationListener; - RecursiveProgramImpl( - const std::shared_ptr& environment, - FlatExpression impl, const DirectExpressionStep* absl_nonnull root) - : environment_(environment), impl_(std::move(impl)), root_(root) {} - - absl::StatusOr TraceImpl( - const ActivationInterface& activation, - EvaluationListener evaluation_listener, google::protobuf::Arena* absl_nonnull arena, - const EvaluateOptions& options) const override { - ABSL_DCHECK(arena != nullptr); - ComprehensionSlots slots(impl_.comprehension_slots_size()); - ExecutionFrameBase frame(activation, std::move(evaluation_listener), - impl_.options(), GetTypeProvider(), - environment_->descriptor_pool.get(), - options.message_factory != nullptr - ? options.message_factory - : environment_->MutableMessageFactory(), - arena, options.embedder_context, slots); - - Value result; - AttributeTrail attribute; - CEL_RETURN_IF_ERROR(root_->Evaluate(frame, result, attribute)); - - return result; - } - - const TypeProvider& GetTypeProvider() const override { - return environment_->type_registry.GetComposedTypeProvider(); - } - - private: - // Keep the Runtime environment alive while programs reference it. - std::shared_ptr environment_; - FlatExpression impl_; - const DirectExpressionStep* absl_nonnull root_; -}; - } // namespace absl::StatusOr> RuntimeImpl::CreateProgram( @@ -131,33 +81,7 @@ RuntimeImpl::CreateTraceableProgram( CEL_ASSIGN_OR_RETURN(auto flat_expr, expr_builder_.CreateExpressionImpl( std::move(ast), options.issues)); - // Special case if the program is fully recursive. - // - // This implementation avoids unnecessary allocs at evaluation time which - // improves performance notably for small expressions. - if (expr_builder_.options().max_recursion_depth != 0 && - !flat_expr.subexpressions().empty() && - // mainline expression is exactly one recursive step. - flat_expr.subexpressions().front().size() == 1 && - flat_expr.subexpressions().front().front().IsGenericStep() && - flat_expr.subexpressions() - .front() - .front() - .GetGenericStep() - ->GetNativeTypeId() == NativeTypeId::For()) { - const DirectExpressionStep* root = - internal::down_cast( - flat_expr.subexpressions().front().front().GetGenericStep()) - ->wrapped(); - return std::make_unique(environment_, - std::move(flat_expr), root); - } - return std::make_unique(environment_, std::move(flat_expr)); } -bool TestOnly_IsRecursiveImpl(const Program* program) { - return dynamic_cast(program) != nullptr; -} - } // namespace cel::runtime_internal diff --git a/runtime/internal/runtime_impl.h b/runtime/internal/runtime_impl.h index 7c5d445f9..ed5e5ad47 100644 --- a/runtime/internal/runtime_impl.h +++ b/runtime/internal/runtime_impl.h @@ -115,11 +115,6 @@ class RuntimeImpl : public Runtime { google::api::expr::runtime::FlatExprBuilder expr_builder_; }; -// Exposed for testing to validate program is recursively planned. -// -// Uses dynamic_casts to test. -bool TestOnly_IsRecursiveImpl(const Program* program); - } // namespace cel::runtime_internal #endif // THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_RUNTIME_IMPL_H_ diff --git a/runtime/optional_types_test.cc b/runtime/optional_types_test.cc index 695f8900f..578b6d5bc 100644 --- a/runtime/optional_types_test.cc +++ b/runtime/optional_types_test.cc @@ -37,7 +37,6 @@ #include "parser/parser.h" #include "runtime/activation.h" #include "runtime/function.h" -#include "runtime/internal/runtime_impl.h" #include "runtime/reference_resolver.h" #include "runtime/runtime.h" #include "runtime/runtime_builder.h" @@ -185,41 +184,6 @@ class OptionalTypesTest bool EnableShortCircuiting() { return std::get<1>(GetParam()); } }; -TEST_P(OptionalTypesTest, RecursivePlan) { - RuntimeOptions opts; - opts.enable_qualified_type_identifiers = true; - opts.max_recursion_depth = -1; - opts.short_circuiting = EnableShortCircuiting(); - - const EvaluateResultTestCase& test_case = GetTestCase(); - - ASSERT_OK_AND_ASSIGN( - auto builder, - CreateStandardRuntimeBuilder(internal::GetTestingDescriptorPool(), opts)); - - ASSERT_OK(EnableOptionalTypes(builder)); - ASSERT_OK( - EnableReferenceResolver(builder, ReferenceResolverEnabled::kAlways)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, - Parse(test_case.expression, "", - ParserOptions{.enable_optional_syntax = true})); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr program, - ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - - EXPECT_TRUE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - - google::protobuf::Arena arena; - Activation activation; - - ASSERT_OK_AND_ASSIGN(Value result, program->Evaluate(&arena, activation)); - - EXPECT_THAT(result, test_case.value_matcher) << test_case.expression; -} - TEST_P(OptionalTypesTest, Defaults) { RuntimeOptions opts; opts.enable_qualified_type_identifiers = true; diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h index 74ad8ecb7..af2f9d945 100644 --- a/runtime/runtime_options.h +++ b/runtime/runtime_options.h @@ -156,18 +156,14 @@ struct RuntimeOptions { // -1 means unbounded. // 0 means disabled (using a heap-based stack machine instead), which is the // default. - ABSL_DEPRECATED( - "The ability to enable recursive planning is being removed in the " - "near future") + ABSL_DEPRECATED("Recursive evaluation has been removed") int max_recursion_depth = 0; // Enable tracing support for recursively planned programs. // // Unlike the stack machine implementation, supporting tracing can affect // performance whether or not tracing is requested for a given evaluation. - ABSL_DEPRECATED( - "The ability to enable recursive planning is being removed in the " - "near future") + ABSL_DEPRECATED("Recursive evaluation has been removed") bool enable_recursive_tracing = false; // Enable fast implementations for some CEL standard functions. diff --git a/runtime/standard_runtime_builder_factory_test.cc b/runtime/standard_runtime_builder_factory_test.cc index 029897233..07bc7f1f9 100644 --- a/runtime/standard_runtime_builder_factory_test.cc +++ b/runtime/standard_runtime_builder_factory_test.cc @@ -38,7 +38,6 @@ #include "parser/parser.h" #include "parser/standard_macros.h" #include "runtime/activation.h" -#include "runtime/internal/runtime_impl.h" #include "runtime/runtime.h" #include "runtime/runtime_issue.h" #include "runtime/runtime_options.h" @@ -52,11 +51,9 @@ using ::absl_testing::IsOk; using ::absl_testing::StatusIs; using ::cel::extensions::ProtobufRuntimeAdapter; using ::cel::test::BoolValueIs; -using ::cel::test::IntValueIs; using ::cel::expr::ParsedExpr; using ::google::api::expr::parser::Parse; using ::testing::ElementsAre; -using ::testing::HasSubstr; using ::testing::TestWithParam; using ::testing::Truly; @@ -78,72 +75,6 @@ absl::StatusOr ParseWithTestMacros(absl::string_view expression) { return Parse(**src, GetMacros()); } -TEST(StandardRuntimeTest, RecursionLimitExceeded) { - RuntimeOptions opts; - opts.max_recursion_depth = 1; - - ASSERT_OK_AND_ASSIGN(auto builder, - CreateStandardRuntimeBuilder( - google::protobuf::DescriptorPool::generated_pool(), opts)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, ParseWithTestMacros("1 + 2")); - - EXPECT_THAT(ProtobufRuntimeAdapter::CreateProgram(*runtime, expr), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("Maximum recursion depth of 1 exceeded"))); -} - -TEST(StandardRuntimeTest, RecursionUnderLimit) { - RuntimeOptions opts; - opts.max_recursion_depth = 2; - - ASSERT_OK_AND_ASSIGN(auto builder, - CreateStandardRuntimeBuilder( - google::protobuf::DescriptorPool::generated_pool(), opts)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, ParseWithTestMacros("1 + 2")); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr program, - ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - - // Whether the implementation is recursive shouldn't affect observable - // behavior, but it does have performance implications (it will skip - // allocating a value stack). - EXPECT_TRUE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - - google::protobuf::Arena arena; - Activation activation; - - ASSERT_OK_AND_ASSIGN(Value result, program->Evaluate(&arena, activation)); - EXPECT_THAT(result, IntValueIs(3)); -} - -TEST(StandardRuntimeTest, RecursionLimitTracksLazyExpressions) { - RuntimeOptions opts; - opts.max_recursion_depth = 8; - - ASSERT_OK_AND_ASSIGN(auto builder, - CreateStandardRuntimeBuilder( - google::protobuf::DescriptorPool::generated_pool(), opts)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, ParseWithTestMacros(R"cel( - cel.bind(a, 4 + (3 + (2 + 1)), - cel.bind(b, 7 + (6 + (5 + a)), - 9 + (8 + b) - ) - ))cel")); - - EXPECT_THAT(ProtobufRuntimeAdapter::CreateProgram(*runtime, expr), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("Maximum recursion depth of 8 exceeded"))); -} - struct EvaluateResultTestCase { std::string name; std::string expression; @@ -177,8 +108,6 @@ TEST_P(StandardRuntimeTest, Defaults) { ASSERT_OK_AND_ASSIGN(std::unique_ptr program, ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - EXPECT_FALSE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - google::protobuf::Arena arena; Activation activation; if (test_case.activation_builder != nullptr) { @@ -191,39 +120,6 @@ TEST_P(StandardRuntimeTest, Defaults) { << test_case.expression; } -TEST_P(StandardRuntimeTest, Recursive) { - RuntimeOptions opts; - opts.max_recursion_depth = -1; - const EvaluateResultTestCase& test_case = GetTestCase(); - - ASSERT_OK_AND_ASSIGN(auto builder, - CreateStandardRuntimeBuilder( - google::protobuf::DescriptorPool::generated_pool(), opts)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, - ParseWithTestMacros(test_case.expression)); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr program, - ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - - // Whether the implementation is recursive shouldn't affect observable - // behavior, but it does have performance implications (it will skip - // allocating a value stack). - EXPECT_TRUE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - - google::protobuf::Arena arena; - Activation activation; - if (test_case.activation_builder != nullptr) { - ASSERT_THAT(test_case.activation_builder(activation), IsOk()); - } - - ASSERT_OK_AND_ASSIGN(Value result, program->Evaluate(&arena, activation)); - EXPECT_THAT(result, BoolValueIs(test_case.expected_result)) - << test_case.expression; -} - TEST_P(StandardRuntimeTest, FastBuiltins) { RuntimeOptions opts; opts.enable_fast_builtins = true; @@ -241,8 +137,6 @@ TEST_P(StandardRuntimeTest, FastBuiltins) { ASSERT_OK_AND_ASSIGN(std::unique_ptr program, ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - EXPECT_FALSE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - google::protobuf::Arena arena; Activation activation; if (test_case.activation_builder != nullptr) { @@ -255,40 +149,6 @@ TEST_P(StandardRuntimeTest, FastBuiltins) { << test_case.expression; } -TEST_P(StandardRuntimeTest, RecursiveFastBuiltins) { - RuntimeOptions opts; - opts.enable_fast_builtins = true; - opts.max_recursion_depth = -1; - const EvaluateResultTestCase& test_case = GetTestCase(); - - ASSERT_OK_AND_ASSIGN(auto builder, - CreateStandardRuntimeBuilder( - google::protobuf::DescriptorPool::generated_pool(), opts)); - - ASSERT_OK_AND_ASSIGN(auto runtime, std::move(builder).Build()); - - ASSERT_OK_AND_ASSIGN(ParsedExpr expr, - ParseWithTestMacros(test_case.expression)); - - ASSERT_OK_AND_ASSIGN(std::unique_ptr program, - ProtobufRuntimeAdapter::CreateProgram(*runtime, expr)); - - // Whether the implementation is recursive shouldn't affect observable - // behavior, but it does have performance implications (it will skip - // allocating a value stack). - EXPECT_TRUE(runtime_internal::TestOnly_IsRecursiveImpl(program.get())); - - google::protobuf::Arena arena; - Activation activation; - if (test_case.activation_builder != nullptr) { - ASSERT_THAT(test_case.activation_builder(activation), IsOk()); - } - - ASSERT_OK_AND_ASSIGN(Value result, program->Evaluate(&arena, activation)); - EXPECT_THAT(result, BoolValueIs(test_case.expected_result)) - << test_case.expression; -} - INSTANTIATE_TEST_SUITE_P( Basic, StandardRuntimeTest, testing::ValuesIn(std::vector{ @@ -668,20 +528,11 @@ TEST(StandardRuntimeTest, RuntimeIssueSupport) { } } -enum class EvalStrategy { kIterative, kRecursive }; - -class StandardRuntimeEvalStrategyTest - : public ::testing::TestWithParam {}; +class StandardRuntimeEvalTest : public ::testing::Test {}; // Check that calls to specialized builtins are validated. -TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinBoolOp) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, InvalidBuiltinBoolOp) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } ASSERT_OK_AND_ASSIGN(auto builder, @@ -699,14 +550,8 @@ TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinBoolOp) { StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinTernaryOp) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, InvalidBuiltinTernaryOp) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } ASSERT_OK_AND_ASSIGN(auto builder, @@ -743,14 +588,8 @@ TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinTernaryOp) { StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinIndex) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, InvalidBuiltinIndex) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } ASSERT_OK_AND_ASSIGN(auto builder, @@ -771,15 +610,8 @@ TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinIndex) { StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinEq) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, InvalidBuiltinEq) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } - ASSERT_OK_AND_ASSIGN(auto builder, CreateStandardRuntimeBuilder( @@ -799,14 +631,8 @@ TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinEq) { StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinIn) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, InvalidBuiltinIn) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } ASSERT_OK_AND_ASSIGN(auto builder, @@ -827,14 +653,8 @@ TEST_P(StandardRuntimeEvalStrategyTest, InvalidBuiltinIn) { StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_P(StandardRuntimeEvalStrategyTest, PrecisionPreservingDoubleFormat) { - EvalStrategy eval_strategy = GetParam(); +TEST_F(StandardRuntimeEvalTest, PrecisionPreservingDoubleFormat) { RuntimeOptions options; - if (eval_strategy == EvalStrategy::kRecursive) { - options.max_recursion_depth = -1; - } else { - options.max_recursion_depth = 0; - } options.enable_precision_preserving_double_format = true; @@ -861,12 +681,5 @@ TEST_P(StandardRuntimeEvalStrategyTest, PrecisionPreservingDoubleFormat) { } } -INSTANTIATE_TEST_SUITE_P( - StandardRuntimeEvalStrategyTest, StandardRuntimeEvalStrategyTest, - testing::Values(EvalStrategy::kIterative, EvalStrategy::kRecursive), - [](const auto& info) -> std::string { - return info.param == EvalStrategy::kIterative ? "Iterative" : "Recursive"; - }); - } // namespace } // namespace cel