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.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_