18.5 Specifying Formats

(deformat NAME:pair PARAM:id-list [BODY:forms]): nil fexpr
Deformat is used to define format functions for PSL expressions. The car of NAME should be a list of identifiers (it may also be a single identifier), the cdr should be nil for atomic expressions or an integer representing a minimal length for lists. PARAM is a list containing a single id, when the format function is used PARAM will be bound to the expression being formatted. Formats are defined by calls on template (described below).

(template FORMAT:list [COMPONENT:form]): any macro
FORMAT is a list of format symbols (described above). Each COMPONENT should correspond to a call on dispatch (*), in FORMAT. If a sub-list of format symbols in included within FORMAT then there must be a corresponding list of components.

This first example illustrates a format for quoted expressions. For example, ’ANY instead of (QUOTE ANY). A minimal length of two is given, since the list (QUOTE) should not be printed as ’. The argument to quote is formatted by a separate call on dispatch.

(deformat (quote . 2) (item)  
  (template '("'" ⋆) (second item)))

The elements of a vector should be enclosed within square brackets. Since the length of vectors will vary a list of format symbols is supplied to be used repetitively for each element. This list will be matched against a corresponding list of components, (vector2list item). Each element is formatted by a recursive call on dispatch. Elements are separated by inconsistent blanks, therefore if the entire vector does not fit on a single line the ouput will be something like

[one two three  
(deformat (vector) (item)  
  (template '(< "[" (⋆ [i 1 1]) "]" >) (vector2list item)))

Given the expression (setq n-one v-one n-two v-two)

(setq n-one v-one  
      n-two v-two)

is preferred over

(setq n-one v-one n-two  

The following can be used to obtain the preferred output.

(deformat ((set setq) . 3) (item)  
  (template '({ ⋆ " " < (⋆ [i 1 1] ⋆ [c 1 0]) > })  
            (first item) (rest item)))

The first form of ouput is obtained by using inconsistent blanks after the names (n-one and n-two) and consistent blanks after the values (v-one and v-two). When this expression will not fit on a single line the consistent blanks will correspond to line breaks and unless a value is too large to fit on an output line, the inconsistent blanks will correspond to spaces. The zero offset associated with the consistent blanks corresponds to the block of names and values. This is why the names line up within a column. If the inner logical brackets were omitted the output would look something like

(setq n-one v-one  
 n-two v-two)

assuming that the expression would not fit on a single line. Notice that the format for a single pair (name and value) is used repetitively.

A format function may contain more than one call on template. The two functions below are equivalent.

(deformat (lambda . 3) (item)  
  (template '({ ⋆ [i 1 1]) (first item))  
  (if (null (second item))  
    (template '("()" [c 1 1] (⋆ [c 1 1]) })  
              (rest (rest item)))  
    (template '((⋆ [c 1 1]) }) (rest item))))  
(deformat (lambda . 3) (item)  
  (template '({ ⋆ [i 1 1] (⋆ [c 1 1]) })  
            (first item)  
            (cons (if (null (second item)) '!(!) (second item))  
                  (rest (rest item)))))