PP Module
signature PP
structure PP :> PP
The module implements a simple form of pretty-printing.
val newline : string
type pp
val toString : pp -> string
val empty : pp
val block : bool * pp list -> pp
val decorate : string * pp * string -> pp
val quote : pp -> pp
val comma : pp -> pp
val colon : pp -> pp
val semicolon : pp -> pp
val fromString : string -> pp
val fromStringSplitEscape : string -> pp
newline
"\n", but on Windows it is "\r\n".
type pp
pp were implemented as
datatype pp = Block of bool * pp list
| Decorate of string * pp * string
but it's actually implemented in a way allowing more efficient processing.
toString pp
pp into a string where, if possible, all of the string's lines are no longer than the current printing line length (see Params.getPrintingLineLength). This translation is carried out using a recursive function that is supplied a value pp of pp to be turned into a string, together with the current indentation ind and the after size aft, i.e., the size of the string that will immediately follow the final line of the translation of pp. A recursive call is not responsible for generating the ind spaces that will preceed pp's translation in the overall translation.
Block(spaceNoBreak, pps) is turned into a string consisting of one of more lines, all but the first of which begin with ind spaces. This is done by recursively translating the elements of pps, in sequence, with appropriate indentations and after sizes. If the translations of a sequence of elements of pps—separated by blanks iff spaceNoBreak is true—fit on a single line (including the ind initial spaces, and leaving room for aft additional characters, if the final element of pps is included), then the elements' translations are combined in this way. But when an element's translation requires multiples lines, it is never combined with other translations, either before or after. The translation of the final element of pp, whether combined with other translations or not, must always be computed by taking into account that aft additional characters will immediately follow its last line.
Decorate(s1, pp, s2) is turned into the string consisting of the concatenation of:
s1,
pp with indentation ind + size s1, and after size size s2 + aft, and
s2.
empty
Block(true, nil).
block
Block.
decorate
Decorate.
quote pp
Decorate("\"", pp, "\"").
comma pp
Decorate("", pp, ",").
colon pp
Decorate("", pp, ":").
semicolon pp
Decorate("", pp, ";").
fromString s
Decorate(s, empty, "").
fromStringSplitEscape s
Block(false,
map (fn c => fromString(Char.toString c))
(explode s))
where Char.toString escapes non-printable characters (as well as double quotes and backslashes) using SML escape sequences.
For example, if the current printing line length is 30, running
val pp =
PP.decorate
("(",
PP.block
(true,
[PP.fromString "once", PP.fromString "upon", PP.fromString "a",
PP.fromString "time"]),
")");
val pp' =
PP.decorate
("[",
PP.block(false, [pp, pp, pp]),
"]");
print(PP.toString pp' ^ "\n");
results in the output
[(once upon a
time)
(once upon a
time)
(once upon a
time)]
And, if the current printing line length is 60, running the same code results in
[(once upon a time)(once upon a time)(once upon a time)]
Forlan Version 4.15
Copyright © 2022 Alley Stoughton