File: pprintf.html

package info (click to toggle)
camlp5 8.04.00-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 11,968 kB
  • sloc: ml: 137,918; makefile: 2,055; perl: 1,729; sh: 1,653; python: 38
file content (634 lines) | stat: -rw-r--r-- 17,956 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <!-- pprintf.html,v -->
  <!-- Copyright (c) INRIA 2007-2017 -->
  <title>pprintf</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <link rel="stylesheet" type="text/css" href="styles/base.css"
        title="Normal" />
</head>
<body>

<div id="menu">
</div>

<div id="content">

<h1 class="top">Pprintf</h1>

<p>This chapter describes "pprintf", a statement to pretty print data.
  It looks like the "sprintf" function of the OCaml library, and
  borrows some ideas of the Format OCaml library. Another statement,
  "lprintf", is a slightly different version of "pprintf" handling
  with locations.</p>

<div id="tableofcontents">
</div>

<h2>Syntax of the pprintf statement</h2>

<p>The "pprintf" statement is added by the <em>parsing kit</em>
"<tt>pa_pprintf.cmo</tt>".</pp>

<p>Notice that, in opposition to "printf", "fprintf", "sprintf", and
  all its variants, which are functions, this "pprintf" is a
  <em>statement</em>, not a function: "pprintf" is a keyword and the
  expander analyzes its string format parameter to generate specific
  statements. In particular, it cannot be used alone and has no type
  by itself.</p>

<pre>
        expression ::= pprintf-statement
 pprintf-statement ::= "pprintf" qualid format expressions
            qualid ::= qualid "." qualid
                     | uident
                     | lident
            format ::= string
       expressions ::= expression expressions
                     | &lt;nothing&gt;
</pre>

<h2>Semantics of pprintf</h2>

<p>The "pprintf" statement converts the format string into a string
  like the "sprintf" of the OCaml library "Printf" does (see the OCaml
  manual for details). The string format can accept new conversion
  specifications, "%p" and "%q", and some pretty printing annotations,
  starting with "@" like in the OCaml library "Format".</p>

<p>The "pprintf" statement takes as first parameter, a value of type
  "pr_context" defined below. Its second parameter is the extended
  format string. It can take other parameters, depending on the
  format, like "sprintf".</p>

<p>The result of "pprintf" is always a string. There is no versions
  applying to files or buffers.</p>

<p>The strings built by "pprintf" are concatened by the function
  "Pretty.sprintf" (see the chapter entitled
  "<a href="pretty.html">Pretty Print</a>") which controls the line
  length and prevents overflowing.</p>

<h3>Printing context</h3>

<p>The "pprintf" statement takes, as first parameter, a <em>printing
  context</em>. It is a value of the following type:</p>

<pre>
  type pr_context =
    { ind : int;
      bef : string;
      aft : string;
      dang : string };
</pre>

<p>The fields are:</p>

<ul>
  <li>"<tt>ind</tt>" : the current indendation</li>
  <li>"<tt>bef</tt>" : what should be printed before, in the same line</li>
  <li>"<tt>aft</tt>" : what should be printed after, in the same line</li>
  <li>"<tt>dang</tt>" : the dangling token to know whether parentheses
    are necessary</li>
</ul>

<p>Basically, the "pprintf" statement concats the "bef" string, the
  formatted string and the "aft" string. The example:</p>

<pre>
  pprintf pc "hello world"
</pre>

<p>is equivalent to (and indeed generates):</p>

<pre>
  Pretty.sprintf "%shello world%s" pc.bef pc.aft
</pre>

<p>But if the format string contains conversion specifications "%p" or
  "%q", the "bef" and "aft" strings are actually transmitted to the
  corresponding functions:</p>

<pre>
  pprintf pc "hello %p world" f x
</pre>

<p>is equivalent to:</p>

<pre>
  f {(pc) with
     bef = Pretty.sprintf "%shello " pc.bef;
     aft = Pretty.sprintf " world%s" pc.aft}
    x
</pre>

<p>Thus, the decision of including the "bef" and the "aft" strings are
  delayed to the called function, allowing this function to possibly
  concatenate "bef" and "aft" to its own strings.</p>

<p>A typical case is, while printing programs, when an expression
  needs to be printed between parentheses. The code which does that
  looks like:</p>

<pre>
  pprintf pc "(%p)" expr e
</pre>

<p>The right parenthesis of this string format is included in the
  "aft" string transmitted to the function "expr". In a situation when
  several right parentheses are concatened this way, the fact that all
  these parentheses are grouped together allows the function which
  eventually print them to decide to break the line or not, these
  parentheses being taken into account in the line length.</p>

<p>For example, if the code contains a print of an program containing
  an application whose source is:</p>

<pre>
  myfunction myarg
</pre>

<p>and if the "aft" contains "))))))", the decision of printing in one
  line as:</p>

<pre>
  myfunction myarg))))))
</pre>

<p>or in two lines as:

<pre>
  myfunction
    myarg))))))
</pre>

<p>is exact, the right parentheses being added to "myarg" to determine
  whether the line overflows or not.</p>

<h3>Extended format</h3>

<p>The extended format used by "pprintf" may contain any strings and
  conversion specifications allowed by the "sprintf" function (see
  module "Printf" of the OCaml library), plus:</p>

<ul>
  <li>the conversion specifications: "<tt>%p</tt>" and
    "<tt>q</tt>",</li>
  <li>the pretty printing annotations introduced by, "<tt>@</tt>"
    and followed by:
    <ul>
      <li>the character "<tt>;</tt>" (semicolon), optionally followed
        by "<tt>&lt;</tt>", two numbers and "<tt>&gt;</tt>",</li>
      <li>the character "<tt>&nbsp;</tt>" (space),</li>
      <li>the character "<tt>[</tt>", optionally followed by the character
        "<tt>&lt;</tt>" and either:
        <ul>
          <li>the character "<tt>a</tt>"</li>
          <li>the character "<tt>b</tt>"</li>
          <li>a number</li>
        </ul>
        and the character "<tt>&gt;</tt>", then followed by format
        string, and ended with "<tt>@]</tt>"</li>
    </ul>
  </li>
</ul>

<p>The format string is applied like in the "sprintf"
  function. Specific actions are done for the extended features. The
  result is a string like for the "sprintf" function. The "string
  before" and "string after" defined by the fields "bef" and "aft" of
  the printing context are taken into account and it is not necessary
  to add them in the format.</p>

<p>Example:</p>

<pre>
  pprintf pc "hello, world"
</pre>

<p>generates:</p>

<pre>
  Pretty.sprintf "%shello, world%s" pc.bef pc.aft;
</pre>

<p>An empty format:</p>

<pre>
  pprintf pc "";
</pre>

<p>just prints the "before" and "after" strings:</p>

<pre>
  Pretty.sprintf "%s%s" pc.bef pc.aft;
</pre>

<h3>Line length</h3>

<p>The function "pprintf" uses the Camlp5 "Pretty" module. The line
  length can be set by changing the value of the reference
  "Pretty.line_length".</p>

<h3>The conversion specifications "p" and "q"</h3>

<p>The "%p" conversion specification works like the "%a" of the printf
  statement. It takes two arguments and applies the first one to the
  printing context and to the second argument. The first argument must
  therefore have type "<tt>pr_context -> t -> unit</tt>" (for some
  type "<tt>t</tt>") and the second one "t".</p>

<p>Notice that this function can be called twice: one to test whether
  the resulting string holds in the line, and another one to possibly
  recall this function to print it in several lines. In the two cases,
  the printing context given as parameter is different.</p>

<p>It uses the functions defined in the
  "<a href="pretty.html">Pretty</a>" module.

<p>Example: the following statement:</p>

<pre>
  pprintf pc "hello, %p, world" f x
</pre>

<p>is equivalent to:</p>

<pre>
  f {(pc) with
     bef = Pretty.sprintf "%shello, " pc.bef;
     aft = Pretty.sprintf ", world%s" pc.aft}
    x
</pre>

<p>The "%q" conversion specification is like "%p" except that it takes
  a third argument which is the value of the "dang" field, useful when
  the syntax has "dangling" problems requiring parentheses. See
  chapter <a href="opretty.html">Extensions of printing</a> for more
  explanations about dangling problems.</p>

<p>The same example with "%q":</p>

<pre>
  pprintf pc "hello, %q, world" f x "abc"
</pre>

<p>is equivalent to:</p>

<pre>
  f {(pc) with
     bef = Pretty.sprintf "%shello, " pc.bef;
     aft = Pretty.sprintf ", world%s" pc.aft;
     dang = "abc"}
    x
</pre>

<h3>The pretty printing annotations</h3>

<h4>Breaks</h4>

<p>The pretty printing annotations allow to indicate places where
  lines can be broken. They all start with the "at" sign "@". The main
  ones are called <em>breaks</em> and are:<p>

<ul>
  <li>"<tt>@;</tt>" specifying: <em>write a space or 'a newline and an
      indentation incremented by 2 spaces'</em></li>
  <li>"<tt>@&nbsp;</tt>" specifying: <em>write a space or 'a newline
      and the indentation'</em></li>
</ul>

<p>Example - where "pc" is a variable of type "pr_context" (for
  example "Pprintf.empty_pc"):</p>

<pre>
  pprintf pc "hello,@;world"
</pre>

<p>builds the string, if it holds in the line:</p>

<pre>
  hello, world
</pre>

<p>and if it does not:</p>

<pre>
  hello,
    world
</pre>

<p>The second form:</p>

<pre>
  pprintf pc "hello,@ world"
</pre>

<p>is printed the same way, if it holds in the line, and if it does
  not, as:</p>

<pre>
  hello,
  world
</pre>

<p>The general form is:</p>

<ul>
  <li>"<tt>@;&lt;s o></tt>", which is a break with "<tt>s</tt>" spaces
    if the string holds in the line, or an indentation offset
    (incrementation of the indentation) of "<tt>o</tt>" spaces if the
    string does not hold in the line.</li>
</ul>

<p>The break "<tt>@;</tt>" is therefore equivalent to "<tt>@;&lt;1
  2></tt>" and "<tt>@&nbsp;</tt>" is equivalent to "<tt>@;&lt;1
  0></tt>".</p>

<h4>Parentheses</h4>

<p>A second form of the pretty printing annotations is the
  parenthesization of format strings possibly containing other pretty
  printing annotations. They start with "<tt>@[</tt>" and end with
  "<tt>@]</tt>".</p>

<p>It allows to change the associativity of the breaks. For example:</p>

<pre>
  pprintf pc "@[the quick brown fox@;jumps@]@;over the lazy dog"
</pre>

<p>If the whole string holds on the line, it is printed:</p>

<pre>
  the quick brown fox jumps over the lazy dog
</pre>

<p>If the whole string does not hold on the line, but "the quick brow
  fox jumps" does, it is printed:</p>

<pre>
  the quick brown fox jumps
    over the lazy dog
</pre>

<p>If the string "the quick brown fox jumps" does not hold on the line,
  the whole string is printed:</p>

<pre>
  the quick brown fox
    jumps
    over the lazy dog
</pre>

<p>Conversely, if the code is right associated:</p>

<pre>
  pprintf pc "the quick brown fox@;@[jumps@;over the lazy dog@]"
</pre>

<p>It can be printed:</p>

<pre>
  the quick brown fox jumps over the lazy dog
</pre>

<p>or:</p>

<pre>
  the quick brown fox
    jumps over the lazy dog
</pre>

<p>or:</p>

<pre>
  the quick brown fox
    jumps
      over the lazy dog
</pre>

<p>The default is left associativity: without parentheses, it is
  printed like in the first example.</p>

<h4>Incrementation of indentation</h4>

<p>The open parenthesis of the parenthesized form, "<tt>@[</tt>" can
  be followed by "<tt>&lt;n></tt>" where "<tt>n</tt>" is a number. It
  increments the current indentation (for possible newlines in the
  parenthesized text) with this number.</p>

<p>Example:</p>

<pre>
  pprintf pc "@[&lt;4>Incrementation@;actually of six characters@]"
</pre>

<p>makes the string (if not holding in the line):</p>

<pre>
  Incrementation
        actually of six characters
</pre>

<h4>Break all or nothing</h4>

<p>The open parenthesis of the parenthesized form, "<tt>@[</tt>" can
  be followed by "<tt>&lt;a></tt>". It specifies that if the string
  does not hold in the line, all breaks between the parentheses (at
  one only level) are printed in two lines, even if sub-strings could
  hold on the line. For example:</p>

<pre>
  pprintf pc "@[&lt;a>the quick brown fox@;jumps@;over the lazy dog@]"
</pre>

<p>can be printed only as:</p>

<pre>
  the quick brown fox jumps over the lazy dog
</pre>

<p>or as:</p>

<pre>
  the quick brown fox
    jumps
    over the lazy dog
</pre>

<h4>Break all</h4>

<p>The open parenthesis of the parenthesized form, "<tt>@[</tt>" can
  be followed by "<tt>&lt;b></tt>". It specifies that all breaks are
  always printed in two lines. For example:</p>

<pre>
  pprintf pc "@[&lt;b>the quick brown fox@;jumps@;over the lazy dog@]"
</pre>

<p>is printed in all circumstances:</p>

<pre>
  the quick brown fox
    jumps
    over the lazy dog
</pre>

<h4>Break all if</h4>

<p>The open parenthesis of the parenthesized form, "<tt>@[</tt>" can
  be followed by "<tt>&lt;i></tt>". Depending on the value of the
  boolean variable of the argument list, the breaks are all printed
  in two lines like with the "break all" option above, or not.
  For example:</p>

<pre>
  pprintf pc "%s@;@[&lt;i>%s,@;%s@]" "good" True "morning" "everybody";
  pprintf pc "%s@;@[&lt;i>%s,@;%s@]" "good" False "morning" "everybody";
</pre>

<p>are printed:</p>

<pre>
  good
    morning,
      everybody
  good morning, everybody
</pre>

<h4>Parentheses not neighbours of breaks</h4>

<p>In the examples above, we can remark that the left parentheses are
  always the begin of the string or are preceeded by a break, and that
  the right parentheses are always the end of the string or followed
  by a break.</p>

<p>When the parentheses "<tt>@[</tt>" and "<tt>@]</tt>" are not
  preceeded or followed by the string begin nor end, nor preceeded or
  followed by breaks, they are considered as the "bef" or "aft" part
  of the neighbour string. For example, the following forms:</p>

<pre>
  pprintf pc "the quick brown fox@[ jumps over@]"
</pre>

<p>and:</p>

<pre>
  pprintf pc "@[the quick brown fox @]jumps over"
</pre>

<p>are respectively equivalent to:</p>

<pre>
  let pc = {(pc) with aft = sprintf " jumps over%s" pc.aft} in
  Pretty.sprintf "%sthe quick brown fox%s" pc.bef pc.aft
</pre>

<p>and:</p>

<pre>
  let pc = {(pc) with bef = sprintf "%sthe quick brown fox" pc.bef} in
  Pretty.sprintf "%sjumps over%s" pc.bef pc.aft
</pre>

<p>In these examples, the results are identical, but it can be
  important if the non-parenthesized part contain one or several
  "%p". In this case, the corresponding function receives the "bef" or
  "aft" part in its pr_context variable and can take it into account
  when printing its data.</p>

<h3>Lprintf</h3>

<p>"Lprintf" is like "pprintf" with the same parameters. It is equivalent
  to an call to the function "expand_lprintf":</p>

<pre>
   lprintf pc "..."
</pre>

<p>is equivalent to:</p>

<pre>
   expand_lprintf pc loc (fun pc -&lt; pprintf pc "...")
</pre>

<p>The function "expand_lprintf" and the variable "loc" must be
  defined by the user in the environment where "lprintf" is used.</p>

<p>"Lprintf" is used in predefined printers "pr_r.ml" and "pr_o.ml" to
  allow optional insertions of location comments in the output.</p>

<h2>Comparison with the OCaml modules Printf and Format</h2>

<h3>Pprintf and Printf</h3>

<p>The statement "pprintf" acts like the function
  "Printf.sprintf". But since it requires this extra parameter of type
  "pr_context" and needs the "%p" and "%q" conversions specifications
  (which do not exist in "Printf"), it was not possible to use the
  "Printf" machinery directly and a new statement had to be added.</p>

<p>The principle of "pprintf" and "sprintf" are the same. However,
  "pprintf" is a syntax extension and has no type by itself. It cannot
  be used alone or without all its required parameters.</p>

<h3>Pprintf and Format</h3>

<p>The pretty printing annotations look like the ones of the OCaml
  module Format. Actually, they have different semantics. They do not
  use <em>boxes</em> like "Format" does. In "pprintf" statement, the
  machinery acts only on indentations.</p>

<p>Notice that, with "pprintf", it is always possible to know the
  current indentation (it is the field "ind" of the "pr_context"
  variable) and it is therefore possible to take decisions before
  printing.</p>

<p>For example, it is possible, in a printer of OCaml statements, to
  decide to print all match cases symmetrically, i.e. all with one
  line for each case or all with newlines after the patterns.</p>

<p>It is what is done in the option "<tt>-flag E</tt>" added by the
  pretty printing kits "pr_r.cmo" (pretty print in revised syntax) and
  "pr_o.cmo" (pretty print in normal syntax). See
  chapter <a href="commands.html">Commands and Files</a> or type
  "<tt>camlp5 pr_r.cmo -help</tt>" or "<tt>camlp5 pr_o.cmo
  -help</tt>".</p>

<p>Another difference is that the internal behaviour of this printing
  system is accessible, and it is always possible to use the basic
  functions of the "Pretty" module ("horiz_vertic" and "sprintf") if
  the behaviour of "pprintf" is not what is desired by the
  programmer.</p>

<h2>Relation with the Camlp5 extensible printers</h2>

<p>The extensible printers of Camlp5 (see its
  corresponding <a href="printers.html">chapter</a>) use the type
  "<tt>pr_context</tt>" of "pprintf". It is therefore possible to use
  "pprintf" in the semantic actions of the extensible printers.  But
  it is not mandatory. An extensible printer can just use the "Pretty"
  module or even neither "pprintf" nor "Pretty".</p>

<p>The printing kits "<tt>pr_r.ml</tt>" and "<tt>pr_o.ml</tt>"
  (respectively pretty print in revised and in normal syntax) and some
  other related to them, are examples of usage of the "pprintf"
  statement.</p>

<h2>The Pprintf module</h2>

<p>See its <a href="library.html#a:Pprintf-module">section</a> in the
  chapter "Library".</p>

<div class="trailer">
</div>

</div>

</body>
</html>