Coverage Report

Created: 2023-11-19 06:10

/proc/self/cwd/parser/macro.cc
Line
Count
Source (jump to first uncovered line)
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 <cstdint>
19
#include <memory>
20
#include <string>
21
#include <utility>
22
#include <vector>
23
24
#include "absl/status/status.h"
25
#include "absl/status/statusor.h"
26
#include "absl/strings/str_cat.h"
27
#include "absl/strings/string_view.h"
28
#include "common/operators.h"
29
#include "internal/lexis.h"
30
#include "internal/no_destructor.h"
31
#include "parser/source_factory.h"
32
33
namespace cel {
34
35
namespace {
36
37
using google::api::expr::v1alpha1::Expr;
38
using google::api::expr::common::CelOperator;
39
40
absl::StatusOr<Macro> MakeMacro(absl::string_view name, size_t argument_count,
41
                                MacroExpander expander,
42
0
                                bool is_receiver_style) {
43
0
  if (!internal::LexisIsIdentifier(name)) {
44
0
    return absl::InvalidArgumentError(absl::StrCat(
45
0
        "Macro function name \"", name, "\" is not a valid identifier"));
46
0
  }
47
0
  if (!expander) {
48
0
    return absl::InvalidArgumentError(
49
0
        absl::StrCat("Macro expander for \"", name, "\" cannot be empty"));
50
0
  }
51
0
  return Macro(name, argument_count, std::move(expander), is_receiver_style);
52
0
}
53
54
absl::StatusOr<Macro> MakeMacro(absl::string_view name, MacroExpander expander,
55
0
                                bool is_receiver_style) {
56
0
  if (!internal::LexisIsIdentifier(name)) {
57
0
    return absl::InvalidArgumentError(absl::StrCat(
58
0
        "Macro function name \"", name, "\" is not a valid identifier"));
59
0
  }
60
0
  if (!expander) {
61
0
    return absl::InvalidArgumentError(
62
0
        absl::StrCat("Macro expander for \"", name, "\" cannot be empty"));
63
0
  }
64
0
  return Macro(name, std::move(expander), is_receiver_style);
65
0
}
66
67
}  // namespace
68
69
absl::StatusOr<Macro> Macro::Global(absl::string_view name,
70
                                    size_t argument_count,
71
0
                                    MacroExpander expander) {
72
0
  return MakeMacro(name, argument_count, std::move(expander), false);
73
0
}
74
75
absl::StatusOr<Macro> Macro::GlobalVarArg(absl::string_view name,
76
0
                                          MacroExpander expander) {
77
0
  return MakeMacro(name, std::move(expander), false);
78
0
}
79
80
absl::StatusOr<Macro> Macro::Receiver(absl::string_view name,
81
                                      size_t argument_count,
82
0
                                      MacroExpander expander) {
83
0
  return MakeMacro(name, argument_count, std::move(expander), true);
84
0
}
85
86
absl::StatusOr<Macro> Macro::ReceiverVarArg(absl::string_view name,
87
0
                                            MacroExpander expander) {
88
0
  return MakeMacro(name, std::move(expander), true);
89
0
}
90
91
7.53k
std::vector<Macro> Macro::AllMacros() {
92
7.53k
  return {HasMacro(),  AllMacro(),  ExistsMacro(), ExistsOneMacro(),
93
7.53k
          Map2Macro(), Map3Macro(), FilterMacro()};
94
7.53k
}
95
96
7.53k
Macro HasMacro() {
97
  // The macro "has(m.f)" which tests the presence of a field, avoiding the
98
  // need to specify the field as a string.
99
7.53k
  static const internal::NoDestructor<Macro> macro(
100
7.53k
      CelOperator::HAS, 1,
101
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
102
7.53k
         const Expr& target, const std::vector<Expr>& args) {
103
488
        if (!args.empty() && args[0].has_select_expr()) {
104
262
          const auto& sel_expr = args[0].select_expr();
105
262
          return sf->NewPresenceTestForMacro(macro_id, sel_expr.operand(),
106
262
                                             sel_expr.field());
107
262
        } else {
108
          // error
109
226
          return Expr();
110
226
        }
111
488
      });
112
7.53k
  return macro.get();
113
7.53k
}
114
115
7.53k
Macro AllMacro() {
116
  // The macro "range.all(var, predicate)", which is true if for all
117
  // elements in range the predicate holds.
118
7.53k
  static const internal::NoDestructor<Macro> macro(
119
7.53k
      CelOperator::ALL, 2,
120
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
121
7.53k
         const Expr& target, const std::vector<Expr>& args) {
122
1.05k
        return sf->NewQuantifierExprForMacro(SourceFactory::QUANTIFIER_ALL,
123
1.05k
                                             macro_id, target, args);
124
1.05k
      },
125
7.53k
      /* receiver style*/ true);
126
7.53k
  return macro.get();
127
7.53k
}
128
129
7.53k
Macro ExistsMacro() {
130
  // The macro "range.exists(var, predicate)", which is true if for at least
131
  // one element in range the predicate holds.
132
7.53k
  static const internal::NoDestructor<Macro> macro(
133
7.53k
      CelOperator::EXISTS, 2,
134
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
135
7.53k
         const Expr& target, const std::vector<Expr>& args) {
136
425
        return sf->NewQuantifierExprForMacro(SourceFactory::QUANTIFIER_EXISTS,
137
425
                                             macro_id, target, args);
138
425
      },
139
7.53k
      /* receiver style*/ true);
140
7.53k
  return macro.get();
141
7.53k
}
142
143
7.53k
Macro ExistsOneMacro() {
144
  // The macro "range.exists_one(var, predicate)", which is true if for
145
  // exactly one element in range the predicate holds.
146
7.53k
  static const internal::NoDestructor<Macro> macro(
147
7.53k
      CelOperator::EXISTS_ONE, 2,
148
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
149
7.53k
         const Expr& target, const std::vector<Expr>& args) {
150
945
        return sf->NewQuantifierExprForMacro(
151
945
            SourceFactory::QUANTIFIER_EXISTS_ONE, macro_id, target, args);
152
945
      },
153
7.53k
      /* receiver style*/ true);
154
7.53k
  return macro.get();
155
7.53k
}
156
157
7.53k
Macro Map2Macro() {
158
  // The macro "range.map(var, function)", applies the function to the vars
159
  // in the range.
160
7.53k
  static const internal::NoDestructor<Macro> macro(
161
7.53k
      CelOperator::MAP, 2,
162
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
163
7.53k
         const Expr& target, const std::vector<Expr>& args) {
164
770
        return sf->NewMapForMacro(macro_id, target, args);
165
770
      },
166
7.53k
      /* receiver style*/ true);
167
7.53k
  return macro.get();
168
7.53k
}
169
170
7.53k
Macro Map3Macro() {
171
  // The macro "range.map(var, predicate, function)", applies the function
172
  // to the vars in the range for which the predicate holds true. The other
173
  // variables are filtered out.
174
7.53k
  static const internal::NoDestructor<Macro> macro(
175
7.53k
      CelOperator::MAP, 3,
176
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
177
7.53k
         const Expr& target, const std::vector<Expr>& args) {
178
427
        return sf->NewMapForMacro(macro_id, target, args);
179
427
      },
180
7.53k
      /* receiver style*/ true);
181
7.53k
  return macro.get();
182
7.53k
}
183
184
7.53k
Macro FilterMacro() {
185
  // The macro "range.filter(var, predicate)", filters out the variables for
186
  // which the predicate is false.
187
7.53k
  static const internal::NoDestructor<Macro> macro(
188
7.53k
      CelOperator::FILTER, 2,
189
7.53k
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
190
7.53k
         const Expr& target, const std::vector<Expr>& args) {
191
472
        return sf->NewFilterExprForMacro(macro_id, target, args);
192
472
      },
193
7.53k
      /* receiver style*/ true);
194
7.53k
  return macro.get();
195
7.53k
}
196
197
0
Macro OptMapMacro() {
198
0
  static const internal::NoDestructor<Macro> macro(
199
0
      "optMap", 2,
200
0
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
201
0
         const Expr& target, const std::vector<Expr>& args) -> Expr {
202
0
        if (args.size() != 2) {
203
0
          return sf->ReportError(args[0].id(), "optMap() requires 2 arguments");
204
0
        }
205
0
        if (!args[0].has_ident_expr()) {
206
0
          return sf->ReportError(
207
0
              args[0].id(),
208
0
              "optMap() variable name must be a simple identifier");
209
0
        }
210
0
        const auto& var_name = args[0].ident_expr().name();
211
0
        const auto& map_expr = args[1];
212
213
0
        std::vector<Expr> call_args;
214
0
        call_args.resize(3);
215
0
        call_args[0] =
216
0
            sf->NewReceiverCallForMacro(macro_id, "hasValue", target, {});
217
0
        auto iter_range = sf->NewListForMacro(macro_id, {});
218
0
        auto accu_init =
219
0
            sf->NewReceiverCallForMacro(macro_id, "value", target, {});
220
0
        auto condition = sf->NewLiteralBoolForMacro(macro_id, false);
221
0
        auto step = sf->NewIdentForMacro(macro_id, var_name);
222
0
        const auto& result = map_expr;
223
0
        auto fold = sf->FoldForMacro(macro_id, "#unused", iter_range, var_name,
224
0
                                     accu_init, condition, step, result);
225
0
        call_args[1] =
226
0
            sf->NewGlobalCallForMacro(macro_id, "optional.of", {fold});
227
0
        call_args[2] = sf->NewGlobalCallForMacro(macro_id, "optional.none", {});
228
0
        return sf->NewGlobalCallForMacro(macro_id, CelOperator::CONDITIONAL,
229
0
                                         call_args);
230
0
      },
231
0
      true);
232
0
  return macro.get();
233
0
}
234
235
0
Macro OptFlatMapMacro() {
236
0
  static const internal::NoDestructor<Macro> macro(
237
0
      "optFlatMap", 2,
238
0
      [](const std::shared_ptr<SourceFactory>& sf, int64_t macro_id,
239
0
         const Expr& target, const std::vector<Expr>& args) -> Expr {
240
0
        if (args.size() != 2) {
241
0
          return sf->ReportError(args[0].id(),
242
0
                                 "optFlatMap() requires 2 arguments");
243
0
        }
244
0
        if (!args[0].has_ident_expr()) {
245
0
          return sf->ReportError(
246
0
              args[0].id(),
247
0
              "optFlatMap() variable name must be a simple identifier");
248
0
        }
249
0
        const auto& var_name = args[0].ident_expr().name();
250
0
        const auto& map_expr = args[1];
251
0
        std::vector<Expr> call_args;
252
0
        call_args.resize(3);
253
0
        call_args[0] =
254
0
            sf->NewReceiverCallForMacro(macro_id, "hasValue", target, {});
255
0
        auto iter_range = sf->NewListForMacro(macro_id, {});
256
0
        auto accu_init =
257
0
            sf->NewReceiverCallForMacro(macro_id, "value", target, {});
258
0
        auto condition = sf->NewLiteralBoolForMacro(macro_id, false);
259
0
        auto step = sf->NewIdentForMacro(macro_id, var_name);
260
0
        const auto& result = map_expr;
261
0
        call_args[1] =
262
0
            sf->FoldForMacro(macro_id, "#unused", iter_range, var_name,
263
0
                             accu_init, condition, step, result);
264
0
        call_args[2] = sf->NewGlobalCallForMacro(macro_id, "optional.none", {});
265
0
        return sf->NewGlobalCallForMacro(macro_id, CelOperator::CONDITIONAL,
266
0
                                         call_args);
267
0
      },
268
0
      true);
269
0
  return macro.get();
270
0
}
271
272
}  // namespace cel