Christophe Turle wrote:
> is there a multiple-value quasi-quotation somewhere ?
>
> like :
>
> `(a ,(values 'x) b) => (a x b)
> `(a ,(values) b) => (a b)
> `(a ,(values 'x 'y) b) => (a x y b)
>
>
> Even a Clisp specific implementation.
Here are the pieces for a CLISP-specific implementation. Hope Google
Groups Beta doesn't munge the formatting.
It would be a lot simpler if you could live without the comma; in other
words $X rather than ,$X. But in some ways this is better because it
doesn't conflict with custom readers for the $ character.
As you can see the problem with this is that the , reader is
pervasively active. CLISP's usual reader knows when it's in a backquote
context, and so it can throw error messages otherwise. That logic is
not duplicated here in the wrapping reader, so the ,$ translation
happens anywhere.
One sneaky way to get the error handling would be to always call the
built-in reader, and then post-filter its output. How? You peek at the
next character, as is done now. If it's a dollar sign, then you swallow
it. Call the old reader, which will produce an unquote. Rip apart the
unquote, and convert it to the MULTIPLE-VALUE-LIST form and return
that.
Then, one finishing touch: check for the ,·@FORM case, for which you
can signal some error. After eating the $ character, peek to see
whether there is a @ character before calling the old comma reader.
;;;
;;; CLISP-specific hack to enable ,$ syntax in backquotes.
;;; This syntax splices multiple values. In other words,
;;;
;;; `(... ,$FORM ..)
;;;
;;; behaves like
;;;
;;; `(... ,@(multiple-value-list FORM) ...)
;;;
;;; Kaz Kylheku <···@ashi.footprints.net>
;;; January 25, 2005
;;;
(defvar *old-comma-reader* nil)
(defun new-comma-reader (stream character)
(let ((next-char (peek-char t stream)))
(if (char= next-char #\$)
(progn
(read-char stream)
(list 'multiple-value-list (read stream)))
(funcall *old-comma-reader* stream character))))
(defun install-hack ()
(unless *old-comma-reader*
(setf *old-comma-reader* (get-macro-character #\,))
(set-macro-character #\, #'new-comma-reader)))
(defun uninstall-hack ()
(when *old-comma-reader*
(set-macro-character #\, *old-comma-reader*)
(setf *old-comma-reader* nil)))
It doesn't seem to work. Here the tests :
CL-USER> `(a ,$(values 'x) b)
(A (MULTIPLE-VALUE-LIST (VALUES 'X)) B)
CL-USER> `(a ,$(values) b)
(A (MULTIPLE-VALUE-LIST (VALUES)) B)
CL-USER> `(a ,$(values 'x 'y) b)
(A (MULTIPLE-VALUE-LIST (VALUES 'X 'Y)) B)
--
___________________________________________________________
Christophe Turle.
sava preview http://perso.wanadoo.fr/turle/lisp/sava.html
(format nil ···@~a.~a" 'c.turle 'wanadoo 'fr)
Christophe Turle wrote:
>
> It doesn't seem to work. Here the tests :
>
> CL-USER> `(a ,$(values 'x) b)
> (A (MULTIPLE-VALUE-LIST (VALUES 'X)) B)
>
> CL-USER> `(a ,$(values) b)
> (A (MULTIPLE-VALUE-LIST (VALUES)) B)
>
> CL-USER> `(a ,$(values 'x 'y) b)
> (A (MULTIPLE-VALUE-LIST (VALUES 'X 'Y)) B)
Aha, try this version. The code I posted is missing the splicing
unquote syntax around the (MULTIPLE-VALUE-LIST ...) form; the reader
should return
(SYSTEM::SPLICE (MULTIPLE-VALUE-LIST ...))
The corrected function is:
.(defun new-comma-reader (stream character)
. (let ((next-char (peek-char T stream)))
. (if (char= next-char #\$)
. (progn
. (read-char stream)
. (list 'system::splice (list 'multiple-value-list (read stream))))
. (funcall *old-comma-reader* stream character))))