/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 |