Reader & writer
===============

Scheme48 has simple S-expression reader & writer libraries, with some facilities beyond R5RS's read & write procedures.

Reader
------

Scheme48's reader facility is exported by the reading structure.  The read binding thereby exported is identical to that of the scheme structure, which is the binding that R5RS specifies under the name read.

 -- procedure: read [port] returns readable-value
     Reads a single S-expression from PORT, whose default value is the current input port.  If the end of the stream is encountered before the beginning of an S-expression, read will return an EOF object. It will signal a read error if text read from PORT does not constitute a complete, well-formed S-expression.

 -- procedure: define-sharp-macro char proc returns unspecified
     Defines a sharp/pound/hash/octothorpe (#) reader macro.  The next time the reader is invoked, if it encounters an octothorpe/sharp followed by CHAR, it applies PROC to CHAR and the input port being read from.  CHAR is not consumed in the input port.  If CHAR is alphabetic, it should be lowercase; otherwise the reader will not recognize it, since the reader converts the character following octothorpes to lowercase.

 -- procedure: reading-error port message irritant ... returns unspecified
     Signals an error while reading, for custom sharp macros.  It is not likely that calls to reading-error will return.

 -- procedure: gobble-line port returns unspecified
     Reads until a newline from PORT.  The newline character sequence is consumed.

Writer
------

Scheme48's writing structure exports its writer facility.  The write and display bindings from it are identical to those from the scheme structure, which are the same bindings that R5RS specifies.

 -- procedure: write object [port] returns unspecified
     Writes OBJECT to PORT, which defaults to the current output port, in a machine-readable manner.  Strings are written with double- quotes; characters are prefixed by #\.  Any object that is unreadable --- anything that does not have a written representation as an S-expression --- is written based on its disclosed representation. Such unreadable objects are converted to a disclosed representation by the disclose generic procedure (see below).

 -- procedure: display object [port] returns unspecified
     Displays OBJECT to PORT, which defaults to the value of the current output port, in a more human-readable manner.  Strings are written without surrounding double-quotes; characters are written as themselves with no prefix.

 -- procedure: recurring-write object port recur returns unspecified
     Writes OBJECT to PORT.  Every time this recurs upon a new object, rather than calling itself or its own looping procedure, it calls RECUR.  This allows customized printing routines that still take advantage of the existence of Scheme48's writer.  For example, display simply calls recurring-write with a recurring procedure that prints strings and characters specially and lets recurring-write handle everything else.

 -- procedure: display-type-name name port returns unspecified
     If NAME is a symbol with an alphabetic initial character, this writes NAME to PORT with the first character uppercased and the remaining character lowercased; otherwise, display-type-name simply writes NAME to PORT with display.

          (display-type-name 'foo)
              -| Foo

          (display-type-name (string->symbol "42foo"))
              -| 42foo

          (display-type-name (cons "foo" "bar"))
              -| (foo . bar)

          (display-type-name (string->symbol "fOo-BaR"))
              -| Foo-bar lisp

          This is used when printing disclosed representations (see below).

Object disclosure
.................

The Generic dispatch system, methods structure exports the generic procedure disclose and its method table &disclose. When recurring-write encounters an object it is unable to write in a rereadable manner, it applies disclose to the unreadable object to acquire a disclosed representation. (If disclose returns #f, ie the object has no disclosed representation, the writer will write #{Random object}.) After converting a value to its disclosed representation, eg a list consisting of the symbol foo, the symbol bar, a byte vector, and a pair (1 . 2), the writer will write #{Foo #{Byte-vector} bar (1 . 2)}.  That is: contents of the list are surrounded by #{ and }, the first element of the list (the `type name') is written with display-type-name, and then the remaining elements of the list are recursively printed out with the RECUR argument.

Typically, when a programmer creates an abstract data type by using Scheme48's record facility, he will not add methods to &disclose but instead define the record type's discloser with the define-record-discloser procedure; see Records.

Example:

     (define-record-type pare rtd/pare
       (kons a d)
       pare?
       (a kar set-kar!)
       (d kdr set-kdr!))

     (define-record-discloser rtd/pare
       (lambda (pare)
         `(pare ,(kar pare) *dot* ,(kdr pare))))

     (write (kons (kons 5 3) (kons 'a 'b)))
         -| #{Pare #{Pare 5 *dot* 3} *dot* #{Pare a *dot* b}} lisp