Thursday, 22 March 2007

ORF and values

As it turns out my previous post does not allow a values form as a place (the macro expands into invalid code).

So here is an updated version which behaves as follows.
When provided with a values form then for each place n, if n is nil
then n will be set to the nth value returned by the values-form.

eg.

(let ((a 1)
b
(c 3))
(orf (values a b c) (values 4 2 5))
(values a b c))

=> 1,2,3


And here it is in all it's glory.


(defmacro orf (place value-form &environment env)
(multiple-value-bind (vars vals store-vars writer reader)
(get-setf-expansion place env)
(let ((tmp-var (loop repeat (length store-vars) collect (gensym))))
`(let* (,@(mapcar 'list vars vals))
(multiple-value-bind ,store-vars ,reader
(multiple-value-bind ,tmp-var ,value-form
,@(loop for store in store-vars for val in tmp-var
collect `(unless ,store (setf ,store ,val)))
,writer))))))