[toronto-lisp] Lenient structs
doug at hcsw.org
doug at hcsw.org
Wed Dec 2 02:30:05 UTC 2009
I mentioned "lenient structs" at the meeting today and like I said they
are a simple but useful example of read macros. A lenient struct is a
class wrapper around a list with a special print-object method that makes
it print like a struct. The only (defined) thing you can do with lenient
structs is print them back out again.
Here's the interesting part about lenient structs with respect to read
macros: The with-lenient-struct-reader macro installs a custom reader
function in a read-table that, when in effect, will cause read-from-string
et al to read #S(...) forms as lenient structs instead of regular structs,
overriding the system's structure reader function.
Lenient structs are used in antiweb so that an intermediate lisp image
process in an antiweb system doesn't need to have the structure in
question's defstruct definition in order to read it in, process it
(as an atom), store it to a DB, read it back out, and print it out
to another process.
http://hoytech.com/antiweb/
;; lenient-struct is so we can read in and print out structs even without a corresponding defstruct
(defclass lenient-struct ()
((contents :accessor lenient-struct-contents
:initform nil
:initarg :contents)))
(defmethod print-object ((l lenient-struct) (s stream))
(format s "#S~S" (lenient-struct-contents l)))
(defmacro! with-lenient-struct-reader (&rest body)
`(let ((*readtable* (copy-readtable *readtable*)))
(let ((,g!read-handler (lambda (stream sub-char numarg)
(declare (ignore sub-char numarg))
(unless (char= #\( (read-char stream)) ;)
(error "bad lenient-struct form")) ;(
(make-instance 'lenient-struct :contents (read-delimited-list #\) stream t)))))
(set-dispatch-macro-character #\# #\s ,g!read-handler)
(set-dispatch-macro-character #\# #\S ,g!read-handler)
, at body)))
More information about the toronto-lisp
mailing list