.chapter "Format Descriptions"
Module lan{ppdesc}, a part of the 3pretty-print-definition*
system, defines a declarative mechanism for specifying how list
structure is to be formatted.  This module is called from the
lan{ppdef} module, if format descriptions are passed in and if
pretty-printing is in effect.  Thus, one may have a simple printer
built from lan{ppdef} which performs circularity checking, without
needing this module.  Conversely, this module may be used by many
other printing environments;  one need only define the dispatching
mechanism and provide 3pp-from-format-description* with the forms
and format descriptions.
.defun pp-from-format-description object format-description
This is the routine which interprets format descriptions, calling back
into the pretty-printer to write the components.
.end_defun

A format description consists of a list of clauses.  Each
clause is a list;  the 3car* of that list is a symbol, and the
3cdr* may contain various "arguments" for that clause.  (In lan{lisp}
implementations which support "packages", these symbols are in the
package used for keywords.  Elsewhere, as in lan{maclisp}, the symbols are
as shown--the colon is actually a part of the symbol.  Thus one can
type, for example, "3:linear-arrangement*" in any implementation.)

A format description may also be a term_i{symbolic format
description}, which is a symbol, with one of the following properties:
.table 3 250 250 0 0 0
.item pp-symbolic-format-description
the property is recursively interpreted as a format description
.item pp-format-description-handler
the property is called as a function, with two arguments: the object
to be pretty-printed, and the format description (the symbol with
the 3pp-format-description-handler* property).  The function
should take care of whatever formatting is needed.
.end_table
Symbolic format descriptions are not only convenient abbreviations
within other format descriptions (a format description can contain
format descriptions for components, as described below), but also
allow an indirection mechanism, in that the definition of the symbolic
format description can be changed (customized) out from under other
format descriptions which reference it.
A non-atomic format description is sometimes referred to as a
term_i{complex format description}.  The object (if not atomic) is written
inside parentheses, in a format determined and parameterized by the
keywords and arguments in the format description.  Basically, this is
a head-body format, for which one can specify the number of elements
which are in the head.  If more than one element is in the head, then
the head 2itself* is written in head-body format (the body of
which is written as a series).  The main body is written as a series.
As a rule, when an integer argument to one of these options is
specified, it may be either an integer, or a function to call to
compute the value.  When an "argument" is a flag, then if it is not
3t* or 3nil*, it also will be assumed to be a function to
call.  The function will receive a single argument, the form.  This is
useful if the quantity may not be a constant, but rather depends on
the "arguments" to the function or special form.
.table 3 250 250
.item :elements-in-head 2number-of-elements*
This specifies the number of elements in the head.  By default, this
is 31*, which is what is wanted for a typical function call.  A
form like 3let* would want 32*, as it has one "distinguished"
argument, making two elements in the head including the 3let*.  As
a special case, if 2number-of-elements* is 30*, then the
entire form is written as a series, rather than in a head-body arrangement.
.item :subgrouping 2subgrouping-size*
The body is grouped into subgroups of length 2subgrouping*.  These
will be written as nested series.  For instance, the
format-description of 3setq* is simply 3((:subgrouping 2))*.
.item :hanging-indentation 2indentation* 2indentation-only?*
2indentation* specifies the hanging indentation to be used for the
main head-body arrangement.  2indentation-only* (optional) is a
flag which says that the head/body should 2always* have hanging
indentation;  that is, the body should never be put on the same line
as the head.
.item :exdent 2exdentation-amount* 2exdentation-predicate*
This is a hack to generalize labels for 3prog*.  It doesn't work.
.item :linear-arrangement
This takes no arguments;  the presence of this clause turns on this
flag.  The body series will be written in a linear arrangement, which
means that either all the elements of the series will be on the same
line, or each will start on a different line.  That is, it undoes the
default "blocking" which packs the code into less vertical space.
.item1 :vertical-linear-arrangement
This says that the elements of the body series should always be
written in a vertical arrangement;  each starts on a new line.
Actually, this doesn't work yet;  it is currently identical to
3:linear-arrangement*.
.item :head-parts 2head-parts...*
The "arguments" to the 3:head-parts* clause are more format
descriptions, which are used as formatting suggestions for the
corresponding parts of the head of the arrangement.  For instance, the
format description for 3let* includes the clause 3(:head-parts
nil :series)*.  The 3nil* corresponds to the 3let*
symbol, and the 3:series* is the format description to use for the
2letlist* of the form.  The reason the items are matched exactly
like that (that is, the reason you have to specify the format
description for the first element of the list which is normally just a
symbol) is 2because* of the 3:head-parts* and
3:body-parts* clauses, in which more format descriptions can be
passed in to deal with other substructures which will may 2not*
have atomic 3car*s.
.item :body-parts 2body-parts...*
Similar to 3:head-parts*.
.end_table

There are a few symbolic format descriptions predefined.
.cindex symbolic format description
.table 3 250 250
.item :series
This is equivalent to 3((:elements-in-head 0))*.  That is, the
list is written strictly as a series.  However, specific formatters
may check for this keyword format description specially;  for
instance, the default symbol format provided by the lan{ppcode}
module (and hence the 3pretty-prin1* function) will write the atom
3nil* as 3()* if it is being written in either 3:series*
or 3:list* format.  (This is poor modularity and will be changed
in a future version.  This behaviour should be provided by the default
symbol format in lan{ppdef}.)
.item :list
This is equivalent to 3((:elements-in-head 1) (:hanging-indentation
1))*.  The keyword may be checked for specially, however (see
3:series*, above).
.item :clause
This is equivalent to 3((:elements-in-head 1) (:linear-arrangement 2)
(:hanging-indentation 2))*.  It is what might be used by other
format descriptions (like those provided by the lan{ppcode} module)
for doing 3cond*, 3case*, and 3typecase* clauses.
.end_table
In all of these cases, of course, the property for these keywords may
be changed if it is not the exact format desired;  the behaviour of
3nil* with the 3:series* and 3:list* formats will be
preserved.

