Coverage Report

Created: 2025-11-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/parser/macro.cc
Line
Count
Source
1
// Copyright 2021 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 "parser/macro.h"
16
17
#include <cstddef>
18
#include <functional>
19
#include <memory>
20
#include <string>
21
#include <utility>
22
#include <vector>
23
24
#include "absl/base/no_destructor.h"
25
#include "absl/log/absl_check.h"
26
#include "absl/status/status.h"
27
#include "absl/status/statusor.h"
28
#include "absl/strings/str_cat.h"
29
#include "absl/strings/string_view.h"
30
#include "absl/types/optional.h"
31
#include "absl/types/span.h"
32
#include "common/expr.h"
33
#include "common/operators.h"
34
#include "internal/lexis.h"
35
#include "parser/macro_expr_factory.h"
36
37
namespace cel {
38
39
namespace {
40
41
using google::api::expr::common::CelOperator;
42
43
1
inline MacroExpander ToMacroExpander(GlobalMacroExpander expander) {
44
1
  ABSL_DCHECK(expander);
45
1
  return [expander = std::move(expander)](
46
1
             MacroExprFactory& factory,
47
1
             absl::optional<std::reference_wrapper<Expr>> target,
48
1.60k
             absl::Span<Expr> arguments) -> absl::optional<Expr> {
49
1.60k
    ABSL_DCHECK(!target.has_value());
50
1.60k
    return (expander)(factory, arguments);
51
1.60k
  };
52
1
}
53
54
6
inline MacroExpander ToMacroExpander(ReceiverMacroExpander expander) {
55
6
  ABSL_DCHECK(expander);
56
6
  return [expander = std::move(expander)](
57
6
             MacroExprFactory& factory,
58
6
             absl::optional<std::reference_wrapper<Expr>> target,
59
1.87k
             absl::Span<Expr> arguments) -> absl::optional<Expr> {
60
1.87k
    ABSL_DCHECK(target.has_value());
61
1.87k
    return (expander)(factory, *target, arguments);
62
1.87k
  };
63
6
}
64
65
absl::optional<Expr> ExpandHasMacro(MacroExprFactory& factory,
66
1.60k
                                    absl::Span<Expr> args) {
67
1.60k
  if (args.size() != 1) {
68
0
    return factory.ReportError("has() requires 1 arguments");
69
0
  }
70
1.60k
  if (!args[0].has_select_expr() || args[0].select_expr().test_only()) {
71
1.58k
    return factory.ReportErrorAt(args[0],
72
1.58k
                                 "has() argument must be a field selection");
73
1.58k
  }
74
24
  return factory.NewPresenceTest(
75
24
      args[0].mutable_select_expr().release_operand(),
76
24
      args[0].mutable_select_expr().release_field());
77
1.60k
}
78
79
1
Macro MakeHasMacro() {
80
1
  auto macro_or_status = Macro::Global(CelOperator::HAS, 1, ExpandHasMacro);
81
1
  ABSL_CHECK_OK(macro_or_status);  // Crash OK
82
1
  return std::move(*macro_or_status);
83
1
}
84
85
absl::optional<Expr> ExpandAllMacro(MacroExprFactory& factory, Expr& target,
86
298
                                    absl::Span<Expr> args) {
87
298
  if (args.size() != 2) {
88
0
    return factory.ReportError("all() requires 2 arguments");
89
0
  }
90
298
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
91
187
    return factory.ReportErrorAt(
92
187
        args[0], "all() variable name must be a simple identifier");
93
187
  }
94
111
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
95
8
    return factory.ReportErrorAt(args[1],
96
8
                                 absl::StrCat("all() variable name cannot be ",
97
8
                                              kAccumulatorVariableName));
98
8
  }
99
103
  auto init = factory.NewBoolConst(true);
100
103
  auto condition =
101
103
      factory.NewCall(CelOperator::NOT_STRICTLY_FALSE, factory.NewAccuIdent());
102
103
  auto step = factory.NewCall(CelOperator::LOGICAL_AND, factory.NewAccuIdent(),
103
103
                              std::move(args[1]));
104
103
  auto result = factory.NewAccuIdent();
105
103
  return factory.NewComprehension(args[0].ident_expr().name(),
106
103
                                  std::move(target), factory.AccuVarName(),
107
103
                                  std::move(init), std::move(condition),
108
103
                                  std::move(step), std::move(result));
109
111
}
110
111
1
Macro MakeAllMacro() {
112
1
  auto status_or_macro = Macro::Receiver(CelOperator::ALL, 2, ExpandAllMacro);
113
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
114
1
  return std::move(*status_or_macro);
115
1
}
116
117
absl::optional<Expr> ExpandExistsMacro(MacroExprFactory& factory, Expr& target,
118
55
                                       absl::Span<Expr> args) {
119
55
  if (args.size() != 2) {
120
0
    return factory.ReportError("exists() requires 2 arguments");
121
0
  }
122
55
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
123
2
    return factory.ReportErrorAt(
124
2
        args[0], "exists() variable name must be a simple identifier");
125
2
  }
126
53
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
127
2
    return factory.ReportErrorAt(
128
2
        args[1], absl::StrCat("exists() variable name cannot be ",
129
2
                              kAccumulatorVariableName));
130
2
  }
131
51
  auto init = factory.NewBoolConst(false);
132
51
  auto condition = factory.NewCall(
133
51
      CelOperator::NOT_STRICTLY_FALSE,
134
51
      factory.NewCall(CelOperator::LOGICAL_NOT, factory.NewAccuIdent()));
135
51
  auto step = factory.NewCall(CelOperator::LOGICAL_OR, factory.NewAccuIdent(),
136
51
                              std::move(args[1]));
137
51
  auto result = factory.NewAccuIdent();
138
51
  return factory.NewComprehension(args[0].ident_expr().name(),
139
51
                                  std::move(target), factory.AccuVarName(),
140
51
                                  std::move(init), std::move(condition),
141
51
                                  std::move(step), std::move(result));
142
53
}
143
144
1
Macro MakeExistsMacro() {
145
1
  auto status_or_macro =
146
1
      Macro::Receiver(CelOperator::EXISTS, 2, ExpandExistsMacro);
147
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
148
1
  return std::move(*status_or_macro);
149
1
}
150
151
absl::optional<Expr> ExpandExistsOneMacro(MacroExprFactory& factory,
152
959
                                          Expr& target, absl::Span<Expr> args) {
153
959
  if (args.size() != 2) {
154
0
    return factory.ReportError("exists_one() requires 2 arguments");
155
0
  }
156
959
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
157
62
    return factory.ReportErrorAt(
158
62
        args[0], "exists_one() variable name must be a simple identifier");
159
62
  }
160
897
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
161
5
    return factory.ReportErrorAt(
162
5
        args[1], absl::StrCat("exists_one() variable name cannot be ",
163
5
                              kAccumulatorVariableName));
164
5
  }
165
892
  auto init = factory.NewIntConst(0);
166
892
  auto condition = factory.NewBoolConst(true);
167
892
  auto accu_ident = factory.NewAccuIdent();
168
892
  auto const_1 = factory.NewIntConst(1);
169
892
  auto inc_step = factory.NewCall(CelOperator::ADD, std::move(accu_ident),
170
892
                                  std::move(const_1));
171
172
892
  auto step = factory.NewCall(CelOperator::CONDITIONAL, std::move(args[1]),
173
892
                              std::move(inc_step), factory.NewAccuIdent());
174
892
  accu_ident = factory.NewAccuIdent();
175
892
  auto result = factory.NewCall(CelOperator::EQUALS, std::move(accu_ident),
176
892
                                factory.NewIntConst(1));
177
892
  return factory.NewComprehension(args[0].ident_expr().name(),
178
892
                                  std::move(target), factory.AccuVarName(),
179
892
                                  std::move(init), std::move(condition),
180
892
                                  std::move(step), std::move(result));
181
897
}
182
183
1
Macro MakeExistsOneMacro() {
184
1
  auto status_or_macro =
185
1
      Macro::Receiver(CelOperator::EXISTS_ONE, 2, ExpandExistsOneMacro);
186
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
187
1
  return std::move(*status_or_macro);
188
1
}
189
190
absl::optional<Expr> ExpandMap2Macro(MacroExprFactory& factory, Expr& target,
191
201
                                     absl::Span<Expr> args) {
192
201
  if (args.size() != 2) {
193
0
    return factory.ReportError("map() requires 2 arguments");
194
0
  }
195
201
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
196
72
    return factory.ReportErrorAt(
197
72
        args[0], "map() variable name must be a simple identifier");
198
72
  }
199
129
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
200
2
    return factory.ReportErrorAt(args[1],
201
2
                                 absl::StrCat("map() variable name cannot be ",
202
2
                                              kAccumulatorVariableName));
203
2
  }
204
127
  auto init = factory.NewList();
205
127
  auto condition = factory.NewBoolConst(true);
206
127
  auto accu_ref = factory.NewAccuIdent();
207
127
  auto accu_update =
208
127
      factory.NewList(factory.NewListElement(std::move(args[1])));
209
127
  auto step = factory.NewCall(CelOperator::ADD, std::move(accu_ref),
210
127
                              std::move(accu_update));
211
127
  return factory.NewComprehension(args[0].ident_expr().name(),
212
127
                                  std::move(target), factory.AccuVarName(),
213
127
                                  std::move(init), std::move(condition),
214
127
                                  std::move(step), factory.NewAccuIdent());
215
129
}
216
217
1
Macro MakeMap2Macro() {
218
1
  auto status_or_macro = Macro::Receiver(CelOperator::MAP, 2, ExpandMap2Macro);
219
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
220
1
  return std::move(*status_or_macro);
221
1
}
222
223
absl::optional<Expr> ExpandMap3Macro(MacroExprFactory& factory, Expr& target,
224
300
                                     absl::Span<Expr> args) {
225
300
  if (args.size() != 3) {
226
0
    return factory.ReportError("map() requires 3 arguments");
227
0
  }
228
300
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
229
15
    return factory.ReportErrorAt(
230
15
        args[0], "map() variable name must be a simple identifier");
231
15
  }
232
285
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
233
6
    return factory.ReportErrorAt(args[1],
234
6
                                 absl::StrCat("map() variable name cannot be ",
235
6
                                              kAccumulatorVariableName));
236
6
  }
237
279
  auto init = factory.NewList();
238
279
  auto condition = factory.NewBoolConst(true);
239
279
  auto accu_ref = factory.NewAccuIdent();
240
279
  auto accu_update =
241
279
      factory.NewList(factory.NewListElement(std::move(args[2])));
242
279
  auto step = factory.NewCall(CelOperator::ADD, std::move(accu_ref),
243
279
                              std::move(accu_update));
244
279
  step = factory.NewCall(CelOperator::CONDITIONAL, std::move(args[1]),
245
279
                         std::move(step), factory.NewAccuIdent());
246
279
  return factory.NewComprehension(args[0].ident_expr().name(),
247
279
                                  std::move(target), factory.AccuVarName(),
248
279
                                  std::move(init), std::move(condition),
249
279
                                  std::move(step), factory.NewAccuIdent());
250
285
}
251
252
1
Macro MakeMap3Macro() {
253
1
  auto status_or_macro = Macro::Receiver(CelOperator::MAP, 3, ExpandMap3Macro);
254
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
255
1
  return std::move(*status_or_macro);
256
1
}
257
258
absl::optional<Expr> ExpandFilterMacro(MacroExprFactory& factory, Expr& target,
259
61
                                       absl::Span<Expr> args) {
260
61
  if (args.size() != 2) {
261
0
    return factory.ReportError("filter() requires 2 arguments");
262
0
  }
263
61
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
264
15
    return factory.ReportErrorAt(
265
15
        args[0], "filter() variable name must be a simple identifier");
266
15
  }
267
46
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
268
1
    return factory.ReportErrorAt(
269
1
        args[1], absl::StrCat("filter() variable name cannot be ",
270
1
                              kAccumulatorVariableName));
271
1
  }
272
45
  auto name = args[0].ident_expr().name();
273
274
45
  auto init = factory.NewList();
275
45
  auto condition = factory.NewBoolConst(true);
276
45
  auto accu_ref = factory.NewAccuIdent();
277
45
  auto accu_update =
278
45
      factory.NewList(factory.NewListElement(std::move(args[0])));
279
45
  auto step = factory.NewCall(CelOperator::ADD, std::move(accu_ref),
280
45
                              std::move(accu_update));
281
45
  step = factory.NewCall(CelOperator::CONDITIONAL, std::move(args[1]),
282
45
                         std::move(step), factory.NewAccuIdent());
283
45
  return factory.NewComprehension(std::move(name), std::move(target),
284
45
                                  factory.AccuVarName(), std::move(init),
285
45
                                  std::move(condition), std::move(step),
286
45
                                  factory.NewAccuIdent());
287
46
}
288
289
1
Macro MakeFilterMacro() {
290
1
  auto status_or_macro =
291
1
      Macro::Receiver(CelOperator::FILTER, 2, ExpandFilterMacro);
292
1
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
293
1
  return std::move(*status_or_macro);
294
1
}
295
296
absl::optional<Expr> ExpandOptMapMacro(MacroExprFactory& factory, Expr& target,
297
0
                                       absl::Span<Expr> args) {
298
0
  if (args.size() != 2) {
299
0
    return factory.ReportError("optMap() requires 2 arguments");
300
0
  }
301
0
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
302
0
    return factory.ReportErrorAt(
303
0
        args[0], "optMap() variable name must be a simple identifier");
304
0
  }
305
0
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
306
0
    return factory.ReportErrorAt(
307
0
        args[1], absl::StrCat("optMap() variable name cannot be ",
308
0
                              kAccumulatorVariableName));
309
0
  }
310
0
  auto var_name = args[0].ident_expr().name();
311
312
0
  auto target_copy = factory.Copy(target);
313
0
  std::vector<Expr> call_args;
314
0
  call_args.reserve(3);
315
0
  call_args.push_back(factory.NewMemberCall("hasValue", std::move(target)));
316
0
  auto iter_range = factory.NewList();
317
0
  auto accu_init = factory.NewMemberCall("value", std::move(target_copy));
318
0
  auto condition = factory.NewBoolConst(false);
319
0
  auto fold = factory.NewComprehension(
320
0
      "#unused", std::move(iter_range), std::move(var_name),
321
0
      std::move(accu_init), std::move(condition), std::move(args[0]),
322
0
      std::move(args[1]));
323
0
  call_args.push_back(factory.NewCall("optional.of", std::move(fold)));
324
0
  call_args.push_back(factory.NewCall("optional.none"));
325
0
  return factory.NewCall(CelOperator::CONDITIONAL, std::move(call_args));
326
0
}
327
328
0
Macro MakeOptMapMacro() {
329
0
  auto status_or_macro = Macro::Receiver("optMap", 2, ExpandOptMapMacro);
330
0
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
331
0
  return std::move(*status_or_macro);
332
0
}
333
334
absl::optional<Expr> ExpandOptFlatMapMacro(MacroExprFactory& factory,
335
                                           Expr& target,
336
0
                                           absl::Span<Expr> args) {
337
0
  if (args.size() != 2) {
338
0
    return factory.ReportError("optFlatMap() requires 2 arguments");
339
0
  }
340
0
  if (!args[0].has_ident_expr() || args[0].ident_expr().name().empty()) {
341
0
    return factory.ReportErrorAt(
342
0
        args[0], "optFlatMap() variable name must be a simple identifier");
343
0
  }
344
0
  if (args[0].ident_expr().name() == kAccumulatorVariableName) {
345
0
    return factory.ReportErrorAt(
346
0
        args[1], absl::StrCat("optFlatMap() variable name cannot be ",
347
0
                              kAccumulatorVariableName));
348
0
  }
349
0
  auto var_name = args[0].ident_expr().name();
350
351
0
  auto target_copy = factory.Copy(target);
352
0
  std::vector<Expr> call_args;
353
0
  call_args.reserve(3);
354
0
  call_args.push_back(factory.NewMemberCall("hasValue", std::move(target)));
355
0
  auto iter_range = factory.NewList();
356
0
  auto accu_init = factory.NewMemberCall("value", std::move(target_copy));
357
0
  auto condition = factory.NewBoolConst(false);
358
0
  call_args.push_back(factory.NewComprehension(
359
0
      "#unused", std::move(iter_range), std::move(var_name),
360
0
      std::move(accu_init), std::move(condition), std::move(args[0]),
361
0
      std::move(args[1])));
362
0
  call_args.push_back(factory.NewCall("optional.none"));
363
0
  return factory.NewCall(CelOperator::CONDITIONAL, std::move(call_args));
364
0
}
365
366
0
Macro MakeOptFlatMapMacro() {
367
0
  auto status_or_macro =
368
0
      Macro::Receiver("optFlatMap", 2, ExpandOptFlatMapMacro);
369
0
  ABSL_CHECK_OK(status_or_macro);  // Crash OK
370
0
  return std::move(*status_or_macro);
371
0
}
372
373
}  // namespace
374
375
absl::StatusOr<Macro> Macro::Global(absl::string_view name,
376
                                    size_t argument_count,
377
1
                                    GlobalMacroExpander expander) {
378
1
  if (!expander) {
379
0
    return absl::InvalidArgumentError(
380
0
        absl::StrCat("macro expander for `", name, "` cannot be empty"));
381
0
  }
382
1
  return Make(name, argument_count, ToMacroExpander(std::move(expander)),
383
1
              /*receiver_style=*/false, /*var_arg_style=*/false);
384
1
}
385
386
absl::StatusOr<Macro> Macro::GlobalVarArg(absl::string_view name,
387
0
                                          GlobalMacroExpander expander) {
388
0
  if (!expander) {
389
0
    return absl::InvalidArgumentError(
390
0
        absl::StrCat("macro expander for `", name, "` cannot be empty"));
391
0
  }
392
0
  return Make(name, 0, ToMacroExpander(std::move(expander)),
393
0
              /*receiver_style=*/false,
394
0
              /*var_arg_style=*/true);
395
0
}
396
397
absl::StatusOr<Macro> Macro::Receiver(absl::string_view name,
398
                                      size_t argument_count,
399
6
                                      ReceiverMacroExpander expander) {
400
6
  if (!expander) {
401
0
    return absl::InvalidArgumentError(
402
0
        absl::StrCat("macro expander for `", name, "` cannot be empty"));
403
0
  }
404
6
  return Make(name, argument_count, ToMacroExpander(std::move(expander)),
405
6
              /*receiver_style=*/true, /*var_arg_style=*/false);
406
6
}
407
408
absl::StatusOr<Macro> Macro::ReceiverVarArg(absl::string_view name,
409
0
                                            ReceiverMacroExpander expander) {
410
0
  if (!expander) {
411
0
    return absl::InvalidArgumentError(
412
0
        absl::StrCat("macro expander for `", name, "` cannot be empty"));
413
0
  }
414
0
  return Make(name, 0, ToMacroExpander(std::move(expander)),
415
0
              /*receiver_style=*/true,
416
0
              /*var_arg_style=*/true);
417
0
}
418
419
4.23k
std::vector<Macro> Macro::AllMacros() {
420
4.23k
  return {HasMacro(),  AllMacro(),  ExistsMacro(), ExistsOneMacro(),
421
4.23k
          Map2Macro(), Map3Macro(), FilterMacro()};
422
4.23k
}
423
424
std::string Macro::Key(absl::string_view name, size_t argument_count,
425
7
                       bool receiver_style, bool var_arg_style) {
426
7
  if (var_arg_style) {
427
0
    return absl::StrCat(name, ":*:", receiver_style ? "true" : "false");
428
0
  }
429
7
  return absl::StrCat(name, ":", argument_count, ":",
430
7
                      receiver_style ? "true" : "false");
431
7
}
432
433
absl::StatusOr<Macro> Macro::Make(absl::string_view name, size_t argument_count,
434
                                  MacroExpander expander, bool receiver_style,
435
7
                                  bool var_arg_style) {
436
7
  if (!internal::LexisIsIdentifier(name)) {
437
0
    return absl::InvalidArgumentError(absl::StrCat(
438
0
        "macro function name `", name, "` is not a valid identifier"));
439
0
  }
440
7
  if (!expander) {
441
0
    return absl::InvalidArgumentError(
442
0
        absl::StrCat("macro expander for `", name, "` cannot be empty"));
443
0
  }
444
7
  return Macro(std::make_shared<Rep>(
445
7
      std::string(name),
446
7
      Key(name, argument_count, receiver_style, var_arg_style), argument_count,
447
7
      std::move(expander), receiver_style, var_arg_style));
448
7
}
449
450
4.23k
const Macro& HasMacro() {
451
4.23k
  static const absl::NoDestructor<Macro> macro(MakeHasMacro());
452
4.23k
  return *macro;
453
4.23k
}
454
455
4.23k
const Macro& AllMacro() {
456
4.23k
  static const absl::NoDestructor<Macro> macro(MakeAllMacro());
457
4.23k
  return *macro;
458
4.23k
}
459
460
4.23k
const Macro& ExistsMacro() {
461
4.23k
  static const absl::NoDestructor<Macro> macro(MakeExistsMacro());
462
4.23k
  return *macro;
463
4.23k
}
464
465
4.23k
const Macro& ExistsOneMacro() {
466
4.23k
  static const absl::NoDestructor<Macro> macro(MakeExistsOneMacro());
467
4.23k
  return *macro;
468
4.23k
}
469
470
4.23k
const Macro& Map2Macro() {
471
4.23k
  static const absl::NoDestructor<Macro> macro(MakeMap2Macro());
472
4.23k
  return *macro;
473
4.23k
}
474
475
4.23k
const Macro& Map3Macro() {
476
4.23k
  static const absl::NoDestructor<Macro> macro(MakeMap3Macro());
477
4.23k
  return *macro;
478
4.23k
}
479
480
4.23k
const Macro& FilterMacro() {
481
4.23k
  static const absl::NoDestructor<Macro> macro(MakeFilterMacro());
482
4.23k
  return *macro;
483
4.23k
}
484
485
0
const Macro& OptMapMacro() {
486
0
  static const absl::NoDestructor<Macro> macro(MakeOptMapMacro());
487
0
  return *macro;
488
0
}
489
490
0
const Macro& OptFlatMapMacro() {
491
0
  static const absl::NoDestructor<Macro> macro(MakeOptFlatMapMacro());
492
0
  return *macro;
493
0
}
494
495
}  // namespace cel