format

    A faithful port of OCaml's Format module: pretty-printing boxes, break hints, tabulations, tags and printf-like format strings

    format
    pretty-printing
    printf
    ocaml
    Download zip
    Author
    Version
    0.1.1
    License
    LGPL-2.1-only WITH OCaml-LGPL-linking-exception
    Last updated
    4 hours ago
    Downloads
    6

    #bobzhang/format

    A faithful MoonBit port of OCaml's Format module (OCaml 4.14): the pretty-printing engine with its boxes, break hints, tabulations, semantic tags and maximum depth, the printf-like functions with their format strings (%d, %s, @[, @ , ...), and the convenience printers.

    let doc = @format.asprintf("@[<hov 2>let x =@ %a@]", [
    Print(ppf => ppf.print_list(
    pp_sep=ppf => ppf.printf(";@ ", []),
    @format.Formatter::print_int,
    @list.List([1, 2, 3]),
    )),
    ])

    #Formatters

    A Formatter prints to output functions (Formatter(out_string), given a function writing strings, or Formatter::of_out_functions), to a StringBuilder (Formatter::of_buffer) or to a list of symbolic items (Formatter::of_symbolic_output_buffer). OCaml's pp_<name> functions are methods of the formatter, without the prefix:

    OCamlMoonBit
    Format.formatter_of_buffer bFormatter::of_buffer(b)
    pp_open_box ppf 2ppf.open_box(2) (also open_hbox, open_vbox, open_hvbox, open_hovbox)
    pp_print_string ppf s, pp_print_asppf.print_string(s), ppf.print_as(size, s)
    pp_print_space ppf (), pp_print_cut, pp_print_breakppf.print_space(), ppf.print_cut(), ppf.print_break(width, offset)
    pp_print_custom_break ~fits ~breaksppf.print_custom_break(fits~, breaks~)
    pp_open_tbox, pp_set_tab, pp_print_tab, pp_print_tbreakppf.open_tbox(), ppf.set_tab(), ppf.print_tab(), ppf.print_tbreak(width, offset)
    pp_open_stag, pp_set_mark_tags, ...ppf.open_stag(StringTag(s)), ppf.set_mark_tags(true), ...
    pp_set_margin, pp_set_geometry, pp_set_max_boxes, ...ppf.set_margin(n), ppf.set_geometry(max_indent~, margin~), ...
    pp_print_list, pp_print_seq, pp_print_text, pp_print_option, pp_print_resultppf.print_list(...), ppf.print_iter(...), ppf.print_text(s), ...
    pp_print_flush ppf (), pp_print_newline ppf ()ppf.print_flush(), ppf.print_newline()

    #Format strings

    MoonBit has no typed format strings, so the format is parsed at run time, exactly like OCaml parses format literals (in the default, "legacy" mode of the compiler), and the arguments are given as an array of Arg:

    ppf.printf("@[<v 2>%s:@,%5.2f@,%a@]", [
    String("total"),
    Float(3.14159),
    Print(ppf => ppf.print_bool(true)),
    ])
    @format.asprintf("%-8s|%08.3e|%#x", [String("a"), Float(-1.5), Int(255)])

    • Int is used by %d %i %u %x %X %o and by * widths and precisions, with the semantics of OCaml's 63-bit int (%x of -1 is 7fffffffffffffff); Int32 by %ld...; Int64 by %Ld and %nd...; Float by %f %e %E %g %G %F %h %H; String by %s %S; Char by %c %C; Bool by %b %B.
    • %a and %t take a Print function (OCaml's %a takes a printer and a value: here, the printer is applied to its value).
    • %{ fmt %} and %( fmt %) take a Format(String).
    • All the formatting directives are supported: boxes @[<hov 2> and @], break hints @ , @,, @;<1 2>, @\n, @., @?, tags @{<tag> and @}, sizes @<n>, @@ and @%.

    The functions are Formatter::printf (OCaml's fprintf), Formatter::kprintf (kfprintf), asprintf, sprintf, kasprintf and dprintf. An invalid format string, or arguments that don't match it, abort the program: they are programming errors, detected by the type checker in OCaml. The error messages are OCaml's, and check_format checks a format string without printing:

    @format.check_format("%{%d") // raises Failure("invalid format \"%{%d\": unclosed sub-format, expected \"%}\" at character number 4")

    The conversions of numbers are also available directly: format_float_c(x, 'e', 6) is C's printf("%.6e", x), hexstring_of_float is OCaml's %h, and string_of_float is OCaml's string_of_float.

    #Differences with OCaml

    • Strings are Unicode. Like in OCaml, widths (of texts, padding, break hints...) and positions in error messages count UTF-8 bytes, so the output is the same as OCaml's for the same text. A Char is a Unicode character: %c prints it in UTF-8, and an invalid conversion such as %é is reported as such (OCaml prints the first byte of the character).
    • There are no global formatters (std_formatter, err_formatter...).
    • NaN with the + or space flag (%+f): the result depends on the C library in OCaml (nan on macOS, +nan on Linux); it is +nan here, as in C99.

    #Testing

    The tests of OCaml's testsuite for Format (tests/lib-format: tformat, pp_print_custom_break, print_if_newline, print_seq, pr6824) are ported with their reference outputs.

    The module is also tested by differential fuzzing against OCaml's Format: random scripts of pretty-printing operations, including printf with random format strings, are run with both implementations and their outputs are compared; see fuzz/README.md.

    #License

    This is a derivative work of OCaml's standard library, so it is distributed under the same license: the GNU Lesser General Public License version 2.1, with the special exception on linking described in LICENSE.

    InvalidArgument

    pub(all) suberror InvalidArgument {
    InvalidArgument(String)
    } derive(Eq,
    Debug
    )

    Error raised by functions given invalid arguments.

    InvalidArgument::equal

    InvalidArgument::not_equal

    fn InvalidArgument::not_equal(x : InvalidArgument, y : InvalidArgument) -> Bool

    Arg

    pub(all) enum Arg {
    Int(Int)
    Int32(Int)
    Int64(Int64)
    Float(Double)
    String(String)
    Char(Char)
    Bool(Bool)
    Print((Formatter) -> Unit)
    Format(String)
    }

    An argument of a printf-like function.

    Formatter

    pub struct Formatter {
    // private fields
    }

    A pretty-printer: the pretty-printing engine and its state.

    Formatter::Formatter

    fn Formatter::Formatter(output : (StringView) -> Unit, flush? : () -> Unit) -> Formatter

    Create a formatter that outputs with output and flushes with flush; newlines and spaces are output with output too. Like OCaml's make_formatter.

    Formatter::close_box

    fn Formatter::close_box(self : Formatter) -> Unit

    Close the most recently opened pretty-printing box.

    Formatter::close_stag

    fn Formatter::close_stag(self : Formatter) -> Unit

    Close the most recently opened semantic tag.

    Formatter::close_tag

    fn Formatter::close_tag(self : Formatter) -> Unit

    Close the most recently opened tag.

    Formatter::close_tbox

    fn Formatter::close_tbox(self : Formatter) -> Unit

    Close the most recently opened tabulation box.

    Formatter::force_newline

    fn Formatter::force_newline(self : Formatter) -> Unit

    Force a new line in the current box. Not the normal way of pretty-printing: prefer break hints within vertical boxes.

    Formatter::get_ellipsis_text

    fn Formatter::get_ellipsis_text(self : Formatter) -> String

    The text printed for boxes beyond the maximum.

    Formatter::get_geometry

    fn Formatter::get_geometry(self : Formatter) -> Geometry

    The geometry of the formatter.

    Formatter::get_margin

    fn Formatter::get_margin(self : Formatter) -> Int

    The right margin.

    Formatter::get_mark_tags

    fn Formatter::get_mark_tags(self : Formatter) -> Bool

    Whether the mark_*_stag markers of tags are output.

    Formatter::get_max_boxes

    fn Formatter::get_max_boxes(self : Formatter) -> Int

    The maximum number of simultaneously opened boxes.

    Formatter::get_max_indent

    fn Formatter::get_max_indent(self : Formatter) -> Int

    The maximum indentation.

    Formatter::get_out_functions

    fn Formatter::get_out_functions(self : Formatter) -> OutFunctions

    The output functions of the formatter.

    Formatter::get_output_functions

    fn Formatter::get_output_functions(self : Formatter) -> ((StringView) -> Unit, () -> Unit)

    The functions that output a string and flush the output, like OCaml's pp_get_formatter_output_functions.

    Formatter::get_print_tags

    fn Formatter::get_print_tags(self : Formatter) -> Bool

    Whether the print_*_stag functions are called on tags.

    Formatter::get_stag_functions

    fn Formatter::get_stag_functions(self : Formatter) -> StagFunctions

    The tag functions of the formatter.

    Formatter::kprintf

    fn[T] Formatter::kprintf(self : Formatter, k : (Formatter) -> T, fmt : String, args : ArrayView[Arg]) -> T

    Like printf, then call k with the formatter, like OCaml's Format.kfprintf.

    Formatter::of_buffer

    fn Formatter::of_buffer(buf : StringBuilder) -> Formatter

    Create a formatter writing to a string builder, like OCaml's formatter_of_buffer.

    Formatter::of_out_functions

    fn Formatter::of_out_functions(out : OutFunctions) -> Formatter

    Create a formatter from its output functions, like OCaml's formatter_of_out_functions.

    Formatter::of_symbolic_output_buffer

    fn Formatter::of_symbolic_output_buffer(sob : SymbolicOutputBuffer) -> Formatter

    Create a formatter whose output is stored in a symbolic output buffer.

    Formatter::open_box

    fn Formatter::open_box(self : Formatter, indent : Int) -> Unit

    Open a structural compacting box: like open_hovbox, but break hints also split the line if that reduces the indentation.

    Formatter::open_hbox

    fn Formatter::open_hbox(self : Formatter) -> Unit

    Open a horizontal box: break hints never split the line.

    Formatter::open_hovbox

    fn Formatter::open_hovbox(self : Formatter, indent : Int) -> Unit

    Open a horizontal-or-vertical compacting box: break hints split the line only when the material doesn't fit on it.

    Formatter::open_hvbox

    fn Formatter::open_hvbox(self : Formatter, indent : Int) -> Unit

    Open a horizontal/vertical box: horizontal if it fits on the line, otherwise vertical.

    Formatter::open_stag

    fn Formatter::open_stag(self : Formatter, tag : Stag) -> Unit

    Open a semantic tag.

    Formatter::open_tag

    fn Formatter::open_tag(self : Formatter, s : String) -> Unit

    Open a string tag (open_stag(StringTag(s))).

    Formatter::open_tbox

    fn Formatter::open_tbox(self : Formatter) -> Unit

    Open a tabulation box.

    Formatter::open_vbox

    fn Formatter::open_vbox(self : Formatter, indent : Int) -> Unit

    Open a vertical box: every break hint splits the line; indent is added to the current indentation.

    Formatter::over_max_boxes

    fn Formatter::over_max_boxes(self : Formatter) -> Bool

    Whether the maximum number of opened boxes is reached.

    Formatter::print_array

    fn[T] Formatter::print_array(self : Formatter, pp_sep? : (Formatter) -> Unit, pp_v : (Formatter, T) -> Unit, a : ArrayView[T]) -> Unit

    Print the elements of an array, like print_list.

    Formatter::print_as

    fn Formatter::print_as(self : Formatter, size : Int, s : String) -> Unit

    Print a string, pretending that its width is size.

    Formatter::print_bool

    fn Formatter::print_bool(self : Formatter, b : Bool) -> Unit

    Print a boolean.

    Formatter::print_break

    fn Formatter::print_break(self : Formatter, width : Int, offset : Int) -> Unit

    Break hint: print width spaces if the line is not split, otherwise split the line and add offset to the indentation.

    Formatter::print_char

    fn Formatter::print_char(self : Formatter, c : Char) -> Unit

    Print a character. Its width is 1.

    Formatter::print_custom_break

    fn Formatter::print_custom_break(self : Formatter, fits~ : (String, Int, String), breaks~ : (String, Int, String)) -> Unit

    Generalized break hint: fits = (before, width, after) is printed if the line is not split, breaks = (before, offset, after) if it is.

    Formatter::print_cut

    fn Formatter::print_cut(self : Formatter) -> Unit

    Break hint printing nothing if the line is not split (@,).

    Formatter::print_float

    fn Formatter::print_float(self : Formatter, f : Double) -> Unit

    Print a floating-point number in OCaml's syntax, like OCaml's string_of_float (12 significant digits).

    Formatter::print_flush

    fn Formatter::print_flush(self : Formatter) -> Unit

    Close all the opened boxes and print all the pending text, then flush the output device.

    Formatter::print_if_newline

    fn Formatter::print_if_newline(self : Formatter) -> Unit

    Execute the next formatting command only if the preceding line has just been split; otherwise, ignore it.

    Formatter::print_int

    fn Formatter::print_int(self : Formatter, i : Int) -> Unit

    Print an integer.

    Formatter::print_iter

    fn[T] Formatter::print_iter(self : Formatter, pp_sep? : (Formatter) -> Unit, pp_v : (Formatter, T) -> Unit, seq : Iter[T]) -> Unit

    Print the elements of an iterator, like OCaml's pp_print_seq.

    Formatter::print_list

    fn[T] Formatter::print_list(self : Formatter, pp_sep? : (Formatter) -> Unit, pp_v : (Formatter, T) -> Unit, l :
    List
    [T]) -> Unit

    Print the elements of a list with pp_v, separated by pp_sep (a cut by default), like OCaml's pp_print_list.

    Formatter::print_newline

    fn Formatter::print_newline(self : Formatter) -> Unit

    Like print_flush, followed by a newline.

    Formatter::print_nothing

    fn Formatter::print_nothing(_self : Formatter) -> Unit

    Print nothing.

    Formatter::print_option

    fn[T] Formatter::print_option(self : Formatter, none? : (Formatter) -> Unit, pp_v : (Formatter, T) -> Unit, o : T?) -> Unit

    Print an optional value with pp_v; None is printed with none, which prints nothing by default, like OCaml's pp_print_option.

    Formatter::print_result

    fn[T, E] Formatter::print_result(self : Formatter, ok~ : (Formatter, T) -> Unit, error~ : (Formatter, E) -> Unit, r : Result[T, E]) -> Unit

    Print a result with ok or error, like OCaml's pp_print_result.

    Formatter::print_space

    fn Formatter::print_space(self : Formatter) -> Unit

    Break hint printing a space if the line is not split (@ ).

    Formatter::print_string

    fn Formatter::print_string(self : Formatter, s : String) -> Unit

    Print a string in the current box. Its width is its length in UTF-8 bytes.

    Formatter::print_tab

    fn Formatter::print_tab(self : Formatter) -> Unit

    Move to the next tabulation stop (print_tbreak(0, 0)).

    Formatter::print_tbreak

    fn Formatter::print_tbreak(self : Formatter, width : Int, offset : Int) -> Unit

    Break hint in a tabulation box: move to the next tabulation stop, then print width spaces; if there is no room, split the line and add offset to the indentation.

    Formatter::print_text

    fn Formatter::print_text(self : Formatter, s : String) -> Unit

    Print free-flowing text, like OCaml's pp_print_text: spaces are break hints and newlines are forced newlines.

    Formatter::printf

    fn Formatter::printf(self : Formatter, fmt : String, args : ArrayView[Arg]) -> Unit

    Print on the formatter according to a format string, like OCaml's Format.fprintf. Conversions take their values from args, in order.

    Invalid formats and arguments that don't match the format abort the program, since they are programming errors (type errors in OCaml).

    Formatter::safe_set_geometry

    fn Formatter::safe_set_geometry(self : Formatter, max_indent~ : Int, margin~ : Int) -> Unit

    Like set_geometry, but does nothing if the geometry is invalid.

    Formatter::set_ellipsis_text

    fn Formatter::set_ellipsis_text(self : Formatter, s : String) -> Unit

    Set the text printed for boxes beyond the maximum (. by default).

    Formatter::set_geometry

    fn Formatter::set_geometry(self : Formatter, max_indent~ : Int, margin~ : Int) -> Unit raise InvalidArgument

    Set the margin and the maximum indentation, which must form a valid geometry.

    Formatter::set_margin

    fn Formatter::set_margin(self : Formatter, n : Int) -> Unit

    Set the right margin (78 by default). Ignored if n < 1.

    Formatter::set_mark_tags

    fn Formatter::set_mark_tags(self : Formatter, b : Bool) -> Unit

    Whether to output the mark_*_stag markers of tags.

    Formatter::set_max_boxes

    fn Formatter::set_max_boxes(self : Formatter, n : Int) -> Unit

    Set the maximum number of simultaneously opened boxes (must be > 1); material in deeper boxes is printed as the ellipsis.

    Formatter::set_max_indent

    fn Formatter::set_max_indent(self : Formatter, n : Int) -> Unit

    Set the maximum indentation: boxes opened beyond it are rejected to the left. Ignored if n <= 1.

    Formatter::set_out_functions

    fn Formatter::set_out_functions(self : Formatter, out : OutFunctions) -> Unit

    Set the output functions of the formatter.

    Formatter::set_output_functions

    fn Formatter::set_output_functions(self : Formatter, out_string : (StringView) -> Unit, out_flush : () -> Unit) -> Unit

    Set the functions that output a string and flush the output, like OCaml's pp_set_formatter_output_functions: the other output functions are unchanged (those of Formatter(output) output newlines and spaces with the current output function).

    Formatter::set_print_tags

    fn Formatter::set_print_tags(self : Formatter, b : Bool) -> Unit

    Whether to call the print_*_stag functions on tags.

    Formatter::set_stag_functions

    fn Formatter::set_stag_functions(self : Formatter, funs : StagFunctions) -> Unit

    Set the tag functions of the formatter.

    Formatter::set_tab

    fn Formatter::set_tab(self : Formatter) -> Unit

    Set a tabulation stop at the current insertion point.

    Formatter::set_tags

    fn Formatter::set_tags(self : Formatter, b : Bool) -> Unit

    Set both print_tags and mark_tags.

    Formatter::update_geometry

    fn Formatter::update_geometry(self : Formatter, update : (Geometry) -> Geometry) -> Unit

    Update the geometry of the formatter.

    Geometry

    pub(all) struct Geometry {
    max_indent : Int
    margin : Int
    } derive(Eq,
    Debug
    )

    The geometry of a formatter.

    Geometry::equal

    fn Geometry::equal(Geometry, Geometry) -> Bool

    Geometry::not_equal

    fn Geometry::not_equal(x : Geometry, y : Geometry) -> Bool

    Geometry::to_repr

    OutFunctions

    pub(all) struct OutFunctions {
    out_string : (StringView) -> Unit
    out_flush : () -> Unit
    out_newline : () -> Unit
    out_spaces : (Int) -> Unit
    out_indent : (Int) -> Unit
    }

    Output functions of a formatter.

    Stag

    pub(all) enum Stag {
    StringTag(String)
    OtherTag(String)
    } derive(Eq,
    Debug
    )

    A semantic tag.

    Stag::equal

    fn Stag::equal(Stag, Stag) -> Bool

    Stag::not_equal

    fn Stag::not_equal(x : Stag, y : Stag) -> Bool

    Stag::to_repr

    StagFunctions

    pub(all) struct StagFunctions {
    mark_open_stag : (Stag) -> String
    mark_close_stag : (Stag) -> String
    print_open_stag : (Stag) -> Unit
    print_close_stag : (Stag) -> Unit
    }

    Functions handling semantic tags.

    SymbolicOutputBuffer

    pub struct SymbolicOutputBuffer {
    // private fields
    }

    A buffer of symbolic output: pretty-printing with no low-level output, so that the output can be post-processed.

    SymbolicOutputBuffer::SymbolicOutputBuffer

    fn SymbolicOutputBuffer::SymbolicOutputBuffer() -> SymbolicOutputBuffer

    Create a buffer of symbolic output.

    SymbolicOutputBuffer::add

    Add an item to the buffer.

    SymbolicOutputBuffer::clear

    fn SymbolicOutputBuffer::clear(self : SymbolicOutputBuffer) -> Unit

    Remove the contents of the buffer.

    SymbolicOutputBuffer::flush

    Return the contents of the buffer and clear it.

    SymbolicOutputBuffer::get

    The contents of the buffer.

    SymbolicOutputItem

    pub(all) enum SymbolicOutputItem {
    OutputFlush
    OutputNewline
    OutputString(String)
    OutputSpaces(Int)
    OutputIndent(Int)
    } derive(Eq,
    Debug
    )

    An item of symbolic output.

    SymbolicOutputItem::equal

    SymbolicOutputItem::not_equal

    asprintf

    fn asprintf(fmt : String, args : ArrayView[Arg]) -> String

    Format into a string, like OCaml's Format.asprintf: the material is printed with a fresh formatter (margin 78) that is flushed at the end.

    char_escaped

    fn char_escaped(c : Char) -> String

    OCaml's Char.escaped, applied to the UTF-8 encoding of a character.

    check_format

    fn check_format(fmt : String) -> Unit raise Failure

    Check that a format string is valid, like the OCaml compiler does for format literals: printing with an invalid format aborts the program. The error messages are OCaml's. Some errors (e.g. an invalid box description) are only detected when printing, like in OCaml.

    check_geometry

    fn check_geometry(g : Geometry) -> Bool

    Whether a geometry is valid: max_indent >= 2 and margin > max_indent.

    default_stag_functions

    let default_stag_functions : StagFunctions

    The default tag functions: string tags are marked as <tag> and </tag>, nothing is printed.

    dprintf

    fn dprintf(fmt : String, args : ArrayView[Arg]) -> ((Formatter) -> Unit)

    Delayed printing, like OCaml's Format.dprintf: the result prints on the formatter it is given.

    format_float_c

    fn format_float_c(x : Double, conv : Char, prec : Int, sign? : Char, alt? : Bool) -> String

    Format a number like C's printf with conversion conv (one of f, e, E, g, G), precision prec and sign flag sign ('+', ' ', or '-' for none). alt is the # flag.

    hexstring_of_float

    fn hexstring_of_float(x : Double, prec : Int, sign : Char) -> String

    Format a number in hexadecimal like OCaml's caml_hexstring_of_float (%h): prec digits after the point, or as many as needed if prec is negative.

    kasprintf

    fn[T] kasprintf(k : (String) -> T, fmt : String, args : ArrayView[Arg]) -> T

    Like asprintf, then call k with the result, like OCaml's Format.kasprintf.

    sprintf

    fn sprintf(fmt : String, args : ArrayView[Arg]) -> String

    Format into a string, like OCaml's Format.sprintf. The functions of %a and %t print on the formatter, as with asprintf.

    string_escaped

    fn string_escaped(s : StringView) -> String

    OCaml's String.escaped, applied to the UTF-8 encoding of a string.

    string_of_float

    fn string_of_float(f : Double) -> String

    OCaml's string_of_float: 12 significant digits, with a . if needed (1., 0.1, 1e+20, inf, nan).

    utf8_length

    fn utf8_length(s : StringView) -> Int

    Length of a string in UTF-8 bytes, which is its width for the pretty-printer, like OCaml's String.length on UTF-8 strings.