18.3 Formats

Suppose we define the following data structure (in the discussion which follows it will be assumed that the selector functions form, root, and suffix have been defined).

(NAMED-FORM <form> <root> <suffix>)

Furthermore, we would like

(named-form (+ left right) argument 1)

to be printed in the form:

argument1: (+ left right)

The format definition which follows could be used to specify that named-forms should be printed out in the above way. Deformat will convert everything which follows its second argument into a formatting function. In the example below, this formatting function will be used to format lists which have the identifer named-form as their first element. When such a list is passed to it, the function creates a sequence of format instructions, specifying what should be printed corresponding to the list.

(deformat (named-form) (item)  
  (template '({ ⋆ ⋆ ":" [i 1 2] ⋆ }) (root item)  
  (suffix item) (form item)))

The function template creates a sequence of formatting instructions for its arguments based on directions specified by the template (the first argument). The template in this example can be understood as follows: The and specify that the components between them should be treated as a single logical unit when they are printed and that an outer pair of parentheses should be printed. The three *’s show where the three components of the data structure should be printed. The ”:” specifies that a colon should be printed after the suffix. The vector [I 1 2] corresponds to a conditional line break. If there is sufficient room for the form then a single space is printed (this is specified by the second element of the vector). Otherwise a line break followed by an indentation of two spaces is inserted.

A template may consist of the following symbols:

      (one two three  

In general if a block will not fit on the current line of output then each consistent blank corresponds to a new line, inconsistent blanks will print as spaces unless it is necessary to force a new line. There is a length and an offset associated with each blank, if a blank is treated as a space then the length represents the number of spaces which will be printed. If a blank is treated as a break to a new line then the offset is used for indentation on the new line. Indentation is from the horizontal position of the first character of the innermost logical block. For example,

     (template '({ ⋆ { (⋆ [c 1 1]) } })  
               '(function (arg-one arg-two)))

will result in

     (function (arg-one  

assuming that it is necessary to force a line break. The consistent blank within the call the template specifies an offset of one. The first character of the innermost logical block is the second left parenthesis, from its position the printer indented a single space. A blank is represented by a vector, the first entry should be either an I or C, these characters designate the type of the blank, I for inconsistent and C for consistent. The second entry is a positive integer which represents length, and the third is a positive integer representing indentation. The algorithm expects to find a blank after each occurence of a right angle bracket, if the formats which have been provided do not follow this convention then an inconsistent blank with length and offset set to zero will be inserted after the right angle bracket.