Skip to content

Commit

Permalink
doc: use mdx for examples in documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
sorawee committed Nov 29, 2023
1 parent 033e11f commit 7c8f1b9
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
(thanks to @EmileTrotignon who made the suggestion in
[the OCaml forum](https://discuss.ocaml.org/t/ann-first-release-of-pretty-expressive-a-pretty-expressive-printer/13516/2)).
* Improve documentation
* Use mdx for documentation

## 0.1 (2023-11-26)

Expand Down
3 changes: 3 additions & 0 deletions doc/dune
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
(documentation
(package pretty_expressive))

(mdx (files :standard - *.mld)
(preludes prelude.ml))
69 changes: 41 additions & 28 deletions doc/index.mld
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,23 @@
This library implements a pretty expressive printer, following the algorithm presented in {{: https://dl.acm.org/doi/abs/10.1145/3622837 }A Pretty Expressive Printer (OOPSLA'23)}.
The pretty printer is expressive, provably optimal, and practically efficient.

{1 Getting Started}
{1 Quick Start}

{[
open Pretty_expressive
(* Sets the page width limit to 80 *)
let cf = Printer.default_cost_factory ~page_width:80 ()
module P = Printer.Make (val cf)
open P
]}

{[
# pretty_print (text "Hello" ^^ text " World!") |> print_endline;;
Hello World!
- : unit = ()
]}

{1 A Tour of Pretty Expressive}

General-purpose pretty printing is a process that produces human readable text from structured data.
Users encode the structured data together with styling choices in an abstract {i document} {{!Pretty_expressive.Printer.Make.doc} [doc]}. This document contains printing instructions: things like text, newlines, and indentation.
Expand All @@ -18,7 +34,7 @@ Here’s a simple example that pretty prints a document encoding a fragment of c
open Pretty_expressive

(** Prints the example document [d] with the page width limit [w] *)
let print_doc (w : int): unit =
let print_doc (w : int) =
let cf = Printer.default_cost_factory ~page_width:w () in
let module P = Printer.Make (val cf) in
let open P in
Expand Down Expand Up @@ -91,35 +107,31 @@ are in scope.
With the above setup, we can pretty-print [d] with the cost factory [cf] by calling [pretty_print d].
This returns a string that we can then put on screen.

Let's now actually use the pretty printer.

{[let () = print_doc 80 |> print_endline]}
Let's now actually use the pretty printer with page width limit of 80.

would output:

{v
{[
# print_doc 80 |> print_endline
while (true) {
f();
if (done()) exit();
}
v}

because the layout fits the page width limit, while having fewer lines.
By contrast:

{[let () = print_doc 20 |> print_endline]}
- : unit = ()
]}

would output:
It outputs the above layout because the layout fits the page width limit, while having fewer lines.
By contrast, with the page width limit of 20:

{v
{[
# print_doc 20 |> print_endline
while (true) {
f();
if (done())
exit();
}
v}
- : unit = ()
]}

because the other layout does not fit the page width limit,
It outputs the above layout because the other layout does not fit the page width limit,
leaving this output layout as the only option.

{2 Alternative Document Construction}
Expand All @@ -130,18 +142,18 @@ Some may be easier than the other.
For example, another way to construct a document for the above example could be:

{[
let d = text "while (true) {" ^^
nest 4
(nl ^^ text "f();" ^^ nl ^^ text "if (done())" ^^
group (nest 4 (nl ^^ text "exit();"))) ^^
nl ^^ text "}"
let d = text "while (true) {" ^^
nest 4
(nl ^^ text "f();" ^^ nl ^^ text "if (done())" ^^
group (nest 4 (nl ^^ text "exit();"))) ^^
nl ^^ text "}"
]}

Here, the {{!Pretty_expressive.Printer.Make.group}[group]} combinator is used.
It creates a choice: whether to collapse {{!Pretty_expressive.Printer.Make.nl}[nl]}
to a single space or not.

See {!Pretty_expressive.Printer.Make} for the full list of combinators that we provide.
See {{!Pretty_expressive.Printer.Make}[Printer.Make]} for the full list of combinators that we provide.
Since combinators are simply regular functions, users may also compose the existing combinators together
to create new user-defined combinators.

Expand Down Expand Up @@ -221,7 +233,7 @@ document construction could take exponential time, and the resulting
document whose DAG size is very large would also cause pretty-printing
to be inefficient.

{[
{@ocaml skip[
lparen <+>
(acat (pretty x :: List.map pretty xs) <|> (* the horizontal style *)
vcat (pretty x :: List.map pretty xs) <|> (* the vertical style *)
Expand Down Expand Up @@ -286,10 +298,11 @@ Consider the example in {!bestpractice}. Each list node can be rendered with thr
the horizontal style, the vertical style, and the argument list style.

{[
# let example_sexp =
List [Atom "abc"; Atom "def"; List [Atom "ghi"; Atom "jkl"; Atom "mno"]];;
val example_sexp : sexp =
let example_sexp =
List [Atom "abc"; Atom "def"; List [Atom "ghi"; Atom "jkl"; Atom "mno"]]
]}

{[
# print_sexp example_sexp 15 |> print_endline;;
(abc
def
Expand Down
1 change: 1 addition & 0 deletions doc/prelude.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#require "pretty_expressive";;
3 changes: 3 additions & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@

(documentation https://sorawee.github.io/pretty-expressive-ocaml/)

(using mdx 0.2)

(package
(name pretty_expressive)
(synopsis "A pretty expressive printer")
(description "A pretty printer implementation of 'A Pretty Expressive Printer' (OOPSLA'23), with an emphasis on expressiveness and optimality.")
(depends (ocaml (>= 4.05))
dune
mdx
(alcotest :with-test)))
4 changes: 4 additions & 0 deletions lib/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
(library
(public_name pretty_expressive)
(name pretty_expressive)
(modules (:standard \ prelude))
(modules_without_implementation signature))

(mdx (files :standard - *.mli)
(preludes prelude.ml))
1 change: 1 addition & 0 deletions lib/prelude.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#require "pretty_expressive";;
60 changes: 30 additions & 30 deletions lib/printer.mli
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,33 @@ val default_cost_factory : page_width:int -> ?computation_width:int -> unit ->
Internally, [default_cost_factory] is defined as:
{[
let default_cost_factory ~page_width ?computation_width () =
(module struct
type t = int * int
let limit = match computation_width with
| None -> (float_of_int page_width) *. 1.2 |> int_of_float
| Some computation_width -> computation_width
let text pos len =
let stop = pos + len in
if stop > page_width then
let maxwc = max page_width pos in
let a = maxwc - page_width in
let b = stop - maxwc in
(b * (2*a + b), 0)
else
(0, 0)
let newline _ = (0, 1)
let combine (o1, h1) (o2, h2) =
(o1 + o2, h1 + h2)
let le (o1, h1) (o2, h2) =
if o1 = o2 then h1 <= h2 else o1 < o2
let debug (o, h) = Printf.sprintf "(%d %d)" o h
end: Signature.CostFactory with type t = int * int)
]} *)
{@ocaml skip[
let default_cost_factory ~page_width ?computation_width () =
(module struct
type t = int * int
let limit = match computation_width with
| None -> (float_of_int page_width) *. 1.2 |> int_of_float
| Some computation_width -> computation_width
let text pos len =
let stop = pos + len in
if stop > page_width then
let maxwc = max page_width pos in
let a = maxwc - page_width in
let b = stop - maxwc in
(b * (2*a + b), 0)
else
(0, 0)
let newline _ = (0, 1)
let combine (o1, h1) (o2, h2) =
(o1 + o2, h1 + h2)
let le (o1, h1) (o2, h2) =
if o1 = o2 then h1 <= h2 else o1 < o2
let debug (o, h) = Printf.sprintf "(%d %d)" o h
end: Signature.CostFactory with type t = int * int)
]} *)
19 changes: 10 additions & 9 deletions lib/signature.mli
Original file line number Diff line number Diff line change
Expand Up @@ -109,15 +109,16 @@ Portal
{5 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 = ()
let left_doc = text "Splatoon" ^^ nl ^^ text "Nier";;
let right_doc = text "Automata" ^^ nl ^^ text "FEZ";;
]}
{[
# 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
Expand Down

0 comments on commit 7c8f1b9

Please sign in to comment.