(declaim (ftype (function (t &optional (or null sb!c::lexenv))) sb!xc:get-setf-expansion))
(defun sb!xc:get-setf-expansion (form &optional environment)
#!+sb-doc
- "Returns five values needed by the SETF machinery: a list of temporary
+ "Return five values needed by the SETF machinery: a list of temporary
variables, a list of values with which to fill them, a list of temporaries
for the new values, the setting function, and the accessing function."
(let (temp)
;; Local functions inhibit global SETF methods.
((and environment
(let ((name (car form)))
- (dolist (x (sb!c::lexenv-functions environment))
+ (dolist (x (sb!c::lexenv-funs environment))
(when (and (eq (car x) name)
- (not (sb!c::defined-function-p (cdr x))))
+ (not (sb!c::defined-fun-p (cdr x))))
(return t)))))
(expand-or-get-setf-inverse form environment))
((setq temp (info :setf :inverse (car form)))
;; for macroexpansion in general. -- WHN 19991128
(funcall temp
form
- ;; As near as I can tell from the ANSI spec, macroexpanders
- ;; have a right to expect an actual lexical environment,
- ;; not just a NIL which is to be interpreted as a null
- ;; lexical environment. -- WHN 19991128
- (or environment (make-null-lexenv))))
+ ;; As near as I can tell from the ANSI spec,
+ ;; macroexpanders have a right to expect an actual
+ ;; lexical environment, not just a NIL which is to
+ ;; be interpreted as a null lexical environment.
+ ;; -- WHN 19991128
+ (coerce-to-lexenv environment)))
(t
(expand-or-get-setf-inverse form environment)))))
;;; If a macro, expand one level and try again. If not, go for the
;;; SETF function.
-(declaim (ftype (function (t sb!c::lexenv)) expand-or-get-setf-inverse))
+(declaim (ftype (function (t (or null sb!c::lexenv)))
+ expand-or-get-setf-inverse))
(defun expand-or-get-setf-inverse (form environment)
(multiple-value-bind (expansion expanded)
(sb!xc:macroexpand-1 form environment)
`(funcall #'(setf ,(car form)))
t))))
-(defun get-setf-method-inverse (form inverse setf-function)
+(defun get-setf-method-inverse (form inverse setf-fun)
(let ((new-var (gensym))
(vars nil)
(vals nil))
(push x vals))
(setq vals (nreverse vals))
(values vars vals (list new-var)
- (if setf-function
+ (if setf-fun
`(,@inverse ,new-var ,@vars)
`(,@inverse ,@vars ,new-var))
`(,(car form) ,@vars))))
\f
;;;; SETF itself
-;;; Except for atoms, we always call GET-SETF-EXPANSION, since it has some
-;;; non-trivial semantics. But when there is a setf inverse, and G-S-E uses
-;;; it, then we return a call to the inverse, rather than returning a hairy let
-;;; form. This is probably important mainly as a convenience in allowing the
-;;; use of SETF inverses without the full interpreter.
+;;; Except for atoms, we always call GET-SETF-EXPANSION, since it has
+;;; some non-trivial semantics. But when there is a setf inverse, and
+;;; G-S-E uses it, then we return a call to the inverse, rather than
+;;; returning a hairy LET form. This is probably important mainly as a
+;;; convenience in allowing the use of SETF inverses without the full
+;;; interpreter.
(defmacro-mundanely setf (&rest args &environment env)
#!+sb-doc
"Takes pairs of arguments like SETQ. The first is a place and the second
returning the value of the leftmost."
(when (< (length args) 2)
(error "~S called with too few arguments: ~S" 'shiftf form))
- (let ((resultvar (gensym)))
- (do ((arglist args (cdr arglist))
- (bindlist nil)
- (storelist nil)
- (lastvar resultvar))
- ((atom (cdr arglist))
- (push `(,lastvar ,(first arglist)) bindlist)
- `(let* ,(nreverse bindlist) ,@(nreverse storelist) ,resultvar))
- (multiple-value-bind (sm1 sm2 sm3 sm4 sm5)
- (get-setf-method (first arglist) env)
- (mapc #'(lambda (var val)
- (push `(,var ,val) bindlist))
- sm1
- sm2)
- (push `(,lastvar ,sm5) bindlist)
- (push sm4 storelist)
- (setq lastvar (first sm3))))))
+ (let (let*-bindings mv-bindings setters getters)
+ (dolist (arg (butlast args))
+ (multiple-value-bind (temps subforms store-vars setter getter)
+ (sb!xc:get-setf-expansion arg env)
+ (mapc (lambda (tmp form)
+ (push `(,tmp ,form) let*-bindings))
+ temps
+ subforms)
+ (push store-vars mv-bindings)
+ (push setter setters)
+ (push getter getters)))
+ ;; Handle the last arg specially here. The getter is just the last
+ ;; arg itself.
+ (push (car (last args)) getters)
+
+ ;; Reverse the collected lists so last bit looks nicer.
+ (setf let*-bindings (nreverse let*-bindings)
+ mv-bindings (nreverse mv-bindings)
+ setters (nreverse setters)
+ getters (nreverse getters))
+
+ (labels ((thunk (mv-bindings getters)
+ (if mv-bindings
+ `((multiple-value-bind
+ ,(car mv-bindings)
+ ,(car getters)
+ ,@(thunk (cdr mv-bindings) (cdr getters))))
+ `(,@setters))))
+ `(let ,let*-bindings
+ (multiple-value-bind ,(car mv-bindings)
+ ,(car getters)
+ ,@(thunk mv-bindings (cdr getters))
+ (values ,@(car mv-bindings)))))))
(defmacro-mundanely push (obj place &environment env)
#!+sb-doc
"Takes an object and a location holding a list. Conses the object onto
the list, returning the modified list. OBJ is evaluated before PLACE."
- (if (symbolp place)
- `(setq ,place (cons ,obj ,place))
- (multiple-value-bind
- (dummies vals newval setter getter)
- (get-setf-method place env)
- (let ((g (gensym)))
- `(let* ((,g ,obj)
- ,@(mapcar #'list dummies vals)
- (,(car newval) (cons ,g ,getter)))
- ,setter)))))
+ (multiple-value-bind (dummies vals newval setter getter)
+ (get-setf-method place env)
+ (let ((g (gensym)))
+ `(let* ((,g ,obj)
+ ,@(mapcar #'list dummies vals)
+ (,(car newval) (cons ,g ,getter)))
+ ,setter))))
(defmacro-mundanely pushnew (obj place &rest keys &environment env)
#!+sb-doc
- "Takes an object and a location holding a list. If the object is already
- in the list, does nothing. Else, conses the object onto the list. Returns
- NIL. If there is a :TEST keyword, this is used for the comparison."
- (if (symbolp place)
- `(setq ,place (adjoin ,obj ,place ,@keys))
- (multiple-value-bind (dummies vals newval setter getter)
- (get-setf-method place env)
- (do* ((d dummies (cdr d))
- (v vals (cdr v))
- (let-list nil))
- ((null d)
- (push (list (car newval) `(adjoin ,obj ,getter ,@keys))
- let-list)
- `(let* ,(nreverse let-list)
- ,setter))
- (push (list (car d) (car v)) let-list)))))
+ "Takes an object and a location holding a list. If the object is
+ already in the list, does nothing; otherwise, conses the object onto
+ the list. Returns the modified list. If there is a :TEST keyword, this
+ is used for the comparison."
+ (multiple-value-bind (dummies vals newval setter getter)
+ (get-setf-method place env)
+ (let ((g (gensym)))
+ `(let* ((,g ,obj)
+ ,@(mapcar #'list dummies vals)
+ (,(car newval) (adjoin ,g ,getter ,@keys)))
+ ,setter))))
(defmacro-mundanely pop (place &environment env)
#!+sb-doc
"The argument is a location holding a list. Pops one item off the front
of the list and returns it."
- (if (symbolp place)
- `(prog1 (car ,place) (setq ,place (cdr ,place)))
- (multiple-value-bind (dummies vals newval setter getter)
- (get-setf-method place env)
- (do* ((d dummies (cdr d))
- (v vals (cdr v))
- (let-list nil))
- ((null d)
- (push (list (car newval) getter) let-list)
- `(let* ,(nreverse let-list)
- (prog1 (car ,(car newval))
- (setq ,(car newval) (cdr ,(car newval)))
- ,setter)))
- (push (list (car d) (car v)) let-list)))))
+ (multiple-value-bind (dummies vals newval setter getter)
+ (get-setf-method place env)
+ (do* ((d dummies (cdr d))
+ (v vals (cdr v))
+ (let-list nil))
+ ((null d)
+ (push (list (car newval) getter) let-list)
+ `(let* ,(nreverse let-list)
+ (prog1 (car ,(car newval))
+ (setq ,(car newval) (cdr ,(car newval)))
+ ,setter)))
+ (push (list (car d) (car v)) let-list))))
(defmacro-mundanely remf (place indicator &environment env)
#!+sb-doc
((eq arg '&rest)
(if (symbolp (cadr ll))
(setq rest-arg (cadr ll))
- (error "Non-symbol &REST arg in definition of ~S." name))
+ (error "Non-symbol &REST argument in definition of ~S." name))
(if (null (cddr ll))
(return nil)
- (error "Illegal stuff after &REST arg.")))
+ (error "Illegal stuff after &REST argument.")))
((memq arg '(&key &allow-other-keys &aux))
(error "~S not allowed in DEFINE-MODIFY-MACRO lambda list." arg))
((symbolp arg)
;;;; DEFSETF
(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
- ;;; Assign setf macro information for NAME, making all appropriate checks.
+ ;;; Assign SETF macro information for NAME, making all appropriate checks.
(defun assign-setf-macro (name expander inverse doc)
+ (with-single-package-locked-error
+ (:symbol name "defining a setf-expander for ~A"))
(cond ((gethash name sb!c:*setf-assumed-fboundp*)
(warn
"defining setf macro for ~S when ~S was previously ~
((not (fboundp `(setf ,name)))
;; All is well, we don't need any warnings.
(values))
- ((info :function :accessor-for name)
- (warn "defining SETF macro for DEFSTRUCT slot ~
- accessor; redefining as a normal function: ~S"
- name)
- (sb!c::proclaim-as-function-name name))
((not (eq (symbol-package name) (symbol-package 'aref)))
(style-warn "defining setf macro for ~S when ~S is fbound"
name `(setf ,name))))
`(eval-when (:compile-toplevel :load-toplevel :execute)
(assign-setf-macro
',access-fn
- #'(lambda (,access-form-var ,env-var)
- (declare (ignore ,env-var))
- (%defsetf ,access-form-var ,(length store-variables)
- #'(lambda (,arglist-var)
- ,@local-decs
- (block ,access-fn
- ,body))))
+ (lambda (,access-form-var ,env-var)
+ (declare (ignore ,env-var))
+ (%defsetf ,access-form-var ,(length store-variables)
+ (lambda (,arglist-var)
+ ,@local-decs
+ ,body)))
nil
',doc))))))
(t
(error "ill-formed DEFSETF for ~S" access-fn))))
(defun %defsetf (orig-access-form num-store-vars expander)
+ (declare (type function expander))
(let (subforms
subform-vars
subform-exprs
(unless (symbolp access-fn)
(error "DEFINE-SETF-EXPANDER access-function name ~S is not a symbol."
access-fn))
- (let ((whole (gensym "WHOLE-"))
- (environment (gensym "ENV-")))
+ (with-unique-names (whole environment)
(multiple-value-bind (body local-decs doc)
(parse-defmacro lambda-list whole body access-fn
'sb!xc:define-setf-expander
:environment environment)
`(eval-when (:compile-toplevel :load-toplevel :execute)
(assign-setf-macro ',access-fn
- #'(lambda (,whole ,environment)
- ,@local-decs
- (block ,access-fn ,body))
+ (lambda (,whole ,environment)
+ ,@local-decs
+ ,body)
nil
',doc)))))
(sb!xc:define-setf-expander ldb (bytespec place &environment env)
#!+sb-doc
"The first argument is a byte specifier. The second is any place form
- acceptable to SETF. Replaces the specified byte of the number in this
+ acceptable to SETF. Replace the specified byte of the number in this
place with bits from the low-order end of the new value."
(declare (type sb!c::lexenv env))
(multiple-value-bind (dummies vals newval setter getter)