.chapter "The PPDEF Module"
	Module lan{ppdef}, built upon the lan{write} package,
provides a basis from which one may construct a pretty-printer for
lan{lisp} expressions.
It defines conventions by which such a pretty-printer may perform
output either with or without special formatting (i.e.,
pretty-printing or not), truncation due to either excessive depth or
length of subexpressions, and detection of circularities in the
structure output.
	A pretty-printer is constructed procedurally.  The conventions
and primitives for doing this were described in
(write-section-page).  The 3pretty-print-definition* lan{lsb}
system, of which lan{ppdef} is the main part, defines additional
conventions, primitives, and dispatch facilities, in order that
customized pretty-printers of lan{lisp} expressions might be
defined.
	The basic way in which this is done is through the
3pp-dispatch* function.  This is the basic recursion function for
pretty-printing with lan{ppdef}.  It examines the object given to
it and the parameters of the current pretty-printing environment (as
established with 3pp-environment*, below), and calls one of
potentially many different functions which may choose the format for
that particular type of expression.  The customization of these
dispatch routines is what enables lan{ppdef} to be used to build
different pretty-printers;  for instance, the lan{lisp} code
pretty-printer defines (among other things) a dispatch routine for
lists whose 3car*s are symbols which will look for properties on
the symbol to tell it what format to select.
	Module lan{ppdef} is one of the modules in the
3pretty-print-definition* system, defined with lan{lsb}.
lan{lsb} systems which define their own formats using lan{ppdef}
should specify 3pretty-print-definition* in their 3built-on*
clause of the system definition.
.section "The Environment Wrapper"
.defmac pp-environment 1(Any-number-of*forms1)*
.lisp
(pp-environment 2form-1* 2form-2* ... 2form-n*)
.end_lisp
evaluates the 2form*s in an augmented lan{write} environment.  For
example, the simplest pretty-printer one could write would be
.lisp
(defun simple-pretty-print (object stream)
  (pp-environment
     ;1Initialize the lan{write} environment.  The 3t* says*
     ; 1that we are pretty-printing.*
     (set-up-for-printing stream t)
     (pp-dispatch object)))
.end_lisp
The variables which this wrapper causes to be bound (over and above
those supplied by the implicit use of 3write-afresh*,
(write-afresh-fun)), are bound using 3progv* in order that the
particular variables bound may be changed without recompilation of
calls to 3pp-environment*.
.end_defmac
	The remainder of this chapter discusses the ways in which the
formatting may be modified and programmed.
.section "The Anaphor Mechanism"
	Detection of circularities in datastructure, besides
preventing infinite recursion or iteration in the output, can provide
an abbreviation facility far superior to simple depth/length
truncation according to the values of 3prinlevel* and
3prinlength*.  With proper treatment, the output produced may even
be sufficient reconstruction of a topologically equivalent expression.
	If circularities are to be detected, a first pass is made over
the data structure to find all parts of it which are self-referential.
Such substructures which are self referencing are then recognized in
two ways in the output stage:  when they are encountered at the outer
level, and then when that same piece of structure is referenced from
within itself.  The first is necessary for the convention chosen for
the method of handling these.  Take, for example, the following
sequence of steps:
.lisp
(setq foo (list nil))
(rplaca foo foo)
(setq foo (cons 'bar foo))
.end_lisp
If we assume that the character "^" is defined to Lisp 3read* such
that a sequence of 2n* "^"s is a subexpression referring to its
enclosing expression 2n* parenthesis nestings out, then we want
the following output for the pretty-print of 3foo*:
.lisp
(bar . (^))
.end_lisp
Thus, the first pass indicates which subparts of lists (and
conceivably other objects) the pretty-printing mechanism must
terminate on, even if they are not atomic.
	There is another mode of operation for circularity detection.
If the indexing pass is left out, circular references may still be
detected if they occur only in positions which are explicitly recursed
to, and refer to an outer expression which was explicitly recursed
to.  For normally output list structure, this is the case for the
3car*.  Take, for example, the case
.lisp
(setq foo (list nil 'foobar))
(rplaca foo foo)
.end_lisp
The circularity in the 3car* of 3foo* is noted even with no
indexing pass because when that part gets recursed to, it is known
that the formatting is "within" that.  In fact, at this time there is
no mechanism to disable this "feature".
	The dispatch mechanism is performed primarily by
3pp-anaphor-dispatch*, below.  2Describe user data-type
handling.*
.defun pp-anaphor-dispatch object
This is the routine to be used for recursively descending through
structure to detect circular references.  It is also all that is
needed to initiate such descent.  The simplest case of a pretty-printer
which fully detects circularities is
.lisp
(defun simple-pretty-print (object stream)
    (pp-environment
       (set-up-for-printing stream t)
       (pp-anaphor-dispatch object)
       (pp-dispatch object)))
.end_lisp
.end_defun
.subsection "Writing Anaphora"

As was stated above, the writing of anaphora is handled in two
"parts".  The presumption is that, if the appropriate labelling or
anaphoric reference is to be made in the output, 2both* the start
of the reference (the outer occurence of the self-referential
structure) and the inner reference (the point at which it references
itself) may need to be handled specially.  The 3pp-environment*
writing environment provides two functional hooks for this purpose,
with suitable defaults.
.defmac pp-with-anaphora-checking routine-for-writing-anaphora 1(Optional*routine-for-wrapping-anaphora1)* 1(Body*forms-to-recursively-write-structure1)*
This macro may be used (like most other similar macros) in one of two
forms.
.lisp
(pp-with-anaphora-checking
    2routine-for-writing-anaphora*
    (1optional* 2routine-for-wrapping-anaphora*))
.end_lisp
sets the routines for writing and for wrapping anaphora.
.lisp
(pp-with-anaphora-checking
    2routine-for-writing-anaphora*
    2routine-for-wrapping-anaphora*
    2form-1* 2form-2* 2...* 2form-n*)
.end_lisp
evaluates each of the 2form*s with the anaphor writing and
wrapping routines bound to those specified.  In either form, either of
the routines may be 3nil*, and some appropriate default will be
used.
.end_defmac
.subsection "Internal Anaphora Routines"
The routines here are internal to 3pp-anaphor-dispatch*;
they may be needed in some esoteric cases where the dispatch mechanism
provided by 3pp-anaphor-dispatch* and 3pp-dispatch* is not
sufficient for the manner in which the object is being interpreted.
.defun pp-anaphor-dispatch-on-subpart object
This is the guts of 3pp-anaphor-dispatch*;  it makes the recursive
calls to 3pp-anaphor-dispatch* on the subparts of 3object*.
.end_defun
.defmac pp-anaphor-wrap object-being-recursed-through 1(Body*forms-to-recurse-through-object1)*
.lisp
(pp-anaphor-wrap 2object-being-recursed-through*
    2form-1* 2form-2* ... 2form-n*)
.end_lisp
evaluates each of the 2form*s in an environment where it is known
that we are processing 2object-being-recursed-through*.  This same
mechanism is used both in the first pass (indexing), and the
second pass (output).
.end_defmac
.defun pp-anaphor-index object
If anaphora indexing has been performed, then if the object is one of
the objects which references itself circularly, then its index is
returned (zero origined).  This may be used, for instance, to do
labeling of circular expressions.
.end_defun
.subsection "Random Anaphora-related Routines"
.defun pp-inside-object? object
This tests to see if we are currently recursing through 2object*.
It returns 3nil* if we are not currently recursing through
2object* (as noted by 3pp-anaphor-wrap*), otherwise returns
the number of levels out 2object* occurs at.  Note the end
condition,
.lisp
(pp-anaphor-wrap 2object*
    (pp-inside-object? 2object*))
 =>  1
.end_lisp
.end_defun
.section "Termination Routines"
Here are various routines which may be useful to writers of pretty-printers.
.defun pp-atomic? x
This is the routine which should be used to see if something should be
treated as "atomic", with respect to iteration down a list.  It
returns 3t* if 2x* is either an atom, is self-referential, or
(in certain Lisp implementations) is a non-atomic object which
requires special treatment (such as a 3hunk* in PDP-10 Maclisp).
.end_defun
.defun pp-atomic-without-anaphora? x
This is just like 3pp-atomic?*, but does not do anaphor
checking.  This is useful for checking something when it is known that
an anaphora wrapper might have been established for that object.
.end_defun
.defun pp-length presumed-list
This returns the number of 3cdr* operations which may be performed
on 2presumed-list* until it becomes 3pp-atomic?*.
.end_defun
.defun pp-check-length presumed-list 1(fixnum*count1)*
This is approximately equal to the expression
.lisp
(not (< (pp-length 2presumed-list*) 2count*))
.end_lisp
but may be significantly faster since it does not bother to compute
the entire length.
.end_defun
.defun pp-truncate? list 1(fixnum*number-of-elements-printed-so-far1)*
This routine tests for 3prinlength* abbreviation.  2List* must
2not* be 3pp-atomic?*.  If this returns 3t*, then the list
being output should be terminated, and some abbreviation indicator
written.  If 2list* has only one element which is atomic (2this
should have a slightly hairier check on this, for moby atoms or
strings or somesuch*) then we decide not to truncate if this should
have been the first item truncated (i.e., 3prinlevel* =
2number-of-elements-printed-so-far*).
.end_defun
.section "The Format Dispatches"

Here are the dispatches and default routines which make the
3pp-dispatch* mechanism programmable.  Where there is a macro for
establishing the dispatch routine for some purpose, it may generally
be used in one of two forms.  One is, for example,
.lisp
(pp-symbol-format #'my-symbol-format-handler)
.end_lisp
which sets the handler (called by 3pp-dispatch*) for atomic
symbols to be the function 3my-symbol-format-handler*.  Setting
various dispatches this way at top-level in a 3pp-environment*
form is how a customized pretty-printer is constructed.

The other way to use a macro such as 3pp-symbol-format* is
.lisp
(pp-symbol-format #'my-symbol-format-handler
  2form1* 2form2* ... 2formn*)
.end_lisp
which evaluates the 2form*s in an environment where the dispatch
for atomic symbols is 2bound* to the function
3my-symbol-format-handler*.
.subsection "Prin1 Style"
There is one flag which is built in to be used by the default dispatch
for atomic symbols.  That is whether the output is being performed in
term_i{prin1 style}; i.e., whether or not the output should be
parsable with lan{lisp} 3read* (mostly anyway).  This flag, of
course, may be used by other dispatch routines.
.defun pp-default-symbol-format symbol
This writes 2symbol* either in 3prin1*
fashion or not, depending on the value of 3*pp-use-prin1-style?*
(below).
.end_defun
.defun pp-default-atom-format object
Like 3pp-default-symbol-format*.
.end_defun
.defvar *pp-use-prin1-style?
This variable, if not 3nil*, causes the 2default* symbol
handler to output the symbol ala 3prin1* rather than just
outputting the characters.
.end_defvar
.defmac pp-use-prin1-style flag 1(Any-number-of*forms1)*
.lisp
(pp-use-prin1-style 2flag*)
.end_lisp
sets 3*pp-use-prin1-style?* to 2flag*.
.lisp
(pp-use-prin1-style 2flag* 2form1* 2form2* ... 2formn*)
.end_lisp
evaluates the 2form*s with 3*pp-use-prin1-style?* bound to
2flag*.
.end_defmac
.subsection "The Available Dispatches"
Here are the available dispatches.  The dispatching performed by
3pp-dispatch* chooses the most specific dispatch applicable to the
object it is handling;  if there is none for that, then the next more
general dispatch will be used;  finally, some appropriate default.
For instance, 3pp-dispatch* of a symbol will try first the format
for symbols;  if that is 3nil*, then it will try the one for
atoms;  if 2that* is 3nil*, then it calls
3pp-default-symbol-format*.

At some point in the future, the dispatches provided will be changed
around to follow more closely the lan{common lisp} type hierarchy
(although there will not be a dispatch defined for every such type!).
In particular, the word 3flonum* will be replaced by 3float*.
.defmac pp-symbol-format hacker 1(Any-number-of*forms1)*
Sets or binds the format used for atomic symbols.  The default is to
use 3pp-default-symbol-format*, above.
.end_defmac
.defmac pp-integer-format hacker 1(Any-number-of*forms1)*
The format used for integers (both bignums and fixnums).  This may get
passed on to the 3pp-number-format* and then the
3pp-atom-format*;  the default is to write the integer in the
current radix, ala Lisp 3prin1*.
.end_defmac
.defmac pp-flonum-format hacker 1(Any-number-of*forms1)*
Similar to 3pp-integer-format*, but for floating point numbers.
.end_defmac
.defmac pp-number-format hacker 1(Any-number-of*forms1)*
This format is tried for numbers when one is not specified for them as
either integers or flonums.
.end_defmac
.defmac pp-atom-format hacker 1(Any-number-of*forms1)*
This, if specified, is used as the superdefault for atoms.  In
general, if the defaulting process gets this far and this is not
specified, the atom will be output via 3prin1*.
.end_defmac
.defmac pp-hunk-format hacker 1(Any-number-of*forms1)*
This is format used for hunks.  The default action is to output the
elements of the hunk as a series within parentheses, with each element
followed by a ".".
.end_defmac
.defmac pp-careful-format flag 1(Any-number-of*forms1)*
This, unlike the other similar wrappers, assigns a flag which says
that when we are 2not* prettyprinting (as determined by the
initial call to 3set-up-for-printing*), we should continue to
check all of the formats for lists.  This allows a 3prin1* variant
to (say) continue to do readmacro inversion.  It also slows things
down.  The default is 3nil*.
.end_defmac
.defmac pp-dumb-list-format hacker 1(Any-number-of*forms1)*
This is the list format tried when pretty-printing is not in effect.
the default action just outputs the elements of the list in
parentheses.
.end_defmac
.defmac pp-list-symbol-format hacker 1(Any-number-of*forms1)*
This is the format used for lists with a 3car* which is a symbol.
It defaults to using the format specified for
3pp-list-atom-format*.
.end_defmac
.defmac pp-list-atom-format hacker 1(Any-number-of*forms1)*
This is the format used for lists with atomic 3car*s.  It defaults
to using the format specified for 3pp-default-list-format*.
.end_defmac
.defmac pp-list-non-atom-format hacker 1(Any-number-of*forms1)*
This format is used for lists with non-atomic 3car*s.  It also
defaults to using that for 3pp-default-list-format*.
.end_defmac
.defmac pp-default-list-format hacker 1(Any-number-of*forms1)*
This is used as the last-resort list format.  If the defaulting
process gets this far, then if a format description was passed in,
that is interpreted by 3pp-from-format-description*;  otherwise,
the list will be output as a head/body with one element in the head,
and the rest of the list the body, as a series.
.end_defmac
.defmac pp-list-wrapper hacker 1(Any-number-of*forms1)*
This is a special format handler with different semantics from the
rest.  It is checked before any of the other list formats are checked,
2without* an anaphor wrapper being established.  This is for
special formats which will not be outputting brackets;  for example,
readmacro inversion.  The routine which handles this should return
3nil* if it did not handle the output, otherwise 3t*.
.end_defmac
.defun pp-call-dispatch dispatch object fd
This routine is used to call one of these format dispatchers.  It is
effectively equivalent to 3funcall*, but in certain
implementations may be specially coded for efficiency.
.end_defun
.subsection "Bracket Depth"
Sometimes the environment established with 3pp-environment* does
not correspond to what was the "top level" of the expression being
printed, but rather some nesting.  This situation arises primarily
when the 3pp-dispatch* formalism is being used to do ordinary
printing, and is entered at some recursion depth through the
lan{lisp}-supplied printing formalism (for example, as a 2user
hunk* dispatch in lan{maclisp}, or via the 3:print-self*
message in lan{nil} or lan{lispm}).

.defun pp-initialize-bracket-depth 1(fixnum*depth1)*
This routine, which should 2only* be called from "toplevel"
(i.e., no bracket nestings) in a 3pp-environment* wrapper,
sets the write environment's idea of what the current bracket nesting
is to 2depth*.  This is useful for cases where the WRITE code is
being used as a subpart of other printing code where the bracket
nesting level gets passed in.
.end_defun
.subsection "Special Anaphor Hacks"
	There is also a mechanism by which one can change the default
idea of how structure is to be recursed through for circularity
checking.  This is important if, for example, things 2about* a
list are going to be output in addition to the parts of the list
itself.  The two means provided are for lists, and (where they are
available), hunks.  These routines get called on one argument, the
object to recurse through.  They are called with an anaphor wrapper
for that object already established, so they need only recursively
call 3pp-anaphor-dispatch* on the appropriate subparts.
.defmac pp-list-anaphor-dispatch hacker 1(Any-number-of*forms1)*
This macro is just like the other format specifiers.  If it is in use,
then all lists (or hunks, if 3hunkp* is 3nil*) will be run
through it, rather than 3pp-anaphor-dispatch* up the car and down
the cdr.
.end_defmac
.defmac pp-hunk-anaphor-dispatch hacker 1(Any-number-of*forms1)*
And this is the same for hunks.  It does 2not* get used for
"user-hunk" type hunks.
.end_defmac
.defun pp-call-anaphor-dispatch dispatch object
This routine is used to call the anaphor dispatchers.  It is
effectively equivalent to a 3funcall*, except that in certain
implementations it has some speed hacks.  Using this and
3define-pp-format*, a pretty-print implementation may define
additional subdispatches.
.end_defun
.section "Dispatching"
.defun pp-dispatch object 1(Optional*format-description?1)*
The primary dispatch routine.
.end_defun
.defun pp-dispatch-1 object format-description?
This is the part of 3pp-dispatch* which handles things which are
neither atoms nor anaphora.  This entry exists for the sake of the
anaphor wrapper hook;  ordinary uses do not need it.
.end_defun
.defun pp-write-list-as-series list-to-write-as-series 1(fixnum*elements-written-so-far1)* force-linear-arrangement?
This can be used to write a list as a series;  a simple call to this
will obviate any need for one to code the iteration oneself using
3write-series* etc.  The elements of 2list-to-write-as-series*
are written as a
series.  No brackets are output, however.  A 3pp-atomic?* tail
is handled properly;  the "list" must not be atomic if
2elements-written-so-far* is 30*, however.
2elements-written-so-far*, incremented by the number of items
written, is returned.  This number may include one for a cons dot, if
one was written;  that is, the number returned is
2elements-written-so-far* plus the number of series elements
written.  2elements-written-so-far* is used to perform
3prinlength* truncation;  the returned result may be used for this
by the caller also.
.end_defun
.defun pp-fixed-series 1(Any-number-of*elements1)*
This is good for calling when one needs to output some fixed known set
of things as a series.  Typically, this will be some (few) components
of a structure.
.end_defun
.defun pp-fixed-series-with-brackets left-bracket right-bracket 1(Any-number-of*elements1)*
Similar to 3pp-fixed-series*, but the left and right bracketing
strings may be specified also.  For example, one might desire to
handle the 3pp-dispatch* message to the 3ship* defstruct by
doing:
.lisp
(pp-fixed-series-with-brackets "#<" ">"
  'ship (ship-name 2ship*)
  (ship-x-position 2ship*)
  (ship-y-position 2ship*))
.end_lisp
This eliminates the need to set up the complicated 3write-series*
wrapper in many simple cases.
.end_defun
.section "Some Simple Pretty-Printers"
.defun pretty-prin1-datum datum 1(Optional*stream1)* 1(Optional*initial-format-description?1)*
This pretty-prints 2datum*, in fancy but default format.
Anaphora checking is performed.
.end_defun
.defun pretty-print-datum datum 1(Optional*stream1)* 1(Optional*initial-format-description?1)*
Like 3pretty-prin1-datum*, but 2datum* is preceded by a newline
and followed by a space.
.end_defun

