~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/lsp/setf.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Peter Van Eynde
  • Date: 2006-05-17 02:46:26 UTC
  • Revision ID: james.westby@ubuntu.com-20060517024626-lljr08ftv9g9vefl
Tags: upstream-0.9h-20060510
ImportĀ upstreamĀ versionĀ 0.9h-20060510

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;;  Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
 
2
;;;;  Copyright (c) 1990, Giuseppe Attardi.
 
3
;;;;
 
4
;;;;    This program is free software; you can redistribute it and/or
 
5
;;;;    modify it under the terms of the GNU Library General Public
 
6
;;;;    License as published by the Free Software Foundation; either
 
7
;;;;    version 2 of the License, or (at your option) any later version.
 
8
;;;;
 
9
;;;;    See file '../Copyright' for full details.
 
10
 
 
11
;;;;                                setf routines
 
12
 
 
13
(in-package "SYSTEM")
 
14
 
 
15
(defun check-stores-number (context stores-list n)
 
16
  (declare (si::c-local))
 
17
  (unless (= (length stores-list) n)
 
18
    (error "~d store-variables expected in setf form ~a." n context)))
 
19
 
 
20
;;; DEFSETF macro.
 
21
(defmacro defsetf (access-fn &rest rest)
 
22
  "Syntax: (defsetf symbol update-fun [doc])
 
23
        or
 
24
        (defsetf symbol lambda-list (store-var) {decl | doc}* {form}*)
 
25
Defines an expansion
 
26
        (setf (SYMBOL arg1 ... argn) value)
 
27
        => (UPDATE-FUN arg1 ... argn value)
 
28
           or
 
29
           (let* ((temp1 ARG1) ... (tempn ARGn) (temp0 value)) rest)
 
30
where REST is the value of the last FORM with parameters in LAMBDA-LIST bound
 
31
to the symbols TEMP1 ... TEMPn and with STORE-VAR bound to the symbol TEMP0.
 
32
The doc-string DOC, if supplied, is saved as a SETF doc and can be retrieved
 
33
by (documentation 'SYMBOL 'setf)."
 
34
  (cond ((and (car rest) (or (symbolp (car rest)) (functionp (car rest))))
 
35
         `(eval-when (compile load eval)
 
36
                 (put-sysprop ',access-fn 'SETF-UPDATE-FN ',(car rest))
 
37
                 (rem-sysprop ',access-fn 'SETF-LAMBDA)
 
38
                 (rem-sysprop ',access-fn 'SETF-METHOD)
 
39
                 (rem-sysprop ',access-fn 'SETF-SYMBOL)
 
40
                 ,@(si::expand-set-documentation access-fn 'setf (cadr rest))
 
41
                 ',access-fn))
 
42
        (t
 
43
         (let* ((store (second rest))
 
44
                (args (first rest))
 
45
                (body (cddr rest))
 
46
                (doc (find-documentation body)))
 
47
           (check-stores-number 'DEFSETF store 1)
 
48
           `(eval-when (compile load eval)
 
49
              (put-sysprop ',access-fn 'SETF-LAMBDA #'(lambda-block ,access-fn (,@store ,@args) ,@body))
 
50
              (rem-sysprop ',access-fn 'SETF-UPDATE-FN)
 
51
              (rem-sysprop ',access-fn 'SETF-METHOD)
 
52
              (rem-sysprop ',access-fn 'SETF-SYMBOL)
 
53
              ,@(si::expand-set-documentation access-fn 'setf doc)
 
54
              ',access-fn)))))
 
55
 
 
56
 
 
57
;;; DEFINE-SETF-METHOD macro.
 
58
(defmacro define-setf-expander (access-fn args &rest body)
 
59
  "Syntax: (define-setf-expander symbol defmacro-lambda-list {decl | doc}*
 
60
          {form}*)
 
61
Defines the SETF-method for generalized-variables (SYMBOL ...).
 
62
When a form (setf (SYMBOL arg1 ... argn) value-form) is evaluated, the FORMs
 
63
given in the DEFINE-SETF-EXPANDER are evaluated in order with the parameters in
 
64
DEFMACRO-LAMBDA-LIST bound to ARG1 ... ARGn.  The last FORM must return five
 
65
values
 
66
        (var1 ... vark)
 
67
        (form1 ... formk)
 
68
        (value-var)
 
69
        storing-form
 
70
        access-form
 
71
in order.  These values are collectively called the five gangs of the
 
72
generalized variable (SYMBOL arg1 ... argn).  The whole SETF form is then
 
73
expanded into
 
74
        (let* ((var1 from1) ... (vark formk)
 
75
               (value-var value-form))
 
76
          storing-form)
 
77
The doc-string DOC, if supplied, is saved as a SETF doc and can be retrieved
 
78
by (DOCUMENTATION 'SYMBOL 'SETF)."
 
79
  (let ((env (member '&environment args :test #'eq)))
 
80
    (if env
 
81
        (setq args (cons (second env)
 
82
                         (nconc (ldiff args env) (cddr env))))
 
83
        (progn
 
84
          (setq env (gensym))
 
85
          (setq args (cons env args))
 
86
          (push `(declare (ignore ,env)) body))))
 
87
  `(eval-when (compile load eval)
 
88
          (put-sysprop ',access-fn 'SETF-METHOD #'(ext::lambda-block ,access-fn ,args ,@body))
 
89
          (rem-sysprop ',access-fn 'SETF-LAMBDA)
 
90
          (rem-sysprop ',access-fn 'SETF-UPDATE-FN)
 
91
          (rem-sysprop ',access-fn 'SETF-SYMBOL)
 
92
          ,@(si::expand-set-documentation access-fn 'setf
 
93
                                          (find-documentation body))
 
94
          ',access-fn))
 
95
 
 
96
 
 
97
;;;; get-setf-expansion.
 
98
 
 
99
(defun get-setf-expansion (form &optional env &aux f)
 
100
  "Args: (form)
 
101
Returns the 'five gangs' (see DEFINE-SETF-EXPANDER) for PLACE as five values.
 
102
Does not check if the third gang is a single-element list."
 
103
  (flet ((rename-arguments (vars &aux names values all-args)
 
104
           (dolist (item vars)
 
105
             (unless (or (fixnump item) (keywordp item))
 
106
               (push item values)
 
107
               (setq item (gensym))
 
108
               (push item names))
 
109
             (push item all-args))
 
110
           (values (gensym) (nreverse names) (nreverse values) (nreverse all-args))))
 
111
    (cond ((symbolp form)
 
112
           (if (and (setq f (macroexpand form env)) (not (equal f form)))
 
113
               (get-setf-expansion f env)
 
114
               (let ((store (gensym)))
 
115
                 (values nil nil (list store) `(setq ,form ,store) form))))
 
116
          ((or (not (consp form)) (not (symbolp (car form))))
 
117
           (error "Cannot get the setf-method of ~S." form))
 
118
          ((setq f (get-sysprop (car form) 'SETF-METHOD))
 
119
           (apply f env (cdr form)))
 
120
          (t
 
121
           (let* ((name (car form)) writer)
 
122
             (multiple-value-bind (store vars inits all)
 
123
                 (rename-arguments (cdr form))
 
124
               (setq writer
 
125
                     (cond ((setq f (get-sysprop name 'SETF-UPDATE-FN))
 
126
                            `(,f ,@all ,store))
 
127
                           ((setq f (get-sysprop name 'STRUCTURE-ACCESS))
 
128
                            (setf-structure-access (car all) (car f) (cdr f) store))
 
129
                           ((setq f (get-sysprop (car form) 'SETF-LAMBDA))
 
130
                            (apply f store all))
 
131
                           ((and (setq f (macroexpand form env)) (not (equal f form)))
 
132
                            (return-from get-setf-expansion
 
133
                              (get-setf-expansion f env)))
 
134
                           (t
 
135
                            `(funcall #'(SETF ,name) ,store ,@all))))
 
136
               (values vars inits (list store) writer (cons name all))))))))
 
137
 
 
138
;;;; SETF definitions.
 
139
 
 
140
(defsetf car (x) (y) `(progn (rplaca ,x ,y) ,y))
 
141
(defsetf cdr (x) (y) `(progn (rplacd ,x ,y), y))
 
142
(defsetf caar (x) (y) `(progn (rplaca (car ,x) ,y) ,y))
 
143
(defsetf cdar (x) (y) `(progn (rplacd (car ,x) ,y) ,y))
 
144
(defsetf cadr (x) (y) `(progn (rplaca (cdr ,x) ,y) ,y))
 
145
(defsetf cddr (x) (y) `(progn (rplacd (cdr ,x) ,y) ,y))
 
146
(defsetf caaar (x) (y) `(progn (rplaca (caar ,x) ,y) ,y))
 
147
(defsetf cdaar (x) (y) `(progn (rplacd (caar ,x) ,y) ,y))
 
148
(defsetf cadar (x) (y) `(progn (rplaca (cdar ,x) ,y) ,y))
 
149
(defsetf cddar (x) (y) `(progn (rplacd (cdar ,x) ,y) ,y))
 
150
(defsetf caadr (x) (y) `(progn (rplaca (cadr ,x) ,y) ,y))
 
151
(defsetf cdadr (x) (y) `(progn (rplacd (cadr ,x) ,y) ,y))
 
152
(defsetf caddr (x) (y) `(progn (rplaca (cddr ,x) ,y) ,y))
 
153
(defsetf cdddr (x) (y) `(progn (rplacd (cddr ,x) ,y) ,y))
 
154
(defsetf caaaar (x) (y) `(progn (rplaca (caaar ,x) ,y) ,y))
 
155
(defsetf cdaaar (x) (y) `(progn (rplacd (caaar ,x) ,y) ,y))
 
156
(defsetf cadaar (x) (y) `(progn (rplaca (cdaar ,x) ,y) ,y))
 
157
(defsetf cddaar (x) (y) `(progn (rplacd (cdaar ,x) ,y) ,y))
 
158
(defsetf caadar (x) (y) `(progn (rplaca (cadar ,x) ,y) ,y))
 
159
(defsetf cdadar (x) (y) `(progn (rplacd (cadar ,x) ,y) ,y))
 
160
(defsetf caddar (x) (y) `(progn (rplaca (cddar ,x) ,y) ,y))
 
161
(defsetf cdddar (x) (y) `(progn (rplacd (cddar ,x) ,y) ,y))
 
162
(defsetf caaadr (x) (y) `(progn (rplaca (caadr ,x) ,y) ,y))
 
163
(defsetf cdaadr (x) (y) `(progn (rplacd (caadr ,x) ,y) ,y))
 
164
(defsetf cadadr (x) (y) `(progn (rplaca (cdadr ,x) ,y) ,y))
 
165
(defsetf cddadr (x) (y) `(progn (rplacd (cdadr ,x) ,y) ,y))
 
166
(defsetf caaddr (x) (y) `(progn (rplaca (caddr ,x) ,y) ,y))
 
167
(defsetf cdaddr (x) (y) `(progn (rplacd (caddr ,x) ,y) ,y))
 
168
(defsetf cadddr (x) (y) `(progn (rplaca (cdddr ,x) ,y) ,y))
 
169
(defsetf cddddr (x) (y) `(progn (rplacd (cdddr ,x) ,y) ,y))
 
170
(defsetf first (x) (y) `(progn (rplaca ,x ,y) ,y))
 
171
(defsetf second (x) (y) `(progn (rplaca (cdr ,x) ,y) ,y))
 
172
(defsetf third (x) (y) `(progn (rplaca (cddr ,x) ,y) ,y))
 
173
(defsetf fourth (x) (y) `(progn (rplaca (cdddr ,x) ,y) ,y))
 
174
(defsetf fifth (x) (y) `(progn (rplaca (cddddr ,x) ,y) ,y))
 
175
(defsetf sixth (x) (y) `(progn (rplaca (nthcdr 5 ,x) ,y) ,y))
 
176
(defsetf seventh (x) (y) `(progn (rplaca (nthcdr 6 ,x) ,y) ,y))
 
177
(defsetf eighth (x) (y) `(progn (rplaca (nthcdr 7 ,x) ,y) ,y))
 
178
(defsetf ninth (x) (y) `(progn (rplaca (nthcdr 8 ,x) ,y) ,y))
 
179
(defsetf tenth (x) (y) `(progn (rplaca (nthcdr 9 ,x) ,y) ,y))
 
180
(defsetf rest (x) (y) `(progn (rplacd ,x ,y) ,y))
 
181
(defsetf svref sys:svset)
 
182
(defsetf elt sys:elt-set)
 
183
(defsetf symbol-value set)
 
184
(defsetf symbol-function sys:fset)
 
185
(defsetf fdefinition sys:fset)
 
186
(defsetf macro-function (s &optional env) (v) `(sys:fset ,s ,v t))
 
187
(defsetf aref (a &rest il) (v) `(sys:aset ,v ,a ,@il))
 
188
(defsetf row-major-aref (a i) (v) `(sys:row-major-aset ,a ,i ,v))
 
189
(defsetf get (s p &optional d) (v)
 
190
  (if d `(progn ,d (sys:putprop ,s ,v ,p)) `(sys:putprop ,s ,v ,p)))
 
191
(defsetf get-sysprop put-sysprop)
 
192
(defsetf nth (n l) (v) `(progn (rplaca (nthcdr ,n ,l) ,v) ,v))
 
193
(defsetf char sys:char-set)
 
194
(defsetf schar sys:schar-set)
 
195
(defsetf bit (a &rest il) (v) `(sys:aset ,v ,a ,@il))
 
196
(defsetf sbit (a &rest il) (v) `(sys:aset ,v ,a ,@il))
 
197
(defsetf fill-pointer sys:fill-pointer-set)
 
198
(defsetf symbol-plist sys:set-symbol-plist)
 
199
(defsetf gethash (k h &optional d) (v) `(sys:hash-set ,k ,h ,v))
 
200
#-clos
 
201
(defsetf documentation (s d) (v) `(sys::set-documentation ,s ,d ,v))
 
202
#+clos
 
203
(defsetf sys:instance-ref sys:instance-set)
 
204
(defsetf compiler-macro-function (fname) (function)
 
205
  `(sys::put-sysprop ,fname 'sys::compiler-macro ,function))
 
206
(defsetf readtable-case sys:readtable-case-set)
 
207
 
 
208
 
 
209
(define-setf-expander getf (&environment env place indicator &optional default)
 
210
  (multiple-value-bind (vars vals stores store-form access-form)
 
211
      (get-setf-expansion place env)
 
212
    (let* ((itemp (gensym)) (store (gensym)) (def (gensym)))
 
213
      (values `(,@vars ,itemp ,def)
 
214
              `(,@vals ,indicator ,default)
 
215
              `(,store)
 
216
              `(let ((,(car stores) (sys:put-f ,access-form ,store ,itemp)))
 
217
                 ,store-form
 
218
                 ,store)
 
219
              `(getf ,access-form ,itemp ,default)))))
 
220
 
 
221
(defsetf subseq (sequence1 start1 &optional end1)
 
222
                (sequence2)
 
223
  `(PROGN (REPLACE ,sequence1 ,sequence2 :START1 ,start1 :END1 ,end1)
 
224
    ,sequence2))
 
225
 
 
226
(define-setf-expander THE (&environment env type place)
 
227
  (multiple-value-bind (vars vals stores store-form access-form)
 
228
      (get-setf-expansion place env)
 
229
    (values vars vals stores
 
230
            (subst `(THE ,type ,(first stores)) (first stores) store-form)
 
231
            `(THE ,type ,access-form))))
 
232
 
 
233
#|
 
234
(define-setf-expander apply (&environment env fn &rest rest)
 
235
  (unless (and (consp fn) (eq (car fn) 'FUNCTION) (symbolp (cadr fn))
 
236
               (null (cddr fn)))
 
237
          (error "Can't get the setf-method of ~S." fn))
 
238
  (multiple-value-bind (vars vals stores store-form access-form)
 
239
      (get-setf-expansion (cons (cadr fn) rest) env)
 
240
    (unless (eq (car (last store-form)) (car (last vars)))
 
241
            (error "Can't get the setf-method of ~S." fn))
 
242
    (values vars vals stores
 
243
            `(apply #',(car store-form) ,@(cdr store-form))
 
244
            `(apply #',(cadr fn) ,@(cdr access-form)))))
 
245
|#
 
246
 
 
247
(define-setf-expander apply (&environment env fn &rest rest)
 
248
  (unless (and (consp fn)
 
249
               (or (eq (car fn) 'FUNCTION) (eq (car fn) 'QUOTE))
 
250
               (symbolp (cadr fn))
 
251
               (null (cddr fn)))
 
252
    (error "Can't get the setf-method of ~S." fn))
 
253
  (multiple-value-bind (vars vals stores store-form access-form)
 
254
      (get-setf-expansion (cons (cadr fn) rest) env)
 
255
    (cond ((eq (car (last store-form)) (car (last vars)))
 
256
           (values vars vals stores
 
257
                   `(apply #',(car store-form) ,@(cdr store-form))
 
258
                   `(apply #',(cadr fn) ,@(cdr access-form))))
 
259
          ((eq (car (last (butlast store-form))) (car (last vars)))
 
260
           (values vars vals stores
 
261
                   `(apply #',(car store-form)
 
262
                           ,@(cdr (butlast store-form 2))
 
263
                           (append ,(car (last (butlast store-form)))
 
264
                                   (list ,(car (last store-form)))))
 
265
                   `(apply #',(cadr fn) ,@(cdr access-form))))
 
266
          (t (error "Can't get the setf-method of ~S." fn)))))
 
267
 
 
268
(define-setf-expander ldb (&environment env bytespec int)
 
269
  (multiple-value-bind (temps vals stores store-form access-form)
 
270
      (get-setf-expansion int env)
 
271
    (let* ((btemp (gensym))
 
272
           (store (gensym))
 
273
           (stemp (first stores)))
 
274
      (values `(,btemp ,@temps)
 
275
              `(,bytespec ,@vals)
 
276
              `(,store)
 
277
              `(let ((,stemp (dpb ,store ,btemp ,access-form)))
 
278
                 ,store-form ,store)
 
279
              `(ldb ,btemp ,access-form)))))
 
280
 
 
281
(define-setf-expander mask-field (&environment env bytespec int)
 
282
  (multiple-value-bind (temps vals stores store-form access-form)
 
283
      (get-setf-expansion int env)
 
284
    (let* ((btemp (gensym))
 
285
           (store (gensym))
 
286
           (stemp (first stores)))
 
287
      (values `(,btemp ,@temps)
 
288
              `(,bytespec ,@vals)
 
289
              `(,store)
 
290
              `(let ((,stemp (deposit-field ,store ,btemp ,access-form)))
 
291
                 ,store-form ,store)
 
292
              `(mask-field ,btemp ,access-form)))))
 
293
 
 
294
 
 
295
;;; The expansion function for SETF.
 
296
(defun setf-expand-1 (place newvalue env)
 
297
  (declare (si::c-local))
 
298
  (multiple-value-bind (vars vals stores store-form access-form)
 
299
      (get-setf-expansion place env)
 
300
    (declare (ignore access-form))
 
301
    (let ((declaration `(declare (:read-only ,@(append vars stores)))))
 
302
      (if (= (length stores) 1)
 
303
        `(let* ,(mapcar #'list
 
304
                        (append vars stores)
 
305
                        (append vals (list newvalue)))
 
306
          ,declaration
 
307
          ,store-form)
 
308
        `(let* ,(mapcar #'list vars vals)
 
309
          (multiple-value-bind ,stores ,newvalue
 
310
            ,declaration
 
311
            ,store-form))))))
 
312
 
 
313
(defun setf-structure-access (struct type index newvalue)
 
314
  (declare (si::c-local))
 
315
  (case type
 
316
    (LIST `(sys:rplaca-nthcdr ,struct ,index ,newvalue))
 
317
    (VECTOR `(sys:elt-set ,struct ,index ,newvalue))
 
318
    (t `(sys::structure-set ,struct ',type ,index ,newvalue))))
 
319
 
 
320
(defun setf-expand (l env)
 
321
  (declare (si::c-local))
 
322
  (cond ((endp l) nil)
 
323
        ((endp (cdr l)) (error "~S is an illegal SETF form." l))
 
324
        (t
 
325
         (cons (setf-expand-1 (car l) (cadr l) env)
 
326
               (setf-expand (cddr l) env)))))
 
327
 
 
328
;;; SETF macro.
 
329
(defmacro setf (&environment env &rest rest)
 
330
  "Syntax: (setf {place form}*)
 
331
Evaluates each FORM and assigns the value to the corresponding PLACE in order.
 
332
Returns the value of the last FORM.
 
333
Each PLACE may be any one of the following:
 
334
  * A symbol that names a variable.
 
335
  * A function call form whose first element is the name of the following
 
336
    functions:
 
337
        nth     elt     subseq  rest    first ... tenth
 
338
        c?r     c??r    c???r   c????r
 
339
        aref    svref   char    schar   bit     sbit    fill-pointer
 
340
        get     getf    documentation   symbol-value    symbol-function
 
341
        symbol-plist    macro-function  gethash         fdefinition
 
342
        char-bit        ldb     mask-field
 
343
        apply   slot-value
 
344
    where '?' stands for either 'a' or 'd'.
 
345
  * A function call form whose first element is:
 
346
        1. an access function for a structure slot
 
347
        1. an accessor method for a CLOS object
 
348
  * the form (THE type place) with PLACE being a place recognized by SETF.
 
349
  * a macro call which expands to a place recognized by SETF.
 
350
  * any form for which a DEFSETF or DEFINE-SETF-EXPANDER declaration has been
 
351
    made."
 
352
  (cond ((endp rest) nil)
 
353
        ((endp (cdr rest)) (error "~S is an illegal SETF form." rest))
 
354
        ((endp (cddr rest)) (setf-expand-1 (car rest) (cadr rest) env))
 
355
        (t (cons 'progn (setf-expand rest env)))))
 
356
 
 
357
;;; PSETF macro.
 
358
 
 
359
(defmacro psetf (&environment env &rest rest)
 
360
  "Syntax: (psetf {place form}*)
 
361
Similar to SETF, but evaluates all FORMs first, and then assigns each value to
 
362
the corresponding PLACE.  Returns NIL."
 
363
  (cond ((endp rest) nil)
 
364
        ((endp (cdr rest)) (error "~S is an illegal PSETF form." rest))
 
365
        ((endp (cddr rest))
 
366
         `(progn ,(setf-expand-1 (car rest) (cadr rest) env)
 
367
                 nil))
 
368
        (t
 
369
         (do ((r rest (cddr r))
 
370
              (pairs nil)
 
371
              (store-forms nil))
 
372
             ((endp r)
 
373
              `(let* ,pairs
 
374
                 ,@(nreverse store-forms)
 
375
                 nil))
 
376
           (when (endp (cdr r)) (error "~S is an illegal PSETF form." rest))
 
377
           (multiple-value-bind (vars vals stores store-form access-form)
 
378
               (get-setf-expansion (car r) env)
 
379
             (declare (ignore access-form))
 
380
             (setq store-forms (cons store-form store-forms))
 
381
             (setq pairs
 
382
                   (nconc pairs
 
383
                          (mapcar #'list
 
384
                                  (append vars stores)
 
385
                                  (append vals (list (cadr r)))))))))))
 
386
 
 
387
 
 
388
;;; SHIFTF macro.
 
389
(defmacro shiftf (&environment env &rest rest)
 
390
  "Syntax: (shiftf {place}+ form)
 
391
Saves the values of PLACE and FORM, and then assigns the value of each PLACE
 
392
to the PLACE on its left.  The rightmost PLACE gets the value of FORM.
 
393
Returns the original value of the leftmost PLACE."
 
394
  (do ((r rest (cdr r))
 
395
       (pairs nil)
 
396
       (stores nil)
 
397
       (store-forms nil)
 
398
       (g (gensym))
 
399
       (access-forms nil))
 
400
      ((endp (cdr r))
 
401
       (setq stores (nreverse stores))
 
402
       (setq store-forms (nreverse store-forms))
 
403
       (setq access-forms (nreverse access-forms))
 
404
       `(let* ,(nconc pairs
 
405
                      (list (list g (car access-forms)))
 
406
                      (mapcar #'list stores (cdr access-forms))
 
407
                      (list (list (car (last stores)) (car r))))
 
408
            ,@store-forms
 
409
            ,g))
 
410
    (multiple-value-bind (vars vals stores1 store-form access-form)
 
411
        (get-setf-expansion (car r) env)
 
412
      (setq pairs (nconc pairs (mapcar #'list vars vals)))
 
413
      (setq stores (cons (car stores1) stores))
 
414
      (setq store-forms (cons store-form store-forms))
 
415
      (setq access-forms (cons access-form access-forms)))))
 
416
 
 
417
 
 
418
;;; ROTATEF macro.
 
419
(defmacro rotatef (&environment env &rest rest)
 
420
  "Syntax: (rotatef {place}*)
 
421
Saves the values of PLACEs, and then assigns to each PLACE the saved value of
 
422
the PLACE to its right.  The rightmost PLACE gets the value of the leftmost
 
423
PLACE.  Returns NIL."
 
424
  (do ((r rest (cdr r))
 
425
       (pairs nil)
 
426
       (stores nil)
 
427
       (store-forms nil)
 
428
       (access-forms nil))
 
429
      ((endp r)
 
430
       (setq stores (nreverse stores))
 
431
       (setq store-forms (nreverse store-forms))
 
432
       (setq access-forms (nreverse access-forms))
 
433
       `(let* ,(nconc pairs
 
434
                      (mapcar #'list stores (cdr access-forms))
 
435
                      (list (list (car (last stores)) (car access-forms))))
 
436
            ,@store-forms
 
437
            nil))
 
438
    (multiple-value-bind (vars vals stores1 store-form access-form)
 
439
        (get-setf-expansion (car r) env)
 
440
      (setq pairs (nconc pairs (mapcar #'list vars vals)))
 
441
      (setq stores (cons (car stores1) stores))
 
442
      (setq store-forms (cons store-form store-forms))
 
443
      (setq access-forms (cons access-form access-forms)))))
 
444
 
 
445
 
 
446
;;; DEFINE-MODIFY-MACRO macro, by Bruno Haible.
 
447
(defmacro define-modify-macro (name lambdalist function &optional docstring)
 
448
  "Syntax: (define-modify-macro symbol lambda-list function-name [doc])
 
449
Defines a read-modify-write macro like INCF.  The defined macro will expand
 
450
a form (SYMBOL place form1 ... formn) into a form that in effect SETFs the
 
451
value of (FUNCTION-NAME place arg1 ... argm) into PLACE, where ARG1 ... ARGm
 
452
are parameters in LAMBDA-LIST which are bound to FORM1 ... FORMn.  For
 
453
example, INCF could be defined as
 
454
        (define-modify-macro incf (&optional (x 1)) +)
 
455
The doc-string DOC, if supplied, is saved as a FUNCTION doc and can be
 
456
retrieved by (DOCUMENTATION 'SYMBOL 'FUNCTION)."
 
457
  (let* ((varlist nil)
 
458
         (restvar nil))
 
459
    (do* ((lambdalistr lambdalist (cdr lambdalistr))
 
460
          (next))
 
461
         ((null lambdalistr))
 
462
      (setq next (first lambdalistr))
 
463
      (cond ((eq next '&OPTIONAL))
 
464
            ((eq next '&REST)
 
465
             (if (symbolp (second lambdalistr))
 
466
               (setq restvar (second lambdalistr))
 
467
               (error "In the definition of ~S: &REST variable ~S should be a symbol."
 
468
                      name (second lambdalistr)
 
469
             ) )
 
470
             (if (null (cddr lambdalistr))
 
471
               (return)
 
472
               (error "Only one variable is allowed after &REST, not ~S"
 
473
                      lambdalistr
 
474
            )) )
 
475
            ((or (eq next '&KEY) (eq next '&ALLOW-OTHER-KEYS) (eq next '&AUX))
 
476
             (error "Illegal in a DEFINE-MODIFY-MACRO lambda list: ~S"
 
477
                    next
 
478
            ))
 
479
            ((symbolp next) (push next varlist))
 
480
            ((and (listp next) (symbolp (first next)))
 
481
             (push (first next) varlist)
 
482
            )
 
483
            (t (error "lambda list may only contain symbols and lists, not ~S"
 
484
                      next
 
485
            )  )
 
486
    ) )
 
487
    (setq varlist (nreverse varlist))
 
488
    `(DEFMACRO ,name (&ENVIRONMENT ENV %REFERENCE ,@lambdalist) ,docstring
 
489
       (MULTIPLE-VALUE-BIND (VARS VALS STORES SETTER GETTER)
 
490
           (GET-SETF-EXPANSION %REFERENCE ENV)
 
491
         (LET ((ALL-VARS (MAPCAR #'(LAMBDA (V) (LIST (GENSYM) V)) (LIST* ,@varlist ,restvar))))
 
492
         (IF (SYMBOLP GETTER)
 
493
             (SUBST (LIST* (QUOTE ,function) GETTER (MAPCAR #'CAR ALL-VARS))
 
494
                    (CAR STORES)
 
495
                    `(LET* ,ALL-VARS ,SETTER))
 
496
             (DO ((D VARS (CDR D))
 
497
                  (V VALS (CDR V))
 
498
                  (LET-LIST NIL (CONS (LIST (CAR D) (CAR V)) LET-LIST)))
 
499
                 ((NULL D)
 
500
                  (SETQ LET-LIST (APPEND (NREVERSE ALL-VARS) LET-LIST))
 
501
                  (PUSH
 
502
                   (LIST
 
503
                    (CAR STORES)
 
504
                    (IF (AND (LISTP %REFERENCE) (EQ (CAR %REFERENCE) 'THE))
 
505
                        (LIST 'THE (CADR %REFERENCE)
 
506
                              (LIST* (QUOTE ,function) GETTER ,@varlist ,restvar))
 
507
                        (LIST* (QUOTE ,function) GETTER (MAPCAR #'CAR ALL-VARS))))
 
508
                   LET-LIST)
 
509
                  `(LET* ,(NREVERSE LET-LIST) ,SETTER)))))))))
 
510
#|
 
511
(defmacro define-modify-macro (name lambda-list function &optional doc-string)
 
512
  (let ((update-form
 
513
         (do ((l lambda-list (cdr l))
 
514
              (vs nil))
 
515
             ((null l) `(list ',function access-form ,@(nreverse vs)))
 
516
           (unless (eq (car l) '&optional)
 
517
                   (if (eq (car l) '&rest)
 
518
                       (return `(list* ',function
 
519
                                       access-form
 
520
                                       ,@(nreverse vs)
 
521
                                       ,(cadr l))))
 
522
                   (if (symbolp (car l))
 
523
                       (setq vs (cons (car l) vs))
 
524
                       (setq vs (cons (caar l) vs)))))))
 
525
    `(defmacro ,name (&environment env reference . ,lambda-list)
 
526
       ,@(if doc-string (list doc-string))
 
527
       (when (symbolp reference)
 
528
             (return-from ,name
 
529
               (let ((access-form reference))
 
530
                 (list 'setq reference ,update-form))))
 
531
       (multiple-value-bind (vars vals stores store-form access-form)
 
532
           (get-setf-expansion reference env)
 
533
         `(let* ,(mapcar #'list
 
534
                  (append vars stores)
 
535
                  (append vals (list ,update-form)))
 
536
           (declare (:read-only ,@stores)) ; Beppe
 
537
           ,store-form)))))
 
538
|#
 
539
 
 
540
;;; Some macro definitions.
 
541
 
 
542
(defmacro remf (&environment env place indicator)
 
543
  "Syntax: (remf place form)
 
544
Removes the property specified by FORM from the property list stored in PLACE.
 
545
Returns T if the property list had the specified property; NIL otherwise."
 
546
  (multiple-value-bind (vars vals stores store-form access-form)
 
547
      (get-setf-expansion place env)
 
548
    (let ((s (gensym)))
 
549
      `(let* (,@(mapcar #'list vars vals) (,s ,indicator))
 
550
         (declare (:read-only ,@vars)) ; Beppe
 
551
         (multiple-value-bind (,(car stores) flag)
 
552
             (sys:rem-f ,access-form ,s)
 
553
           ,store-form
 
554
           flag)))))
 
555
 
 
556
(define-modify-macro incf (&optional (delta 1)) +
 
557
  "Syntax: (incf place [form])
 
558
Increments the value of PLACE by the value of FORM.  FORM defaults to 1.")
 
559
 
 
560
(define-modify-macro decf (&optional (delta 1)) -
 
561
  "Syntax: (decf place [form])
 
562
Decrements the value of PLACE by the value of FORM.  FORM defaults to 1.")
 
563
 
 
564
(defmacro push (&environment env item place)
 
565
  "Syntax: (push form place)
 
566
Evaluates FORM, conses the value of FORM to the value stored in PLACE, and
 
567
makes it the new value of PLACE.  Returns the new value of PLACE."
 
568
  (multiple-value-bind (vars vals stores store-form access-form)
 
569
      (get-setf-expansion place env)
 
570
    (when (and (null vars) (eq access-form place))
 
571
      (return-from push `(setq ,place (cons ,item ,place))))
 
572
    ;; The item to be pushed has to be evaluated before the destination
 
573
    (unless (constantp item)
 
574
      (setq vals (cons item vals)
 
575
            item (gensym)
 
576
            vars (cons item vars)))
 
577
    `(let* ,(mapcar #'list
 
578
                    (append vars stores)
 
579
                    (append vals (list (list 'cons item access-form))))
 
580
       (declare (:read-only ,@vars)) ; Beppe
 
581
       ,store-form)))
 
582
 
 
583
(defmacro pushnew (&environment env item place &rest rest)
 
584
  "Syntax: (pushnew form place {keyword-form value-form}*)
 
585
Evaluates FORM first.  If the value is already in the list stored in PLACE,
 
586
does nothing.  Else, conses the value onto the list and makes the result the
 
587
new value of PLACE.  Returns NIL.  KEYWORD-FORMs and VALUE-FORMs are used to
 
588
check if the value of FORM is already in PLACE as if their values are passed
 
589
to MEMBER."
 
590
  (multiple-value-bind (vars vals stores store-form access-form)
 
591
      (get-setf-expansion place env)
 
592
    (when (and (null vars) (eq access-form place))
 
593
      (return-from pushnew `(setq ,place (adjoin ,item ,place ,@rest))))
 
594
    ;; The item to be pushed has to be evaluated before the destination
 
595
    (unless (constantp item)
 
596
      (setq vals (cons item vals)
 
597
            item (gensym)
 
598
            vars (cons item vars)))
 
599
    `(let* ,(mapcar #'list
 
600
                    (append vars stores)
 
601
                    (append vals
 
602
                            (list (list* 'adjoin item access-form rest))))
 
603
       (declare (:read-only ,@vars)) ; Beppe
 
604
       ,store-form)))
 
605
 
 
606
(defmacro pop (&environment env place)
 
607
  "Syntax: (pop place)
 
608
Gets the cdr of the value stored in PLACE and makes it the new value of PLACE.
 
609
Returns the car of the old value in PLACE."
 
610
  (multiple-value-bind (vars vals stores store-form access-form)
 
611
      (get-setf-expansion place env)
 
612
    (if (and (null vars) (eq access-form place))
 
613
        `(prog1 (car ,place) (setq ,place (cdr ,place)))
 
614
        `(let* ,(mapcar #'list
 
615
                        (append vars stores)
 
616
                        (append vals (list (list 'cdr access-form))))
 
617
          (declare (:read-only ,@vars)) ; Beppe
 
618
          (prog1 (car ,access-form)
 
619
            ,store-form)))))
 
620
 
 
621
(define-setf-expander values (&rest values &environment env)
 
622
  (let ((all-vars '())
 
623
        (all-vals '())
 
624
        (all-stores '())
 
625
        (all-storing-forms '())
 
626
        (all-get-forms '()))
 
627
    (dolist (item (reverse values))
 
628
      (multiple-value-bind (vars vals stores storing-form get-form)
 
629
          (get-setf-expansion item env)
 
630
        ;; If a place has more than one store variable, the other ones
 
631
        ;; are set to nil.
 
632
        (let ((extra (rest stores)))
 
633
          (unless (endp extra)
 
634
            (setf vars (append extra vars)
 
635
                  vals (append (make-list (length extra)) vals)
 
636
                  stores (list (first stores)))))
 
637
        (setf all-vars (append vars all-vars)
 
638
              all-vals (append vals all-vals)
 
639
              all-stores (append stores all-stores)
 
640
              all-storing-forms (cons storing-form all-storing-forms)
 
641
              all-get-forms (cons get-form all-get-forms))))
 
642
    (values all-vars all-vals all-stores `(values ,@all-storing-forms)
 
643
            `(values ,@all-get-forms))))
 
644
#|
 
645
;;; Proposed extension:
 
646
; Expansion of (SETF (VALUES place1 ... placek) form)
 
647
; --> (MULTIPLE-VALUE-BIND (dummy1 ... dummyk) form
 
648
;       (SETF place1 dummy1 ... placek dummyk)
 
649
;       (VALUES dummy1 ... dummyk))
 
650
(define-setf-expander VALUES (&environment env &rest subplaces)
 
651
  (do ((temps) (vals) (stores)
 
652
       (storeforms) (accessforms)
 
653
       (placesr subplaces))
 
654
      ((atom placesr)
 
655
       (setq temps (nreverse temps)
 
656
             vals (nreverse vals)
 
657
             stores (nreverse stores)
 
658
             storeforms (nreverse storeforms)
 
659
             accessforms (nreverse accessforms))
 
660
       (values temps
 
661
            vals
 
662
            stores
 
663
            `(VALUES ,@storeforms)
 
664
            `(VALUES ,@accessforms)))
 
665
    (multiple-value-bind (SM1 SM2 SM3 SM4 SM5)
 
666
        (get-setf-expansion (pop placesr) env)
 
667
      (setq temps (revappend SM1 temps)
 
668
            vals (revappend SM2 vals)
 
669
            stores (revappend SM3 stores)
 
670
            storeforms (cons SM4 storeforms)
 
671
            accessforms (cons SM5 accessforms)))))
 
672
|#