Combinator Formatting

A library of procedures for formatting Scheme objects to text in
various ways, and for easily concatenating, composing and extending
these formatters efficiently without resorting to capturing and
manipulating intermediate strings.

This library takes a combinator approach. Formats are nested chains
of closures, which are called to produce their output as needed.
The primary goal of this library is to have, first and foremost, a
maximally expressive and extensible formatting library. The next
most important goal is scalability - to be able to handle
arbitrarily large output and not build intermediate results except
where necessary. The third goal is brevity and ease of use.

(pretty/unshared <obj>)

As above but without sharing.

(slashified <str> [<quote-ch> <esc-ch> <renamer>])

Outputs the string <str>, escaping any quote or escape characters.
If <esc-ch> is #f escapes only the <quote-ch> by
doubling it, as in SQL strings and CSV values. If <renamer> is
provided, it should be a procedure of one character which maps that
character to its escape value, e.g. #\newline=>#\n, or #f if
there is no escape value.

(fmt#f (slashified"hi, "bob!""))

=>"hi, "bob!""

(maybe-slashified <str> <pred> [<quote-ch> <esc-ch> <renamer>])

Like slashified, but first checks if any quoting is required (by
the existence of either any quote or escape characters, or any
character matching <pred>), and if so outputs the string in quotes
and with escapes. Otherwise outputs the string as is.

Operators are available with just a "c" prefix, e.g. c+, c-, c*, c/,
etc. c++ is a prefix operator, c++/post is postfix. ||, | and
|= are written as c-or, c-bit-or and c-bit-or= respectively.

Function applications are written with c-apply. Other control
structures such as c-for and c-while work as expected. The full
list is in the procedure index below.

When a C formatter encounters an object it doesn't know how to write
(including lists and records), it outputs them according to the
format state's current 'gen variable. This allows you to specify
generators for your own types, e.g. if you are using your own AST
records in a compiler.

If the 'gen variable isn't set it defaults to the c-expr/sexp
procedure, which formats an s-expression as if it were C code. Thus
instead of c-apply you can just use a list. The full API is
available via normal s-expressions - formatters that aren't keywords
in C are prefixed with a % or otherwise made invalid C identifiers so
that they can't be confused with function application.