Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/ast/expr_proto.cc
Line
Count
Source
1
// Copyright 2024 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
15
#include "common/ast/expr_proto.h"
16
17
#include <algorithm>
18
#include <cstddef>
19
#include <cstdint>
20
#include <stack>
21
#include <vector>
22
23
#include "cel/expr/syntax.pb.h"
24
#include "google/protobuf/struct.pb.h"
25
#include "absl/base/attributes.h"
26
#include "absl/base/nullability.h"
27
#include "absl/functional/overload.h"
28
#include "absl/status/status.h"
29
#include "absl/strings/str_cat.h"
30
#include "absl/types/variant.h"
31
#include "common/ast/constant_proto.h"
32
#include "common/constant.h"
33
#include "common/expr.h"
34
#include "internal/status_macros.h"
35
36
namespace cel::ast_internal {
37
38
namespace {
39
40
using ExprProto = cel::expr::Expr;
41
using ConstantProto = cel::expr::Constant;
42
using StructExprProto = cel::expr::Expr::CreateStruct;
43
44
class ExprToProtoState final {
45
 private:
46
  struct Frame final {
47
    const Expr* absl_nonnull expr;
48
    cel::expr::Expr* absl_nonnull proto;
49
  };
50
51
 public:
52
  absl::Status ExprToProto(const Expr& expr,
53
12.1k
                           cel::expr::Expr* absl_nonnull proto) {
54
12.1k
    Push(expr, proto);
55
12.1k
    Frame frame;
56
2.60M
    while (Pop(frame)) {
57
2.59M
      CEL_RETURN_IF_ERROR(ExprToProtoImpl(*frame.expr, frame.proto));
58
2.59M
    }
59
12.1k
    return absl::OkStatus();
60
12.1k
  }
61
62
 private:
63
  absl::Status ExprToProtoImpl(const Expr& expr,
64
2.59M
                               cel::expr::Expr* absl_nonnull proto) {
65
2.59M
    return absl::visit(
66
2.59M
        absl::Overload(
67
2.59M
            [&expr, proto](const UnspecifiedExpr&) -> absl::Status {
68
0
              proto->Clear();
69
0
              proto->set_id(expr.id());
70
0
              return absl::OkStatus();
71
0
            },
72
2.59M
            [this, &expr, proto](const Constant& const_expr) -> absl::Status {
73
499k
              return ConstExprToProto(expr, const_expr, proto);
74
499k
            },
75
2.59M
            [this, &expr, proto](const IdentExpr& ident_expr) -> absl::Status {
76
927k
              return IdentExprToProto(expr, ident_expr, proto);
77
927k
            },
78
2.59M
            [this, &expr,
79
2.59M
             proto](const SelectExpr& select_expr) -> absl::Status {
80
20.3k
              return SelectExprToProto(expr, select_expr, proto);
81
20.3k
            },
82
2.59M
            [this, &expr, proto](const CallExpr& call_expr) -> absl::Status {
83
1.11M
              return CallExprToProto(expr, call_expr, proto);
84
1.11M
            },
85
2.59M
            [this, &expr, proto](const ListExpr& list_expr) -> absl::Status {
86
13.4k
              return ListExprToProto(expr, list_expr, proto);
87
13.4k
            },
88
2.59M
            [this, &expr,
89
2.59M
             proto](const StructExpr& struct_expr) -> absl::Status {
90
3.12k
              return StructExprToProto(expr, struct_expr, proto);
91
3.12k
            },
92
2.59M
            [this, &expr, proto](const MapExpr& map_expr) -> absl::Status {
93
11.0k
              return MapExprToProto(expr, map_expr, proto);
94
11.0k
            },
95
2.59M
            [this, &expr, proto](
96
2.59M
                const ComprehensionExpr& comprehension_expr) -> absl::Status {
97
1.73k
              return ComprehensionExprToProto(expr, comprehension_expr, proto);
98
1.73k
            }),
99
2.59M
        expr.kind());
100
2.59M
  }
101
102
  absl::Status ConstExprToProto(const Expr& expr, const Constant& const_expr,
103
499k
                                ExprProto* absl_nonnull proto) {
104
499k
    proto->Clear();
105
499k
    proto->set_id(expr.id());
106
499k
    return ConstantToProto(const_expr, proto->mutable_const_expr());
107
499k
  }
108
109
  absl::Status IdentExprToProto(const Expr& expr, const IdentExpr& ident_expr,
110
927k
                                ExprProto* absl_nonnull proto) {
111
927k
    proto->Clear();
112
927k
    auto* ident_proto = proto->mutable_ident_expr();
113
927k
    proto->set_id(expr.id());
114
927k
    ident_proto->set_name(ident_expr.name());
115
927k
    return absl::OkStatus();
116
927k
  }
117
118
  absl::Status SelectExprToProto(const Expr& expr,
119
                                 const SelectExpr& select_expr,
120
20.3k
                                 ExprProto* absl_nonnull proto) {
121
20.3k
    proto->Clear();
122
20.3k
    auto* select_proto = proto->mutable_select_expr();
123
20.3k
    proto->set_id(expr.id());
124
20.3k
    if (select_expr.has_operand()) {
125
20.3k
      Push(select_expr.operand(), select_proto->mutable_operand());
126
20.3k
    }
127
20.3k
    select_proto->set_field(select_expr.field());
128
20.3k
    select_proto->set_test_only(select_expr.test_only());
129
20.3k
    return absl::OkStatus();
130
20.3k
  }
131
132
  absl::Status CallExprToProto(const Expr& expr, const CallExpr& call_expr,
133
1.11M
                               ExprProto* absl_nonnull proto) {
134
1.11M
    proto->Clear();
135
1.11M
    auto* call_proto = proto->mutable_call_expr();
136
1.11M
    proto->set_id(expr.id());
137
1.11M
    if (call_expr.has_target()) {
138
3.15k
      Push(call_expr.target(), call_proto->mutable_target());
139
3.15k
    }
140
1.11M
    call_proto->set_function(call_expr.function());
141
1.11M
    if (!call_expr.args().empty()) {
142
1.11M
      call_proto->mutable_args()->Reserve(
143
1.11M
          static_cast<int>(call_expr.args().size()));
144
2.13M
      for (const auto& argument : call_expr.args()) {
145
2.13M
        Push(argument, call_proto->add_args());
146
2.13M
      }
147
1.11M
    }
148
1.11M
    return absl::OkStatus();
149
1.11M
  }
150
151
  absl::Status ListExprToProto(const Expr& expr, const ListExpr& list_expr,
152
13.4k
                               ExprProto* absl_nonnull proto) {
153
13.4k
    proto->Clear();
154
13.4k
    auto* list_proto = proto->mutable_list_expr();
155
13.4k
    proto->set_id(expr.id());
156
13.4k
    if (!list_expr.elements().empty()) {
157
11.2k
      list_proto->mutable_elements()->Reserve(
158
11.2k
          static_cast<int>(list_expr.elements().size()));
159
52.6k
      for (size_t i = 0; i < list_expr.elements().size(); ++i) {
160
41.3k
        const auto& element_expr = list_expr.elements()[i];
161
41.3k
        auto* element_proto = list_proto->add_elements();
162
41.3k
        if (element_expr.has_expr()) {
163
41.3k
          Push(element_expr.expr(), element_proto);
164
41.3k
        }
165
41.3k
        if (element_expr.optional()) {
166
0
          list_proto->add_optional_indices(static_cast<int32_t>(i));
167
0
        }
168
41.3k
      }
169
11.2k
    }
170
13.4k
    return absl::OkStatus();
171
13.4k
  }
172
173
  absl::Status StructExprToProto(const Expr& expr,
174
                                 const StructExpr& struct_expr,
175
3.12k
                                 ExprProto* absl_nonnull proto) {
176
3.12k
    proto->Clear();
177
3.12k
    auto* struct_proto = proto->mutable_struct_expr();
178
3.12k
    proto->set_id(expr.id());
179
3.12k
    struct_proto->set_message_name(struct_expr.name());
180
3.12k
    if (!struct_expr.fields().empty()) {
181
255
      struct_proto->mutable_entries()->Reserve(
182
255
          static_cast<int>(struct_expr.fields().size()));
183
2.64k
      for (const auto& field_expr : struct_expr.fields()) {
184
2.64k
        auto* field_proto = struct_proto->add_entries();
185
2.64k
        field_proto->set_id(field_expr.id());
186
2.64k
        field_proto->set_field_key(field_expr.name());
187
2.64k
        if (field_expr.has_value()) {
188
2.64k
          Push(field_expr.value(), field_proto->mutable_value());
189
2.64k
        }
190
2.64k
        if (field_expr.optional()) {
191
0
          field_proto->set_optional_entry(true);
192
0
        }
193
2.64k
      }
194
255
    }
195
3.12k
    return absl::OkStatus();
196
3.12k
  }
197
198
  absl::Status MapExprToProto(const Expr& expr, const MapExpr& map_expr,
199
11.0k
                              ExprProto* absl_nonnull proto) {
200
11.0k
    proto->Clear();
201
11.0k
    auto* map_proto = proto->mutable_struct_expr();
202
11.0k
    proto->set_id(expr.id());
203
11.0k
    if (!map_expr.entries().empty()) {
204
4.28k
      map_proto->mutable_entries()->Reserve(
205
4.28k
          static_cast<int>(map_expr.entries().size()));
206
182k
      for (const auto& entry_expr : map_expr.entries()) {
207
182k
        auto* entry_proto = map_proto->add_entries();
208
182k
        entry_proto->set_id(entry_expr.id());
209
182k
        if (entry_expr.has_key()) {
210
182k
          Push(entry_expr.key(), entry_proto->mutable_map_key());
211
182k
        }
212
182k
        if (entry_expr.has_value()) {
213
182k
          Push(entry_expr.value(), entry_proto->mutable_value());
214
182k
        }
215
182k
        if (entry_expr.optional()) {
216
0
          entry_proto->set_optional_entry(true);
217
0
        }
218
182k
      }
219
4.28k
    }
220
11.0k
    return absl::OkStatus();
221
11.0k
  }
222
223
  absl::Status ComprehensionExprToProto(
224
      const Expr& expr, const ComprehensionExpr& comprehension_expr,
225
1.73k
      ExprProto* absl_nonnull proto) {
226
1.73k
    proto->Clear();
227
1.73k
    auto* comprehension_proto = proto->mutable_comprehension_expr();
228
1.73k
    proto->set_id(expr.id());
229
1.73k
    comprehension_proto->set_iter_var(comprehension_expr.iter_var());
230
1.73k
    comprehension_proto->set_iter_var2(comprehension_expr.iter_var2());
231
1.73k
    if (comprehension_expr.has_iter_range()) {
232
1.73k
      Push(comprehension_expr.iter_range(),
233
1.73k
           comprehension_proto->mutable_iter_range());
234
1.73k
    }
235
1.73k
    comprehension_proto->set_accu_var(comprehension_expr.accu_var());
236
1.73k
    if (comprehension_expr.has_accu_init()) {
237
1.73k
      Push(comprehension_expr.accu_init(),
238
1.73k
           comprehension_proto->mutable_accu_init());
239
1.73k
    }
240
1.73k
    if (comprehension_expr.has_loop_condition()) {
241
1.73k
      Push(comprehension_expr.loop_condition(),
242
1.73k
           comprehension_proto->mutable_loop_condition());
243
1.73k
    }
244
1.73k
    if (comprehension_expr.has_loop_step()) {
245
1.73k
      Push(comprehension_expr.loop_step(),
246
1.73k
           comprehension_proto->mutable_loop_step());
247
1.73k
    }
248
1.73k
    if (comprehension_expr.has_result()) {
249
1.73k
      Push(comprehension_expr.result(), comprehension_proto->mutable_result());
250
1.73k
    }
251
1.73k
    return absl::OkStatus();
252
1.73k
  }
253
254
2.59M
  void Push(const Expr& expr, ExprProto* absl_nonnull proto) {
255
2.59M
    frames_.push(Frame{&expr, proto});
256
2.59M
  }
257
258
2.60M
  bool Pop(Frame& frame) {
259
2.60M
    if (frames_.empty()) {
260
12.1k
      return false;
261
12.1k
    }
262
2.59M
    frame = frames_.top();
263
2.59M
    frames_.pop();
264
2.59M
    return true;
265
2.60M
  }
266
267
  std::stack<Frame, std::vector<Frame>> frames_;
268
};
269
270
class ExprFromProtoState final {
271
 private:
272
  struct Frame final {
273
    const ExprProto* absl_nonnull proto;
274
    Expr* absl_nonnull expr;
275
  };
276
277
 public:
278
10.3k
  absl::Status ExprFromProto(const ExprProto& proto, Expr& expr) {
279
10.3k
    Push(proto, expr);
280
10.3k
    Frame frame;
281
395k
    while (Pop(frame)) {
282
385k
      CEL_RETURN_IF_ERROR(ExprFromProtoImpl(*frame.proto, *frame.expr));
283
385k
    }
284
10.3k
    return absl::OkStatus();
285
10.3k
  }
286
287
 private:
288
385k
  absl::Status ExprFromProtoImpl(const ExprProto& proto, Expr& expr) {
289
385k
    switch (proto.expr_kind_case()) {
290
0
      case ExprProto::EXPR_KIND_NOT_SET:
291
0
        expr.Clear();
292
0
        expr.set_id(proto.id());
293
0
        return absl::OkStatus();
294
118k
      case ExprProto::kConstExpr:
295
118k
        return ConstExprFromProto(proto, proto.const_expr(), expr);
296
61.6k
      case ExprProto::kIdentExpr:
297
61.6k
        return IdentExprFromProto(proto, proto.ident_expr(), expr);
298
17.2k
      case ExprProto::kSelectExpr:
299
17.2k
        return SelectExprFromProto(proto, proto.select_expr(), expr);
300
167k
      case ExprProto::kCallExpr:
301
167k
        return CallExprFromProto(proto, proto.call_expr(), expr);
302
9.20k
      case ExprProto::kListExpr:
303
9.20k
        return ListExprFromProto(proto, proto.list_expr(), expr);
304
11.1k
      case ExprProto::kStructExpr:
305
11.1k
        if (proto.struct_expr().message_name().empty()) {
306
8.70k
          return MapExprFromProto(proto, proto.struct_expr(), expr);
307
8.70k
        }
308
2.45k
        return StructExprFromProto(proto, proto.struct_expr(), expr);
309
0
      case ExprProto::kComprehensionExpr:
310
0
        return ComprehensionExprFromProto(proto, proto.comprehension_expr(),
311
0
                                          expr);
312
0
      default:
313
0
        return absl::InvalidArgumentError(
314
0
            absl::StrCat("unexpected ExprKindCase: ",
315
0
                         static_cast<int>(proto.expr_kind_case())));
316
385k
    }
317
385k
  }
318
319
  absl::Status ConstExprFromProto(const ExprProto& proto,
320
                                  const ConstantProto& const_proto,
321
118k
                                  Expr& expr) {
322
118k
    expr.Clear();
323
118k
    expr.set_id(proto.id());
324
118k
    return ConstantFromProto(const_proto, expr.mutable_const_expr());
325
118k
  }
326
327
  absl::Status IdentExprFromProto(const ExprProto& proto,
328
                                  const ExprProto::Ident& ident_proto,
329
61.6k
                                  Expr& expr) {
330
61.6k
    expr.Clear();
331
61.6k
    expr.set_id(proto.id());
332
61.6k
    auto& ident_expr = expr.mutable_ident_expr();
333
61.6k
    ident_expr.set_name(ident_proto.name());
334
61.6k
    return absl::OkStatus();
335
61.6k
  }
336
337
  absl::Status SelectExprFromProto(const ExprProto& proto,
338
                                   const ExprProto::Select& select_proto,
339
17.2k
                                   Expr& expr) {
340
17.2k
    expr.Clear();
341
17.2k
    expr.set_id(proto.id());
342
17.2k
    auto& select_expr = expr.mutable_select_expr();
343
17.2k
    if (select_proto.has_operand()) {
344
17.2k
      Push(select_proto.operand(), select_expr.mutable_operand());
345
17.2k
    }
346
17.2k
    select_expr.set_field(select_proto.field());
347
17.2k
    select_expr.set_test_only(select_proto.test_only());
348
17.2k
    return absl::OkStatus();
349
17.2k
  }
350
351
  absl::Status CallExprFromProto(const ExprProto& proto,
352
                                 const ExprProto::Call& call_proto,
353
167k
                                 Expr& expr) {
354
167k
    expr.Clear();
355
167k
    expr.set_id(proto.id());
356
167k
    auto& call_expr = expr.mutable_call_expr();
357
167k
    call_expr.set_function(call_proto.function());
358
167k
    if (call_proto.has_target()) {
359
782
      Push(call_proto.target(), call_expr.mutable_target());
360
782
    }
361
167k
    call_expr.mutable_args().reserve(
362
167k
        static_cast<size_t>(call_proto.args().size()));
363
317k
    for (const auto& argument_proto : call_proto.args()) {
364
317k
      Push(argument_proto, call_expr.add_args());
365
317k
    }
366
167k
    return absl::OkStatus();
367
167k
  }
368
369
  absl::Status ListExprFromProto(const ExprProto& proto,
370
                                 const ExprProto::CreateList& list_proto,
371
9.20k
                                 Expr& expr) {
372
9.20k
    expr.Clear();
373
9.20k
    expr.set_id(proto.id());
374
9.20k
    auto& list_expr = expr.mutable_list_expr();
375
9.20k
    list_expr.mutable_elements().reserve(
376
9.20k
        static_cast<size_t>(list_proto.elements().size()));
377
40.2k
    for (int i = 0; i < list_proto.elements().size(); ++i) {
378
31.0k
      const auto& element_proto = list_proto.elements()[i];
379
31.0k
      auto& element_expr = list_expr.add_elements();
380
31.0k
      Push(element_proto, element_expr.mutable_expr());
381
31.0k
      const auto& optional_indicies_proto = list_proto.optional_indices();
382
31.0k
      element_expr.set_optional(std::find(optional_indicies_proto.begin(),
383
31.0k
                                          optional_indicies_proto.end(),
384
31.0k
                                          i) != optional_indicies_proto.end());
385
31.0k
    }
386
9.20k
    return absl::OkStatus();
387
9.20k
  }
388
389
  absl::Status StructExprFromProto(const ExprProto& proto,
390
                                   const StructExprProto& struct_proto,
391
2.45k
                                   Expr& expr) {
392
2.45k
    expr.Clear();
393
2.45k
    expr.set_id(proto.id());
394
2.45k
    auto& struct_expr = expr.mutable_struct_expr();
395
2.45k
    struct_expr.set_name(struct_proto.message_name());
396
2.45k
    struct_expr.mutable_fields().reserve(
397
2.45k
        static_cast<size_t>(struct_proto.entries().size()));
398
2.45k
    for (const auto& field_proto : struct_proto.entries()) {
399
858
      switch (field_proto.key_kind_case()) {
400
0
        case StructExprProto::Entry::KEY_KIND_NOT_SET:
401
0
          ABSL_FALLTHROUGH_INTENDED;
402
858
        case StructExprProto::Entry::kFieldKey:
403
858
          break;
404
0
        case StructExprProto::Entry::kMapKey:
405
0
          return absl::InvalidArgumentError("encountered map entry in struct");
406
0
        default:
407
0
          return absl::InvalidArgumentError(absl::StrCat(
408
0
              "unexpected struct field kind: ", field_proto.key_kind_case()));
409
858
      }
410
858
      auto& field_expr = struct_expr.add_fields();
411
858
      field_expr.set_id(field_proto.id());
412
858
      field_expr.set_name(field_proto.field_key());
413
858
      if (field_proto.has_value()) {
414
858
        Push(field_proto.value(), field_expr.mutable_value());
415
858
      }
416
858
      field_expr.set_optional(field_proto.optional_entry());
417
858
    }
418
2.45k
    return absl::OkStatus();
419
2.45k
  }
420
421
  absl::Status MapExprFromProto(const ExprProto& proto,
422
                                const ExprProto::CreateStruct& map_proto,
423
8.70k
                                Expr& expr) {
424
8.70k
    expr.Clear();
425
8.70k
    expr.set_id(proto.id());
426
8.70k
    auto& map_expr = expr.mutable_map_expr();
427
8.70k
    map_expr.mutable_entries().reserve(
428
8.70k
        static_cast<size_t>(map_proto.entries().size()));
429
8.70k
    for (const auto& entry_proto : map_proto.entries()) {
430
3.86k
      switch (entry_proto.key_kind_case()) {
431
0
        case StructExprProto::Entry::KEY_KIND_NOT_SET:
432
0
          ABSL_FALLTHROUGH_INTENDED;
433
3.86k
        case StructExprProto::Entry::kMapKey:
434
3.86k
          break;
435
0
        case StructExprProto::Entry::kFieldKey:
436
0
          return absl::InvalidArgumentError("encountered struct field in map");
437
0
        default:
438
0
          return absl::InvalidArgumentError(absl::StrCat(
439
0
              "unexpected map entry kind: ", entry_proto.key_kind_case()));
440
3.86k
      }
441
3.86k
      auto& entry_expr = map_expr.add_entries();
442
3.86k
      entry_expr.set_id(entry_proto.id());
443
3.86k
      if (entry_proto.has_map_key()) {
444
3.86k
        Push(entry_proto.map_key(), entry_expr.mutable_key());
445
3.86k
      }
446
3.86k
      if (entry_proto.has_value()) {
447
3.86k
        Push(entry_proto.value(), entry_expr.mutable_value());
448
3.86k
      }
449
3.86k
      entry_expr.set_optional(entry_proto.optional_entry());
450
3.86k
    }
451
8.70k
    return absl::OkStatus();
452
8.70k
  }
453
454
  absl::Status ComprehensionExprFromProto(
455
      const ExprProto& proto,
456
0
      const ExprProto::Comprehension& comprehension_proto, Expr& expr) {
457
0
    expr.Clear();
458
0
    expr.set_id(proto.id());
459
0
    auto& comprehension_expr = expr.mutable_comprehension_expr();
460
0
    comprehension_expr.set_iter_var(comprehension_proto.iter_var());
461
0
    comprehension_expr.set_iter_var2(comprehension_proto.iter_var2());
462
0
    comprehension_expr.set_accu_var(comprehension_proto.accu_var());
463
0
    if (comprehension_proto.has_iter_range()) {
464
0
      Push(comprehension_proto.iter_range(),
465
0
           comprehension_expr.mutable_iter_range());
466
0
    }
467
0
    if (comprehension_proto.has_accu_init()) {
468
0
      Push(comprehension_proto.accu_init(),
469
0
           comprehension_expr.mutable_accu_init());
470
0
    }
471
0
    if (comprehension_proto.has_loop_condition()) {
472
0
      Push(comprehension_proto.loop_condition(),
473
0
           comprehension_expr.mutable_loop_condition());
474
0
    }
475
0
    if (comprehension_proto.has_loop_step()) {
476
0
      Push(comprehension_proto.loop_step(),
477
0
           comprehension_expr.mutable_loop_step());
478
0
    }
479
0
    if (comprehension_proto.has_result()) {
480
0
      Push(comprehension_proto.result(), comprehension_expr.mutable_result());
481
0
    }
482
0
    return absl::OkStatus();
483
0
  }
484
485
385k
  void Push(const ExprProto& proto, Expr& expr) {
486
385k
    frames_.push(Frame{&proto, &expr});
487
385k
  }
488
489
395k
  bool Pop(Frame& frame) {
490
395k
    if (frames_.empty()) {
491
10.3k
      return false;
492
10.3k
    }
493
385k
    frame = frames_.top();
494
385k
    frames_.pop();
495
385k
    return true;
496
395k
  }
497
498
  std::stack<Frame, std::vector<Frame>> frames_;
499
};
500
501
}  // namespace
502
503
absl::Status ExprToProto(const Expr& expr,
504
12.1k
                         cel::expr::Expr* absl_nonnull proto) {
505
12.1k
  ExprToProtoState state;
506
12.1k
  return state.ExprToProto(expr, proto);
507
12.1k
}
508
509
10.3k
absl::Status ExprFromProto(const cel::expr::Expr& proto, Expr& expr) {
510
10.3k
  ExprFromProtoState state;
511
10.3k
  return state.ExprFromProto(proto, expr);
512
10.3k
}
513
514
}  // namespace cel::ast_internal