package pretty_expressive

  1. Overview
  2. Docs

The pretty printer and doc combinators, parameterized by a cost factory. See Signature.PrinterT for details.

A pretty expressive printer. The rest of this section assumes that the program begins with

open Pretty_expressive

let cf = Printer.default_cost_factory ~page_width:10 ()
module P = Printer.Make (val cf)
open P

Parameters

Signature

type doc

The doc type

type cost = C.t

The cost type

Text document

val text : string -> doc

text s is a document for textual content s; s must not contain a newline.

Examples:

# pretty_print (text "Portal") |> print_endline;;
Portal
- : unit = ()

Newline documents

val newline : string option -> doc

newline s is a document for a newline. When s is None, it flattens to fail. When s is not None, it flattens to text s. See flatten for more details.

val nl : doc

nl is a document for a newline that flattens to a single space.

val break : doc

break is a document for a newline that flattens to an empty string.

val hard_nl : doc

hard_nl is a document for a newline that fails to flatten.

Choice document

val (<|>) : doc -> doc -> doc

a <|> b is a document for a choice between document a and b.

# let print_doc w =
    let cf = Printer.default_cost_factory ~page_width:w () in
    let module P = Printer.Make (val cf) in
    let open P in
    pretty_print (text "Chrono Trigger" <|>
                 (text "Octopath" <> nl <> text "Traveler")) |> print_endline;;
val print_doc : int -> unit = <fun>
# print_doc 10;;
Octopath
Traveler
- : unit = ()
# print_doc 15;;
Chrono Trigger
- : unit = ()

See also Best Practice for Document Construction

Concatenation document

val (<>) : doc -> doc -> doc

a <> b is a document for concatenation of documents a and b without alignment. It's also known as the unaligned concatenation, which is widely used in traditional pretty printers.

Examples:

# let left_doc = text "Splatoon" <> nl <> text "Nier";;
val left_doc : doc = <abstr>
# let right_doc = text "Automata" <> nl <> text "FEZ";;
val right_doc : doc = <abstr>
# pretty_print (left_doc <> right_doc) |> print_endline;;
Splatoon
NierAutomata
FEZ
- : unit = ()

By "without alignment," we mean that the right document is not treated as as box with a rigid structure. This makes it easy to format code in C-like languages, whose array expression, function call, and curly braces should not be rigid.

Indentation documents

val align : doc -> doc

align d is a document that aligns d at the column position.

Examples:

# pretty_print (left_doc <> align right_doc) |> print_endline;;
Splatoon
NierAutomata
    FEZ
- : unit = ()

The aligned concatenation operator (<+>) is a derived combinator that composes (<>) and align together. It is especially useful for languages that uses the the box model for code styling.

val nest : int -> doc -> doc

nest n d is a document that increments the indentation level by n when rendering d.

Examples:

# pretty_print (text "when 1 = 2:" <> nest 4 (nl <> text "print 'oh no!'"))
  |> print_endline;;
when 1 = 2:
    print 'oh no!'
- : unit = ()

The increment does not affect content on the current line. In the following example, when 1 = 2: is not further indented.

# pretty_print (nest 4 (text "when 1 = 2:" <> nl <> text "print 'oh no!'"))
  |> print_endline;;
when 1 = 2:
    print 'oh no!'
- : unit = ()
val reset : doc -> doc

reset d is a document that resets indentation level to 0 in d. This is especially useful for formatting multi-line strings and multi-line comments.

Examples:

# let s_d = reset (text "#<<EOF" <> nl <>
                   text "Zelda" <> nl <>
                   text "Baba is you" <> nl <>
                   text "EOF");;
val s_d : doc = <abstr>
# pretty_print (text "when 1 = 2:" <> nest 4 (nl <> text "print " <> s_d))
  |> print_endline;;
when 1 = 2:
    print #<<EOF
Zelda
Baba is you
EOF
- : unit = ()

Cost document

val cost : cost -> doc -> doc

cost c d is a document that artificially adds cost c to d.

In the below example, we artificially adds overflow to text "Chrono Trigger", making it a non-optimal choice, even though text "Chrono Trigger" would have been the optimal choice had cost not been used.

Examples:

# pretty_print (cost (1, 0) (text "CrossCode") <|>
                (text "Final" <> nl <> text "Fantasy")) |> print_endline;;
Final
Fantasy
- : unit = ()
# pretty_print (text "CrossCode" <|>
                (text "Final" <> nl <> text "Fantasy")) |> print_endline;;
CrossCode
- : unit = ()

cost is especially useful in combination with a custom cost factory. See the section for further details.

Failure document

val fail : doc

A document that always fails. It interacts with (<|>): failing branches are pruned away.

Examples:

# pretty_print (text "Sea of Stars" <> fail) |> print_endline;;
Exception: Failure "fails to render".
# pretty_print ((text "Sea of Stars" <> fail) <|> text "Hades") |> print_endline;;
Hades
- : unit = ()

Pretty printing functions

val print : ?init_c:int -> doc -> Util.info

print d prints the document d to an info record. The optional ~init_c can be used to indicate that the printing begins at a non-zero column position.

val pretty_print : ?init_c:int -> doc -> string

pretty_print d prints the document d to a string. The optional ~init_c can be used to indicate that the printing begins at a non-zero column position.

Examples:

# print_string "Languages: ";
  pretty_print (align (text "Racket" <> nl <>
                       text "OCaml" <> nl <>
                       text "Pyret")) |> print_endline;;
Languages: Racket
OCaml
Pyret
- : unit = ()
# print_string "Languages: ";
  pretty_print ~init_c:11
               (align (text "Racket" <> nl <>
                       text "OCaml" <> nl <>
                       text "Pyret")) |> print_endline;;
Languages: Racket
           OCaml
           Pyret
- : unit = ()

Other derived combinators

val flatten : doc -> doc

flatten d is a document that replaces newlines and indentation spaces with what's specified in newline when rendering d.

Examples:

# pretty_print (flatten (text "Fire Emblem" <> nl <> text "Awakening"))
  |> print_endline;;
Fire Emblem Awakening
- : unit = ()
# pretty_print (flatten (text "Mario + Rabbids" <> break <> text "Kingdom Battle"))
  |> print_endline;;
Mario + RabbidsKingdom Battle
- : unit = ()
# pretty_print (flatten (text "XCOM 2" <> hard_nl <> text "War of the Chosen"))
  |> print_endline;;
Exception: Failure "fails to render".
# pretty_print (flatten (text "Tactics Ogre" <>
                         newline (Some ": ") <>
                         text "Reborn"))
  |> print_endline;;
Tactics Ogre: Reborn
- : unit = ()
val group : doc -> doc

group d is a shorthand for d <|> flatten d. This combinator is a part of most traditional pretty printers.

val (<+>) : doc -> doc -> doc

a <+> b is a shorthand for a <> align b. It is also known as the aligned concatenation.

val (<$>) : doc -> doc -> doc

a <$> b is a shorthand for a <> hard_nl <> b.

val (<->) : doc -> doc -> doc

a <-> b is a shorthand for flatten a <+> b. This is especially useful when combined with hard_nl and (<|>): it can be used when we want to do aligned concatenation, but don't want the left part to have multiple lines.

val fold_doc : (doc -> doc -> doc) -> doc list -> doc

fold_doc (++) ds is a shorthand for d_1 ++ d_2 ++ ... ++ d_n where d_1 d_2 ... d_n are drawn from ds.

val vcat : doc list -> doc

vcat ds is a shorthand for d_1 <$> d_2 <$> ... <$> d_n where d_1 d_2 ... d_n are drawn from ds.

val hcat : doc list -> doc

vcat ds is a shorthand for d_1 <-> d_2 <-> ... <-> d_n where d_1 d_2 ... d_n are drawn from ds.

val empty : doc

Equivalent to text ""

val space : doc

Equivalent to text " "

val comma : doc

Equivalent to text ","

val lbrack : doc

Equivalent to text "["

val rbrack : doc

Equivalent to text "]"

val lbrace : doc

Equivalent to text "{"

val rbrace : doc

Equivalent to text "}"

val lparen : doc

Equivalent to text "("

val rparen : doc

Equivalent to text ")"

val dquote : doc

Equivalent to text "\""

OCaml

Innovation. Community. Security.