|
32 | 32 |
|
33 | 33 | namespace clang {
|
34 | 34 | namespace transformer {
|
35 |
| -/// A stencil is represented as a sequence of "parts" that can each individually |
36 |
| -/// generate a code string based on a match result. The different kinds of |
37 |
| -/// parts include (raw) text, references to bound nodes and assorted operations |
38 |
| -/// on bound nodes. |
39 |
| -/// |
40 |
| -/// Users can create custom Stencil operations by implementing this interface. |
41 |
| -class StencilPartInterface { |
| 35 | +class StencilInterface { |
42 | 36 | public:
|
43 |
| - virtual ~StencilPartInterface() = default; |
| 37 | + virtual ~StencilInterface() = default; |
44 | 38 |
|
45 | 39 | /// Evaluates this part to a string and appends it to \c Result. \c Result is
|
46 |
| - /// undefined in the case of an error. |
| 40 | + /// undefined in the case of an error. `Result` is an out parameter to |
| 41 | + /// optimize the expected common case of evaluating a sequence of generators. |
47 | 42 | virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
|
48 | 43 | std::string *Result) const = 0;
|
49 | 44 |
|
50 |
| - /// Constructs a string representation of the StencilPart. StencilParts |
51 |
| - /// generated by the `selection` and `run` functions do not have a unique |
52 |
| - /// string representation. |
| 45 | + /// Convenience version of `eval`, for the case where the generator is being |
| 46 | + /// evaluated on its own. |
| 47 | + llvm::Expected<std::string> |
| 48 | + eval(const ast_matchers::MatchFinder::MatchResult &R) const; |
| 49 | + |
| 50 | + /// Constructs a string representation of the StencilInterface. The |
| 51 | + /// representation must be deterministic, but is not required to be unique. |
53 | 52 | virtual std::string toString() const = 0;
|
54 | 53 |
|
55 | 54 | protected:
|
56 |
| - StencilPartInterface() = default; |
| 55 | + StencilInterface() = default; |
57 | 56 |
|
58 | 57 | // Since this is an abstract class, copying/assigning only make sense for
|
59 | 58 | // derived classes implementing `clone()`.
|
60 |
| - StencilPartInterface(const StencilPartInterface &) = default; |
61 |
| - StencilPartInterface &operator=(const StencilPartInterface &) = default; |
62 |
| -}; |
63 |
| - |
64 |
| -/// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result |
65 |
| -/// in a copy of the underlying pointee object. |
66 |
| -class StencilPart { |
67 |
| -public: |
68 |
| - explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl) |
69 |
| - : Impl(std::move(Impl)) {} |
70 |
| - |
71 |
| - /// See `StencilPartInterface::eval()`. |
72 |
| - llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, |
73 |
| - std::string *Result) const { |
74 |
| - return Impl->eval(Match, Result); |
75 |
| - } |
76 |
| - |
77 |
| - std::string toString() const { |
78 |
| - if (Impl == nullptr) |
79 |
| - return ""; |
80 |
| - return Impl->toString(); |
81 |
| - } |
82 |
| - |
83 |
| -private: |
84 |
| - std::shared_ptr<StencilPartInterface> Impl; |
| 59 | + StencilInterface(const StencilInterface &) = default; |
| 60 | + StencilInterface &operator=(const StencilInterface &) = default; |
85 | 61 | };
|
86 | 62 |
|
87 | 63 | /// A sequence of code fragments, references to parameters and code-generation
|
88 |
| -/// operations that together can be evaluated to (a fragment of) source code, |
89 |
| -/// given a match result. |
| 64 | +/// operations that together can be evaluated to (a fragment of) source code or |
| 65 | +/// a diagnostic message, given a match result. |
| 66 | +/// |
| 67 | +/// We use a `shared_ptr` to allow for easy and cheap copying of stencils. |
| 68 | +/// Since `StencilInterface` is an immutable interface, the sharing doesn't |
| 69 | +/// impose any risks. Otherwise, we would have to add a virtual `copy` method to |
| 70 | +/// the API and implement it for all derived classes. |
90 | 71 | class Stencil {
|
| 72 | + std::shared_ptr<StencilInterface> Impl; |
| 73 | + |
91 | 74 | public:
|
92 | 75 | Stencil() = default;
|
93 |
| - Stencil(std::vector<StencilPart> Parts) : Parts(std::move(Parts)) {} |
94 |
| - |
95 |
| - /// Composes a stencil from a series of parts. |
96 |
| - template <typename... Ts> static Stencil cat(Ts &&... Parts) { |
97 |
| - Stencil S; |
98 |
| - S.Parts = {wrap(std::forward<Ts>(Parts))...}; |
99 |
| - return S; |
100 |
| - } |
| 76 | + explicit Stencil(std::shared_ptr<StencilInterface> Ptr) |
| 77 | + : Impl(std::move(Ptr)) {} |
101 | 78 |
|
102 |
| - /// Appends data from a \p OtherStencil to this stencil. |
103 |
| - void append(Stencil OtherStencil); |
| 79 | + StencilInterface *operator->() const { return Impl.get(); } |
104 | 80 |
|
105 |
| - // Evaluates the stencil given a match result. Requires that the nodes in the |
106 |
| - // result includes any ids referenced in the stencil. References to missing |
107 |
| - // nodes will result in an invalid_argument error. |
108 | 81 | llvm::Expected<std::string>
|
109 |
| - eval(const ast_matchers::MatchFinder::MatchResult &Match) const; |
110 |
| - |
111 |
| - // Allow Stencils to operate as std::function, for compatibility with |
112 |
| - // Transformer's TextGenerator. |
113 |
| - llvm::Expected<std::string> |
114 |
| - operator()(const ast_matchers::MatchFinder::MatchResult &Result) const { |
115 |
| - return eval(Result); |
116 |
| - } |
117 |
| - |
118 |
| - /// Constructs a string representation of the Stencil. The string is not |
119 |
| - /// guaranteed to be unique. |
120 |
| - std::string toString() const { |
121 |
| - std::vector<std::string> PartStrings; |
122 |
| - PartStrings.reserve(Parts.size()); |
123 |
| - for (const auto &Part : Parts) |
124 |
| - PartStrings.push_back(Part.toString()); |
125 |
| - return llvm::join(PartStrings, ", "); |
| 82 | + operator()(const ast_matchers::MatchFinder::MatchResult &R) { |
| 83 | + return Impl->eval(R); |
126 | 84 | }
|
127 |
| - |
128 |
| -private: |
129 |
| - static StencilPart wrap(llvm::StringRef Text); |
130 |
| - static StencilPart wrap(RangeSelector Selector); |
131 |
| - static StencilPart wrap(StencilPart Part) { return Part; } |
132 |
| - |
133 |
| - std::vector<StencilPart> Parts; |
134 | 85 | };
|
135 | 86 |
|
| 87 | +namespace detail { |
| 88 | +/// Convenience function to construct a \c Stencil. Overloaded for common cases |
| 89 | +/// so that user doesn't need to specify which factory function to use. This |
| 90 | +/// pattern gives benefits similar to implicit constructors, while maintaing a |
| 91 | +/// higher degree of explictness. |
| 92 | +Stencil makeStencil(llvm::StringRef Text); |
| 93 | +Stencil makeStencil(RangeSelector Selector); |
| 94 | +inline Stencil makeStencil(Stencil S) { return S; } |
| 95 | +} // namespace detail |
| 96 | + |
| 97 | +/// Constructs the string representing the concatenation of the given \p |
| 98 | +/// Parts. If only one element is passed in \p Parts, returns that element. |
| 99 | +Stencil catVector(std::vector<Stencil> Parts); |
| 100 | + |
| 101 | +/// Concatenates 0+ stencil pieces into a single stencil. Arguments can be raw |
| 102 | +/// text, ranges in the matched code (\p RangeSelector) or other `Stencil`s. |
| 103 | +template <typename... Ts> Stencil cat(Ts &&... Parts) { |
| 104 | + return catVector({detail::makeStencil(std::forward<Ts>(Parts))...}); |
| 105 | +} |
| 106 | + |
136 | 107 | //
|
137 | 108 | // Functions for conveniently building stencils.
|
138 | 109 | //
|
139 | 110 |
|
140 |
| -/// Convenience wrapper for Stencil::cat that can be imported with a using decl. |
141 |
| -template <typename... Ts> Stencil cat(Ts &&... Parts) { |
142 |
| - return Stencil::cat(std::forward<Ts>(Parts)...); |
143 |
| -} |
144 |
| -/// Convenience wrapper for Stencil constructor of the same type. Declaration |
145 |
| -/// outside of the class supports transition of `Stencil` type to an alias |
146 |
| -/// rather than a class. |
147 |
| -inline Stencil catVector(std::vector<StencilPart> Parts) { |
148 |
| - return Stencil(std::move(Parts)); |
149 |
| -} |
150 |
| - |
151 | 111 | /// \returns exactly the text provided.
|
152 |
| -StencilPart text(llvm::StringRef Text); |
| 112 | +Stencil text(llvm::StringRef Text); |
153 | 113 |
|
154 | 114 | /// \returns the source corresponding to the selected range.
|
155 |
| -StencilPart selection(RangeSelector Selector); |
| 115 | +Stencil selection(RangeSelector Selector); |
156 | 116 |
|
157 | 117 | /// Generates the source of the expression bound to \p Id, wrapping it in
|
158 | 118 | /// parentheses if it may parse differently depending on context. For example, a
|
159 | 119 | /// binary operation is always wrapped, while a variable reference is never
|
160 | 120 | /// wrapped.
|
161 |
| -StencilPart expression(llvm::StringRef Id); |
| 121 | +Stencil expression(llvm::StringRef Id); |
162 | 122 |
|
163 | 123 | /// Constructs an idiomatic dereferencing of the expression bound to \p ExprId.
|
164 | 124 | /// \p ExprId is wrapped in parentheses, if needed.
|
165 |
| -StencilPart deref(llvm::StringRef ExprId); |
| 125 | +Stencil deref(llvm::StringRef ExprId); |
166 | 126 |
|
167 | 127 | /// Constructs an expression that idiomatically takes the address of the
|
168 | 128 | /// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if
|
169 | 129 | /// needed.
|
170 |
| -StencilPart addressOf(llvm::StringRef ExprId); |
| 130 | +Stencil addressOf(llvm::StringRef ExprId); |
171 | 131 |
|
172 | 132 | /// Constructs a `MemberExpr` that accesses the named member (\p Member) of the
|
173 | 133 | /// object bound to \p BaseId. The access is constructed idiomatically: if \p
|
174 | 134 | /// BaseId is bound to `e` and \p Member identifies member `m`, then returns
|
175 | 135 | /// `e->m`, when e is a pointer, `e2->m` when e = `*e2` and `e.m` otherwise.
|
176 | 136 | /// Additionally, `e` is wrapped in parentheses, if needed.
|
177 |
| -StencilPart access(llvm::StringRef BaseId, StencilPart Member); |
178 |
| -inline StencilPart access(llvm::StringRef BaseId, llvm::StringRef Member) { |
| 137 | +Stencil access(llvm::StringRef BaseId, Stencil Member); |
| 138 | +inline Stencil access(llvm::StringRef BaseId, llvm::StringRef Member) { |
179 | 139 | return access(BaseId, text(Member));
|
180 | 140 | }
|
181 | 141 |
|
182 | 142 | /// Chooses between the two stencil parts, based on whether \p ID is bound in
|
183 | 143 | /// the match.
|
184 |
| -StencilPart ifBound(llvm::StringRef Id, StencilPart TruePart, |
185 |
| - StencilPart FalsePart); |
| 144 | +Stencil ifBound(llvm::StringRef Id, Stencil TrueStencil, Stencil FalseStencil); |
186 | 145 |
|
187 | 146 | /// Chooses between the two strings, based on whether \p ID is bound in the
|
188 | 147 | /// match.
|
189 |
| -inline StencilPart ifBound(llvm::StringRef Id, llvm::StringRef TrueText, |
190 |
| - llvm::StringRef FalseText) { |
| 148 | +inline Stencil ifBound(llvm::StringRef Id, llvm::StringRef TrueText, |
| 149 | + llvm::StringRef FalseText) { |
191 | 150 | return ifBound(Id, text(TrueText), text(FalseText));
|
192 | 151 | }
|
193 | 152 |
|
194 |
| -/// Wraps a MatchConsumer in a StencilPart, so that it can be used in a Stencil. |
195 |
| -/// This supports user-defined extensions to the Stencil language. |
196 |
| -StencilPart run(MatchConsumer<std::string> C); |
| 153 | +/// Wraps a \c MatchConsumer in a \c Stencil, so that it can be used in a \c |
| 154 | +/// Stencil. This supports user-defined extensions to the \c Stencil language. |
| 155 | +Stencil run(MatchConsumer<std::string> C); |
197 | 156 |
|
198 | 157 | /// For debug use only; semantics are not guaranteed.
|
199 | 158 | ///
|
200 | 159 | /// \returns the string resulting from calling the node's print() method.
|
201 |
| -StencilPart dPrint(llvm::StringRef Id); |
| 160 | +Stencil dPrint(llvm::StringRef Id); |
202 | 161 | } // namespace transformer
|
203 |
| - |
204 |
| -namespace tooling { |
205 |
| -// DEPRECATED: These are temporary aliases supporting client migration to the |
206 |
| -// `transformer` namespace. |
207 |
| -using Stencil = transformer::Stencil; |
208 |
| -using StencilPart = transformer::StencilPart; |
209 |
| -namespace stencil { |
210 |
| -using transformer::access; |
211 |
| -using transformer::addressOf; |
212 |
| -using transformer::cat; |
213 |
| -using transformer::deref; |
214 |
| -using transformer::dPrint; |
215 |
| -using transformer::expression; |
216 |
| -using transformer::ifBound; |
217 |
| -using transformer::run; |
218 |
| -using transformer::selection; |
219 |
| -using transformer::text; |
220 |
| -/// \returns the source corresponding to the identified node. |
221 |
| -/// FIXME: Deprecated. Write `selection(node(Id))` instead. |
222 |
| -inline transformer::StencilPart node(llvm::StringRef Id) { |
223 |
| - return selection(tooling::node(Id)); |
224 |
| -} |
225 |
| -} // namespace stencil |
226 |
| -} // namespace tooling |
227 | 162 | } // namespace clang
|
228 | 163 | #endif // LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
|
0 commit comments