CIRCT  19.0.0git
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 
25 namespace circt {
26 namespace pretty {
27 
28 //===----------------------------------------------------------------------===//
29 // PrettyPrinter standin that buffers tokens until flushed.
30 //===----------------------------------------------------------------------===//
31 
32 /// Buffer tokens for clients that need to adjust things.
33 struct BufferingPP {
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 
74 namespace detail {
75 void emitNBSP(unsigned n, llvm::function_ref<void(Token)> add);
76 } // end namespace detail
77 
78 /// Add convenience methods for generating pretty-printing tokens.
79 template <typename PPTy = PrettyPrinter>
80 class TokenBuilder {
81  PPTy &pp;
82 
83 public:
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 
160 public:
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)
172 template <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 
183 public:
184  PrintEventAndStorageListener(CallableTy &c) : callable(c) {}
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.
194  CallbackToken getToken(DataTy obj) {
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.
207 enum class PP {
208  bbox2,
209  cbox0,
210  cbox2,
211  end,
212  eof,
213  ibox0,
214  ibox2,
215  nbsp,
216  neverbox,
217  neverbreak,
218  newline,
219  space,
220  zerobreak,
221 };
222 
223 /// String wrapper to indicate string has external storage.
224 struct PPExtString {
225  StringRef str;
226  explicit PPExtString(StringRef str) : str(str) {}
227 };
228 
229 /// String wrapper to indicate string needs to be saved.
230 struct PPSaveString {
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.
240 template <typename PPTy = PrettyPrinter>
241 class TokenStream : public TokenBuilder<PPTy> {
243 
244 protected:
246 
247 public:
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:
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.
376 template <typename CallableType, typename DataType,
377  typename PPTy = PrettyPrinter>
378 class TokenStreamWithCallback : public TokenStream<PPTy> {
381 
382  const bool enableCallback;
383 
384 public:
387  bool enableCallback)
388  : TokenStream<PPTy>(pp, saver), saver(saver),
390  /// Add a Callback token.
391  void addCallback(DataType d) {
392  if (enableCallback)
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.
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.
std::enable_if_t< std::is_base_of_v< Token, T > > add(Args &&...args)
Add new token.
void nbsp(unsigned n)
Add multiple non-breaking spaces as a single token.
void eof()
End of a stream.
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 PPSaveString &str)
String must be saved.
auto scopedBox(T &&t, Callable &&c, Token close=EndToken())
Open a box, invoke the lambda, and close it after.
TokenStream & operator<<(const char *s)
Add a string literal (external storage).
TokenStream & operator<<(StringRef s)
Add a string token (saved to storage).
auto invokeWithStringOS(Callable &&c)
Helper to invoke code with a llvm::raw_ostream argument for compatibility.
TokenStream & writeQuotedEscaped(StringRef str, bool useHexEscapes=false, StringRef left="\"", StringRef right="\"")
TokenStream & operator<<(const PPExtString &str)
String has external storage.
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 & operator<<(Token t)
Stream support for user-created Token's.
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:
Definition: PrettyPrinter.h:49
Breaks
Style of breaking within a group:
Definition: PrettyPrinter.h:44
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
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.