CIRCT 20.0.0git
Loading...
Searching...
No Matches
PrettyPrinterHelpers.h
Go to the documentation of this file.
1//===- PrettyPrinterHelpers.h - Pretty printing helpers -------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Helper classes for using PrettyPrinter.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef CIRCT_SUPPORT_PRETTYPRINTERHELPERS_H
14#define CIRCT_SUPPORT_PRETTYPRINTERHELPERS_H
15
17#include "llvm/ADT/STLExtras.h"
18#include "llvm/ADT/ScopeExit.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/Support/Allocator.h"
21#include "llvm/Support/StringSaver.h"
22#include "llvm/Support/raw_ostream.h"
23#include <queue>
24
25namespace circt {
26namespace pretty {
27
28//===----------------------------------------------------------------------===//
29// PrettyPrinter standin that buffers tokens until flushed.
30//===----------------------------------------------------------------------===//
31
32/// Buffer tokens for clients that need to adjust things.
34 using BufferVec = SmallVectorImpl<Token>;
36 bool hasEOF = false;
37
39
40 void add(Token t) {
41 assert(!hasEOF);
42 tokens.push_back(t);
43 }
44
45 /// Add a range of tokens.
46 template <typename R>
47 void addTokens(R &&newTokens) {
48 assert(!hasEOF);
49 llvm::append_range(tokens, newTokens);
50 }
51
52 /// Buffer a final EOF, no tokens allowed after this.
53 void eof() {
54 assert(!hasEOF);
55 hasEOF = true;
56 }
57
58 /// Flush buffered tokens to the specified pretty printer.
59 /// Emit the EOF is one was added.
60 void flush(PrettyPrinter &pp) {
61 pp.addTokens(tokens);
62 tokens.clear();
63 if (hasEOF) {
64 pp.eof();
65 hasEOF = false;
66 }
67 }
68};
69
70//===----------------------------------------------------------------------===//
71// Convenience Token builders.
72//===----------------------------------------------------------------------===//
73
74namespace detail {
75void emitNBSP(unsigned n, llvm::function_ref<void(Token)> add);
76} // end namespace detail
77
78/// Add convenience methods for generating pretty-printing tokens.
79template <typename PPTy = PrettyPrinter>
81 PPTy &pp;
82
83public:
84 TokenBuilder(PPTy &pp) : pp(pp) {}
85
86 //===- Add tokens -------------------------------------------------------===//
87
88 /// Add new token.
89 template <typename T, typename... Args>
90 typename std::enable_if_t<std::is_base_of_v<Token, T>> add(Args &&...args) {
91 pp.add(T(std::forward<Args>(args)...));
92 }
93 void addToken(Token t) { pp.add(t); }
94
95 /// End of a stream.
96 void eof() { pp.eof(); }
97
98 //===- Strings ----------------------------------------------------------===//
99
100 /// Add a literal (with external storage).
101 void literal(StringRef str) { add<StringToken>(str); }
102
103 /// Add a non-breaking space.
104 void nbsp() { literal(" "); }
105
106 /// Add multiple non-breaking spaces as a single token.
107 void nbsp(unsigned n) {
108 detail::emitNBSP(n, [&](Token t) { addToken(t); });
109 }
110
111 //===- Breaks -----------------------------------------------------------===//
112
113 /// Add a 'neverbreak' break. Always 'fits'.
114 void neverbreak() { add<BreakToken>(0, 0, true); }
115
116 /// Add a newline (break too wide to fit, always breaks).
117 void newline() { add<BreakToken>(PrettyPrinter::kInfinity); }
118
119 /// Add breakable spaces.
120 void spaces(uint32_t n) { add<BreakToken>(n); }
121
122 /// Add a breakable space.
123 void space() { spaces(1); }
124
125 /// Add a break that is zero-wide if not broken.
126 void zerobreak() { add<BreakToken>(0); }
127
128 //===- Groups -----------------------------------------------------------===//
129
130 /// Start a IndentStyle::Block group with specified offset.
131 void bbox(int32_t offset = 0, Breaks breaks = Breaks::Consistent) {
132 add<BeginToken>(offset, breaks, IndentStyle::Block);
133 }
134
135 /// Start a consistent group with specified offset.
136 void cbox(int32_t offset = 0, IndentStyle style = IndentStyle::Visual) {
137 add<BeginToken>(offset, Breaks::Consistent, style);
138 }
139
140 /// Start an inconsistent group with specified offset.
141 void ibox(int32_t offset = 0, IndentStyle style = IndentStyle::Visual) {
142 add<BeginToken>(offset, Breaks::Inconsistent, style);
143 }
144
145 /// Start a group that cannot break, including nested groups.
146 /// Use sparingly.
147 void neverbox() { add<BeginToken>(0, Breaks::Never); }
148
149 /// End a group.
150 void end() { add<EndToken>(); }
151};
152
153/// PrettyPrinter::Listener that saves strings while live.
154/// Once they're no longer referenced, memory is reset.
155/// Allows differentiating between strings to save and external strings.
157 llvm::BumpPtrAllocator alloc;
158 llvm::StringSaver strings;
159
160public:
162
163 /// Add string, save in storage.
164 [[nodiscard]] StringRef save(StringRef str) { return strings.save(str); }
165
166 /// PrettyPrinter::Listener::clear -- indicates no external refs.
167 void clear() override;
168};
169
170/// Note: Callable class must implement a callable with signature:
171/// void (Data)
172template <typename CallableTy, typename DataTy>
174
175 /// List of all the unique data associated with each callback token.
176 /// The fact that tokens on a stream can never be printed out of order,
177 /// ensures that CallbackTokens are always added and invoked in FIFO order,
178 /// hence no need to record an index into the Data list.
179 std::queue<DataTy> dataQ;
180 /// The storage for the callback, as a function object.
181 CallableTy &callable;
182
183public:
185
186 /// PrettyPrinter::Listener::print -- indicates all the preceding tokens on
187 /// the stream have been printed.
188 /// This is invoked when the CallbackToken is printed.
189 void print() override {
190 std::invoke(callable, dataQ.front());
191 dataQ.pop();
192 }
193 /// Get a token with the obj data.
195 // Insert data onto the list.
196 dataQ.push(obj);
197 return CallbackToken();
198 }
199};
200
201//===----------------------------------------------------------------------===//
202// Streaming support.
203//===----------------------------------------------------------------------===//
204
205/// Send one of these to TokenStream to add the corresponding token.
206/// See TokenBuilder for details of each.
207enum class PP {
208 bbox2,
209 cbox0,
210 cbox2,
211 end,
212 eof,
213 ibox0,
214 ibox2,
215 nbsp,
216 neverbox,
218 newline,
219 space,
220 zerobreak,
221};
222
223/// String wrapper to indicate string has external storage.
225 StringRef str;
226 explicit PPExtString(StringRef str) : str(str) {}
227};
228
229/// String wrapper to indicate string needs to be saved.
231 StringRef str;
232 explicit PPSaveString(StringRef str) : str(str) {}
233};
234
235/// Wrap a PrettyPrinter with TokenBuilder features as well as operator<<'s.
236/// String behavior:
237/// Strings streamed as `const char *` are assumed to have external storage,
238/// and StringRef's are saved until no longer needed.
239/// Use PPExtString() and PPSaveString() wrappers to specify/override behavior.
240template <typename PPTy = PrettyPrinter>
241class TokenStream : public TokenBuilder<PPTy> {
243
244protected:
246
247public:
248 /// Create a TokenStream using the specified PrettyPrinter and StringSaver
249 /// storage. Strings are saved in `saver`, which is generally the listener in
250 /// the PrettyPrinter, but may not be (e.g., using BufferingPP).
252
253 /// Add a string literal (external storage).
254 TokenStream &operator<<(const char *s) {
255 Base::literal(s);
256 return *this;
257 }
258 /// Add a string token (saved to storage).
259 TokenStream &operator<<(StringRef s) {
260 Base::template add<StringToken>(saver.save(s));
261 return *this;
262 }
263
264 /// String has external storage.
266 Base::literal(str.str);
267 return *this;
268 }
269
270 /// String must be saved.
272 Base::template add<StringToken>(saver.save(str.str));
273 return *this;
274 }
275
276 /// Convenience for inline streaming of builder methods.
278 switch (s) {
279 case PP::bbox2:
280 Base::bbox(2);
281 break;
282 case PP::cbox0:
283 Base::cbox(0);
284 break;
285 case PP::cbox2:
286 Base::cbox(2);
287 break;
288 case PP::end:
289 Base::end();
290 break;
291 case PP::eof:
292 Base::eof();
293 break;
294 case PP::ibox0:
295 Base::ibox(0);
296 break;
297 case PP::ibox2:
298 Base::ibox(2);
299 break;
300 case PP::nbsp:
301 Base::nbsp();
302 break;
303 case PP::neverbox:
304 Base::neverbox();
305 break;
306 case PP::neverbreak:
307 Base::neverbreak();
308 break;
309 case PP::newline:
310 Base::newline();
311 break;
312 case PP::space:
313 Base::space();
314 break;
315 case PP::zerobreak:
316 Base::zerobreak();
317 break;
318 }
319 return *this;
320 }
321
322 /// Stream support for user-created Token's.
324 Base::addToken(t);
325 return *this;
326 }
327
328 /// General-purpose "format this" helper, for types not supported by
329 /// operator<< yet.
330 template <typename T>
332 invokeWithStringOS([&](auto &os) { os << std::forward<T>(t); });
333 return *this;
334 }
335
336 /// Helper to invoke code with a llvm::raw_ostream argument for compatibility.
337 /// All data is gathered into a single string token.
338 template <typename Callable, unsigned BufferLen = 128>
339 auto invokeWithStringOS(Callable &&c) {
340 SmallString<BufferLen> ss;
341 llvm::raw_svector_ostream ssos(ss);
342 auto flush = llvm::make_scope_exit([&]() {
343 if (!ss.empty())
344 *this << ss;
345 });
346 return std::invoke(std::forward<Callable>(c), ssos);
347 }
348
349 /// Write escaped versions of the string, saved in storage.
350 TokenStream &writeEscaped(StringRef str, bool useHexEscapes = false) {
351 return writeQuotedEscaped(str, useHexEscapes, "", "");
352 }
353 TokenStream &writeQuotedEscaped(StringRef str, bool useHexEscapes = false,
354 StringRef left = "\"",
355 StringRef right = "\"") {
356 // Add as a single StringToken.
357 invokeWithStringOS([&](auto &os) {
358 os << left;
359 os.write_escaped(str, useHexEscapes);
360 os << right;
361 });
362 return *this;
363 }
364
365 /// Open a box, invoke the lambda, and close it after.
366 template <typename T, typename Callable>
367 auto scopedBox(T &&t, Callable &&c, Token close = EndToken()) {
368 *this << std::forward<T>(t);
369 auto done = llvm::make_scope_exit([&]() { *this << close; });
370 return std::invoke(std::forward<Callable>(c));
371 }
372};
373
374/// Wrap the TokenStream with a helper for CallbackTokens, to record the print
375/// events on the stream.
376template <typename CallableType, typename DataType,
377 typename PPTy = PrettyPrinter>
381
382 const bool enableCallback;
383
384public:
390 /// Add a Callback token.
391 void addCallback(DataType d) {
392 if (enableCallback)
393 Base::addToken(saver.getToken(d));
394 }
395};
396} // end namespace pretty
397} // end namespace circt
398
399#endif // CIRCT_SUPPORT_PRETTYPRINTERHELPERS_H
assert(baseType &&"element must be base type")
void addTokens(R &&tokens)
Add a range of tokens.
static constexpr uint32_t kInfinity
Note: Callable class must implement a callable with signature: void (Data)
CallableTy & callable
The storage for the callback, as a function object.
CallbackToken getToken(DataTy obj)
Get a token with the obj data.
std::queue< DataTy > dataQ
List of all the unique data associated with each callback token.
void print() override
PrettyPrinter::Listener::print – indicates all the preceding tokens on the stream have been printed.
Add convenience methods for generating pretty-printing tokens.
std::enable_if_t< std::is_base_of_v< Token, T > > add(Args &&...args)
Add new token.
void literal(StringRef str)
Add a literal (with external storage).
void newline()
Add a newline (break too wide to fit, always breaks).
void ibox(int32_t offset=0, IndentStyle style=IndentStyle::Visual)
Start an inconsistent group with specified offset.
void bbox(int32_t offset=0, Breaks breaks=Breaks::Consistent)
Start a IndentStyle::Block group with specified offset.
void nbsp(unsigned n)
Add multiple non-breaking spaces as a single token.
void space()
Add a breakable space.
void cbox(int32_t offset=0, IndentStyle style=IndentStyle::Visual)
Start a consistent group with specified offset.
void spaces(uint32_t n)
Add breakable spaces.
void nbsp()
Add a non-breaking space.
void neverbreak()
Add a 'neverbreak' break. Always 'fits'.
void neverbox()
Start a group that cannot break, including nested groups.
void zerobreak()
Add a break that is zero-wide if not broken.
Wrap the TokenStream with a helper for CallbackTokens, to record the print events on the stream.
PrintEventAndStorageListener< CallableType, DataType > & saver
TokenStreamWithCallback(PPTy &pp, PrintEventAndStorageListener< CallableType, DataType > &saver, bool enableCallback)
void addCallback(DataType d)
Add a Callback token.
Wrap a PrettyPrinter with TokenBuilder features as well as operator<<'s.
TokenStream & operator<<(const PPExtString &str)
String has external storage.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
auto invokeWithStringOS(Callable &&c)
Helper to invoke code with a llvm::raw_ostream argument for compatibility.
TokenStream & operator<<(Token t)
Stream support for user-created Token's.
TokenStream & operator<<(StringRef s)
Add a string token (saved to storage).
TokenStream & operator<<(const PPSaveString &str)
String must be saved.
TokenStream(PPTy &pp, TokenStringSaver &saver)
Create a TokenStream using the specified PrettyPrinter and StringSaver storage.
TokenStream & addAsString(T &&t)
General-purpose "format this" helper, for types not supported by operator<< yet.
TokenStream & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
TokenStream & operator<<(const char *s)
Add a string literal (external storage).
TokenStream & writeEscaped(StringRef str, bool useHexEscapes=false)
Write escaped versions of the string, saved in storage.
TokenStream & operator<<(PP s)
Convenience for inline streaming of builder methods.
PrettyPrinter::Listener that saves strings while live.
void clear() override
PrettyPrinter::Listener::clear – indicates no external refs.
StringRef save(StringRef str)
Add string, save in storage.
void emitNBSP(unsigned n, llvm::function_ref< void(Token)> add)
Add multiple non-breaking spaces as a single token.
PP
Send one of these to TokenStream to add the corresponding token.
IndentStyle
Style of indent when starting a group:
Breaks
Style of breaking within a group:
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Buffer tokens for clients that need to adjust things.
SmallVectorImpl< Token > BufferVec
void addTokens(R &&newTokens)
Add a range of tokens.
void flush(PrettyPrinter &pp)
Flush buffered tokens to the specified pretty printer.
void eof()
Buffer a final EOF, no tokens allowed after this.
String wrapper to indicate string has external storage.
String wrapper to indicate string needs to be saved.
Listener to Token storage events.