/proc/self/cwd/parser/macro.h
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 | | #ifndef THIRD_PARTY_CEL_CPP_PARSER_MACRO_H_ |
16 | | #define THIRD_PARTY_CEL_CPP_PARSER_MACRO_H_ |
17 | | |
18 | | #include <cstddef> |
19 | | #include <functional> |
20 | | #include <memory> |
21 | | #include <string> |
22 | | #include <utility> |
23 | | #include <vector> |
24 | | |
25 | | #include "absl/base/attributes.h" |
26 | | #include "absl/functional/any_invocable.h" |
27 | | #include "absl/status/statusor.h" |
28 | | #include "absl/strings/string_view.h" |
29 | | #include "absl/types/optional.h" |
30 | | #include "absl/types/span.h" |
31 | | #include "common/expr.h" |
32 | | #include "parser/macro_expr_factory.h" |
33 | | |
34 | | namespace cel { |
35 | | |
36 | | // MacroExpander converts the arguments of a function call that matches a |
37 | | // Macro. |
38 | | // |
39 | | // If this is a receiver-style macro, the second argument (optional expr) will |
40 | | // be engaged. In the case of a global call, it will be `absl::nullopt`. |
41 | | // |
42 | | // Should return the replacement subexpression if replacement should occur, |
43 | | // otherwise absl::nullopt. If `absl::nullopt` is returned, none of the |
44 | | // arguments including the target must have been modified. Doing so is undefined |
45 | | // behavior. Otherwise the expander is free to mutate the arguments and either |
46 | | // include or exclude them from the result. |
47 | | // |
48 | | // We use `std::reference_wrapper<Expr>` to be consistent with the fact that we |
49 | | // do not use raw pointers elsewhere with `Expr` and friends. Ideally we would |
50 | | // just use `absl::optional<Expr&>`, but that is not currently allowed and our |
51 | | // `optional_ref<T>` is internal. |
52 | | using MacroExpander = absl::AnyInvocable<absl::optional<Expr>( |
53 | | MacroExprFactory&, absl::optional<std::reference_wrapper<Expr>>, |
54 | | absl::Span<Expr>) const>; |
55 | | |
56 | | // `GlobalMacroExpander` is a `MacroExpander` for global macros. |
57 | | using GlobalMacroExpander = absl::AnyInvocable<absl::optional<Expr>( |
58 | | MacroExprFactory&, absl::Span<Expr>) const>; |
59 | | |
60 | | // `ReceiverMacroExpander` is a `MacroExpander` for receiver-style macros. |
61 | | using ReceiverMacroExpander = absl::AnyInvocable<absl::optional<Expr>( |
62 | | MacroExprFactory&, Expr&, absl::Span<Expr>) const>; |
63 | | |
64 | | // Macro interface for describing the function signature to match and the |
65 | | // MacroExpander to apply. |
66 | | // |
67 | | // Note: when a Macro should apply to multiple overloads (based on arg count) of |
68 | | // a given function, a Macro should be created per arg-count. |
69 | | class Macro final { |
70 | | public: |
71 | | static absl::StatusOr<Macro> Global(absl::string_view name, |
72 | | size_t argument_count, |
73 | | GlobalMacroExpander expander); |
74 | | |
75 | | static absl::StatusOr<Macro> GlobalVarArg(absl::string_view name, |
76 | | GlobalMacroExpander expander); |
77 | | |
78 | | static absl::StatusOr<Macro> Receiver(absl::string_view name, |
79 | | size_t argument_count, |
80 | | ReceiverMacroExpander expander); |
81 | | |
82 | | static absl::StatusOr<Macro> ReceiverVarArg(absl::string_view name, |
83 | | ReceiverMacroExpander expander); |
84 | | |
85 | 92.1k | Macro(const Macro&) = default; |
86 | 46.2k | Macro(Macro&&) = default; |
87 | | Macro& operator=(const Macro&) = default; |
88 | | Macro& operator=(Macro&&) = default; |
89 | | |
90 | | // Function name to match. |
91 | 0 | absl::string_view function() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
92 | 0 | return rep_->function; |
93 | 0 | } |
94 | | |
95 | | // argument_count() for the function call. |
96 | | // |
97 | | // When the macro is a var-arg style macro, the return value will be zero, but |
98 | | // the MacroKey will contain a `*` where the arg count would have been. |
99 | 0 | size_t argument_count() const { return rep_->arg_count; } |
100 | | |
101 | | // is_receiver_style returns true if the macro matches a receiver style call. |
102 | 0 | bool is_receiver_style() const { return rep_->receiver_style; } |
103 | | |
104 | 0 | bool is_variadic() const { return rep_->var_arg_style; } |
105 | | |
106 | | // key() returns the macro signatures accepted by this macro. |
107 | | // |
108 | | // Format: `<function>:<arg-count>:<is-receiver>`. |
109 | | // |
110 | | // When the macros is a var-arg style macro, the `arg-count` value is |
111 | | // represented as a `*`. |
112 | 29.4k | absl::string_view key() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
113 | 29.4k | return rep_->key; |
114 | 29.4k | } |
115 | | |
116 | | // Expander returns the MacroExpander to apply when the macro key matches the |
117 | | // parsed call signature. |
118 | 3.48k | const MacroExpander& expander() const ABSL_ATTRIBUTE_LIFETIME_BOUND { |
119 | 3.48k | return rep_->expander; |
120 | 3.48k | } |
121 | | |
122 | | ABSL_MUST_USE_RESULT absl::optional<Expr> Expand( |
123 | | MacroExprFactory& factory, |
124 | | absl::optional<std::reference_wrapper<Expr>> target, |
125 | 3.48k | absl::Span<Expr> arguments) const { |
126 | 3.48k | return (expander())(factory, target, arguments); |
127 | 3.48k | } |
128 | | |
129 | 0 | friend void swap(Macro& lhs, Macro& rhs) noexcept { |
130 | 0 | using std::swap; |
131 | 0 | swap(lhs.rep_, rhs.rep_); |
132 | 0 | } |
133 | | |
134 | | ABSL_DEPRECATED("use MacroRegistry and RegisterStandardMacros") |
135 | | static std::vector<Macro> AllMacros(); |
136 | | |
137 | | private: |
138 | | struct Rep final { |
139 | | Rep(std::string function, std::string key, size_t arg_count, |
140 | | MacroExpander expander, bool receiver_style, bool var_arg_style) |
141 | 7 | : function(std::move(function)), |
142 | 7 | key(std::move(key)), |
143 | 7 | arg_count(arg_count), |
144 | 7 | expander(std::move(expander)), |
145 | 7 | receiver_style(receiver_style), |
146 | 7 | var_arg_style(var_arg_style) {} |
147 | | |
148 | | std::string function; |
149 | | std::string key; |
150 | | size_t arg_count; |
151 | | MacroExpander expander; |
152 | | bool receiver_style; |
153 | | bool var_arg_style; |
154 | | }; |
155 | | |
156 | | static std::string Key(absl::string_view name, size_t argument_count, |
157 | | bool receiver_style, bool var_arg_style); |
158 | | |
159 | | static absl::StatusOr<Macro> Make(absl::string_view name, |
160 | | size_t argument_count, |
161 | | MacroExpander expander, bool receiver_style, |
162 | | bool var_arg_style); |
163 | | |
164 | 7 | explicit Macro(std::shared_ptr<const Rep> rep) : rep_(std::move(rep)) {} |
165 | | |
166 | | std::shared_ptr<const Rep> rep_; |
167 | | }; |
168 | | |
169 | | // The macro "has(m.f)" which tests the presence of a field, avoiding the |
170 | | // need to specify the field as a string. |
171 | | const Macro& HasMacro(); |
172 | | |
173 | | // The macro "range.all(var, predicate)", which is true if for all |
174 | | // elements in range the predicate holds. |
175 | | const Macro& AllMacro(); |
176 | | |
177 | | // The macro "range.exists(var, predicate)", which is true if for at least |
178 | | // one element in range the predicate holds. |
179 | | const Macro& ExistsMacro(); |
180 | | |
181 | | // The macro "range.exists_one(var, predicate)", which is true if for |
182 | | // exactly one element in range the predicate holds. |
183 | | const Macro& ExistsOneMacro(); |
184 | | |
185 | | // The macro "range.map(var, function)", applies the function to the vars |
186 | | // in the range. |
187 | | const Macro& Map2Macro(); |
188 | | |
189 | | // The macro "range.map(var, predicate, function)", applies the function |
190 | | // to the vars in the range for which the predicate holds true. The other |
191 | | // variables are filtered out. |
192 | | const Macro& Map3Macro(); |
193 | | |
194 | | // The macro "range.filter(var, predicate)", filters out the variables for |
195 | | // which the predicate is false. |
196 | | const Macro& FilterMacro(); |
197 | | |
198 | | // `OptMapMacro` |
199 | | // |
200 | | // Apply a transformation to the optional's underlying value if it is not empty |
201 | | // and return an optional typed result based on the transformation. The |
202 | | // transformation expression type must return a type T which is wrapped into |
203 | | // an optional. |
204 | | // |
205 | | // msg.?elements.optMap(e, e.size()).orValue(0) |
206 | | const Macro& OptMapMacro(); |
207 | | |
208 | | // `OptFlatMapMacro` |
209 | | // |
210 | | // Apply a transformation to the optional's underlying value if it is not empty |
211 | | // and return the result. The transform expression must return an optional(T) |
212 | | // rather than type T. This can be useful when dealing with zero values and |
213 | | // conditionally generating an empty or non-empty result in ways which cannot |
214 | | // be expressed with `optMap`. |
215 | | // |
216 | | // msg.?elements.optFlatMap(e, e[?0]) // return the first element if present. |
217 | | const Macro& OptFlatMapMacro(); |
218 | | |
219 | | } // namespace cel |
220 | | |
221 | | namespace google::api::expr::parser { |
222 | | |
223 | | using MacroExpander = cel::MacroExpander; |
224 | | |
225 | | using Macro = cel::Macro; |
226 | | |
227 | | } // namespace google::api::expr::parser |
228 | | |
229 | | #endif // THIRD_PARTY_CEL_CPP_PARSER_MACRO_H_ |