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
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
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.
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
)
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
)
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.
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
))))
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
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.
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
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
)
78 (sb!xc
:get-setf-expansion expansion environment
)
79 (make-setf-quintuple-simple form environment
80 t
`(funcall #'(setf ,(car form
)))))))
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
))
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
118 (defmacro-mundanely setf
(&whole form
&rest args
&environment env
)
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."
125 (return-from setf nil
))
126 (destructuring-bind (place value-form . more
) args
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.
134 (when (and (listp place
)
135 (let ((op (car place
)))
136 (or (info :setf
:expander op
) (info :setf
:inverse op
))))
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
)))
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
)
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
)
170 ;; Handle the last arg specially here. The getter is just the last
172 (getters (car (last args
)))
173 (labels ((thunk (mv-bindings getters setters
)
175 (gen-mv-bind (car mv-bindings
) (car getters
)
176 (thunk (cdr mv-bindings
) (cdr getters
) 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
)))))))))
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
)))
191 (return-from expand nil
)))
192 (collect ((let*-bindings
) (mv-bindings) (setters))
193 (do ((a args
(cddr 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
))
208 (car (build (let*-bindings
) (mv-bindings)
209 (de-values-ify (setters))))))
210 (build (let*-bindings mv-bindings setters
)
212 (gen-let* (car let
*-bindings
)
213 (gen-mv-bind (caar mv-bindings
) (cdar mv-bindings
)
214 (build (cdr let
*-bindings
) (cdr mv-bindings
)
218 (defmacro-mundanely psetf
(&rest pairs
&environment env
)
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
)
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
)
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.
244 (declare (type sb
!c
::lexenv env
))
246 (collect ((let*-bindings
) (mv-bindings) (setters) (getters))
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
)
255 (getters (car (getters)))
256 (labels ((thunk (mv-bindings getters
)
258 `((multiple-value-bind ,(car mv-bindings
) ,(car getters
)
259 ,@(thunk (cdr mv-bindings
) (cdr getters
))))
261 `(let* ,(reduce #'append
(let*-bindings
))
262 ,@(thunk (mv-bindings) (cdr (getters))))))))
264 (defmacro-mundanely push
(obj place
&environment env
)
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
)
272 ,@(mapcar #'list dummies vals
)
273 (,(car newval
) (cons ,g
,getter
))
277 (defmacro-mundanely pushnew
(obj place
&rest keys
278 &key key test test-not
&environment env
)
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
)
289 ,@(mapcar #'list dummies vals
)
290 (,(car newval
) (adjoin ,g
,getter
,@keys
))
294 (defmacro-mundanely pop
(place &environment env
)
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
)
303 (,(car newval
) (cdr ,list-head
))
308 (defmacro-mundanely remf
(place indicator
&environment env
)
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
)
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))
329 (when (endp tail
) (return (values plist nil
)))
330 (let ((key (pop 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
)
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
)
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
))
369 (defmacro-mundanely incf
(place &optional
(delta 1) &environment env
)
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
)
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
)
385 "Creates a new read-modify-write macro like PUSH or INCF."
386 (let ((other-args 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
))
396 (cond ((eq arg
'&optional
))
398 (if (symbolp (cadr ll
))
399 (setq rest-arg
(cadr ll
))
400 (error "Non-symbol &REST argument in definition of ~S." name
))
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
))
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
))))
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 ()
426 (clear-info :setf
:expander name
)
427 (setf (info :setf
:inverse name
) inverse
))
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
))
434 (setf (fdocumentation name
'setf
) doc
))
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.
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.
454 (warn "defining setf macro for ~S when ~S was previously ~
455 treated as a function" name setf-fn-name
)))
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
)))))
464 (defun !quietly-assign-setf-macro
; For cold-init
465 (name expander expander-lambda-list inverse doc
)
468 (def!macro sb
!xc
:defsetf
(access-fn &rest rest
)
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
))
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
494 `(eval-when (:compile-toplevel
:load-toplevel
:execute
)
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
)
514 (let ((temp (if name-hints
515 (copy-symbol (car 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
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
)
566 (or (member x temp-vars
)
567 (member x fun-temp-vars
)
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
)
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
)
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
)
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 '())
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. --
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
))))
619 (values all-dummies all-vals newvals
620 `(values ,@(setters)) `(values ,@(getters))))))
622 (sb!xc
:define-setf-expander getf
(place prop
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))
630 (def-temp (if default
(gensym))))
631 (values `(,@temps
,ptemp
,@(if default
`(,def-temp
)))
632 `(,@values
,prop
,@(if default
`(,default
)))
634 `(let ((,(car stores
) (%putf
,get
,ptemp
,newval
))
636 ,def-temp
;; prevent unused style-warning
639 `(getf ,get
,ptemp
,@(if default
`(,def-temp
)))))))
641 (sb!xc
:define-setf-expander get
(symbol prop
&optional default
)
642 (let ((symbol-temp (gensym))
644 (def-temp (if default
(gensym)))
646 (values `(,symbol-temp
,prop-temp
,@(if default
`(,def-temp
)))
647 `(,symbol
,prop
,@(if default
`(,default
)))
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)))
659 `(,key-temp
,hashtable-temp
,@(if default
`(,default-temp
)))
660 `(,key
,hashtable
,@(if default
`(,default
)))
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
)
672 (stemp (first stores
)))
673 (values `(,ind
,@temps
)
678 (dpb (if ,store
1 0) (byte 1 ,ind
) ,access-form
))
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
))
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
)
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))
731 (values (list* n-size n-pos dummies
)
732 (list* (second bytespec
) (third bytespec
) vals
)
734 `(let ((,(car newval
) (dpb ,n-new
(byte ,n-size
,n-pos
)
739 `(ldb (byte ,n-size
,n-pos
) ,getter
)))
740 (let ((btemp (gensym))
742 (values (cons btemp dummies
)
745 `(let ((,(car newval
) (dpb ,gnuval
,btemp
,getter
)))
748 `(ldb ,btemp
,getter
))))))
750 (sb!xc
:define-setf-expander mask-field
(bytespec place
&environment env
)
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))
760 (values (cons btemp dummies
)
763 `(let ((,(car newval
) (deposit-field ,gnuval
,btemp
,getter
))
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
))
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
))