Still more duplicate code removed from 'setf'. It never ends.
[sbcl.git] / src / code / setf.lisp
blobaeeb34dd05787ad210746fc6579e1aa136a92f79
1 ;;;; SETF and friends
2 ;;;;
3 ;;;; Note: The expansions for SETF and friends sometimes create
4 ;;;; needless LET-bindings of argument values. The compiler will
5 ;;;; remove most of these spurious bindings, so SETF doesn't worry too
6 ;;;; much about creating them.
8 ;;;; This software is part of the SBCL system. See the README file for
9 ;;;; more information.
10 ;;;;
11 ;;;; This software is derived from the CMU CL system, which was
12 ;;;; written at Carnegie Mellon University and released into the
13 ;;;; public domain. The software is in the public domain and is
14 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
15 ;;;; files for more information.
17 (in-package "SB!IMPL")
19 ;;; The inverse for a generalized-variable reference function is stored in
20 ;;; one of two ways:
21 ;;;
22 ;;; A SETF inverse property corresponds to the short form of DEFSETF. It is
23 ;;; the name of a function takes the same args as the reference form, plus a
24 ;;; new-value arg at the end.
25 ;;;
26 ;;; A SETF method expander is created by the long form of DEFSETF or
27 ;;; by DEFINE-SETF-EXPANDER. It is a function that is called on the reference
28 ;;; form and that produces five values: a list of temporary variables, a list
29 ;;; of value forms, a list of the single store-value form, a storing function,
30 ;;; and an accessing function.
31 (declaim (ftype (function (t &optional (or null sb!c::lexenv))) sb!xc:get-setf-expansion))
32 (defun sb!xc:get-setf-expansion (form &optional environment)
33 #!+sb-doc
34 "Return five values needed by the SETF machinery: a list of temporary
35 variables, a list of values with which to fill them, a list of temporaries
36 for the new values, the setting function, and the accessing function."
37 (acond ((symbolp form)
38 (multiple-value-bind (expansion expanded)
39 (sb!xc:macroexpand-1 form environment)
40 (if expanded
41 (sb!xc:get-setf-expansion expansion environment)
42 (let ((new-var (sb!xc:gensym "NEW")))
43 (values nil nil (list new-var)
44 `(setq ,form ,new-var) form)))))
45 ;; Local functions inhibit global SETF methods.
46 ((and environment
47 (let ((name (car form)))
48 (dolist (x (sb!c::lexenv-funs environment))
49 (when (and (eq (car x) name)
50 (not (sb!c::defined-fun-p (cdr x))))
51 (return t)))))
52 (expand-or-get-setf-inverse form environment))
53 ((info :setf :inverse (car form))
54 (make-setf-quintuple-simple form environment nil `(,it)))
55 ((info :setf :expander (car form))
56 ;; KLUDGE: It may seem as though this should go through
57 ;; *MACROEXPAND-HOOK*, but the ANSI spec seems fairly explicit
58 ;; that *MACROEXPAND-HOOK* is a hook for MACROEXPAND-1, not
59 ;; for macroexpansion in general. -- WHN 19991128
60 (funcall it form
61 ;; As near as I can tell from the ANSI spec,
62 ;; macroexpanders have a right to expect an actual
63 ;; lexical environment, not just a NIL which is to
64 ;; be interpreted as a null lexical environment.
65 ;; -- WHN 19991128
66 (coerce-to-lexenv environment)))
68 (expand-or-get-setf-inverse form environment))))
70 ;;; If a macro, expand one level and try again. If not, go for the
71 ;;; SETF function.
72 (declaim (ftype (function (t (or null sb!c::lexenv)))
73 expand-or-get-setf-inverse))
74 (defun expand-or-get-setf-inverse (form environment)
75 (multiple-value-bind (expansion expanded)
76 (%macroexpand-1 form environment)
77 (if expanded
78 (sb!xc:get-setf-expansion expansion environment)
79 (make-setf-quintuple-simple form environment
80 t `(funcall #'(setf ,(car form)))))))
82 ;;;; SETF itself
84 ;; Code shared by SETF, PSETF, SHIFTF attempting to minimize the expansion.
85 ;; This has significant speed+space benefit to a non-preprocessing interpreter,
86 ;; and to some degree a preprocessing interpreter.
87 (labels ((gen-let* (bindings body-forms)
88 (cond ((not bindings) body-forms)
90 (when (and (singleton-p body-forms)
91 (listp (car body-forms))
92 (eq (caar body-forms) 'let*))
93 (let ((nested (cdar body-forms))) ; extract the nested LET*
94 (setq bindings (append bindings (car nested))
95 body-forms (cdr nested))))
96 `((let* ,bindings ,@body-forms)))))
97 (gen-mv-bind (stores values body-forms)
98 (if (singleton-p stores)
99 (gen-let* `((,(car stores) ,values)) body-forms)
100 `((multiple-value-bind ,stores ,values ,@body-forms))))
101 ;; Instead of emitting (PROGN (VALUES (SETQ ...) (SETQ ...)) NIL)
102 ;; the SETQs can be lifted into the PROGN. This is unimportant
103 ;; for compiled code, but it helps the interpreter not needlessly
104 ;; collect arguments to call VALUES; and it's more human-readable.
105 (de-values-ify (forms)
106 (mapcan (lambda (form)
107 (if (and (listp form) (eq (car form) 'values))
108 (copy-list (cdr form))
109 (list form)))
110 forms)))
112 ;;; Except for atoms, we always call GET-SETF-EXPANSION, since it has
113 ;;; some non-trivial semantics. But when there is a setf inverse, and
114 ;;; G-S-E uses it, then we return a call to the inverse, rather than
115 ;;; returning a hairy LET form. This is probably important mainly as a
116 ;;; convenience in allowing the use of SETF inverses without the full
117 ;;; interpreter.
118 (defmacro-mundanely setf (&whole form &rest args &environment env)
119 #!+sb-doc
120 "Takes pairs of arguments like SETQ. The first is a place and the second
121 is the value that is supposed to go into that place. Returns the last
122 value. The place argument may be any of the access forms for which SETF
123 knows a corresponding setting form."
124 (unless args
125 (return-from setf nil))
126 (destructuring-bind (place value-form . more) args
127 (when more
128 (return-from setf `(progn ,@(sb!c::explode-setq form 'error))))
129 ;; Macros without a SETF expander/inverse can be expanded now,
130 ;; for shorter output in the case where (M) is a macro invocation
131 ;; expanding to *A-VAR*, rather than deferring the macroexpansion
132 ;; to GET-SETF-EXPANSION which will introduce a needless gensym.
133 (loop
134 (when (and (listp place)
135 (let ((op (car place)))
136 (or (info :setf :expander op) (info :setf :inverse op))))
137 (return))
138 (multiple-value-bind (expansion macro-p) (%macroexpand-1 place env)
139 (cond (macro-p (setq place expansion)) ; iterate
140 ((symbolp place) (return-from setf `(setq ,place ,value-form)))
141 (t (return)))))
142 (multiple-value-bind (temps vals newval setter)
143 (sb!xc:get-setf-expansion place env)
144 (let ((inverse (info :setf :inverse (car place))))
145 (if (and inverse (eq inverse (car setter)))
146 `(,inverse ,@(cdr place) ,value-form)
147 (car (gen-let* (mapcar #'list temps vals)
148 (gen-mv-bind newval value-form
149 (list setter)))))))))
151 ;; various SETF-related macros
153 (defmacro-mundanely shiftf (&whole form &rest args &environment env)
154 #!+sb-doc
155 "One or more SETF-style place expressions, followed by a single
156 value expression. Evaluates all of the expressions in turn, then
157 assigns the value of each expression to the place on its left,
158 returning the value of the leftmost."
159 (declare (type sb!c::lexenv env))
160 (when (< (length args) 2)
161 (error "~S called with too few arguments: ~S" 'shiftf form))
162 (collect ((let-bindings) (mv-bindings) (setters) (getters))
163 (dolist (arg (butlast args))
164 (multiple-value-bind (temps subforms store-vars setter getter)
165 (sb!xc:get-setf-expansion arg env)
166 (let-bindings (mapcar #'list temps subforms))
167 (mv-bindings store-vars)
168 (setters setter)
169 (getters getter)))
170 ;; Handle the last arg specially here. The getter is just the last
171 ;; arg itself.
172 (getters (car (last args)))
173 (labels ((thunk (mv-bindings getters setters)
174 (if mv-bindings
175 (gen-mv-bind (car mv-bindings) (car getters)
176 (thunk (cdr mv-bindings) (cdr getters) setters))
177 setters)))
178 (let ((outputs (loop for i below (length (car (mv-bindings)))
179 collect (sb!xc:gensym "OUT"))))
180 `(let ,(reduce #'append (let-bindings))
181 ,@(gen-mv-bind outputs (car (getters))
182 (thunk (mv-bindings) (cdr (getters))
183 `(,@(de-values-ify (setters))
184 (values ,@outputs)))))))))
186 (labels
187 ((expand (args env operator single-op)
188 (cond ((singleton-p (cdr args)) ; commonest case probably
189 (return-from expand `(progn (,single-op ,@args) nil)))
190 ((not args)
191 (return-from expand nil)))
192 (collect ((let*-bindings) (mv-bindings) (setters))
193 (do ((a args (cddr a)))
194 ((endp a))
195 (when (endp (cdr a))
196 (error "Odd number of args to ~S." operator))
197 (let ((place (car a))
198 (value-form (cadr a)))
199 (when (and (not (symbolp place)) (eq operator 'psetq))
200 (error 'simple-program-error
201 :format-control "Place ~S in PSETQ is not a SYMBOL"
202 :format-arguments (list place)))
203 (multiple-value-bind (temps vals stores setter)
204 (sb!xc:get-setf-expansion place env)
205 (let*-bindings (mapcar #'list temps vals))
206 (mv-bindings (cons stores value-form))
207 (setters setter))))
208 (car (build (let*-bindings) (mv-bindings)
209 (de-values-ify (setters))))))
210 (build (let*-bindings mv-bindings setters)
211 (if let*-bindings
212 (gen-let* (car let*-bindings)
213 (gen-mv-bind (caar mv-bindings) (cdar mv-bindings)
214 (build (cdr let*-bindings) (cdr mv-bindings)
215 setters)))
216 `(,@setters nil))))
218 (defmacro-mundanely psetf (&rest pairs &environment env)
219 #!+sb-doc
220 "This is to SETF as PSETQ is to SETQ. Args are alternating place
221 expressions and values to go into those places. All of the subforms and
222 values are determined, left to right, and only then are the locations
223 updated. Returns NIL."
224 (expand pairs env 'psetf 'setf))
226 (defmacro-mundanely psetq (&rest pairs &environment env)
227 #!+sb-doc
228 "PSETQ {var value}*
229 Set the variables to the values, like SETQ, except that assignments
230 happen in parallel, i.e. no assignments take place until all the
231 forms have been evaluated."
232 (expand pairs env 'psetq 'setq))))
234 ;;; FIXME: Compiling this definition of ROTATEF apparently blows away the
235 ;;; definition in the cross-compiler itself, so that after that, any
236 ;;; ROTATEF operations can no longer be compiled, because
237 ;;; GET-SETF-EXPANSION is called instead of SB!XC:GET-SETF-EXPANSION.
238 (defmacro-mundanely rotatef (&rest args &environment env)
239 #!+sb-doc
240 "Takes any number of SETF-style place expressions. Evaluates all of the
241 expressions in turn, then assigns to each place the value of the form to
242 its right. The rightmost form gets the value of the leftmost.
243 Returns NIL."
244 (declare (type sb!c::lexenv env))
245 (when args
246 (collect ((let*-bindings) (mv-bindings) (setters) (getters))
247 (dolist (arg args)
248 (multiple-value-bind (temps subforms store-vars setter getter)
249 (sb!xc:get-setf-expansion arg env)
250 (let*-bindings (mapcar #'list temps subforms))
251 (mv-bindings store-vars)
252 (setters setter)
253 (getters getter)))
254 (setters nil)
255 (getters (car (getters)))
256 (labels ((thunk (mv-bindings getters)
257 (if mv-bindings
258 `((multiple-value-bind ,(car mv-bindings) ,(car getters)
259 ,@(thunk (cdr mv-bindings) (cdr getters))))
260 (setters))))
261 `(let* ,(reduce #'append(let*-bindings))
262 ,@(thunk (mv-bindings) (cdr (getters))))))))
264 (defmacro-mundanely push (obj place &environment env)
265 #!+sb-doc
266 "Takes an object and a location holding a list. Conses the object onto
267 the list, returning the modified list. OBJ is evaluated before PLACE."
268 (multiple-value-bind (dummies vals newval setter getter)
269 (sb!xc:get-setf-expansion place env)
270 (let ((g (gensym)))
271 `(let* ((,g ,obj)
272 ,@(mapcar #'list dummies vals)
273 (,(car newval) (cons ,g ,getter))
274 ,@(cdr newval))
275 ,setter))))
277 (defmacro-mundanely pushnew (obj place &rest keys
278 &key key test test-not &environment env)
279 #!+sb-doc
280 "Takes an object and a location holding a list. If the object is
281 already in the list, does nothing; otherwise, conses the object onto
282 the list. Returns the modified list. If there is a :TEST keyword, this
283 is used for the comparison."
284 (declare (ignore key test test-not))
285 (multiple-value-bind (dummies vals newval setter getter)
286 (sb!xc:get-setf-expansion place env)
287 (let ((g (gensym)))
288 `(let* ((,g ,obj)
289 ,@(mapcar #'list dummies vals)
290 (,(car newval) (adjoin ,g ,getter ,@keys))
291 ,@(cdr newval))
292 ,setter))))
294 (defmacro-mundanely pop (place &environment env)
295 #!+sb-doc
296 "The argument is a location holding a list. Pops one item off the front
297 of the list and returns it."
298 (multiple-value-bind (dummies vals newval setter getter)
299 (sb!xc:get-setf-expansion place env)
300 (let ((list-head (gensym)))
301 `(let* (,@(mapcar #'list dummies vals)
302 (,list-head ,getter)
303 (,(car newval) (cdr ,list-head))
304 ,@(cdr newval))
305 ,setter
306 (car ,list-head)))))
308 (defmacro-mundanely remf (place indicator &environment env)
309 #!+sb-doc
310 "Place may be any place expression acceptable to SETF, and is expected
311 to hold a property list or (). This list is destructively altered to
312 remove the property specified by the indicator. Returns T if such a
313 property was present, NIL if not."
314 (multiple-value-bind (temps vals newval setter getter)
315 (sb!xc:get-setf-expansion place env)
316 (let* ((flag (make-symbol "FLAG"))
317 (body `(multiple-value-bind (,(car newval) ,flag)
318 ;; See ANSI 5.1.3 for why we do out-of-order evaluation
319 (truly-the (values list boolean)
320 (%remf ,indicator ,getter))
321 ,(if (cdr newval) `(let ,(cdr newval) ,setter) setter)
322 ,flag)))
323 (if temps `(let* ,(mapcar #'list temps vals) ,body) body))))
325 ;; Perform the work of REMF.
326 (defun %remf (indicator plist)
327 (let ((tail plist) (predecessor))
328 (loop
329 (when (endp tail) (return (values plist nil)))
330 (let ((key (pop tail)))
331 (when (atom tail)
332 (error (if tail
333 "Improper list in REMF."
334 "Odd-length list in REMF.")))
335 (let ((next (cdr tail)))
336 (when (eq key indicator)
337 ;; This function is strict in its return type!
338 (the list next) ; for effect
339 (return (values (cond (predecessor
340 (setf (cdr predecessor) next)
341 plist)
343 next))
344 t)))
345 (setq predecessor tail tail next))))))
347 ;;; INCF and DECF have a straightforward expansion, avoiding temp vars,
348 ;;; when the PLACE is a non-macro symbol. Otherwise we do the generalized
349 ;;; SETF-like thing. The compiler doesn't care either way, but this
350 ;;; reduces the incentive to treat some macros as special-forms when
351 ;;; squeezing more performance from a Lisp interpreter.
352 ;;; DEFINE-MODIFY-MACRO could be used, but this expands more compactly.
353 (declaim (inline xsubtract))
354 (defun xsubtract (a b) (- b a)) ; exchanged subtract
355 (flet ((expand (place delta env operator)
356 (when (symbolp place)
357 (multiple-value-bind (expansion expanded)
358 (sb!xc:macroexpand-1 place env)
359 (unless expanded
360 (return-from expand `(setq ,place (,operator ,delta ,place))))
361 ;; GET-SETF-EXPANSION would have macroexpanded too, so do it now.
362 (setq place expansion)))
363 (multiple-value-bind (dummies vals newval setter getter)
364 (sb!xc:get-setf-expansion place env)
365 `(let* (,@(mapcar #'list dummies vals)
366 (,(car newval) (,operator ,delta ,getter))
367 ,@(cdr newval))
368 ,setter))))
369 (defmacro-mundanely incf (place &optional (delta 1) &environment env)
370 #!+sb-doc
371 "The first argument is some location holding a number. This number is
372 incremented by the second argument, DELTA, which defaults to 1."
373 (expand place delta env '+))
375 (defmacro-mundanely decf (place &optional (delta 1) &environment env)
376 #!+sb-doc
377 "The first argument is some location holding a number. This number is
378 decremented by the second argument, DELTA, which defaults to 1."
379 (expand place delta env 'xsubtract)))
381 ;;;; DEFINE-MODIFY-MACRO stuff
383 (def!macro sb!xc:define-modify-macro (name lambda-list function &optional doc-string)
384 #!+sb-doc
385 "Creates a new read-modify-write macro like PUSH or INCF."
386 (let ((other-args nil)
387 (rest-arg nil)
388 (env (make-symbol "ENV")) ; To beautify resulting arglist.
389 (reference (make-symbol "PLACE"))) ; Note that these will be nonexistent
390 ; in the final expansion anyway.
391 ;; Parse out the variable names and &REST arg from the lambda list.
392 (do ((ll lambda-list (cdr ll))
393 (arg nil))
394 ((null ll))
395 (setq arg (car ll))
396 (cond ((eq arg '&optional))
397 ((eq arg '&rest)
398 (if (symbolp (cadr ll))
399 (setq rest-arg (cadr ll))
400 (error "Non-symbol &REST argument in definition of ~S." name))
401 (if (null (cddr ll))
402 (return nil)
403 (error "Illegal stuff after &REST argument.")))
404 ((memq arg '(&key &allow-other-keys &aux))
405 (error "~S not allowed in DEFINE-MODIFY-MACRO lambda list." arg))
406 ((symbolp arg)
407 (push arg other-args))
408 ((and (listp arg) (symbolp (car arg)))
409 (push (car arg) other-args))
410 (t (error "Illegal stuff in lambda list."))))
411 (setq other-args (nreverse other-args))
412 `(#-sb-xc-host sb!xc:defmacro
413 #+sb-xc-host defmacro-mundanely
414 ,name (,reference ,@lambda-list &environment ,env)
415 ,@(when doc-string (list (the string doc-string)))
416 (expand-rmw-macro ',function ,reference (list* ,@other-args ,rest-arg)
417 ,env ',other-args))))
419 ;;;; DEFSETF
421 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
422 ;;; Assign SETF macro information for NAME, making all appropriate checks.
423 (macrolet ((assign-it ()
424 `(progn
425 (when inverse
426 (clear-info :setf :expander name)
427 (setf (info :setf :inverse name) inverse))
428 (when expander
429 #-sb-xc-host (setf (%fun-lambda-list expander)
430 expander-lambda-list)
431 (clear-info :setf :inverse name)
432 (setf (info :setf :expander name) expander))
433 (when doc
434 (setf (fdocumentation name 'setf) doc))
435 name)))
436 (defun assign-setf-macro (name expander expander-lambda-list inverse doc)
437 #+sb-xc-host (declare (ignore expander-lambda-list))
438 (with-single-package-locked-error
439 (:symbol name "defining a setf-expander for ~A"))
440 (let ((setf-fn-name `(setf ,name)))
441 (multiple-value-bind (where-from present-p)
442 (info :function :where-from setf-fn-name)
443 ;; One might think that :DECLARED merits a style warning, but SBCL
444 ;; provides ~58 standard accessors as both (SETF F) and a macro.
445 ;; So allow the user to declaim an FTYPE and we'll hush up.
446 ;; What's good for the the goose is good for the gander.
447 (case where-from
448 (:assumed
449 ;; This indicates probable user error. Compilation assumed something
450 ;; to be functional; a macro says otherwise. Because :where-from's
451 ;; default can be :assumed, PRESENT-P disambiguates "defaulted" from
452 ;; "known" to have made an existence assumption.
453 (when present-p
454 (warn "defining setf macro for ~S when ~S was previously ~
455 treated as a function" name setf-fn-name)))
456 (:defined
457 ;; Somebody defined (SETF F) but then also said F has a macro.
458 ;; A soft warning seems appropriate because in this case it's
459 ;; at least in theory not wrong to call the function.
460 ;; The user can declare an FTYPE if both things are intentional.
461 (style-warn "defining setf macro for ~S when ~S is also defined"
462 name setf-fn-name)))))
463 (assign-it))
464 (defun !quietly-assign-setf-macro ; For cold-init
465 (name expander expander-lambda-list inverse doc)
466 (assign-it))))
468 (def!macro sb!xc:defsetf (access-fn &rest rest)
469 #!+sb-doc
470 "Associates a SETF update function or macro with the specified access
471 function or macro. The format is complex. See the manual for details."
472 (unless (symbolp access-fn)
473 (error "~S access-function name ~S is not a symbol."
474 'sb!xc:defsetf access-fn))
475 (typecase rest
476 ((cons (and symbol (not null)) (or null (cons string null)))
477 `(eval-when (:load-toplevel :compile-toplevel :execute)
478 (assign-setf-macro ',access-fn nil nil ',(car rest) ',(cadr rest))))
479 ((cons list (cons list))
480 (destructuring-bind (lambda-list (&rest store-variables) &body body) rest
481 (with-unique-names (whole access-form environment)
482 ;; FIXME: a defsetf lambda-list is *NOT* a macro lambda list!
483 ;; Suppose that (MY-ACC ((X))) is a macro, not a function,
484 ;; and you attempt to destructure the X. It parses ok by accident,
485 ;; but when you attempt to bind to subforms of MY-ACC,
486 ;; you find that ((X)) is not a well-formed sexpr.
487 (multiple-value-bind (body local-decs doc)
488 ;; This technique of parsing the stores as part of the
489 ;; the function's lambda list is loathsome.
490 (parse-defmacro `(,lambda-list ,@store-variables)
491 whole body access-fn 'defsetf
492 :environment environment
493 :anonymousp t)
494 `(eval-when (:compile-toplevel :load-toplevel :execute)
495 (assign-setf-macro
496 ',access-fn
497 (lambda (,access-form ,environment)
498 (make-setf-quintuple ,access-form ,environment
499 ,(length store-variables)
500 (lambda (,whole ,environment)
501 ,@local-decs ,body)))
502 ',lambda-list nil ',doc))))))
504 (error "Ill-formed DEFSETF for ~S" access-fn))))
506 ;; Much of the SETF framework shares logic to assemble the first two values
507 ;; for GET-SETF-EXPANSION while eschewing bindings for constant arguments.
508 (flet ((collect-call-temps (place-subforms environment name-hints)
509 (collect ((temp-vars) (temp-vals) (call-arguments))
510 (dolist (form place-subforms
511 (values (temp-vars) (temp-vals) (call-arguments)))
512 (call-arguments (if (sb!xc:constantp form environment)
513 form
514 (let ((temp (if name-hints
515 (copy-symbol (car name-hints))
516 (gensymify form))))
517 (temp-vars temp)
518 (temp-vals form)
519 temp)))
520 (pop name-hints)))))
522 ;; Return the 5-part expansion of a SETF form that calls #'(SETF Fn)
523 ;; when SETF-FUN-P is non-nil, or the short form of a DEFSETF, when NIL.
524 ;; INVERSE should be (FUNCALL #'(SETF x)) or (SETTER-FN) respectively.
525 (defun make-setf-quintuple-simple (access-form environment setf-fun-p inverse)
526 (multiple-value-bind (temp-vars temp-vals args)
527 (collect-call-temps (cdr access-form) environment nil)
528 (let ((store (sb!xc:gensym "NEW")))
529 (values temp-vars temp-vals (list store)
530 `(,@inverse ,@(if setf-fun-p `(,store ,@args) `(,@args ,store)))
531 `(,(car access-form) ,@args)))))
533 ;; Return the 5-part expansion of a SETF form defined by the long form
534 ;; of DEFSETF.
535 ;; FIXME: totally broken if there are keyword arguments. lp#1452947
536 (defun make-setf-quintuple (access-form environment num-store-vars expander)
537 (declare (type function expander))
538 (multiple-value-bind (temp-vars temp-vals call-arguments)
539 (collect-call-temps (cdr access-form) environment nil)
540 (let ((stores (make-gensym-list num-store-vars "NEW")))
541 (values temp-vars temp-vals stores
542 (funcall expander (cons call-arguments stores) environment)
543 `(,(car access-form) ,@call-arguments)))))
545 ;; Expand a macro defined by DEFINE-MODIFY-MACRO.
546 ;; The generated call resembles (FUNCTION PLACE . ARG-FORMS) but the
547 ;; read and write of PLACE - not including its subforms - are done
548 ;; only after all ARG-FORMS are evaluated.
549 (defun expand-rmw-macro (function place arg-forms environment name-hints)
550 (multiple-value-bind (temp-vars temp-vals stores setter getter)
551 (sb!xc:get-setf-expansion place environment)
552 (multiple-value-bind (fun-temp-vars fun-temp-vals call-arguments)
553 (collect-call-temps arg-forms environment name-hints)
554 (let* ((compute `(,function ,getter ,@call-arguments))
555 (set-fn (and (listp setter) (car setter)))
556 (newval-temp (car stores))
557 (newval-binding `((,newval-temp ,compute))))
558 ;; Try to elide the binding of NEWVAL-TEMP. If the SINGLETON-P test
559 ;; passes, then NEWVAL-TEMP is the last argument to the setter form.
560 ;; Checking that everything else is an expected symbol
561 ;; ensures that no other reference to NEWVAL-TEMP exists.
562 (when (and (singleton-p (member newval-temp setter))
563 (or (eq set-fn 'setq)
564 (and (eq (info :function :kind set-fn) :function)
565 (every (lambda (x)
566 (or (member x temp-vars)
567 (member x fun-temp-vars)
568 (eq x newval-temp)))
569 (cdr setter)))))
570 (setq newval-binding nil
571 setter (append (butlast setter) (list compute))))
572 (let ((bindings (append (mapcar #'list temp-vars temp-vals)
573 (mapcar #'list fun-temp-vars fun-temp-vals)
574 newval-binding
575 (cdr stores))))
576 (if bindings `(let* ,bindings ,setter) setter)))))))
578 ;;;; DEFMACRO DEFINE-SETF-EXPANDER and various DEFINE-SETF-EXPANDERs
580 ;;; DEFINE-SETF-EXPANDER is a lot like DEFMACRO.
581 (def!macro sb!xc:define-setf-expander (access-fn lambda-list &body body)
582 #!+sb-doc
583 "Syntax like DEFMACRO, but creates a setf expander function. The body
584 of the definition must be a form that returns five appropriate values."
585 (unless (symbolp access-fn)
586 (error "~S access-function name ~S is not a symbol."
587 'sb!xc:define-setf-expander access-fn))
588 (with-unique-names (whole environment)
589 (multiple-value-bind (body local-decs doc)
590 (parse-defmacro lambda-list whole body access-fn
591 'sb!xc:define-setf-expander
592 :environment environment)
593 `(eval-when (:compile-toplevel :load-toplevel :execute)
594 (assign-setf-macro ',access-fn
595 (lambda (,whole ,environment)
596 ,@local-decs
597 ,body)
598 ',lambda-list
600 ',doc)))))
602 (sb!xc:define-setf-expander values (&rest places &environment env)
603 (declare (type sb!c::lexenv env))
604 (collect ((setters) (getters))
605 (let ((all-dummies '())
606 (all-vals '())
607 (newvals '()))
608 (dolist (place places)
609 (multiple-value-bind (dummies vals newval setter getter)
610 (sb!xc:get-setf-expansion place env)
611 ;; ANSI 5.1.2.3 explains this logic quite precisely. --
612 ;; CSR, 2004-06-29
613 (setq all-dummies (append all-dummies dummies (cdr newval))
614 all-vals (append all-vals vals
615 (mapcar (constantly nil) (cdr newval)))
616 newvals (append newvals (list (car newval))))
617 (setters setter)
618 (getters getter)))
619 (values all-dummies all-vals newvals
620 `(values ,@(setters)) `(values ,@(getters))))))
622 (sb!xc:define-setf-expander getf (place prop
623 &optional default
624 &environment env)
625 (declare (type sb!c::lexenv env))
626 (multiple-value-bind (temps values stores set get)
627 (sb!xc:get-setf-expansion place env)
628 (let ((newval (gensym))
629 (ptemp (gensym))
630 (def-temp (if default (gensym))))
631 (values `(,@temps ,ptemp ,@(if default `(,def-temp)))
632 `(,@values ,prop ,@(if default `(,default)))
633 `(,newval)
634 `(let ((,(car stores) (%putf ,get ,ptemp ,newval))
635 ,@(cdr stores))
636 ,def-temp ;; prevent unused style-warning
637 ,set
638 ,newval)
639 `(getf ,get ,ptemp ,@(if default `(,def-temp)))))))
641 (sb!xc:define-setf-expander get (symbol prop &optional default)
642 (let ((symbol-temp (gensym))
643 (prop-temp (gensym))
644 (def-temp (if default (gensym)))
645 (newval (gensym)))
646 (values `(,symbol-temp ,prop-temp ,@(if default `(,def-temp)))
647 `(,symbol ,prop ,@(if default `(,default)))
648 (list newval)
649 `(progn ,def-temp ;; prevent unused style-warning
650 (%put ,symbol-temp ,prop-temp ,newval))
651 `(get ,symbol-temp ,prop-temp ,@(if default `(,def-temp))))))
653 (sb!xc:define-setf-expander gethash (key hashtable &optional default)
654 (let ((key-temp (gensym))
655 (hashtable-temp (gensym))
656 (default-temp (if default (gensym)))
657 (new-value-temp (gensym)))
658 (values
659 `(,key-temp ,hashtable-temp ,@(if default `(,default-temp)))
660 `(,key ,hashtable ,@(if default `(,default)))
661 `(,new-value-temp)
662 `(progn ,default-temp ;; prevent unused style-warning
663 (%puthash ,key-temp ,hashtable-temp ,new-value-temp))
664 `(gethash ,key-temp ,hashtable-temp ,@(if default `(,default-temp))))))
666 (sb!xc:define-setf-expander logbitp (index int &environment env)
667 (declare (type sb!c::lexenv env))
668 (multiple-value-bind (temps vals stores store-form access-form)
669 (sb!xc:get-setf-expansion int env)
670 (let ((ind (gensym))
671 (store (gensym))
672 (stemp (first stores)))
673 (values `(,ind ,@temps)
674 `(,index
675 ,@vals)
676 (list store)
677 `(let ((,stemp
678 (dpb (if ,store 1 0) (byte 1 ,ind) ,access-form))
679 ,@(cdr stores))
680 ,store-form
681 ,store)
682 `(logbitp ,ind ,access-form)))))
684 ;;; CMU CL had a comment here that:
685 ;;; Evil hack invented by the gnomes of Vassar Street (though not as evil as
686 ;;; it used to be.) The function arg must be constant, and is converted to
687 ;;; an APPLY of the SETF function, which ought to exist.
689 ;;; Historical note: The hack was considered evil becase prior to the
690 ;;; standardization of #'(SETF F) as a namespace for functions, all that existed
691 ;;; were SETF expanders. To "invert" (APPLY #'F A B .. LAST), you assumed that
692 ;;; the SETF expander was ok to use on (F A B .. LAST), yielding something
693 ;;; like (set-F A B .. LAST). If the LAST arg didn't move (based on comparing
694 ;;; gensyms between the "getter" and "setter" forms), you'd stick APPLY
695 ;;; in front and hope for the best. Plus AREF still had to be special-cased.
697 ;;; It may not be clear (wasn't to me..) that this is a standard thing, but See
698 ;;; "5.1.2.5 APPLY Forms as Places" in the ANSI spec. I haven't actually
699 ;;; verified that this code has any correspondence to that code, but at least
700 ;;; ANSI has some place for SETF APPLY. -- WHN 19990604
701 (sb!xc:define-setf-expander apply (functionoid &rest args)
702 ;; Technically (per CLHS) this only must allow AREF,BIT,SBIT
703 ;; but there's not much danger in allowing other stuff.
704 (unless (typep functionoid '(cons (eql function) (cons symbol null)))
705 (error "SETF of APPLY is only defined for function args like #'SYMBOL."))
706 (let ((function (second functionoid))
707 (new-var (gensym))
708 (vars (make-gensym-list (length args))))
709 (values vars args (list new-var)
710 `(apply #'(setf ,function) ,new-var ,@vars)
711 `(apply #',function ,@vars))))
713 ;;; Special-case a BYTE bytespec so that the compiler can recognize it.
714 ;;; FIXME: it is suboptimal that (INCF (LDB (BYTE 9 0) (ELT X 0)))
715 ;;; performs two reads of (ELT X 0), once to get the value from which
716 ;;; to extract a 9-bit subfield, and again to combine the incremented
717 ;;; value with the other bits. I don't think it's wrong per se,
718 ;;; but is worthy of some thought as to whether it can be improved.
719 (sb!xc:define-setf-expander ldb (bytespec place &environment env)
720 #!+sb-doc
721 "The first argument is a byte specifier. The second is any place form
722 acceptable to SETF. Replace the specified byte of the number in this
723 place with bits from the low-order end of the new value."
724 (declare (type sb!c::lexenv env))
725 (multiple-value-bind (dummies vals newval setter getter)
726 (sb!xc:get-setf-expansion place env)
727 (if (and (consp bytespec) (eq (car bytespec) 'byte))
728 (let ((n-size (gensym))
729 (n-pos (gensym))
730 (n-new (gensym)))
731 (values (list* n-size n-pos dummies)
732 (list* (second bytespec) (third bytespec) vals)
733 (list n-new)
734 `(let ((,(car newval) (dpb ,n-new (byte ,n-size ,n-pos)
735 ,getter))
736 ,@(cdr newval))
737 ,setter
738 ,n-new)
739 `(ldb (byte ,n-size ,n-pos) ,getter)))
740 (let ((btemp (gensym))
741 (gnuval (gensym)))
742 (values (cons btemp dummies)
743 (cons bytespec vals)
744 (list gnuval)
745 `(let ((,(car newval) (dpb ,gnuval ,btemp ,getter)))
746 ,setter
747 ,gnuval)
748 `(ldb ,btemp ,getter))))))
750 (sb!xc:define-setf-expander mask-field (bytespec place &environment env)
751 #!+sb-doc
752 "The first argument is a byte specifier. The second is any place form
753 acceptable to SETF. Replaces the specified byte of the number in this place
754 with bits from the corresponding position in the new value."
755 (declare (type sb!c::lexenv env))
756 (multiple-value-bind (dummies vals newval setter getter)
757 (sb!xc:get-setf-expansion place env)
758 (let ((btemp (gensym))
759 (gnuval (gensym)))
760 (values (cons btemp dummies)
761 (cons bytespec vals)
762 (list gnuval)
763 `(let ((,(car newval) (deposit-field ,gnuval ,btemp ,getter))
764 ,@(cdr newval))
765 ,setter
766 ,gnuval)
767 `(mask-field ,btemp ,getter)))))
769 (defun setf-expand-the (the type place env)
770 (declare (type sb!c::lexenv env))
771 (multiple-value-bind (temps subforms store-vars setter getter)
772 (sb!xc:get-setf-expansion place env)
773 (values temps subforms store-vars
774 `(multiple-value-bind ,store-vars
775 (,the ,type (values ,@store-vars))
776 ,setter)
777 `(,the ,type ,getter))))
779 (sb!xc:define-setf-expander the (type place &environment env)
780 (setf-expand-the 'the type place env))
782 (sb!xc:define-setf-expander truly-the (type place &environment env)
783 (setf-expand-the 'truly-the type place env))