libstdc++: Refactor loops in std::__platform_semaphore
[official-gcc.git] / gcc / pretty-print-format-impl.h
blobec4425c9dafb4ed04f0b8963029ebb9ec24407cd
1 /* Implementation detail of pp_format.
2 Copyright (C) 2002-2024 Free Software Foundation, Inc.
3 Contributed by Gabriel Dos Reis <gdr@integrable-solutions.net>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_PRETTY_PRINT_FORMAT_IMPL_H
22 #define GCC_PRETTY_PRINT_FORMAT_IMPL_H
24 #include "pretty-print.h"
25 #include "diagnostic-event-id.h"
27 /* A struct representing a pending item to be printed within
28 pp_format.
30 These can represent:
31 - a run of text within one of the output_buffers's obstacks
32 - begin/end named color
33 - open/close quote
34 - begin/end URL
35 - event IDs
36 - custom data (for the formatter, for the pretty_printer,
37 or the output format)
39 These are built into pp_token_list instances.
41 Doing so allows for interaction between:
43 - pretty_printer formatting codes (such as C++'s %H and %I,
44 which can't be printed until we've seen both)
46 - output formats, such as text vs SARIF (so each can handle URLs
47 and event IDs it its own way)
49 - optimization records, where we want to stash data into the
50 formatted messages
52 - urlifiers: these can be run in phase 3 of formatting
54 without needing lots of fragile logic on char pointers.
56 To avoid needing lots of heap allocation/deallocation, pp_token
57 instances are allocated in the pretty_printer's chunk_obstack:
58 they must not outlive phase 3 of formatting of the given
59 pp_formatted_chunks level. */
61 struct pp_token
63 public:
64 enum class kind
66 text,
68 begin_color,
69 end_color,
71 begin_quote,
72 end_quote,
74 begin_url,
75 end_url,
77 event_id,
79 custom_data,
81 NUM_KINDS
84 pp_token (enum kind k);
86 pp_token (const pp_token &) = delete;
87 pp_token (pp_token &&) = delete;
89 virtual ~pp_token () = default;
91 pp_token &operator= (const pp_token &) = delete;
92 pp_token &operator= (pp_token &&) = delete;
94 void dump (FILE *out) const;
95 void DEBUG_FUNCTION dump () const { dump (stderr); }
97 static void *operator new (size_t sz, obstack &s);
98 static void operator delete (void *);
100 enum kind m_kind;
102 // Intrusive doubly-linked list
103 pp_token *m_prev;
104 pp_token *m_next;
107 /* Subclasses of pp_token for the various kinds of token. */
109 struct pp_token_text : public pp_token
111 pp_token_text (label_text &&value)
112 : pp_token (kind::text),
113 m_value (std::move (value))
115 gcc_assert (m_value.get ());
118 label_text m_value;
121 template <>
122 template <>
123 inline bool
124 is_a_helper <pp_token_text *>::test (pp_token *tok)
126 return tok->m_kind == pp_token::kind::text;
129 template <>
130 template <>
131 inline bool
132 is_a_helper <const pp_token_text *>::test (const pp_token *tok)
134 return tok->m_kind == pp_token::kind::text;
137 struct pp_token_begin_color : public pp_token
139 pp_token_begin_color (label_text &&value)
140 : pp_token (kind::begin_color),
141 m_value (std::move (value))
143 gcc_assert (m_value.get ());
146 label_text m_value;
149 template <>
150 template <>
151 inline bool
152 is_a_helper <pp_token_begin_color *>::test (pp_token *tok)
154 return tok->m_kind == pp_token::kind::begin_color;
157 template <>
158 template <>
159 inline bool
160 is_a_helper <const pp_token_begin_color *>::test (const pp_token *tok)
162 return tok->m_kind == pp_token::kind::begin_color;
165 struct pp_token_end_color : public pp_token
167 pp_token_end_color ()
168 : pp_token (kind::end_color)
173 struct pp_token_begin_quote : public pp_token
175 pp_token_begin_quote ()
176 : pp_token (kind::begin_quote)
181 struct pp_token_end_quote : public pp_token
183 pp_token_end_quote ()
184 : pp_token (kind::end_quote)
189 struct pp_token_begin_url : public pp_token
191 pp_token_begin_url (label_text &&value)
192 : pp_token (kind::begin_url),
193 m_value (std::move (value))
195 gcc_assert (m_value.get ());
198 label_text m_value;
201 template <>
202 template <>
203 inline bool
204 is_a_helper <pp_token_begin_url*>::test (pp_token *tok)
206 return tok->m_kind == pp_token::kind::begin_url;
209 template <>
210 template <>
211 inline bool
212 is_a_helper <const pp_token_begin_url*>::test (const pp_token *tok)
214 return tok->m_kind == pp_token::kind::begin_url;
217 struct pp_token_end_url : public pp_token
219 pp_token_end_url ()
220 : pp_token (kind::end_url)
225 struct pp_token_event_id : public pp_token
227 pp_token_event_id (diagnostic_event_id_t event_id)
228 : pp_token (kind::event_id),
229 m_event_id (event_id)
231 gcc_assert (event_id.known_p ());
234 diagnostic_event_id_t m_event_id;
237 template <>
238 template <>
239 inline bool
240 is_a_helper <pp_token_event_id *>::test (pp_token *tok)
242 return tok->m_kind == pp_token::kind::event_id;
245 template <>
246 template <>
247 inline bool
248 is_a_helper <const pp_token_event_id *>::test (const pp_token *tok)
250 return tok->m_kind == pp_token::kind::event_id;
253 struct pp_token_custom_data : public pp_token
255 class value
257 public:
258 virtual ~value () {}
259 virtual void dump (FILE *out) const = 0;
261 /* Hook for lowering a custom_data token to standard tokens.
262 Return true and write to OUT if possible.
263 Return false for custom_data that is to be handled by
264 the token_printer. */
265 virtual bool as_standard_tokens (pp_token_list &out) = 0;
268 pp_token_custom_data (std::unique_ptr<value> val)
269 : pp_token (kind::custom_data),
270 m_value (std::move (val))
272 gcc_assert (m_value.get ());
275 std::unique_ptr<value> m_value;
278 template <>
279 template <>
280 inline bool
281 is_a_helper <pp_token_custom_data *>::test (pp_token *tok)
283 return tok->m_kind == pp_token::kind::custom_data;
286 template <>
287 template <>
288 inline bool
289 is_a_helper <const pp_token_custom_data *>::test (const pp_token *tok)
291 return tok->m_kind == pp_token::kind::custom_data;
294 /* A list of pp_token, with ownership of the tokens, using
295 a particular obstack to allocate its tokens. These are
296 also allocated on the obstack during formatting (or, occasionally,
297 the stack). */
299 class pp_token_list
301 public:
302 // Allocate a new pp_token_list within S.
303 static pp_token_list *make (obstack &s)
305 return new (s) pp_token_list (s);
307 static void *operator new (size_t sz, obstack &s);
308 static void operator delete (void *);
310 pp_token_list (obstack &s);
311 pp_token_list (const pp_token_list &) = delete;
312 pp_token_list (pp_token_list &&);
314 ~pp_token_list ();
316 pp_token &operator= (const pp_token_list &) = delete;
317 pp_token &operator= (pp_token_list &&) = delete;
319 /* Make a pp_token of the given subclass, using the relevant obstack to provide
320 the memory. The pp_token must therefore not outlive the current
321 pp_formatted_chunks level during formatting. */
322 template<typename Subclass, typename... Args>
323 std::unique_ptr<pp_token>
324 make_token (Args&&... args)
326 return std::unique_ptr<pp_token>
327 (new (m_obstack) Subclass (std::forward<Args> (args)...));
330 template<typename Subclass, typename... Args>
331 void push_back (Args&&... args)
333 auto tok = make_token<Subclass> (std::forward<Args> (args)...);
334 push_back (std::move (tok));
336 void push_back_text (label_text &&text);
337 void push_back (std::unique_ptr<pp_token> tok);
338 void push_back_list (pp_token_list &&list);
340 std::unique_ptr<pp_token> pop_front ();
342 std::unique_ptr<pp_token> remove_token (pp_token *tok);
344 void insert_after (std::unique_ptr<pp_token> new_tok,
345 pp_token *relative_tok);
347 void replace_custom_tokens ();
348 void merge_consecutive_text_tokens ();
349 void apply_urlifier (const urlifier &urlifier);
351 void dump (FILE *out) const;
352 void DEBUG_FUNCTION dump () const { dump (stderr); }
354 obstack &m_obstack;
356 pp_token *m_first;
357 pp_token *m_end;
360 /* The pp_formatted_chunks data structure forms a stack of the results from the
361 first phase of formatting (pp_format) which have not yet been
362 output (pp_output_formatted_text). A stack is necessary because
363 the diagnostic starter may decide to generate its own output by way
364 of the formatter. */
365 class pp_formatted_chunks
367 friend class pretty_printer;
368 friend class pp_markup::context;
369 friend class output_buffer;
371 public:
372 pp_token_list * const * get_token_lists () const { return m_args; }
374 void append_formatted_chunk (obstack &s, const char *content);
376 void dump (FILE *out) const;
377 void DEBUG_FUNCTION dump () const { dump (stderr); }
379 // For use in selftests
380 pp_formatted_chunks *get_prev () const { return m_prev; }
382 private:
383 /* Pointer to previous level on the stack. */
384 pp_formatted_chunks *m_prev;
386 /* Array of chunks to output. Each chunk is a doubly-linked list of
387 pp_token.
389 The chunks can be printed via pp_formatted_chunks::dump ().
391 In the first phase of formatting, even-numbered chunks are
392 to be output verbatim, odd-numbered chunks are format specifiers.
393 For example, given:
394 pp_format (pp,
395 "foo: %i, bar: %s, opt: %qs",
396 42, "baz", "-foption");
398 after phase 1 we might have:
399 (gdb) call buffer->cur_chunk_array->dump()
400 0: [TEXT("foo: ")]
401 1: [TEXT("i")]
402 2: [TEXT(", bar: ")]
403 3: [TEXT("s")]
404 4: [TEXT(", opt: ")]
405 5: [TEXT("qs")]
407 The second phase replaces all odd-numbered chunks with formatted
408 token lists. In the above example, after phase 2 we might have:
409 (gdb) call pp->m_buffer->cur_chunk_array->dump()
410 0: [TEXT("foo: ")]
411 1: [TEXT("42")]
412 2: [TEXT(", bar: ")]
413 3: [TEXT("baz")]
414 4: [TEXT(", opt: ")]
415 5: [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
416 For example the %qs has become the three tokens:
417 [BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
419 The third phase (in pp_output_formatted_text):
421 (1) merges the tokens from all the chunks into one list,
422 giving e.g.
423 (gdb) call tokens.dump()
424 [TEXT("foo: "), TEXT("42"), TEXT(", bar: "), TEXT("baz"),
425 TEXT(", opt: "), BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
427 (2) lowers some custom tokens into non-custom tokens
429 (3) merges consecutive text tokens, giving e.g.:
430 (gdb) call tokens.dump()
431 [TEXT("foo: 42, bar: baz, option: "),
432 BEGIN_QUOTE, TEXT("-foption"), END_QUOTE]
434 (4) if provided with a urlifier, tries to apply it to quoted text,
435 giving e.g:
436 (gdb) call tokens.dump()
437 [TEXT("foo: 42, bar: baz, option: "), BEGIN_QUOTE,
438 BEGIN_URL("http://example.com"), TEXT("-foption"), END_URL, END_QUOTE]
440 (5) emits all tokens in sequence with appropriate line-wrapping. This
441 can be overridded via the pretty_printer's token_printer, allowing for
442 output formats to e.g. override how URLs are handled, or to handle
443 custom_data that wasn't lowered in (2) above, e.g. for handling JSON
444 output of optimization records. */
445 pp_token_list *m_args[PP_NL_ARGMAX * 2];
447 /* The pp_tokens, pp_token_lists, and the accumulated text buffers are
448 allocated within the output_buffer's chunk_obstack. In the above
449 example, the in-memory layout of the chunk_obstack might look like
450 this after phase 1:
452 + pp_formatted_chunks instance <--- START of pp_formatted_chunks level
454 + pp_token_list for chunk 0 (m_first: *)
456 + "foo: \0" <-------------\ |
457 | | |
458 + pp_token_text (borrowed: *) <-------/
460 + pp_token_list for chunk 1
462 + "i\0" <------------------\
464 + pp_token_text (borrowed: *)
466 + ...etc for chunks 2 to 4...
468 + pp_token_list for chunk 5
470 + "qs\0" <-----------------\
472 + pp_token_text (borrowed: *)
476 obstack grows this way
478 At each stage, allocation of additional text buffers, tokens, and lists
479 grow forwards in the obstack (though the internal pointers in linked
480 lists might point backwards to earlier objects within the same
481 pp_formatted_chunks level). */
484 #endif /* GCC_PRETTY_PRINT_FORMAT_IMPL_H */