• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SRI-CSL / yices2 / 12367760548

17 Dec 2024 06:41AM UTC coverage: 65.285% (-0.6%) from 65.92%
12367760548

push

github

web-flow
Fixes GitHub coverage issue (#544)

* Update action.yml

* Update action.yml

81020 of 124102 relevant lines covered (65.29%)

1509382.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.5
/src/io/pretty_printer.h
1
/*
2
 * This file is part of the Yices SMT Solver.
3
 * Copyright (C) 2017 SRI International.
4
 *
5
 * Yices is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * Yices is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

19
/*
20
 * PRETTY PRINTER
21
 *
22
 * This is based on "Pretty Printing", Oppen, 1979.
23
 *
24
 * The input to the pretty printer is a sequence of
25
 * tokens, that contains atomic tokens + block delimiters.
26
 * - Atomic tokens are strings to be printed. They should not
27
 *   contain line breaks, or start or end with spaces.
28
 * - A block is a sequence of tokens of the form
29
 *
30
 *      open_block token .... token close_block
31
 *
32
 * An open-block has the following attributes:
33
 * - label = string to be printed at the start of the block (may be empty)
34
 * - whether the block is enclosed by '(' and ')'
35
 * - whether a space or line break is allowed between the label and the
36
 *   next text element
37
 * - a set of possible formats for that block. There are four
38
 *   choices: horizontal, vertical, mixed, tight.
39
 * - the indentation for mixed and vertical formats
40
 * - the (shorter) indentation for the tight format
41
 *
42
 * The possible formats are
43
 *
44
 *      (label b_1 .... b_n)   Horizontal layout
45
 *
46
 *      (label b_1             Vertical layout
47
 *             b_2
48
 *             ...
49
 *             b_n)
50
 *
51
 *      (label b_1 ....        Mixed HV layout
52
 *             b_k .... b_n)
53
 *
54
 *      (label                 Tight layout
55
 *         b_1
56
 *         b_2
57
 *         ...
58
 *         b_n)
59
 *
60
 * There are constraints between the selected layout for a block and the
61
 * allowed layouts for its sub-blocks:
62
 * - if b is printed horizontally, then all its sub-blocks must also be
63
 *   printed horizontally
64
 * - if b is printed in vertical or mixed layouts, then all
65
 *   its sub-blocks must be printed horizontally
66
 *
67
 * As in Oppen's paper the pretty printer consists of two main components
68
 * - a printer does the actual printing.
69
 * - a formatter computes the size of each block (or a lower bound that's
70
 *   larger than the current line width) and feeds that information to
71
 *   the printer.
72
 */
73

74
#ifndef __PRETTY_PRINTER_H
75
#define __PRETTY_PRINTER_H
76

77
#include <stdbool.h>
78
#include <stdint.h>
79
#include <stdio.h>
80
#include <assert.h>
81

82
#include "io/writer.h"
83
#include "utils/ptr_queues.h"
84
#include "utils/ptr_vectors.h"
85
#include "utils/tagged_pointers.h"
86

87

88
/*
89
 * LAYOUTS
90
 */
91

92
/*
93
 * Bit masks to represent a set of layouts
94
 * (in the low-order bits of an unsigned int).
95
 * - 0001: horizontal
96
 * - 0010: mixed horizontal/vertical
97
 * - 0100: vertical
98
 * - 1000: tight vertical
99
 */
100
#define PP_H_LAYOUT ((uint32_t) 1)
101
#define PP_M_LAYOUT ((uint32_t) 2)
102
#define PP_V_LAYOUT ((uint32_t) 4)
103
#define PP_T_LAYOUT ((uint32_t) 8)
104

105

106
/*
107
 * Possible combinations of two or three layouts
108
 */
109
#define PP_HM_LAYOUT  (PP_H_LAYOUT|PP_M_LAYOUT)
110
#define PP_HV_LAYOUT  (PP_H_LAYOUT|PP_V_LAYOUT)
111
#define PP_HT_LAYOUT  (PP_H_LAYOUT|PP_T_LAYOUT)
112
#define PP_MT_LAYOUT  (PP_M_LAYOUT|PP_T_LAYOUT)
113
#define PP_VT_LAYOUT  (PP_V_LAYOUT|PP_T_LAYOUT)
114
#define PP_HMT_LAYOUT (PP_H_LAYOUT|PP_M_LAYOUT|PP_T_LAYOUT)
115
#define PP_HVT_LAYOUT (PP_H_LAYOUT|PP_V_LAYOUT|PP_T_LAYOUT)
116

117

118
/*
119
 * DISPLAY AREA
120
 */
121

122
/*
123
 * The display area is a rectangle characterized by
124
 * its width, height, and offset as follows:
125
 *
126
 *                  <----------- width ------------->
127
 *                   _______________________________
128
 * <---- offset --->|                               |   ^
129
 *                  |                               |   |
130
 *                  |                               | Height
131
 *                  |                               |   |
132
 *                  |                               |   v
133
 *                   -------------------------------
134
 *
135
 *
136
 * The printer keeps track of the current print line within that area.
137
 * The start of each line is defined by its indentation (measured from
138
 * the first column of the rectangle).
139
 *
140
 * By default, each line has enough space for (width - indent) characters.
141
 * There's a 'stretch' option that can be used to make the lines wider.
142
 * If stretch is true, then each line extends to the right and has
143
 * space for 'width' characters independent of 'indent'.
144
 *
145
 * A 'truncate' flag specifies how to deal with an atomic token that does
146
 * not fit on the print line (e.g., if the indentation is large):
147
 * - if 'truncate' is true, the token is truncated (nothing is printed
148
 * beyond the display area's boundary).
149
 * - otherwise, the token is printed in full and may extend beyond the
150
 *   right boundary.
151
 */
152
typedef struct pp_area_s {
153
  uint32_t width;
154
  uint32_t height;
155
  uint32_t offset;
156
  bool stretch;
157
  bool truncate;
158
} pp_area_t;
159

160

161
/*
162
 * Minimal width and height
163
 */
164
#define PP_MINIMAL_WIDTH  4
165
#define PP_MINIMAL_HEIGHT 1
166

167
/*
168
 * Default print area:
169
 * - 80 columns
170
 * - infinitely many lines
171
 * - no offset
172
 * - stretch disabled
173
 * - truncate enabled
174
 */
175
#define PP_DEFAULT_WIDTH  80
176
#define PP_DEFAULT_HEIGHT UINT32_MAX
177
#define PP_DEFAULT_OFFSET 0
178
#define PP_DEFAULT_STRETCH false
179
#define PP_DEFAULT_TRUNCATE true
180

181

182

183
/*
184
 * TOKENS
185
 */
186

187
/*
188
 * Token descriptors encode formatting information.  The string label
189
 * of an open token or the content of an atomic token are not kept in
190
 * the descriptor. They are obtained via calls to user-provided
191
 * functions.  To help in this conversion, the descriptors include a
192
 * 32bit user-tag (which can be anything the conversion functions need
193
 * to identify the token).
194
 */
195

196
/*
197
 * Atomic token descriptor
198
 * - size = size of the token when converted to string
199
 * - bsize = block size = size of the token + number of closing parentheses
200
 *   that follow it.
201
 *
202
 * Size and user_tag should be set appropriately when the token is created.
203
 * bsize is computed by the formatter.
204
 */
205
typedef struct pp_atomic_token_s {
206
  uint32_t bsize;
207
  uint32_t size;
208
  uint32_t user_tag;
209
} pp_atomic_token_t;
210

211

212
/*
213
 * Open block descriptor
214
 * - bsize = block size = size of the block + number of closing
215
 *           parentheses that follow it.
216
 * - csize = maximal block size of the sub-blocks and atoms in that block
217
 * - fsize = block size of the first sub-block or atom
218
 *
219
 * - label_size = size of the label (0 if there's no label)
220
 * - indent = indentation for VLAYOUT or MLAYOUT
221
 * - short_indent = indentation for TLAYOUT
222
 * - formats = allowed formats
223
 * - flags = whether the block is enclosed with '(' and ')
224
 *           whether space/break is allowed after the label
225
 * - user_tag = provided by the user
226
 *
227
 * The fields bsize, csize, and fsize are computed by the formatter.
228
 * All the other components must be set when the token is created.
229
 */
230
typedef struct pp_open_token_s {
231
  uint32_t bsize;
232
  uint32_t csize;
233
  uint32_t fsize;
234
  uint8_t  formats;
235
  uint8_t  flags;
236
  uint16_t label_size;
237
  uint16_t indent;
238
  uint16_t short_indent;
239
  uint32_t user_tag;
240
} pp_open_token_t;
241

242

243
/*
244
 * bit masks for the flag field:
245
 *  b0 --> 1 for blocks that require '(' and ')
246
 *         0 for blocks with no delimiters
247
 *  b1 --> 1 if space/break is allowed after the label
248
 *         0 otherwise
249
 */
250
#define PP_TOKEN_PAR_MASK ((uint32_t) 0x1)
251
#define PP_TOKEN_SEP_MASK ((uint32_t) 0x2)
252

253
/*
254
 * Test the format bits
255
 */
256
static inline bool tk_has_hlayout(pp_open_token_t *tk) {
62,017✔
257
  return (tk->formats & PP_H_LAYOUT) != 0;
62,017✔
258
}
259

260
static inline bool tk_has_mlayout(pp_open_token_t *tk) {
3,011✔
261
  return (tk->formats & PP_M_LAYOUT) != 0;
3,011✔
262
}
263

264
static inline bool tk_has_vlayout(pp_open_token_t *tk) {
2,540✔
265
  return (tk->formats & PP_V_LAYOUT) != 0;
2,540✔
266
}
267

268
static inline bool tk_has_tlayout(pp_open_token_t *tk) {
269
  return (tk->formats & PP_T_LAYOUT) != 0;
270
}
271

272
/*
273
 * Test the flags
274
 */
275
static inline bool tk_has_par(pp_open_token_t *tk) {
341,243✔
276
  return (tk->flags & PP_TOKEN_PAR_MASK) != 0;
341,243✔
277
}
278

279
static inline bool tk_sep_allowed(pp_open_token_t *tk) {
279,697✔
280
  return (tk->flags & PP_TOKEN_SEP_MASK) != 0;
279,697✔
281
}
282

283

284
/*
285
 * Close block descriptor.
286
 * - we just need to know whether the block ends with ')'
287
 * - we use the same flags encoding as for open_blocks
288
 */
289
typedef struct pp_close_token_s {
290
  uint32_t flags;
291
  uint32_t user_tag;
292
} pp_close_token_t;
293

294
/*
295
 * Check the flag
296
 */
297
static inline bool tk_has_close_par(pp_close_token_t *tk) {
418,839✔
298
  return (tk->flags && PP_TOKEN_PAR_MASK) != 0;
418,839✔
299
}
300

301

302

303
/*
304
 * Large bsize: when we know that a token or block doesn't
305
 * fit on the line, we can set its bsize field to any large
306
 * enough number. We use the constant 2^30.
307
 */
308
#define PP_MAX_BSIZE ((uint32_t) 1073741824)
309

310

311

312
/*
313
 * TAGGED POINTERS
314
 */
315

316
/*
317
 * Tokens are accessed via tagged (void *) pointers
318
 * The token type is encoded in the lower 2bits:
319
 * 00 --> open token
320
 * 01 --> atomic token
321
 * 10 --> close token
322
 * 11 --> separator token
323
 *
324
 * A separator is an atomic token that's printed without
325
 * spaces before or after.
326
 */
327
typedef enum {
328
  PP_TOKEN_OPEN_TAG,
329
  PP_TOKEN_ATOMIC_TAG,
330
  PP_TOKEN_CLOSE_TAG,
331
  PP_TOKEN_SEPARATOR_TAG,
332
} pp_tk_ptr_tag;
333

334
// check the pointer type
335
static inline bool ptr_has_open_tag(void *p) {
336
  return ptr_tag(p) == PP_TOKEN_OPEN_TAG;
337
}
338

339
static inline bool ptr_has_atomic_tag(void *p) {
340
  return ptr_tag(p) == PP_TOKEN_ATOMIC_TAG;
341
}
342

343
static inline bool ptr_has_close_tag(void *p) {
344
  return ptr_tag(p) == PP_TOKEN_CLOSE_TAG;
345
}
346

347
static inline bool ptr_has_separator_tag(void *p) {
348
  return ptr_tag(p) == PP_TOKEN_SEPARATOR_TAG;
349
}
350

351
// add a tag to a pointer
352
static inline void *tag_open(pp_open_token_t *p) {
142,594✔
353
  return tag_ptr(p, PP_TOKEN_OPEN_TAG);
142,594✔
354
}
355

356
static inline void *tag_atomic(pp_atomic_token_t *p) {
155,961✔
357
  return tag_ptr(p, PP_TOKEN_ATOMIC_TAG);
155,961✔
358
}
359

360
static inline void *tag_close(void *p) {
99,624✔
361
  return tag_ptr(p, PP_TOKEN_CLOSE_TAG);
99,624✔
362
}
363

364
static inline void *tag_separator(pp_atomic_token_t *p) {
×
365
  return tag_ptr(p, PP_TOKEN_SEPARATOR_TAG);
×
366
}
367

368
// check and untag
369
static inline pp_open_token_t *untag_open(void *p) {
279,226✔
370
  assert(ptr_has_open_tag(p));
371
  return untag_ptr(p);
279,226✔
372
}
373

374
static inline pp_atomic_token_t *untag_atomic(void *p) {
311,922✔
375
  assert(ptr_has_atomic_tag(p));
376
  return untag_ptr(p);
311,922✔
377
}
378

379
static inline void *untag_close(void *p) {
279,226✔
380
  assert(ptr_has_close_tag(p));
381
  return untag_ptr(p);
279,226✔
382
}
383

384
static inline pp_atomic_token_t *untag_separator(void *p) {
×
385
  assert(ptr_has_separator_tag(p));
386
  return untag_ptr(p);
×
387
}
388

389

390
/*
391
 * The pretty printer requires several user-provided functions to
392
 * convert tokens to string. To help in this conversion, each token
393
 * has a user_tag, which must be set when the token is created.
394
 *
395
 * Conversion functions:
396
 * - get_label(ptr, tk): label of an open-block token tk
397
 * - get_string(ptr, tk): convert atomic token tk to a string.
398
 * - get_truncated(ptr, tk, n): convert atomic token tk to a
399
 *   string of length <= n (where n < tk->size).
400
 *
401
 * All the conversions take a generic user-provided pointer as first
402
 * argument and must return a character string (terminated by '\0').
403
 * For consistency,
404
 * - get_label(ptr, tk) should return a string of length equal to tk->label_size.
405
 * - get_string(ptr, tk) should return a string of length equal to tk->size.
406
 *
407
 * Free functions: when token tk is consumed, one of the
408
 * following function is called.
409
 * - free_open_token(ptr, tk)
410
 * - free_atomic_token(ptr, tk)
411
 * - free_close_token(ptr, tk)
412
 * The first argument 'ptr' is the same user-provided pointer as used
413
 * by the conversion functions.
414
 *
415
 * All functions and the user-provided pointer are stored in a
416
 * 'pp_token_converter' structure.
417
 */
418
typedef char *(*get_label_fun_t)(void *ptr, pp_open_token_t *tk);
419
typedef char *(*get_string_fun_t)(void *ptr, pp_atomic_token_t *tk);
420
typedef char *(*get_truncated_fun_t)(void *ptr, pp_atomic_token_t *tk, uint32_t n);
421

422
typedef void (*free_open_token_fun_t)(void *ptr, pp_open_token_t *tk);
423
typedef void (*free_atomic_token_fun_t)(void *ptr, pp_atomic_token_t *tk);
424
typedef void (*free_close_token_fun_t)(void *ptr, pp_close_token_t *tk);
425

426
typedef struct pp_token_converter_s {
427
  void *user_ptr;
428
  get_label_fun_t get_label;
429
  get_string_fun_t get_string;
430
  get_truncated_fun_t get_truncated;
431
  free_open_token_fun_t free_open_token;
432
  free_atomic_token_fun_t free_atomic_token;
433
  free_close_token_fun_t free_close_token;
434
} pp_token_converter_t;
435

436

437

438
/*
439
 * PRINTER
440
 */
441

442
/*
443
 * There are three possible print modes:
444
 * - HMODE: horizontal, with space as separator
445
 * - VMODE: vertical, with a specified indentation
446
 * - HVMODE: mix of both.
447
 *
448
 * If a new atom 's' is to be printed:
449
 * - in HMODE: print a space then print s
450
 * - in VMODE: print a line break, indent, then print s
451
 * - in HVMODE: check whether s fits on the current line
452
 *   if yes, print a space then print s
453
 *   if no, print a line break, indent, print s.
454
 *
455
 * There's an immediate correspondence between layouts
456
 * and print modes:
457
 * - HLAYOUT --> HMODE
458
 * - VLAYOUT and TLAYOUT --> VMODE
459
 */
460
typedef enum {
461
  PP_HMODE,
462
  PP_VMODE,
463
  PP_HVMODE,
464
} pp_print_mode_t;
465

466

467
/*
468
 * A print state keeps track of the current print mode
469
 * and indentation. States are stored on a stack.
470
 */
471
typedef struct pp_state_s {
472
  pp_print_mode_t mode;
473
  uint32_t indent; // indent increment
474
} pp_state_t;
475

476

477
/*
478
 * Stack:
479
 * - print states are stored in data[0 ... top]
480
 * - size is the total size of the array data
481
 * - the current state is in data[top]
482
 * - the bottom element data[0] is the initial printing mode.
483
 * - by default this is (horizontal mode, indent = 0,)
484
 */
485
typedef struct pp_stack_s {
486
  pp_state_t *data;
487
  uint32_t top;
488
  uint32_t size;
489
} pp_stack_t;
490

491
// default and maximal size of the stack
492
#define DEF_PP_STACK_SIZE 20
493
#define MAX_PP_STACK_SIZE (UINT32_MAX/sizeof(pp_state_t))
494

495

496
/*
497
 * The printer is attached to a writer, to a converter
498
 * structure, and to a display area.
499
 *
500
 * It keeps track of a current print-line, defined by
501
 * - line = line number (0 means top of the display area)
502
 * - col = cursor location
503
 * - margin = end of the line
504
 *
505
 * When we get close to the end of the line, the printer
506
 * may have to store pending tokens (that fit on the line
507
 * but can't be printed for sure yet because '...' may be needed).
508
 * These tokens are stored in a 'pending_token' vector and
509
 * the printer keeps track of the column where they will be
510
 * printed if possible in 'pending_col'.
511
 *
512
 * The printer also use control parameters:
513
 * - stack = stack of printer states
514
 * - mode = current print mode (copied from the stack top)
515
 * - indent = current indentation
516
 * - next_margin = margin to use after the following line break
517
 *               = width of the next line
518
 * - no_break = true to prevent line break
519
 * - no_space = true to prevent space
520
 * - full_line = true if the current line is full
521
 * - overfull_count = number of open blocks seen since the line has been full
522
 */
523
typedef struct printer_s {
524
  // writer object + display area + converter
525
  writer_t writer;
526
  pp_area_t area;
527
  pp_token_converter_t conv;
528

529
  // control parameters
530
  pp_stack_t stack;
531
  pp_print_mode_t mode;
532
  uint32_t indent;
533
  uint32_t next_margin;
534
  bool no_break;
535
  bool no_space;
536
  bool full_line;
537
  uint32_t overfull_count;
538

539
  // current print line
540
  uint32_t line;
541
  uint32_t col;
542
  uint32_t margin;
543

544
  // pending tokens
545
  pvector_t pending_tokens;
546
  uint32_t pending_col;
547
} printer_t;
548

549

550

551

552
/*
553
 * FORMATTER
554
 */
555

556
/*
557
 * The formatter looks ahead in the token stream to compute
558
 * - the bsize of all atomic tokens
559
 * - the bsize and csize of all open tokens
560
 *
561
 * The formatter works as if all the tokens were printed on
562
 * a single (long) horizontal line (the formatting line).
563
 * The formatter state includes:
564
 *
565
 * 1) A queue of tokens.
566
 *    - input tokens are added to this queue
567
 *    - they are removed from the queue when their bsize
568
 *      is known or as soon as it's known that their bsize is
569
 *      larger than max_width (= the display area width).
570
 *
571
 * 2) A queue of block descriptors. For each block we store:
572
 *    - a pointer to the corresponding open token descriptor
573
 *    - the column where the block starts on the formatting line
574
 *    - the current csize for that block = largest bsize among
575
 *      its sub-blocks.
576
 *
577
 * 3) The formatting line parameters:
578
 *    - length = size of the line = column where new tokens are added
579
 *    - no_space = flag that determines whether a space should be
580
 *                 added before the next token.
581
 *
582
 * 4) A optional head_token
583
 *    - if head_token isn't NULL then it's the start of a block
584
 *      whose bsize is known to be larger than max_width but
585
 *      whose fsize and csize fields are not known yet.
586
 *
587
 * 5) An optional last_atom
588
 *    - if last_atom isn't NULL then it's the last atomic token
589
 *      on the line and that token is followed by nothing or
590
 *      by closed parentheses
591
 *    - if last_atom != NULL then atom_col is the start of the
592
 *      atom on the line
593
 *
594
 *
595
 * Note: we could send tokens to the printer as soon as we know that
596
 * bsize is larger than the space left on the printer's line, but that
597
 * complicates the code.
598
 *
599
 *
600
 * The formatting line looks (approximately) like this:
601
 *
602
 *                                                             length
603
 * ______________________________________________________________|__
604
 *  |Head    |B0            |B1         | .... |B_n   ... atom)))|
605
 * --------------------------------------------------------------|--
606
 *  ^        ^              ^                  ^          ^
607
 * head    col_0         col_1              col_n        atom_col
608
 *
609
 *
610
 * The following invariants hold:
611
 * 1) head_token->bsize > max_width
612
 *    head_token->fsize <= head_token->csize <= max_width
613
 *    head_token->fsize = head_token->csize = 0 if B0 is
614
 *    the first sub block of the head block.
615
 *
616
 * 2) length - col_i <= max_width
617
 *    token_i->fsize <= token_i->csize <= max_width
618
 *    token_i->fsize = token_i->csize is 0 if B_i+1 is
619
 *    the first sub-block of B_i
620
 *   (or, for i=n, if the last_atom is the first component of B_n).
621
 */
622

623
/*
624
 * Block descriptor:
625
 * - col = start of the block on the formatting line
626
 * - token = attached open_token descriptor
627
 */
628
typedef struct pp_block_s {
629
  uint32_t col;
630
  pp_open_token_t *token;
631
} pp_block_t;
632

633

634
/*
635
 * Queue of block descriptor (same implementation as int_queue
636
 * and ptr_queue):
637
 * - data = array elements
638
 * - size = size of that array
639
 * - head, tail = array indices between 0 and size-1
640
 * This forms a list of block descriptors as follows:
641
 * - head = tail --> the queue is empty
642
 * - head < tail --> the queue is data[head ... tail-1]
643
 * - head > tail --> the queue is data[head ... size-1]
644
 *                   followed by  data[0 ... tail-1]
645
 */
646
typedef struct pp_block_queue_s {
647
  pp_block_t *data;
648
  uint32_t size;
649
  uint32_t head;
650
  uint32_t tail;
651
} pp_block_queue_t;
652

653

654
// initial size and maximal size of the queue
655
#define DEF_BLOCK_QUEUE_SIZE 20
656
#define MAX_BLOCK_QUEUE_SIZE (UINT32_MAX/sizeof(pp_block_t))
657

658

659
/*
660
 * Formatter structure:
661
 * - a pointer to the printer
662
 * - a queue of tokens (stored as tagged pointers)
663
 *
664
 * Block queue:
665
 * - block_queue = the queue itself
666
 * - queue_size = number of blocks in the queue
667
 * - nclosed = number of closed blocks in the queue
668
 * - head_token = pointer to token starting the enclosing
669
 *   block (or NULL)
670
 * - head_closed = true if the head block is close
671
 *
672
 * Last atom:
673
 * - pointer to the last atom in the token queue (or NULL)
674
 * - atom_col = start of that atom on the line
675
 *
676
 * Line descriptors:
677
 * - no_space: flag to prevent ' '
678
 * - length = the full length of the line
679
 * - max_width = maximal block width (any block whose bsize
680
 *   is known to be more than max_width gets assigned
681
 *   bsize = MAX_BSIZE).
682
 *
683
 * Depth counter:
684
 * - depth = number of open token seen - number of close token seen
685
 */
686
typedef struct formatter_s {
687
  printer_t *printer;
688
  ptr_queue_t token_queue;
689

690
  // block queue, head token, and related variables
691
  pp_block_queue_t block_queue;
692
  uint32_t queue_size;
693
  uint32_t nclosed;
694
  pp_open_token_t *head_token;
695
  bool head_closed;
696

697
  // last atom
698
  pp_atomic_token_t *last_atom;
699
  uint32_t atom_col;
700

701
  // control flag, line size, max_width
702
  bool no_space;
703
  uint32_t length;
704
  uint32_t max_width;
705

706
  // depth
707
  uint32_t depth;
708
} formatter_t;
709

710

711
/*
712
 * PRETTY PRINTER
713
 */
714
typedef struct pp_s {
715
  printer_t printer;
716
  formatter_t formatter;
717
} pp_t;
718

719

720

721
/*
722
 * PRETTY-PRINTER INTERFACE
723
 */
724

725
/*
726
 * Initialization for a file
727
 * - converter = converter interface (copied internally).
728
 * - file = output stream to use (must either be NULL or an open, writable file)
729
 *   if file is NULL, pp is initialized for a string buffer
730
 *   otherwise, pp writes to the file.
731
 * - area = specify display area + truncate + stretch
732
 * - mode = initial print mode
733
 * - indent = initial indentation (increment)
734
 * If area s is NULL then the default area is used:
735
 * width = 80, height = infinite, offset = 0, don't stretch, truncate.
736
 */
737
extern void init_pp(pp_t *pp, pp_token_converter_t *converter, FILE *file,
738
                    pp_area_t *area, pp_print_mode_t mode, uint32_t indent);
739

740

741
/*
742
 * Check the writer type: either a stream or a string writer.
743
 */
744
static inline bool is_stream_pp(pp_t *pp) {
49,812✔
745
  return is_stream_writer(&pp->printer.writer);
49,812✔
746
}
747

748
static inline bool is_string_pp(pp_t *pp) {
749
  return is_string_writer(&pp->printer.writer);
750
}
751

752

753
/*
754
 * Process token tk.
755
 */
756
extern void pp_push_token(pp_t *pp, void *tk);
757

758

759
/*
760
 * Flush the printer: empty the internal queues and print
761
 * the pending tokens. Reset the line counter to 0.
762
 * - if new_line is true, also print '\n'
763
 */
764
extern void flush_pp(pp_t *pp, bool new_line);
765

766

767
/*
768
 * After flush: extract the string constructed by pp
769
 * - pp must be initialized for a string buffer (i.e., file = NULL)
770
 * - the string's length is stored in *len
771
 * - the string must be deleted by free when it's no longer needed
772
 */
773
extern char *pp_get_string(pp_t *pp, uint32_t *len);
774

775

776
/*
777
 * Delete the printer: free memory.
778
 * (This may call the free_token functions in pp->converter).
779
 */
780
extern void delete_pp(pp_t *pp);
781

782

783
/*
784
 * Check whether the print area is full
785
 * - if this is true, it's useless to push new tokens
786
 * - this also return true if pp->printed_failed is true
787
 *   (i.e., one of fputs, fputc, or fflush returned an error).
788
 */
789
extern bool pp_is_full(pp_t *pp);
790

791

792
/*
793
 * Get the printer depth = number of open blocks
794
 */
795
static inline uint32_t pp_depth(pp_t *pp) {
250✔
796
  return pp->formatter.depth;
250✔
797
}
798

799

800
/*
801
 * Initialize an open token tk and return the tagged pointer tag_open(tk).
802
 * - formats = allowed formats for that token (PP_??_LAYOUT)
803
 * - lsize = label size
804
 * - indent = indentation for V and M layouts
805
 * - short_indent = indentation for the T layout
806
 * - flags = combination of PP_TOKEN_PAR_MASK and PP_TOKEN_SEP_MASK
807
 * - user_tag = whatever the converter needs
808
 */
809
extern void *init_open_token(pp_open_token_t *tk, uint32_t formats, uint32_t flags,
810
                             uint16_t lsize, uint16_t indent, uint16_t short_indent,
811
                             uint32_t user_tag);
812

813

814
/*
815
 * Initialize an atomic token tk and return the tagged pointer tag_atomic(tk).
816
 * - size = token size (when converted to a string)
817
 * - user_tag = whatever the converter needs
818
 */
819
extern void *init_atomic_token(pp_atomic_token_t *tk, uint32_t size, uint32_t user_tag);
820

821
/*
822
 * Same thing got a separator token tk (return tag_separator(tk))
823
 * - size = token size when converted to string
824
 * - user_tag = tag for the converter
825
 */
826
extern void *init_separator_token(pp_atomic_token_t *tk, uint32_t size, uint32_t user_tag);
827

828

829
/*
830
 * Initialize a close token tk and return the tagged pointer tag_close(tk).
831
 * - par: true if the token contains ')'
832
 * - user_tag: any thing used by the free_close_token in the converter
833
 */
834
extern void *init_close_token(pp_close_token_t *tk, bool par, uint32_t user_tag);
835

836

837

838

839
#endif /* __PRETTY_PRINTER_H */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc