I wrote the following code as part of a thin wrapper for LispWorks' COM package, in order to make accessing properties in COM objects look more like s-expressions:
;;; Create dispatch function for '#<' and '#>'.
(eval-when (:load-toplevel :compile-toplevel :execute)
(defun com-dispatch-function (invoke-function)
(lambda (stream sub-char infix)
(declare (ignore sub-char infix))
(destructuring-bind (thing object &rest args)
(read stream)
`(,invoke-function ,object (symbol-name ',thing) ,@args)))))
;;; COM 'get property' read macro.
(set-dispatch-macro-character
#\# #\<
(com-dispatch-function 'com::invoke-dispatch-get-property))
So now, instead of
(invoke-dispatch-get-property object "Property" argument)
I can write
#<(property object argument)
However when I try to use this syntax in a macro definition like so:
(defmacro something ((object) &body body)
(let ((excel (gensym)))
`(cclet* ((,excel #<(application ,object)))
,@)))
the compiler will complain for using a comma outside a backquote.
I guess the reason for the error is that the reader macro function should co-operate with the backquote syntax somehow, but I can not figure out a way to do that. Any suggestions?
Thanks!
Having stated in a comment that this was not possible to do portably, here is why it must in fact be possible: if it was not it would not be possible to write a readmacro for #\(
without relying on special implementation-specific magic.
However one thing you need to do when implementing readmacros like this is to tell the reader that you are reading recursively. This allows things like #
n=
/ #
n#
to work but it looks like it may also let the reader know that it might expect to see a comma without a surrounding backquote for LispWorks. That's probably done as a sanity check although I can't speak for the LW implementors.
To do this you must be sure to call read
as ‘(read s t nil t)` (or anyway make sure the fourth argument is true).
This means the guts of your function should be
(destructuring-bind (thing object &rest args) (read stream t nil t)
`(,invoke-function ,object (symbol-name ',thing) ,@args))