From 7c8f1b9290c1c44673119b5d88112459411f25b7 Mon Sep 17 00:00:00 2001 From: Sorawee Porncharoenwase Date: Tue, 28 Nov 2023 19:09:23 -0800 Subject: [PATCH] doc: use mdx for examples in documentation --- CHANGES.md | 1 + doc/dune | 3 +++ doc/index.mld | 69 ++++++++++++++++++++++++++++------------------- doc/prelude.ml | 1 + dune-project | 3 +++ lib/dune | 4 +++ lib/prelude.ml | 1 + lib/printer.mli | 60 ++++++++++++++++++++--------------------- lib/signature.mli | 19 ++++++------- 9 files changed, 94 insertions(+), 67 deletions(-) create mode 100644 doc/prelude.ml create mode 100644 lib/prelude.ml diff --git a/CHANGES.md b/CHANGES.md index d35f5b7..7d8fcc5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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) diff --git a/doc/dune b/doc/dune index 1904dec..44f6111 100644 --- a/doc/dune +++ b/doc/dune @@ -1,2 +1,5 @@ (documentation (package pretty_expressive)) + +(mdx (files :standard - *.mld) + (preludes prelude.ml)) diff --git a/doc/index.mld b/doc/index.mld index e323d0c..ab07f7c 100644 --- a/doc/index.mld +++ b/doc/index.mld @@ -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. @@ -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 @@ -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} @@ -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. @@ -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 *) @@ -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 diff --git a/doc/prelude.ml b/doc/prelude.ml new file mode 100644 index 0000000..ce0cf79 --- /dev/null +++ b/doc/prelude.ml @@ -0,0 +1 @@ +#require "pretty_expressive";; diff --git a/dune-project b/dune-project index 230f80a..ebecbd5 100644 --- a/dune-project +++ b/dune-project @@ -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))) diff --git a/lib/dune b/lib/dune index 206f202..2909775 100644 --- a/lib/dune +++ b/lib/dune @@ -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)) diff --git a/lib/prelude.ml b/lib/prelude.ml new file mode 100644 index 0000000..ce0cf79 --- /dev/null +++ b/lib/prelude.ml @@ -0,0 +1 @@ +#require "pretty_expressive";; diff --git a/lib/printer.mli b/lib/printer.mli index dcc5927..3a167d5 100644 --- a/lib/printer.mli +++ b/lib/printer.mli @@ -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) + ]} *) diff --git a/lib/signature.mli b/lib/signature.mli index 0bf538e..4c67836 100644 --- a/lib/signature.mli +++ b/lib/signature.mli @@ -109,15 +109,16 @@ Portal {5 Examples:} {[ -# let left_doc = text "Splatoon" ^^ nl ^^ text "Nier";; -val left_doc : doc = -# let right_doc = text "Automata" ^^ nl ^^ text "FEZ";; -val right_doc : doc = -# 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