Coverage Report

Created: 2026-01-12 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/common/expr.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/expr.h"
16
17
#include <utility>
18
#include <vector>
19
20
#include "absl/base/no_destructor.h"
21
#include "absl/functional/overload.h"
22
#include "absl/log/absl_check.h"
23
#include "absl/types/variant.h"
24
#include "common/constant.h"
25
26
namespace cel {
27
28
namespace {
29
30
struct CopyStackRecord {
31
  const Expr* src;
32
  Expr* dst;
33
};
34
35
0
void CopyNode(CopyStackRecord element, std::vector<CopyStackRecord>& stack) {
36
0
  const Expr* src = element.src;
37
0
  Expr* dst = element.dst;
38
0
  dst->set_id(src->id());
39
0
  absl::visit(
40
0
      absl::Overload(
41
0
          [=](const UnspecifiedExpr&) {
42
0
            dst->mutable_kind().emplace<UnspecifiedExpr>();
43
0
          },
44
0
          [=](const IdentExpr& i) {
45
0
            dst->mutable_ident_expr().set_name(i.name());
46
0
          },
47
0
          [=](const Constant& c) { dst->mutable_const_expr() = c; },
48
0
          [&](const SelectExpr& s) {
49
0
            dst->mutable_select_expr().set_field(s.field());
50
0
            dst->mutable_select_expr().set_test_only(s.test_only());
51
52
0
            if (s.has_operand()) {
53
0
              stack.push_back({&s.operand(),
54
0
                               &dst->mutable_select_expr().mutable_operand()});
55
0
            }
56
0
          },
57
0
          [&](const CallExpr& c) {
58
0
            dst->mutable_call_expr().set_function(c.function());
59
0
            if (c.has_target()) {
60
0
              stack.push_back(
61
0
                  {&c.target(), &dst->mutable_call_expr().mutable_target()});
62
0
            }
63
0
            dst->mutable_call_expr().mutable_args().resize(c.args().size());
64
0
            for (int i = 0; i < dst->mutable_call_expr().mutable_args().size();
65
0
                 ++i) {
66
0
              stack.push_back(
67
0
                  {&c.args()[i], &dst->mutable_call_expr().mutable_args()[i]});
68
0
            }
69
0
          },
70
0
          [&](const ListExpr& c) {
71
0
            auto& dst_list = dst->mutable_list_expr();
72
0
            dst_list.mutable_elements().resize(c.elements().size());
73
0
            for (int i = 0; i < src->list_expr().elements().size(); ++i) {
74
0
              dst_list.mutable_elements()[i].set_optional(
75
0
                  c.elements()[i].optional());
76
0
              stack.push_back({&c.elements()[i].expr(),
77
0
                               &dst_list.mutable_elements()[i].mutable_expr()});
78
0
            }
79
0
          },
80
0
          [&](const StructExpr& s) {
81
0
            auto& dst_struct = dst->mutable_struct_expr();
82
0
            dst_struct.mutable_fields().resize(s.fields().size());
83
0
            dst_struct.set_name(s.name());
84
0
            for (int i = 0; i < s.fields().size(); ++i) {
85
0
              dst_struct.mutable_fields()[i].set_optional(
86
0
                  s.fields()[i].optional());
87
0
              dst_struct.mutable_fields()[i].set_name(s.fields()[i].name());
88
0
              dst_struct.mutable_fields()[i].set_id(s.fields()[i].id());
89
0
              stack.push_back(
90
0
                  {&s.fields()[i].value(),
91
0
                   &dst_struct.mutable_fields()[i].mutable_value()});
92
0
            }
93
0
          },
94
0
          [&](const MapExpr& c) {
95
0
            auto& dst_map = dst->mutable_map_expr();
96
0
            dst_map.mutable_entries().resize(c.entries().size());
97
0
            for (int i = 0; i < c.entries().size(); ++i) {
98
0
              dst_map.mutable_entries()[i].set_optional(
99
0
                  c.entries()[i].optional());
100
0
              dst_map.mutable_entries()[i].set_id(c.entries()[i].id());
101
0
              stack.push_back({&c.entries()[i].key(),
102
0
                               &dst_map.mutable_entries()[i].mutable_key()});
103
0
              stack.push_back({&c.entries()[i].value(),
104
0
                               &dst_map.mutable_entries()[i].mutable_value()});
105
0
            }
106
0
          },
107
0
          [&](const ComprehensionExpr& c) {
108
0
            auto& dst_comprehension = dst->mutable_comprehension_expr();
109
0
            dst_comprehension.set_iter_var(c.iter_var());
110
0
            dst_comprehension.set_iter_var2(c.iter_var2());
111
0
            dst_comprehension.set_accu_var(c.accu_var());
112
0
            if (c.has_accu_init()) {
113
0
              stack.push_back(
114
0
                  {&c.accu_init(), &dst_comprehension.mutable_accu_init()});
115
0
            }
116
0
            if (c.has_iter_range()) {
117
0
              stack.push_back(
118
0
                  {&c.iter_range(), &dst_comprehension.mutable_iter_range()});
119
0
            }
120
0
            if (c.has_loop_condition()) {
121
0
              stack.push_back({&c.loop_condition(),
122
0
                               &dst_comprehension.mutable_loop_condition()});
123
0
            }
124
0
            if (c.has_loop_step()) {
125
0
              stack.push_back(
126
0
                  {&c.loop_step(), &dst_comprehension.mutable_loop_step()});
127
0
            }
128
0
            if (c.has_result()) {
129
0
              stack.push_back(
130
0
                  {&c.result(), &dst_comprehension.mutable_result()});
131
0
            }
132
0
          }),
133
0
      src->kind());
134
0
}
135
136
0
void CloneImpl(const Expr& expr, Expr& dst) {
137
0
  std::vector<CopyStackRecord> stack;
138
0
  stack.push_back({&expr, &dst});
139
0
  while (!stack.empty()) {
140
0
    CopyStackRecord element = stack.back();
141
0
    stack.pop_back();
142
0
    CopyNode(element, stack);
143
0
  }
144
0
}
145
146
}  // namespace
147
148
0
const UnspecifiedExpr& UnspecifiedExpr::default_instance() {
149
0
  static const absl::NoDestructor<UnspecifiedExpr> instance;
150
0
  return *instance;
151
0
}
152
153
0
const IdentExpr& IdentExpr::default_instance() {
154
0
  static const absl::NoDestructor<IdentExpr> instance;
155
0
  return *instance;
156
0
}
157
158
0
const SelectExpr& SelectExpr::default_instance() {
159
0
  static const absl::NoDestructor<SelectExpr> instance;
160
0
  return *instance;
161
0
}
162
163
0
const CallExpr& CallExpr::default_instance() {
164
0
  static const absl::NoDestructor<CallExpr> instance;
165
0
  return *instance;
166
0
}
167
168
0
const ListExpr& ListExpr::default_instance() {
169
0
  static const absl::NoDestructor<ListExpr> instance;
170
0
  return *instance;
171
0
}
172
173
0
const StructExpr& StructExpr::default_instance() {
174
0
  static const absl::NoDestructor<StructExpr> instance;
175
0
  return *instance;
176
0
}
177
178
0
const MapExpr& MapExpr::default_instance() {
179
0
  static const absl::NoDestructor<MapExpr> instance;
180
0
  return *instance;
181
0
}
182
183
0
const ComprehensionExpr& ComprehensionExpr::default_instance() {
184
0
  static const absl::NoDestructor<ComprehensionExpr> instance;
185
0
  return *instance;
186
0
}
187
188
0
const Expr& Expr::default_instance() {
189
0
  static const absl::NoDestructor<Expr> instance;
190
0
  return *instance;
191
0
}
192
193
0
Expr& Expr::operator=(const Expr& other) {
194
0
  if (this == &other) {
195
0
    return *this;
196
0
  }
197
0
  Expr tmp;
198
0
  CloneImpl(other, tmp);
199
0
  *this = std::move(tmp);
200
0
  return *this;
201
0
}
202
203
0
Expr::Expr(const Expr& other) { CloneImpl(other, *this); }
204
205
namespace common_internal {
206
struct ExprEraseTag {};
207
}  // namespace common_internal
208
209
namespace {
210
0
void Expand(Expr** tail, Expr* cur) {
211
0
  static common_internal::ExprEraseTag tag;
212
0
  switch (cur->kind_case()) {
213
0
    case ExprKindCase::kSelectExpr: {
214
0
      SelectExpr& select = cur->mutable_select_expr();
215
0
      if (select.has_operand()) {
216
0
        select.mutable_operand().SetNext(tag, *tail);
217
0
        *tail = &select.mutable_operand();
218
0
      }
219
0
      break;
220
0
    }
221
0
    case ExprKindCase::kCallExpr: {
222
0
      CallExpr& call = cur->mutable_call_expr();
223
0
      if (call.has_target()) {
224
0
        call.mutable_target().SetNext(tag, *tail);
225
0
        *tail = &call.mutable_target();
226
0
      }
227
0
      for (auto& arg : call.mutable_args()) {
228
0
        arg.SetNext(tag, *tail);
229
0
        *tail = &arg;
230
0
      }
231
0
      break;
232
0
    }
233
0
    case ExprKindCase::kListExpr: {
234
0
      for (auto& arg : cur->mutable_list_expr().mutable_elements()) {
235
0
        arg.mutable_expr().SetNext(tag, *tail);
236
0
        *tail = &arg.mutable_expr();
237
0
      }
238
0
      break;
239
0
    }
240
0
    case ExprKindCase::kStructExpr: {
241
0
      for (auto& field : cur->mutable_struct_expr().mutable_fields()) {
242
0
        field.mutable_value().SetNext(tag, *tail);
243
0
        *tail = &field.mutable_value();
244
0
      }
245
0
      break;
246
0
    }
247
0
    case ExprKindCase::kMapExpr: {
248
0
      for (auto& entry : cur->mutable_map_expr().mutable_entries()) {
249
0
        entry.mutable_key().SetNext(tag, *tail);
250
0
        *tail = &entry.mutable_key();
251
0
        entry.mutable_value().SetNext(tag, *tail);
252
0
        *tail = &entry.mutable_value();
253
0
      }
254
0
      break;
255
0
    }
256
0
    case ExprKindCase::kComprehensionExpr: {
257
0
      if (cur->comprehension_expr().has_accu_init()) {
258
0
        cur->mutable_comprehension_expr().mutable_accu_init().SetNext(tag,
259
0
                                                                      *tail);
260
0
        *tail = &cur->mutable_comprehension_expr().mutable_accu_init();
261
0
      }
262
0
      if (cur->comprehension_expr().has_iter_range()) {
263
0
        cur->mutable_comprehension_expr().mutable_iter_range().SetNext(tag,
264
0
                                                                       *tail);
265
0
        *tail = &cur->mutable_comprehension_expr().mutable_iter_range();
266
0
      }
267
0
      if (cur->comprehension_expr().has_loop_condition()) {
268
0
        cur->mutable_comprehension_expr().mutable_loop_condition().SetNext(
269
0
            tag, *tail);
270
0
        *tail = &cur->mutable_comprehension_expr().mutable_loop_condition();
271
0
      }
272
0
      if (cur->comprehension_expr().has_loop_step()) {
273
0
        cur->mutable_comprehension_expr().mutable_loop_step().SetNext(tag,
274
0
                                                                      *tail);
275
0
        *tail = &cur->mutable_comprehension_expr().mutable_loop_step();
276
0
      }
277
0
      if (cur->comprehension_expr().has_result()) {
278
0
        cur->mutable_comprehension_expr().mutable_result().SetNext(tag, *tail);
279
0
        *tail = &cur->mutable_comprehension_expr().mutable_result();
280
0
      }
281
0
      break;
282
0
    }
283
0
    default:
284
      // Leaf node, nothing to expand.
285
      // Also a fallback in case we add a new node type.
286
      // Note: already in the deleter list so we can't delete now, will be
287
      // deleted after ordering the AST.
288
0
      break;
289
0
  }
290
0
}
291
}  // namespace
292
293
0
void Expr::FlattenedErase() {
294
  // High level idea is to build a topological ordering of the AST, then erase
295
  // leaf to root.
296
0
  this->u_.next = nullptr;
297
0
  Expr* prev_tail = nullptr;
298
0
  Expr* tail = this;
299
300
0
  while (tail != prev_tail) {
301
0
    Expr* next_prev_tail = tail;
302
0
    Expr* expand_ptr = tail;
303
0
    while (expand_ptr != prev_tail) {
304
0
      ABSL_DCHECK(expand_ptr != nullptr);  // Linked list is broken or changed.
305
0
      Expr* next_expand_ptr = expand_ptr->u_.next;
306
0
      Expand(&tail, expand_ptr);
307
0
      expand_ptr = next_expand_ptr;
308
0
    }
309
0
    prev_tail = next_prev_tail;
310
0
  }
311
312
0
  Expr* node = tail;
313
0
  while (node != nullptr) {
314
0
    Expr* next = node->u_.next;
315
0
    node->Clear();
316
0
    node = next;
317
0
  }
318
0
}
319
320
}  // namespace cel