Reduce FASL size for some top-level functions.
[sbcl.git] / src / code / setf.lisp
blob0120d2d5fd169dfb04ff3147682d68d8d2d39c18
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 lexenv-designator))
32 sb!xc:get-setf-expansion))
33 (defun sb!xc:get-setf-expansion (form &optional environment)
34 #!+sb-doc
35 "Return five values needed by the SETF machinery: a list of temporary
36 variables, a list of values with which to fill them, a list of temporaries
37 for the new values, the setting function, and the accessing function."
38 (if (symbolp form)
39 (multiple-value-bind (expansion expanded)
40 (sb!xc:macroexpand-1 form environment)
41 (if expanded
42 (sb!xc:get-setf-expansion expansion environment)
43 (let ((store (sb!xc:gensym "NEW")))
44 (values nil nil (list store) `(setq ,form ,store) form))))
45 (let ((name (car form)))
46 (flet ((expand (call arg-maker)
47 ;; Produce the expansion of a SETF form that calls either
48 ;; #'(SETF name) or an inverse given by short form DEFSETF.
49 (multiple-value-bind (temp-vars temp-vals args)
50 (collect-setf-temps (cdr form) environment nil)
51 (let ((store (sb!xc:gensym "NEW")))
52 (values temp-vars temp-vals (list store)
53 `(,.call ,@(funcall arg-maker store args))
54 `(,name ,@args))))))
55 ;; Local functions inhibit global SETF methods.
56 (unless (sb!c::fun-locally-defined-p name environment)
57 (acond ((info :setf :inverse name)
58 (return-from sb!xc:get-setf-expansion
59 (expand `(,it) (lambda (new args) `(,@args ,new)))))
60 ((info :setf :expander name)
61 (return-from sb!xc:get-setf-expansion
62 (if (consp it)
63 (make-setf-quintuple form environment
64 (car it) (cdr it))
65 (funcall it form environment))))))
66 ;; When NAME is a macro, retry from the top.
67 ;; Otherwise default to the function named `(SETF ,name).
68 (multiple-value-bind (expansion expanded)
69 (%macroexpand-1 form environment)
70 (if expanded
71 (sb!xc:get-setf-expansion expansion environment)
72 (expand `(funcall #'(setf ,name)) #'cons)))))))
74 ;; Expand PLACE until it is a form that SETF might know something about.
75 ;; Macros are expanded only when no SETF expander (or inverse) exists.
76 ;; Symbol-macros are always expanded because there are no SETF expanders
77 ;; for them. This is useful mainly when a symbol-macro or ordinary macro
78 ;; expands to a "mundane" lexical or special variable.
79 (defun macroexpand-for-setf (place environment)
80 (loop
81 (when (and (listp place)
82 (let ((op (car place)))
83 (or (info :setf :expander op) (info :setf :inverse op))))
84 (return place))
85 (multiple-value-bind (expansion macro-p) (%macroexpand-1 place environment)
86 (if macro-p
87 (setq place expansion) ; iterate
88 (return place)))))
90 ;;;; SETF itself
92 ;; Code shared by SETF, PSETF, SHIFTF attempting to minimize the expansion.
93 ;; This has significant speed+space benefit to a non-preprocessing interpreter,
94 ;; and to some degree a preprocessing interpreter.
95 (labels ((gen-let* (bindings body-forms)
96 (cond ((not bindings) body-forms)
98 (when (and (singleton-p body-forms)
99 (listp (car body-forms))
100 (eq (caar body-forms) 'let*))
101 (let ((nested (cdar body-forms))) ; extract the nested LET*
102 (setq bindings (append bindings (car nested))
103 body-forms (cdr nested))))
104 `((let* ,bindings ,@body-forms)))))
105 (gen-mv-bind (stores values body-forms)
106 (if (singleton-p stores)
107 (gen-let* `((,(car stores) ,values)) body-forms)
108 `((multiple-value-bind ,stores ,values ,@body-forms))))
109 (forms-list (form)
110 (if (and (consp form) (eq (car form) 'progn))
111 (cdr form)
112 (list form)))
113 ;; Instead of emitting (PROGN (VALUES (SETQ ...) (SETQ ...)) NIL)
114 ;; the SETQs can be lifted into the PROGN. This is unimportant
115 ;; for compiled code, but it helps the interpreter not needlessly
116 ;; collect arguments to call VALUES; and it's more human-readable.
117 (de-values-ify (forms)
118 (mapcan (lambda (form)
119 (if (and (listp form) (eq (car form) 'values))
120 (copy-list (cdr form))
121 (list form)))
122 forms)))
124 (defmacro-mundanely setf (&whole form &rest args &environment env)
125 #!+sb-doc
126 "Takes pairs of arguments like SETQ. The first is a place and the second
127 is the value that is supposed to go into that place. Returns the last
128 value. The place argument may be any of the access forms for which SETF
129 knows a corresponding setting form."
130 (unless args
131 (return-from setf nil))
132 (destructuring-bind (place value-form . more) args
133 (when more
134 (return-from setf `(progn ,@(sb!c::explode-setq form 'error))))
135 (when (symbolp (setq place (macroexpand-for-setf place env)))
136 (return-from setf `(setq ,place ,value-form)))
137 (let* ((fun (car place))
138 (inverse (info :setf :inverse fun)))
139 (when (and inverse (not (sb!c::fun-locally-defined-p fun env)))
140 (return-from setf `(,inverse ,@(cdr place) ,value-form))))
141 (multiple-value-bind (temps vals newval setter)
142 (sb!xc:get-setf-expansion place env)
143 (car (gen-let* (mapcar #'list temps vals)
144 (gen-mv-bind newval value-form (forms-list setter)))))))
146 ;; various SETF-related macros
148 (defmacro-mundanely shiftf (&whole form &rest args &environment env)
149 #!+sb-doc
150 "One or more SETF-style place expressions, followed by a single
151 value expression. Evaluates all of the expressions in turn, then
152 assigns the value of each expression to the place on its left,
153 returning the value of the leftmost."
154 (declare (type sb!c::lexenv env))
155 (when (< (length args) 2)
156 (error "~S called with too few arguments: ~S" 'shiftf form))
157 (collect ((let-bindings) (mv-bindings) (setters) (getters))
158 (dolist (arg (butlast args))
159 (multiple-value-bind (temps subforms store-vars setter getter)
160 (sb!xc:get-setf-expansion arg env)
161 (let-bindings (mapcar #'list temps subforms))
162 (mv-bindings store-vars)
163 (setters setter)
164 (getters getter)))
165 ;; Handle the last arg specially here. The getter is just the last
166 ;; arg itself.
167 (getters (car (last args)))
168 (labels ((thunk (mv-bindings getters setters)
169 (if mv-bindings
170 (gen-mv-bind (car mv-bindings) (car getters)
171 (thunk (cdr mv-bindings) (cdr getters) setters))
172 setters)))
173 (let ((outputs (loop for i below (length (car (mv-bindings)))
174 collect (sb!xc:gensym "OUT"))))
175 `(let ,(reduce #'append (let-bindings))
176 ,@(gen-mv-bind outputs (car (getters))
177 (thunk (mv-bindings) (cdr (getters))
178 `(,@(de-values-ify (setters))
179 (values ,@outputs)))))))))
181 (labels
182 ((expand (args env operator single-op)
183 (cond ((singleton-p (cdr args)) ; commonest case probably
184 (return-from expand `(progn (,single-op ,@args) nil)))
185 ((not args)
186 (return-from expand nil)))
187 (collect ((let*-bindings) (mv-bindings) (setters))
188 (do ((a args (cddr a)))
189 ((endp a))
190 (when (endp (cdr a))
191 (error "Odd number of args to ~S." operator))
192 (let ((place (car a))
193 (value-form (cadr a)))
194 (when (and (not (symbolp place)) (eq operator 'psetq))
195 (error 'simple-program-error
196 :format-control "Place ~S in PSETQ is not a SYMBOL"
197 :format-arguments (list place)))
198 (multiple-value-bind (temps vals stores setter)
199 (sb!xc:get-setf-expansion place env)
200 (let*-bindings (mapcar #'list temps vals))
201 (mv-bindings (cons stores value-form))
202 (setters setter))))
203 (car (build (let*-bindings) (mv-bindings)
204 (de-values-ify (setters))))))
205 (build (let*-bindings mv-bindings setters)
206 (if let*-bindings
207 (gen-let* (car let*-bindings)
208 (gen-mv-bind (caar mv-bindings) (cdar mv-bindings)
209 (build (cdr let*-bindings) (cdr mv-bindings)
210 setters)))
211 `(,@setters nil))))
213 (defmacro-mundanely psetf (&rest pairs &environment env)
214 #!+sb-doc
215 "This is to SETF as PSETQ is to SETQ. Args are alternating place
216 expressions and values to go into those places. All of the subforms and
217 values are determined, left to right, and only then are the locations
218 updated. Returns NIL."
219 (expand pairs env 'psetf 'setf))
221 (defmacro-mundanely psetq (&rest pairs &environment env)
222 #!+sb-doc
223 "PSETQ {var value}*
224 Set the variables to the values, like SETQ, except that assignments
225 happen in parallel, i.e. no assignments take place until all the
226 forms have been evaluated."
227 (expand pairs env 'psetq 'setq))))
229 ;;; FIXME: Compiling this definition of ROTATEF apparently blows away the
230 ;;; definition in the cross-compiler itself, so that after that, any
231 ;;; ROTATEF operations can no longer be compiled, because
232 ;;; GET-SETF-EXPANSION is called instead of SB!XC:GET-SETF-EXPANSION.
233 (defmacro-mundanely rotatef (&rest args &environment env)
234 #!+sb-doc
235 "Takes any number of SETF-style place expressions. Evaluates all of the
236 expressions in turn, then assigns to each place the value of the form to
237 its right. The rightmost form gets the value of the leftmost.
238 Returns NIL."
239 (declare (type sb!c::lexenv env))
240 (when args
241 (collect ((let*-bindings) (mv-bindings) (setters) (getters))
242 (dolist (arg args)
243 (multiple-value-bind (temps subforms store-vars setter getter)
244 (sb!xc:get-setf-expansion arg env)
245 (let*-bindings (mapcar #'list temps subforms))
246 (mv-bindings store-vars)
247 (setters setter)
248 (getters getter)))
249 (setters nil)
250 (getters (car (getters)))
251 (labels ((thunk (mv-bindings getters)
252 (if mv-bindings
253 `((multiple-value-bind ,(car mv-bindings) ,(car getters)
254 ,@(thunk (cdr mv-bindings) (cdr getters))))
255 (setters))))
256 `(let* ,(reduce #'append(let*-bindings))
257 ,@(thunk (mv-bindings) (cdr (getters))))))))
259 (defmacro-mundanely push (obj place &environment env)
260 #!+sb-doc
261 "Takes an object and a location holding a list. Conses the object onto
262 the list, returning the modified list. OBJ is evaluated before PLACE."
263 ;; If PLACE has multiple store locations, what should we do?
264 ;; In other Lisp implementations:
265 ;; - One errs, says "Multiple store variables not expected"
266 ;; - One pushes multiple values produced by OBJ form into multiple places.
267 ;; - At least two produce an incorrect expansion that doesn't even work.
268 (expand-rmw-macro 'cons (list obj) place '() nil env '(item)))
270 (defmacro-mundanely pushnew (obj place &rest keys &environment env)
271 #!+sb-doc
272 "Takes an object and a location holding a list. If the object is
273 already in the list, does nothing; otherwise, conses the object onto
274 the list. Keyword arguments are accepted as per the ADJOIN function."
275 ;; Passing AFTER-ARGS-BINDP = NIL causes the forms subsequent to PLACE
276 ;; to be inserted literally as-is, giving the (apparently) desired behavior
277 ;; of *not* evaluating them before the Read/Modify/Write of PLACE, which
278 ;; seems to be an exception to the 5.1.3 exception on L-to-R evaluation.
279 ;; The spec only mentions that ITEM is eval'd before PLACE.
280 (expand-rmw-macro 'adjoin (list obj) place keys nil env '(item)))
282 (defmacro-mundanely pop (place &environment env)
283 #!+sb-doc
284 "The argument is a location holding a list. Pops one item off the front
285 of the list and returns it."
286 (if (symbolp (setq place (macroexpand-for-setf place env)))
287 `(prog1 (car ,place) (setq ,place (cdr ,place)))
288 (multiple-value-bind (temps vals stores setter getter)
289 (sb!xc:get-setf-expansion place env)
290 (let ((list (copy-symbol 'list))
291 (ret (copy-symbol 'car)))
292 `(let* (,@(mapcar #'list temps vals)
293 (,list ,getter)
294 (,ret (car ,list))
295 (,(car stores) (cdr ,list))
296 ,@(cdr stores))
297 ,setter
298 ,ret)))))
300 (defmacro-mundanely remf (place indicator &environment env)
301 #!+sb-doc
302 "Place may be any place expression acceptable to SETF, and is expected
303 to hold a property list or (). This list is destructively altered to
304 remove the property specified by the indicator. Returns T if such a
305 property was present, NIL if not."
306 (multiple-value-bind (temps vals newval setter getter)
307 (sb!xc:get-setf-expansion place env)
308 (let* ((flag (make-symbol "FLAG"))
309 (body `(multiple-value-bind (,(car newval) ,flag)
310 ;; See ANSI 5.1.3 for why we do out-of-order evaluation
311 (truly-the (values list boolean)
312 (%remf ,indicator ,getter))
313 ,(if (cdr newval) `(let ,(cdr newval) ,setter) setter)
314 ,flag)))
315 (if temps `(let* ,(mapcar #'list temps vals) ,body) body))))
317 ;; Perform the work of REMF.
318 (defun %remf (indicator plist)
319 (let ((tail plist) (predecessor))
320 (loop
321 (when (endp tail) (return (values plist nil)))
322 (let ((key (pop tail)))
323 (when (atom tail)
324 (error (if tail
325 "Improper list in REMF."
326 "Odd-length list in REMF.")))
327 (let ((next (cdr tail)))
328 (when (eq key indicator)
329 ;; This function is strict in its return type!
330 (the list next) ; for effect
331 (return (values (cond (predecessor
332 (setf (cdr predecessor) next)
333 plist)
335 next))
336 t)))
337 (setq predecessor tail tail next))))))
339 ;;; INCF and DECF have a straightforward expansion, avoiding temp vars,
340 ;;; when the PLACE is a non-macro symbol. Otherwise we do the generalized
341 ;;; SETF-like thing. The compiler doesn't care either way, but this
342 ;;; reduces the incentive to treat some macros as special-forms when
343 ;;; squeezing more performance from a Lisp interpreter.
344 ;;; DEFINE-MODIFY-MACRO could be used, but this expands more compactly.
345 (flet ((expand (place delta env operator)
346 (if (symbolp (setq place (macroexpand-for-setf place env)))
347 `(setq ,place (,operator ,delta ,place))
348 (multiple-value-bind (dummies vals newval setter getter)
349 (sb!xc:get-setf-expansion place env)
350 `(let* (,@(mapcar #'list dummies vals)
351 (,(car newval) (,operator ,delta ,getter))
352 ,@(cdr newval))
353 ,setter)))))
354 (defmacro-mundanely incf (place &optional (delta 1) &environment env)
355 #!+sb-doc
356 "The first argument is some location holding a number. This number is
357 incremented by the second argument, DELTA, which defaults to 1."
358 (expand place delta env '+))
360 (defmacro-mundanely decf (place &optional (delta 1) &environment env)
361 #!+sb-doc
362 "The first argument is some location holding a number. This number is
363 decremented by the second argument, DELTA, which defaults to 1."
364 (expand place delta env 'xsubtract)))
366 ;;;; DEFINE-MODIFY-MACRO stuff
368 (def!macro sb!xc:define-modify-macro (name lambda-list function &optional doc-string)
369 #!+sb-doc
370 "Creates a new read-modify-write macro like PUSH or INCF."
371 (binding* (((llks required optional rest)
372 (parse-lambda-list
373 lambda-list
374 :accept (lambda-list-keyword-mask '(&optional &rest))
375 :context "a DEFINE-MODIFY-MACRO lambda list"))
376 (args (append required
377 (mapcar (lambda (x) (if (listp x) (car x) x))
378 optional)))
379 (place (make-symbol "PLACE"))
380 (env (make-symbol "ENV")))
381 (declare (ignore llks))
382 `(#-sb-xc-host sb!xc:defmacro
383 #+sb-xc-host defmacro-mundanely
384 ,name (,place ,@lambda-list &environment ,env)
385 ,@(when doc-string (list (the string doc-string)))
386 (expand-rmw-macro ',function '() ,place
387 (list* ,@args ,(car rest)) t ,env ',args))))
389 ;;;; DEFSETF
391 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
392 ;;; Assign SETF macro information for NAME, making all appropriate checks.
393 (macrolet ((assign-it ()
394 `(progn
395 (when inverse
396 (clear-info :setf :expander name)
397 (setf (info :setf :inverse name) inverse))
398 (when expander
399 #-sb-xc-host
400 (setf (%fun-lambda-list
401 (if (listp expander) (cdr expander) expander))
402 expander-lambda-list)
403 (clear-info :setf :inverse name)
404 (setf (info :setf :expander name) expander))
405 (when doc
406 (setf (fdocumentation name 'setf) doc))
407 name)))
408 (defun %defsetf (name expander expander-lambda-list inverse &optional doc)
409 #+sb-xc-host (declare (ignore expander-lambda-list))
410 (with-single-package-locked-error
411 (:symbol name "defining a setf-expander for ~A"))
412 (let ((setf-fn-name `(setf ,name)))
413 (multiple-value-bind (where-from present-p)
414 (info :function :where-from setf-fn-name)
415 ;; One might think that :DECLARED merits a style warning, but SBCL
416 ;; provides ~58 standard accessors as both (SETF F) and a macro.
417 ;; So allow the user to declaim an FTYPE and we'll hush up.
418 ;; What's good for the the goose is good for the gander.
419 (case where-from
420 (:assumed
421 ;; This indicates probable user error. Compilation assumed something
422 ;; to be functional; a macro says otherwise. Because :where-from's
423 ;; default can be :assumed, PRESENT-P disambiguates "defaulted" from
424 ;; "known" to have made an existence assumption.
425 (when present-p
426 (warn "defining setf macro for ~S when ~S was previously ~
427 treated as a function" name setf-fn-name)))
428 (:defined
429 ;; Somebody defined (SETF F) but then also said F has a macro.
430 ;; A soft warning seems appropriate because in this case it's
431 ;; at least in theory not wrong to call the function.
432 ;; The user can declare an FTYPE if both things are intentional.
433 (style-warn "defining setf macro for ~S when ~S is also defined"
434 name setf-fn-name)))))
435 (assign-it))
436 (defun !quietly-defsetf (name expander expander-lambda-list inverse &optional doc)
437 #+sb-xc-host (declare (ignore expander-lambda-list))
438 (assign-it))))
440 (def!macro sb!xc:defsetf (access-fn &rest rest)
441 #!+sb-doc
442 "Associates a SETF update function or macro with the specified access
443 function or macro. The format is complex. See the manual for details."
444 (unless (symbolp access-fn)
445 (error "~S access-function name ~S is not a symbol."
446 'sb!xc:defsetf access-fn))
447 (typecase rest
448 ((cons (and symbol (not null)) (or null (cons string null)))
449 `(eval-when (:load-toplevel :compile-toplevel :execute)
450 (%defsetf ',access-fn nil nil ',(car rest) ,@(cdr rest))))
451 ((cons list (cons list))
452 (destructuring-bind (lambda-list (&rest stores) &body body) rest
453 (binding* (((llks req opt rest key aux env)
454 (parse-lambda-list
455 lambda-list
456 :accept (lambda-list-keyword-mask
457 '(&optional &rest &key &allow-other-keys
458 &environment))
459 :context "a DEFSETF lambda list"))
460 ((forms decls doc) (parse-body body))
461 ((outer-decls inner-decls)
462 (extract-var-decls decls (append env stores)))
463 (subforms (copy-symbol 'subforms))
464 (env-var (if env (car env) (copy-symbol 'env)))
465 (lambda-list (make-lambda-list llks nil req opt rest key)))
466 (declare (ignore aux))
467 `(eval-when (:compile-toplevel :load-toplevel :execute)
468 (%defsetf ',access-fn
469 (cons ,(length stores)
470 (lambda (,subforms ,env-var ,@stores)
471 ,@(if outer-decls (list outer-decls))
472 ,@(unless env `((declare (ignore ,env-var))))
473 (apply (lambda ,lambda-list
474 ,@inner-decls (block ,access-fn ,@forms))
475 ,subforms)))
476 ',lambda-list nil ,@(and doc
477 `(,doc)))))))
479 (error "Ill-formed DEFSETF for ~S" access-fn))))
481 ;; Given SEXPRS which is a list of things to evaluate, return four values:
482 ;; - a list of uninterned symbols to bind to any non-constant sexpr
483 ;; - a list of things to bind those symbols to
484 ;; - a list parallel to SEXPRS with each non-constant element
485 ;; replaced by its temporary variable from the first list.
486 ;; - a bitmask over the sexprs containing a 1 for each non-constant.
487 ;; Uninterned symbols are named according to the NAME-HINTS so that
488 ;; expansions use variables resembling the DEFSETF whence they came.
490 (defun collect-setf-temps (sexprs environment name-hints)
491 (labels ((next-name-hint ()
492 (let ((sym (pop name-hints))) ; OK if list was nil
493 (case sym
494 (&optional (next-name-hint))
495 ((&key &rest) (setq name-hints nil))
496 (t (if (listp sym) (car sym) sym)))))
497 (nice-tempname (form)
498 (acond ((next-name-hint) (copy-symbol it))
499 (t (gensymify form)))))
500 (collect ((temp-vars) (temp-vals) (call-arguments))
501 (let ((mask 0) (bit 1))
502 (dolist (form sexprs (values (temp-vars) (temp-vals) (call-arguments)
503 mask))
504 (call-arguments (if (sb!xc:constantp form environment)
505 (progn (next-name-hint) form) ; Skip one hint.
506 (let ((temp (nice-tempname form)))
507 (setq mask (logior mask bit))
508 (temp-vars temp)
509 (temp-vals form)
510 temp)))
511 (setq bit (ash bit 1)))))))
513 ;; Return the 5-part expansion of a SETF form defined by the long form
514 ;; of DEFSETF.
515 ;; FIXME: totally broken if there are keyword arguments. lp#1452947
516 (defun make-setf-quintuple (access-form environment num-store-vars expander)
517 (declare (type function expander))
518 (multiple-value-bind (temp-vars temp-vals call-arguments)
519 ;; FORMALS affect aesthetics only, not behavior.
520 (let ((formals #-sb-xc-host (%fun-lambda-list expander)))
521 (collect-setf-temps (cdr access-form) environment formals))
522 (let ((stores (let ((sb!xc:*gensym-counter* 1))
523 (make-gensym-list num-store-vars "NEW"))))
524 (values temp-vars temp-vals stores
525 (apply expander call-arguments environment stores)
526 `(,(car access-form) ,@call-arguments)))))
528 ;; Expand a macro defined by DEFINE-MODIFY-MACRO.
529 ;; The generated call resembles (FUNCTION <before-args> PLACE <after-args>)
530 ;; but the read/write of PLACE is done after all {BEFORE,AFTER}-ARG-FORMS are
531 ;; evaluated. Subforms of PLACE are evaluated in the usual order.
533 ;; Exception: See comment at PUSHNEW for the effect of AFTER-ARGS-BINDP = NIL.
534 (defun expand-rmw-macro (function before-arg-forms place after-arg-forms
535 after-args-bindp environment name-hints)
536 ;; Note that NAME-HINTS do the wrong thing if you have both "before" and
537 ;; "after" args. In that case it is probably best to specify them as ().
538 (binding* (((before-temps before-vals before-args)
539 (collect-setf-temps before-arg-forms environment name-hints))
540 ((place-temps place-subforms stores setter getter)
541 (sb!xc:get-setf-expansion place environment))
542 ((after-temps after-vals after-args)
543 (if after-args-bindp
544 (collect-setf-temps after-arg-forms environment name-hints)
545 (values nil nil after-arg-forms)))
546 (compute `(,function ,@before-args ,getter ,@after-args))
547 (set-fn (and (listp setter) (car setter)))
548 (newval-temp (car stores))
549 (newval-binding `((,newval-temp ,compute))))
550 ;; Elide the binding of NEWVAL-TEMP if it is ref'd exactly once
551 ;; and all the call arguments are temporaries and/or constants.
552 (when (and (= (count newval-temp setter) 1)
553 (or (eq set-fn 'setq)
554 (and (eq (info :function :kind set-fn) :function)
555 (every (lambda (x)
556 (or (member x place-temps)
557 (eq x newval-temp)
558 (sb!xc:constantp x environment)))
559 (cdr setter)))))
560 (setq newval-binding nil
561 setter (substitute compute newval-temp setter)))
562 (let ((bindings
563 (flet ((zip (list1 list2) (mapcar #'list list1 list2)))
564 (append (zip before-temps before-vals)
565 (zip place-temps place-subforms)
566 (zip after-temps after-vals)
567 newval-binding
568 (cdr stores)))))
569 (if bindings `(let* ,bindings ,setter) setter))))
571 ;;;; DEFMACRO DEFINE-SETF-EXPANDER and various DEFINE-SETF-EXPANDERs
573 ;;; DEFINE-SETF-EXPANDER is a lot like DEFMACRO.
574 (def!macro sb!xc:define-setf-expander (access-fn lambda-list &body body)
575 #!+sb-doc
576 "Syntax like DEFMACRO, but creates a setf expander function. The body
577 of the definition must be a form that returns five appropriate values."
578 (unless (symbolp access-fn)
579 (error "~S access-function name ~S is not a symbol."
580 'sb!xc:define-setf-expander access-fn))
581 (multiple-value-bind (def arglist doc)
582 ;; Perhaps it would be more elegant to keep the docstring attached
583 ;; to the expander function, as for CAS?
584 (make-macro-lambda `(setf-expander ,access-fn) lambda-list body
585 'sb!xc:define-setf-expander access-fn
586 :doc-string-allowed :external)
587 (declare (ignore arglist))
588 `(eval-when (:compile-toplevel :load-toplevel :execute)
589 (%defsetf ',access-fn ,def ',lambda-list nil ,@(and doc
590 `(,doc))))))
592 (sb!xc:define-setf-expander values (&rest places &environment env)
593 (declare (type sb!c::lexenv env))
594 (collect ((setters) (getters))
595 (let ((all-dummies '())
596 (all-vals '())
597 (newvals '()))
598 (dolist (place places)
599 (multiple-value-bind (dummies vals newval setter getter)
600 (sb!xc:get-setf-expansion place env)
601 ;; ANSI 5.1.2.3 explains this logic quite precisely. --
602 ;; CSR, 2004-06-29
603 (setq all-dummies (append all-dummies dummies (cdr newval))
604 all-vals (append all-vals vals
605 (mapcar (constantly nil) (cdr newval)))
606 newvals (append newvals (list (car newval))))
607 (setters setter)
608 (getters getter)))
609 (values all-dummies all-vals newvals
610 `(values ,@(setters)) `(values ,@(getters))))))
612 (sb!xc:define-setf-expander getf (place prop &optional default &environment env)
613 (declare (type sb!c::lexenv env))
614 (binding* (((place-tempvars place-tempvals stores set get)
615 (sb!xc:get-setf-expansion place env))
616 ((call-tempvars call-tempvals call-args bitmask)
617 (collect-setf-temps (list prop default) env '(indicator default)))
618 (newval (gensym "NEW")))
619 (values `(,@place-tempvars ,@call-tempvars)
620 `(,@place-tempvals ,@call-tempvals)
621 `(,newval)
622 `(let ((,(car stores) (%putf ,get ,(first call-args) ,newval))
623 ,@(cdr stores))
624 ;; prevent "unused variable" style-warning
625 ,@(when (logbitp 1 bitmask) (last call-tempvars))
626 ,set
627 ,newval)
628 `(getf ,get ,@call-args))))
630 ;; CLHS Notes on DEFSETF say that: "A setf of a call on access-fn also evaluates
631 ;; all of access-fn's arguments; it cannot treat any of them specially."
632 ;; An implication is that even though the DEFAULT argument to GET,GETHASH serves
633 ;; no purpose except when used in a R/M/W context such as PUSH, you can't elide
634 ;; it. In particular, this must fail: (SETF (GET 'SYM 'IND (ERROR "Foo")) 3).
636 (sb!xc:defsetf get (symbol indicator &optional default &environment e) (newval)
637 (let ((constp (sb!xc:constantp default e)))
638 ;; always reference default's temp var to "use" it
639 `(%put ,symbol ,indicator ,(if constp newval `(progn ,default ,newval)))))
641 ;; A possible optimization for read/modify/write of GETHASH
642 ;; would be to predetermine the vector element where the key/value pair goes.
643 (sb!xc:defsetf gethash (key hashtable &optional default &environment e) (newval)
644 (let ((constp (sb!xc:constantp default e)))
645 ;; always reference default's temp var to "use" it
646 `(%puthash ,key ,hashtable ,(if constp newval `(progn ,default ,newval)))))
648 ;;; CMU CL had a comment here that:
649 ;;; Evil hack invented by the gnomes of Vassar Street (though not as evil as
650 ;;; it used to be.) The function arg must be constant, and is converted to
651 ;;; an APPLY of the SETF function, which ought to exist.
653 ;;; Historical note: The hack was considered evil becase prior to the
654 ;;; standardization of #'(SETF F) as a namespace for functions, all that existed
655 ;;; were SETF expanders. To "invert" (APPLY #'F A B .. LAST), you assumed that
656 ;;; the SETF expander was ok to use on (F A B .. LAST), yielding something
657 ;;; like (set-F A B .. LAST). If the LAST arg didn't move (based on comparing
658 ;;; gensyms between the "getter" and "setter" forms), you'd stick APPLY
659 ;;; in front and hope for the best. Plus AREF still had to be special-cased.
661 ;;; It may not be clear (wasn't to me..) that this is a standard thing, but See
662 ;;; "5.1.2.5 APPLY Forms as Places" in the ANSI spec. I haven't actually
663 ;;; verified that this code has any correspondence to that code, but at least
664 ;;; ANSI has some place for SETF APPLY. -- WHN 19990604
665 (sb!xc:define-setf-expander apply (functionoid &rest args)
666 ;; Technically (per CLHS) this only must allow AREF,BIT,SBIT
667 ;; but there's not much danger in allowing other stuff.
668 (unless (typep functionoid '(cons (eql function) (cons symbol null)))
669 (error "SETF of APPLY is only defined for function args like #'SYMBOL."))
670 (let ((function (second functionoid))
671 (new-var (gensym))
672 (vars (make-gensym-list (length args))))
673 (values vars args (list new-var)
674 `(apply #'(setf ,function) ,new-var ,@vars)
675 `(apply #',function ,@vars))))
677 ;;; Perform expansion of SETF on LDB, MASK-FIELD, or LOGBITP.
678 ;;; It is preferable to destructure the BYTE form and bind temp vars to its
679 ;;; parts rather than bind a temp for its result. (See the source transforms
680 ;;; for LDB/DPB). But for constant arguments to BYTE, we don't need any temp.
681 (defun setf-expand-ldb (bytespec-form place env store-fun load-fun)
682 (binding* ((spec (%macroexpand bytespec-form env))
683 ((byte-tempvars byte-tempvals byte-args)
684 (if (typep spec '(cons (eql byte)
685 (and (not (cons integer (cons integer)))
686 (cons t (cons t null)))))
687 (collect-setf-temps (cdr spec) env '(size pos))
688 (collect-setf-temps (list spec) env '(bytespec))))
689 (byte (if (cdr byte-args) (cons 'byte byte-args) (car byte-args)))
690 ((place-tempvars place-tempvals stores setter getter)
691 (sb!xc:get-setf-expansion place env))
692 (newval (sb!xc:gensym "NEW"))
693 (new-int `(,store-fun
694 ,(if (eq load-fun 'logbitp) `(if ,newval 1 0) newval)
695 ,byte ,getter)))
696 (values `(,@byte-tempvars ,@place-tempvars)
697 `(,@byte-tempvals ,@place-tempvals)
698 (list newval)
699 ;; FIXME: expand-rmw-macro has code for determining whether
700 ;; a binding of a "newval" can be elided.
701 (if (and (typep setter '(cons (eql setq)
702 (cons symbol (cons t null))))
703 (singleton-p stores)
704 (eq (third setter) (first stores)))
705 `(progn (setq ,(second setter) ,new-int) ,newval)
706 `(let ((,(car stores) ,new-int) ,@(cdr stores))
707 ,setter
708 ,newval))
709 (if (eq load-fun 'logbitp)
710 ;; If there was a temp for the POS, then use it.
711 ;; Otherwise use the constant POS from the original spec.
712 `(logbitp ,(or (car byte-tempvars) (third spec)) ,getter)
713 `(,load-fun ,byte ,getter)))))
715 ;;; SETF of LOGBITP is not mandated by CLHS but is nice to have.
716 ;;; FIXME: the code is suboptimal. Better code would "pre-shift" the 1 bit,
717 ;;; so that result = (in & ~mask) | (flag ? mask : 0)
718 ;;; Additionally (setf (logbitp N x) t) is extremely stupid- it first clears
719 ;;; and then sets the bit, though it does manage to pre-shift the constants.
720 (sb!xc:define-setf-expander logbitp (index place &environment env)
721 (setf-expand-ldb `(byte 1 ,index) place env 'dpb 'logbitp))
723 ;;; Special-case a BYTE bytespec so that the compiler can recognize it.
724 ;;; FIXME: it is suboptimal that (INCF (LDB (BYTE 9 0) (ELT X 0)))
725 ;;; performs two reads of (ELT X 0), once to get the value from which
726 ;;; to extract a 9-bit subfield, and again to combine the incremented
727 ;;; value with the other bits. I don't think it's wrong per se,
728 ;;; but is worthy of some thought as to whether it can be improved.
729 (sb!xc:define-setf-expander ldb (bytespec place &environment env)
730 #!+sb-doc
731 "The first argument is a byte specifier. The second is any place form
732 acceptable to SETF. Replace the specified byte of the number in this
733 place with bits from the low-order end of the new value."
734 (setf-expand-ldb bytespec place env 'dpb 'ldb))
736 (sb!xc:define-setf-expander mask-field (bytespec place &environment env)
737 #!+sb-doc
738 "The first argument is a byte specifier. The second is any place form
739 acceptable to SETF. Replaces the specified byte of the number in this place
740 with bits from the corresponding position in the new value."
741 (setf-expand-ldb bytespec place env 'deposit-byte 'mask-field))
743 (defun setf-expand-the (the type place env)
744 (declare (type sb!c::lexenv env))
745 (multiple-value-bind (temps subforms store-vars setter getter)
746 (sb!xc:get-setf-expansion place env)
747 (values temps subforms store-vars
748 `(multiple-value-bind ,store-vars
749 (,the ,type (values ,@store-vars))
750 ,setter)
751 `(,the ,type ,getter))))
753 (sb!xc:define-setf-expander the (type place &environment env)
754 (setf-expand-the 'the type place env))
756 (sb!xc:define-setf-expander truly-the (type place &environment env)
757 (setf-expand-the 'truly-the type place env))