Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/runtime/internal/runtime_impl.cc
Line
Count
Source
1
// Copyright 2023 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
#include "runtime/internal/runtime_impl.h"
15
16
#include <memory>
17
#include <utility>
18
19
#include "absl/base/nullability.h"
20
#include "absl/log/absl_check.h"
21
#include "absl/status/statusor.h"
22
#include "base/ast.h"
23
#include "base/type_provider.h"
24
#include "common/native_type.h"
25
#include "common/value.h"
26
#include "eval/eval/attribute_trail.h"
27
#include "eval/eval/comprehension_slots.h"
28
#include "eval/eval/direct_expression_step.h"
29
#include "eval/eval/evaluator_core.h"
30
#include "internal/casts.h"
31
#include "internal/status_macros.h"
32
#include "runtime/activation_interface.h"
33
#include "runtime/runtime.h"
34
#include "google/protobuf/arena.h"
35
36
namespace cel::runtime_internal {
37
namespace {
38
39
using ::google::api::expr::runtime::AttributeTrail;
40
using ::google::api::expr::runtime::ComprehensionSlots;
41
using ::google::api::expr::runtime::DirectExpressionStep;
42
using ::google::api::expr::runtime::ExecutionFrameBase;
43
using ::google::api::expr::runtime::FlatExpression;
44
using ::google::api::expr::runtime::WrappedDirectStep;
45
46
class ProgramImpl final : public TraceableProgram {
47
 public:
48
  using EvaluationListener = TraceableProgram::EvaluationListener;
49
  ProgramImpl(
50
      const std::shared_ptr<const RuntimeImpl::Environment>& environment,
51
      FlatExpression impl)
52
0
      : environment_(environment), impl_(std::move(impl)) {}
53
54
  absl::StatusOr<Value> TraceImpl(
55
      const ActivationInterface& activation,
56
      EvaluationListener evaluation_listener, google::protobuf::Arena* absl_nonnull arena,
57
0
      const EvaluateOptions& options) const override {
58
0
    ABSL_DCHECK(arena != nullptr);
59
0
    auto state =
60
0
        impl_.MakeEvaluatorState(environment_->descriptor_pool.get(),
61
0
                                 options.message_factory != nullptr
62
0
                                     ? options.message_factory
63
0
                                     : environment_->MutableMessageFactory(),
64
0
                                 arena);
65
0
    return impl_.EvaluateWithCallback(activation, options.embedder_context,
66
0
                                      std::move(evaluation_listener), state);
67
0
  }
68
69
0
  const TypeProvider& GetTypeProvider() const override {
70
0
    return environment_->type_registry.GetComposedTypeProvider();
71
0
  }
72
73
 private:
74
  // Keep the Runtime environment alive while programs reference it.
75
  std::shared_ptr<const RuntimeImpl::Environment> environment_;
76
  FlatExpression impl_;
77
};
78
79
class RecursiveProgramImpl final : public TraceableProgram {
80
 public:
81
  using EvaluationListener = TraceableProgram::EvaluationListener;
82
  RecursiveProgramImpl(
83
      const std::shared_ptr<const RuntimeImpl::Environment>& environment,
84
      FlatExpression impl, const DirectExpressionStep* absl_nonnull root)
85
0
      : environment_(environment), impl_(std::move(impl)), root_(root) {}
86
87
  absl::StatusOr<Value> TraceImpl(
88
      const ActivationInterface& activation,
89
      EvaluationListener evaluation_listener, google::protobuf::Arena* absl_nonnull arena,
90
0
      const EvaluateOptions& options) const override {
91
0
    ABSL_DCHECK(arena != nullptr);
92
0
    ComprehensionSlots slots(impl_.comprehension_slots_size());
93
0
    ExecutionFrameBase frame(activation, std::move(evaluation_listener),
94
0
                             impl_.options(), GetTypeProvider(),
95
0
                             environment_->descriptor_pool.get(),
96
0
                             options.message_factory != nullptr
97
0
                                 ? options.message_factory
98
0
                                 : environment_->MutableMessageFactory(),
99
0
                             arena, options.embedder_context, slots);
100
101
0
    Value result;
102
0
    AttributeTrail attribute;
103
0
    CEL_RETURN_IF_ERROR(root_->Evaluate(frame, result, attribute));
104
105
0
    return result;
106
0
  }
107
108
0
  const TypeProvider& GetTypeProvider() const override {
109
0
    return environment_->type_registry.GetComposedTypeProvider();
110
0
  }
111
112
 private:
113
  // Keep the Runtime environment alive while programs reference it.
114
  std::shared_ptr<const RuntimeImpl::Environment> environment_;
115
  FlatExpression impl_;
116
  const DirectExpressionStep* absl_nonnull root_;
117
};
118
119
}  // namespace
120
121
absl::StatusOr<std::unique_ptr<Program>> RuntimeImpl::CreateProgram(
122
    std::unique_ptr<Ast> ast,
123
0
    const Runtime::CreateProgramOptions& options) const {
124
0
  return CreateTraceableProgram(std::move(ast), options);
125
0
}
126
127
absl::StatusOr<std::unique_ptr<TraceableProgram>>
128
RuntimeImpl::CreateTraceableProgram(
129
    std::unique_ptr<Ast> ast,
130
0
    const Runtime::CreateProgramOptions& options) const {
131
0
  CEL_ASSIGN_OR_RETURN(auto flat_expr, expr_builder_.CreateExpressionImpl(
132
0
                                           std::move(ast), options.issues));
133
134
  // Special case if the program is fully recursive.
135
  //
136
  // This implementation avoids unnecessary allocs at evaluation time which
137
  // improves performance notably for small expressions.
138
0
  if (expr_builder_.options().max_recursion_depth != 0 &&
139
0
      !flat_expr.subexpressions().empty() &&
140
      // mainline expression is exactly one recursive step.
141
0
      flat_expr.subexpressions().front().size() == 1 &&
142
0
      flat_expr.subexpressions().front().front()->GetNativeTypeId() ==
143
0
          NativeTypeId::For<WrappedDirectStep>()) {
144
0
    const DirectExpressionStep* root =
145
0
        internal::down_cast<const WrappedDirectStep*>(
146
0
            flat_expr.subexpressions().front().front().get())
147
0
            ->wrapped();
148
0
    return std::make_unique<RecursiveProgramImpl>(environment_,
149
0
                                                  std::move(flat_expr), root);
150
0
  }
151
152
0
  return std::make_unique<ProgramImpl>(environment_, std::move(flat_expr));
153
0
}
154
155
0
bool TestOnly_IsRecursiveImpl(const Program* program) {
156
0
  return dynamic_cast<const RecursiveProgramImpl*>(program) != nullptr;
157
0
}
158
159
}  // namespace cel::runtime_internal