1
;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
2
;;;; Copyright (c) 1990, Giuseppe Attardi.
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.
9
;;;; See file '../Copyright' for full details.
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)))
21
(defmacro defsetf (access-fn &rest rest)
22
"Syntax: (defsetf symbol update-fun [doc])
24
(defsetf symbol lambda-list (store-var) {decl | doc}* {form}*)
26
(setf (SYMBOL arg1 ... argn) value)
27
=> (UPDATE-FUN arg1 ... argn value)
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))
43
(let* ((store (second 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)
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}*
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
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
74
(let* ((var1 from1) ... (vark formk)
75
(value-var value-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)))
81
(setq args (cons (second env)
82
(nconc (ldiff args env) (cddr env))))
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))
97
;;;; get-setf-expansion.
99
(defun get-setf-expansion (form &optional env &aux f)
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)
105
(unless (or (fixnump item) (keywordp item))
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)))
121
(let* ((name (car form)) writer)
122
(multiple-value-bind (store vars inits all)
123
(rename-arguments (cdr form))
125
(cond ((setq f (get-sysprop name 'SETF-UPDATE-FN))
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))
131
((and (setq f (macroexpand form env)) (not (equal f form)))
132
(return-from get-setf-expansion
133
(get-setf-expansion f env)))
135
`(funcall #'(SETF ,name) ,store ,@all))))
136
(values vars inits (list store) writer (cons name all))))))))
138
;;;; SETF definitions.
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))
201
(defsetf documentation (s d) (v) `(sys::set-documentation ,s ,d ,v))
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)
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)
216
`(let ((,(car stores) (sys:put-f ,access-form ,store ,itemp)))
219
`(getf ,access-form ,itemp ,default)))))
221
(defsetf subseq (sequence1 start1 &optional end1)
223
`(PROGN (REPLACE ,sequence1 ,sequence2 :START1 ,start1 :END1 ,end1)
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))))
234
(define-setf-expander apply (&environment env fn &rest rest)
235
(unless (and (consp fn) (eq (car fn) 'FUNCTION) (symbolp (cadr 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)))))
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))
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)))))
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))
273
(stemp (first stores)))
274
(values `(,btemp ,@temps)
277
`(let ((,stemp (dpb ,store ,btemp ,access-form)))
279
`(ldb ,btemp ,access-form)))))
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))
286
(stemp (first stores)))
287
(values `(,btemp ,@temps)
290
`(let ((,stemp (deposit-field ,store ,btemp ,access-form)))
292
`(mask-field ,btemp ,access-form)))))
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
305
(append vals (list newvalue)))
308
`(let* ,(mapcar #'list vars vals)
309
(multiple-value-bind ,stores ,newvalue
313
(defun setf-structure-access (struct type index newvalue)
314
(declare (si::c-local))
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))))
320
(defun setf-expand (l env)
321
(declare (si::c-local))
323
((endp (cdr l)) (error "~S is an illegal SETF form." l))
325
(cons (setf-expand-1 (car l) (cadr l) env)
326
(setf-expand (cddr l) env)))))
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
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
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
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)))))
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))
366
`(progn ,(setf-expand-1 (car rest) (cadr rest) env)
369
(do ((r rest (cddr r))
374
,@(nreverse store-forms)
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))
385
(append vals (list (cadr r)))))))))))
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))
401
(setq stores (nreverse stores))
402
(setq store-forms (nreverse store-forms))
403
(setq access-forms (nreverse access-forms))
405
(list (list g (car access-forms)))
406
(mapcar #'list stores (cdr access-forms))
407
(list (list (car (last stores)) (car r))))
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)))))
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
424
(do ((r rest (cdr r))
430
(setq stores (nreverse stores))
431
(setq store-forms (nreverse store-forms))
432
(setq access-forms (nreverse access-forms))
434
(mapcar #'list stores (cdr access-forms))
435
(list (list (car (last stores)) (car access-forms))))
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)))))
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)."
459
(do* ((lambdalistr lambdalist (cdr lambdalistr))
462
(setq next (first lambdalistr))
463
(cond ((eq next '&OPTIONAL))
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)
470
(if (null (cddr lambdalistr))
472
(error "Only one variable is allowed after &REST, not ~S"
475
((or (eq next '&KEY) (eq next '&ALLOW-OTHER-KEYS) (eq next '&AUX))
476
(error "Illegal in a DEFINE-MODIFY-MACRO lambda list: ~S"
479
((symbolp next) (push next varlist))
480
((and (listp next) (symbolp (first next)))
481
(push (first next) varlist)
483
(t (error "lambda list may only contain symbols and lists, not ~S"
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))))
493
(SUBST (LIST* (QUOTE ,function) GETTER (MAPCAR #'CAR ALL-VARS))
495
`(LET* ,ALL-VARS ,SETTER))
496
(DO ((D VARS (CDR D))
498
(LET-LIST NIL (CONS (LIST (CAR D) (CAR V)) LET-LIST)))
500
(SETQ LET-LIST (APPEND (NREVERSE ALL-VARS) LET-LIST))
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))))
509
`(LET* ,(NREVERSE LET-LIST) ,SETTER)))))))))
511
(defmacro define-modify-macro (name lambda-list function &optional doc-string)
513
(do ((l lambda-list (cdr l))
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
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)
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
535
(append vals (list ,update-form)))
536
(declare (:read-only ,@stores)) ; Beppe
540
;;; Some macro definitions.
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)
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)
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.")
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.")
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)
576
vars (cons item vars)))
577
`(let* ,(mapcar #'list
579
(append vals (list (list 'cons item access-form))))
580
(declare (:read-only ,@vars)) ; Beppe
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
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)
598
vars (cons item vars)))
599
`(let* ,(mapcar #'list
602
(list (list* 'adjoin item access-form rest))))
603
(declare (:read-only ,@vars)) ; Beppe
606
(defmacro pop (&environment env 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
616
(append vals (list (list 'cdr access-form))))
617
(declare (:read-only ,@vars)) ; Beppe
618
(prog1 (car ,access-form)
621
(define-setf-expander values (&rest values &environment env)
625
(all-storing-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
632
(let ((extra (rest stores)))
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))))
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)
655
(setq temps (nreverse temps)
657
stores (nreverse stores)
658
storeforms (nreverse storeforms)
659
accessforms (nreverse accessforms))
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)))))