(DEFINE-FILE-INFO READTABLE "XCL" PACKAGE "LISP") (il:filecreated "13-Jun-90 16:19:18" il:|{PELE:MV:ENVOS}SOURCES>CMLSETF.;6| 40556 il:|changes| il:|to:| (il:functions get-setf-method) il:|previous| il:|date:| "11-Jun-90 15:06:52" il:|{PELE:MV:ENVOS}SOURCES>CMLSETF.;5| ) ; Copyright (c) 1986, 1987, 1988, 1990 by Venue & Xerox Corporation. All rights reserved. (il:prettycomprint il:cmlsetfcoms) (il:rpaqq il:cmlsetfcoms ((il:functions get-setf-method get-simple-setf-method get-setf-method-multiple-value) (il:define-types il:setfs) (il:functions defsetf define-modify-macro define-setf-method) (il:coms (il:* il:|;;| "Support for defstruct and friends ") (il:functions define-shared-setf-macro define-shared-setf get-shared-setf-method)) (il:functions setf setf-error) (il:functions psetf shiftf rotatef pop remf) (il:functions incf decf) (il:functions maybe-make-binding-form count-occurrences) (il:functions push pushnew) (il:setfs car cdr caaaar caaadr caaar caadar caaddr caadr caar cadaar cadadr cadar caddar cadddr caddr cadr cdaaar cdaadr cdaar cdadar cdaddr cdadr cdar cddaar cddadr cddar cdddar cddddr cdddr cddr first second third fourth fifth sixth seventh eighth ninth tenth rest nthcdr nth getf apply ldb mask-field char-bit the) (il:coms (il:* il:\;  "Some IL setfs, for no especially good reason") (il:setfs il:gethash) (il:functions il:%set-il-gethash)) (il:prop il:proptype :setf-method-expander :setf-inverse :shared-setf-inverse) (il:prop (il:filetype il:makefile-environment) il:cmlsetf) (il:declare\: il:donteval@load il:doeval@compile il:dontcopy il:compilervars (il:addvars (il:nlama) (il:nlaml) (il:lama))))) (defun get-setf-method (form &optional environment) (let (temp) (cond ((symbolp form) (il:* il:|;;| "Symbols have a simple, constant SETF method.") (values nil nil (list (setq temp (il:gensym))) `(setq ,form ,temp) form)) ((not (consp form)) (il:* il:\; "Syntax error") (setf-error form)) ((setq temp (il:local-macro-function (car form) environment)) (il:* il:|;;|  "Lexical macros cannot have SETF methods defined upon them, so just expand this and try again.") (get-setf-method (funcall temp form environment) environment)) ((setq temp (or (get (car form) ':setf-inverse) (get (car form) 'il:setf-inverse) (get (car form) 'il:setfn))) (get-simple-setf-method form temp)) ((setq temp (get (car form) ':shared-setf-inverse)) (get-shared-setf-method form temp)) ((setq temp (or (get (car form) ':setf-method-expander) (get (car form) 'il:setf-method-expander))) (il:* il:|;;| "Do check number of the Store Variables") (multiple-value-bind (temps values stores setter getter) (funcall temp form environment) (when (/= (length stores) 1) (warn "SETF method contains more than one store variable. Only top of the elements was accepted." ) (setq stores (list (car stores)))) (values temps values stores setter getter))) (t (multiple-value-bind (expansion done) (macroexpand-1 form environment) (if (and done (not (eq expansion form))) (get-setf-method expansion environment) (setf-error (car form) form))))))) (defun get-simple-setf-method (form setf-inverse) (il:* il:|;;| "Produce SETF method for a form that has a setf-inverse. Five values to return are: temp vars, values to bind them to, store temp var, store form, access form; the latter two are expressions that can use any of them temp vars.") (let ((new-var (il:gensym)) vars vals args setf-inverse-form get-form) (setq args (mapcar #'(lambda (arg) (cond ((if (consp arg) (eq (car arg) 'quote) (constantp arg)) (il:* il:|;;| "We don't need gensym for this constant argument. The test is a little more conservative than CL:CONSTANTP because it's not obvious that it's ok to evaluate a \"constant expression\" multiple times and get the same EQ object every time.") arg) (t (il:* il:|;;|  "Anything else might be side-effected, so will need to bind") (push arg vals) (let ((g (il:gensym))) (push g vars) g)))) (cdr form))) (setq setf-inverse-form (macroexpand-1 `(,setf-inverse ,@args ,new-var))) (setq get-form (macroexpand-1 `(,(car form) ,@args))) (il:* il:|;;|  "ARGS is now the arguments to FORM with gensyms substituted for the non-constant expressions") (values (setq vars (nreverse vars)) (setq vals (nreverse vals)) (list new-var) setf-inverse-form get-form))) (defun get-setf-method-multiple-value (form &optional environment) (let (temp) (cond ((symbolp form) (il:* il:|;;| "Symbols have a simple, constant SETF method.") (values nil nil (list (setq temp (il:gensym))) `(setq ,form ,temp) form)) ((not (consp form)) (il:* il:\; "Syntax error") (setf-error form)) ((setq temp (il:local-macro-function (car form) environment)) (il:* il:|;;|  "Lexical macros cannot have SETF methods defined upon them, so just expand this and try again.") (get-setf-method (funcall temp form environment) environment)) ((setq temp (or (get (car form) ':setf-inverse) (get (car form) 'il:setf-inverse) (get (car form) 'il:setfn))) (get-simple-setf-method form temp)) ((setq temp (get (car form) ':shared-setf-inverse)) (get-shared-setf-method form temp)) ((setq temp (or (get (car form) ':setf-method-expander) (get (car form) 'il:setf-method-expander))) (il:* il:|;;| "Does not check the number of Store Variables.") (funcall temp form environment)) (t (multiple-value-bind (expansion done) (macroexpand-1 form environment) (if (and done (not (eq expansion form))) (get-setf-method expansion environment) (setf-error (car form) form))))))) (xcl:def-define-type il:setfs "Common Lisp SETF definitions") (xcl:defdefiner (defsetf (:prototype (lambda (name) (and (symbolp name) `(defsetf ,name "Inverse function"))))) il:setfs ( name &rest rest &environment env) (il:* il:|;;;| "Associates a SETF update function or macro with the specified access function or macro") (cond ((null rest) (error "No body for DEFSETF of ~A" name)) ((and (listp (car rest)) (cdr rest) (listp (cadr rest))) (il:* il:|;;| "The complex form:") (il:* il:|;;| "(defsetf access-fn args (store-var) {decl | doc}* {form}*)") (xcl:destructuring-bind (arg-list (store-var &rest others) &body body) rest (if others (cerror "Ignore the extra items in the list." "Currently only one new-value variable is allowed in DEFSETF.")) (let ((whole-var (xcl:pack (list name "-setf-form") (symbol-package name))) (environment (xcl:pack (list name "-setf-env") (symbol-package name))) (expander (xcl:pack (list name "-setf-expander") (symbol-package name)))) (multiple-value-bind (code decls doc) (il:parse-defmacro arg-list whole-var body name env :environment environment) `(progn (eval-when (eval compile load) (setf (symbol-function ',expander) #'(lambda (access-form ,environment) (let* ((dummies (mapcar #'(lambda (x) (il:gensym)) (cdr access-form))) (,whole-var (cons (car access-form) dummies)) (,store-var (il:gensym))) (values dummies (cdr access-form) (list ,store-var) (block ,name ,code) ,whole-var)))) (set-setf-method-expander ',name ',expander)) ,@(and doc `((setf (documentation ',name 'setf) ,doc)))))))) ((symbolp (car rest)) (il:* il:|;;| "The short form:") (il:* il:|;;| "(defsetf access-fn update-fn [doc])") (let ((update-fn (car rest)) (doc (cadr rest))) `(progn (eval-when (load compile eval) (set-setf-inverse ',name ',update-fn)) ,@(and doc `((setf (documentation ',name 'setf) ,doc)))))) (t (error "Ill-formed DEFSETF for ~S." name)))) (xcl:defdefiner (define-modify-macro (:prototype (lambda (name) (and (symbolp name) `(define-modify-macro ,name ,@( xcl::%make-function-prototype )))))) il:functions (name lambda-list function &optional doc-string) "Creates a new read-modify-write macro like PUSH or INCF." (let ((other-args nil) (rest-arg nil)) (do ((ll lambda-list (cdr ll)) (arg nil)) ((null ll)) (setq arg (car ll)) (cond ((eq arg '&optional)) ((eq arg '&rest) (setq rest-arg (cadr ll)) (return nil)) ((symbolp arg) (push arg other-args)) (t (push (car arg) other-args)))) (setq other-args (nreverse other-args)) `(defmacro ,name (si::%$$modify-macro-form ,@lambda-list &environment si::%$$modify-macro-environment) ,doc-string (multiple-value-bind (dummies vals newvals setter getter) (get-setf-method si::%$$modify-macro-form si::%$$modify-macro-environment) `(,'let* (,@(mapcar #'list dummies vals) (,(car newvals) ,,(if rest-arg `(list* ',function getter ,@other-args ,rest-arg) `(list ',function getter ,@other-args)))) ,setter))))) (xcl:defdefiner (define-setf-method (:prototype (lambda (name) (and (symbolp name) `(define-setf-method ,name ( "Arg list" ) "Body") )))) il:setfs (name lambda-list &environment env &body body) (let ((whole (xcl:pack (list "whole-" name) (symbol-package name))) (environment (xcl:pack (list "env-" name) (symbol-package name))) (expander (xcl:pack (list "setf-expander-" name) (symbol-package name)))) (multiple-value-bind (newbody local-decs doc) (il:parse-defmacro lambda-list whole body name env :environment environment :error-string "Setf expander for ~S cannot be called with ~S args.") `(eval-when (eval compile load) (defun ,expander (,whole ,environment) ,@local-decs (block ,name ,newbody)) (set-setf-method-expander ',name ',expander) ,@(and doc `((setf (documentation ',name 'setf) ,doc))))))) (il:* il:|;;| "Support for defstruct and friends ") (xcl:defdefiner define-shared-setf-macro il:functions (name accessor arg-list store-var &body body &environment env) (il:* il:|;;;| "Defines a shared SETF update function for a family of accessores -- used by defstruct") (if (not (and (consp store-var) (eq 1 (length store-var)))) (error "Store-var should be a list of one element: ~s" store-var)) (multiple-value-bind (code decls doc) (xcl:parse-body body env t) `(defmacro ,name (,accessor ,@arg-list ,@store-var) ,@doc ,@decls ,@code))) (xcl:defdefiner define-shared-setf il:setfs (name shared-expander &optional doc) (il:* il:|;;;| "Associates a shared SETF update macro with the specified accessor function -- used by defstruct") `(progn (eval-when (load compile eval) (set-shared-setf-inverse ',name ',shared-expander)) ,@(and doc `((setf (documentation ',name 'setf) ,doc))))) (defun get-shared-setf-method (form shared-setf-inverse) (il:* il:|;;| "Produce SETF method for a form that has a shared-setf-inverse. Five values to return are: temp vars, values to bind them to, store temp var, store form, access form; the latter two are expressions that can use any of them temp vars.") (let ((new-var (il:gensym)) vars vals args shared-setf-inverse-form get-form) (setq args (mapcar #'(lambda (arg) (cond ((if (consp arg) (eq (car arg) 'quote) (constantp arg)) (il:* il:|;;| "We don't need gensym for this constant argument. The test is a little more conservative than CL:CONSTANTP because it's not obvious that it's ok to evaluate a \"constant expression\" multiple times and get the same EQ object every time.") arg) (t (il:* il:|;;|  "Anything else might be side-effected, so will need to bind") (push arg vals) (let ((g (il:gensym))) (push g vars) g)))) (cdr form))) (setq shared-setf-inverse-form (macroexpand-1 `(,shared-setf-inverse ,(car form) ,@args ,new-var))) (setq get-form (macroexpand-1 `(,(car form) ,@args))) (il:* il:|;;|  "ARGS is now the arguments to FORM with gensyms substituted for the non-constant expressions") (values (setq vars (nreverse vars)) (setq vals (nreverse vals)) (list new-var) shared-setf-inverse-form get-form))) (defmacro setf (place new-value &rest others &environment env) (il:* il:|;;;| "Takes pairs of arguments like SETQ. The first is a place and the second is the value that is supposed to go into that place. Returns the last value. The place argument may be any of the access forms for which SETF knows a corresponding setting form.") (il:* il:|;;;| "We short-circuit the normal SETF-method mechanism for two very common special cases, so as to produce much simpler and more efficient code. The two cases are symbols and forms with simple inverses.") (cond (others `(progn (setf ,place ,new-value) (setf ,@others))) (t (prog (temp) lp (cond ((symbolp place) (return `(setq ,place ,new-value))) ((not (consp place)) (setf-error place)) ((setq temp (il:local-macro-function (car place) env)) (il:* il:|;;| "Before looking for an inverse, we have to macroexpand until it isn't a reference to a lexical macro, since those can't have SETF methods.") (setq place (funcall temp place env))) ((and (symbolp (car place)) (setq temp (or (get (car place) ':setf-inverse) (get (car place) 'il:setf-inverse) (get (car place) 'il:setfn)))) (return `(,temp ,@(cdr place) ,new-value))) ((and (symbolp (car place)) (setq temp (get (car place) ':shared-setf-inverse))) (return `(,temp ,(car place) ,@(cdr place) ,new-value))) ((or (get (car place) ':setf-method-expander) (get (car place) 'il:setf-method-expander)) (il:* il:|;;| "General setf hair") (return (multiple-value-bind (dummies vals newvals setter getter) (get-setf-method place env) `(,'let* (,@(mapcar #'list dummies vals) (,(car newvals) ,new-value)) ,setter)))) (t (il:* il:\; "Try macro expanding") (multiple-value-bind (expansion done) (macroexpand-1 place env) (cond ((and done (not (eq expansion place))) (setq place expansion)) (t (return (setf-error (car place) place))))))) (go lp))))) (defun setf-error (fn &optional form) (il:* il:|;;| "Common error routine for invalid SETF's. FN is the thing we tried to find a setf method for, FORM is its parent (not supplied when the form is a non-list).") (error "~S is not a known location specifier for SETF." fn)) (defmacro psetf (&rest args &environment env) "This is to SETF as PSETQ is to SETQ. Args are alternating place expressions and values to go into those places. All of the subforms and values are determined, left to right, and only then are the locations updated. Returns NIL." (do ((a args (cddr a)) (let-list nil) (setf-list nil)) ((atom a) `(,'let ,(reverse let-list) ,@(reverse setf-list) nil)) (if (atom (cdr a)) (error "Odd number of args to PSETF.")) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method (car a) env) (declare (ignore getter)) (do* ((d dummies (cdr d)) (v vals (cdr v))) ((null d)) (push (list (car d) (car v)) let-list)) (push (list (car newval) (cadr a)) let-list) (push setter setf-list)))) (defmacro shiftf (&rest args &environment env) "Assigns to each place the value of the form to its right, returns old value of 1st" (cond ((or (null args) (null (cdr args))) (error "SHIFTF needs at least two arguments")) (t (do* ((a args (cdr a)) (let-list nil) (setf-list nil) (result (il:gensym)) (next-var result)) ((atom (cdr a)) (push (list next-var (car a)) let-list) `(,'let* ,(reverse let-list) ,@(reverse setf-list) ,result)) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method (car a) env) (do ((d dummies (cdr d)) (v vals (cdr v))) ((null d)) (push (list (car d) (car v)) let-list)) (push (list next-var getter) let-list) (push setter setf-list) (setq next-var (car newval))))))) (defmacro rotatef (&rest args &environment env) "Assigns to each place the value of the form to its right; last gets first. Returns NIL." (il:* il:|;;| "forms evaluated in order") (cond ((null args) nil) ((null (cdr args)) `(progn ,(car args) nil)) (t (do ((a args (cdr a)) (let-list nil) (setf-list nil) (next-var nil) (fix-me nil)) ((atom a) (rplaca fix-me next-var) `(,'let* ,(reverse let-list) ,@(reverse setf-list) nil)) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method (car a) env) (do ((d dummies (cdr d)) (v vals (cdr v))) ((null d)) (push (list (car d) (car v)) let-list)) (push (list next-var getter) let-list) (il:* il:|;;| "We don't know the newval variable for the last form yet,so fake it for the first getter and fix it at the end.") (unless fix-me (setq fix-me (car let-list))) (push setter setf-list) (setq next-var (car newval))))))) (defmacro pop (place &environment env) "Pops one item off the front of PLACE 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) `(,'let* (,@(mapcar #'list dummies vals) ,(list (car newval) getter)) (prog1 (car ,(car newval)) (setq ,(car newval) (cdr ,(car newval))) ,setter))))) (defmacro remf (place indicator &environment env) "Destructively remove INDICATOR from PLACE, returning T if it was present, NIL if not" (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (let ((ind-temp (il:gensym)) (local1 (il:gensym)) (local2 (il:gensym))) `(,'let* (,@(mapcar #'list dummies vals) (,(car newval) ,getter) (,ind-temp ,indicator)) (do ((,local1 ,(car newval) (cddr ,local1)) (,local2 nil ,local1)) ((atom ,local1) nil) (cond ((atom (cdr ,local1)) (error "Odd-length property list in REMF.")) ((eq (car ,local1) ,ind-temp) (cond (,local2 (rplacd (cdr ,local2) (cddr ,local1)) (return t)) (t (setq ,(car newval) (cddr ,(car newval))) ,setter (return t)))))))))) (define-modify-macro incf (&optional (delta 1)) + "The first argument is some location holding a number. This number is incremented by the second argument, DELTA, which defaults to 1.") (define-modify-macro decf (&optional (delta 1)) - "The first argument is some location holding a number. This number is decremented by the second argument, DELTA, which defaults to 1.") (defun maybe-make-binding-form (newval-form dummies vals newvar setter getter) (il:* il:|;;| "For use in SETF-like forms to produce their final expression without using the NEWVAR gensym where possible. DUMMIES thru GETTER are the five values returned from the SETF method. NEWVAL-FORM is an expression to which the (sole) NEWVAR is logically to be bound, written in terms of the GETTER form. If it looks like there are no side-effect problems, we substitute NEWVAL-FORM into SETTER; otherwise we return a binding form that returns SETTER correctly.") (if (or dummies (> (count-occurrences (car newvar) setter) 1)) (il:* il:\;  " have to do messy binding form") `(,'let* (,@(mapcar #'list dummies vals) (,(car newvar) ,newval-form)) ,setter) (il:* il:\;  "No temp vars, setter used only once, so nothing can be side-effected, so store it directly") (subst newval-form (car newvar) setter))) (defun count-occurrences (symbol form) (cond ((consp form) (+ (count-occurrences symbol (car form)) (count-occurrences symbol (cdr form)))) ((eq symbol form) 1) (t 0))) (defmacro push (obj place &environment env) "Conses OBJ onto PLACE, returning the modified list." (if (symbolp place) `(setq ,place (cons ,obj ,place)) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (maybe-make-binding-form `(cons ,obj ,getter) dummies vals newval setter getter)))) (defmacro pushnew (obj place &rest keys &environment env) "Conses OBJ onto PLACE unless its already there, using :TEST if necessary" (if (symbolp place) `(setq ,place (adjoin ,obj ,place ,@keys)) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (maybe-make-binding-form `(adjoin ,obj ,getter ,@keys) dummies vals newval setter getter)))) (defsetf car (x) (v) `(car (rplaca ,x ,v))) (defsetf cdr (x) (v) `(cdr (rplacd ,x ,v))) (defsetf caaaar (x) (v) `(car (rplaca (caaar ,x) ,v))) (defsetf caaadr (x) (v) `(car (rplaca (caadr ,x) ,v))) (defsetf caaar (x) (v) `(car (rplaca (caar ,x) ,v))) (defsetf caadar (x) (v) `(car (rplaca (cadar ,x) ,v))) (defsetf caaddr (x) (v) `(car (rplaca (caddr ,x) ,v))) (defsetf caadr (x) (v) `(car (rplaca (cadr ,x) ,v))) (defsetf caar (x) (v) `(car (rplaca (car ,x) ,v))) (defsetf cadaar (x) (v) `(car (rplaca (cdaar ,x) ,v))) (defsetf cadadr (x) (v) `(car (rplaca (cdadr ,x) ,v))) (defsetf cadar (x) (v) `(car (rplaca (cdar ,x) ,v))) (defsetf caddar (x) (v) `(car (rplaca (cddar ,x) ,v))) (defsetf cadddr (x) (v) `(car (rplaca (cdddr ,x) ,v))) (defsetf caddr (x) (v) `(car (rplaca (cddr ,x) ,v))) (defsetf cadr (x) (v) `(car (rplaca (cdr ,x) ,v))) (defsetf cdaaar (x) (v) `(cdr (rplacd (caaar ,x) ,v))) (defsetf cdaadr (x) (v) `(cdr (rplacd (caadr ,x) ,v))) (defsetf cdaar (x) (v) `(cdr (rplacd (caar ,x) ,v))) (defsetf cdadar (x) (v) `(cdr (rplacd (cadar ,x) ,v))) (defsetf cdaddr (x) (v) `(cdr (rplacd (caddr ,x) ,v))) (defsetf cdadr (x) (v) `(cdr (rplacd (cadr ,x) ,v))) (defsetf cdar (x) (v) `(cdr (rplacd (car ,x) ,v))) (defsetf cddaar (x) (v) `(cdr (rplacd (cdaar ,x) ,v))) (defsetf cddadr (x) (v) `(cdr (rplacd (cdadr ,x) ,v))) (defsetf cddar (x) (v) `(cdr (rplacd (cdar ,x) ,v))) (defsetf cdddar (x) (v) `(cdr (rplacd (cddar ,x) ,v))) (defsetf cddddr (x) (v) `(cdr (rplacd (cdddr ,x) ,v))) (defsetf cdddr (x) (v) `(cdr (rplacd (cddr ,x) ,v))) (defsetf cddr (x) (v) `(cdr (rplacd (cdr ,x) ,v))) (defsetf first (x) (v) `(car (rplaca ,x ,v))) (defsetf second (x) (v) `(car (rplaca (cdr ,x) ,v))) (defsetf third (x) (v) `(car (rplaca (cddr ,x) ,v))) (defsetf fourth (x) (v) `(car (rplaca (cdddr ,x) ,v))) (defsetf fifth (x) (v) `(car (rplaca (cddddr ,x) ,v))) (defsetf sixth (x) (v) `(car (rplaca (cdr (cddddr ,x)) ,v))) (defsetf seventh (x) (v) `(car (rplaca (cddr (cddddr ,x)) ,v))) (defsetf eighth (x) (v) `(car (rplaca (cdddr (cddddr ,x)) ,v))) (defsetf ninth (x) (v) `(car (rplaca (cddddr (cddddr ,x)) ,v))) (defsetf tenth (x) (v) `(car (rplaca (cdr (cddddr (cddddr ,x))) ,v))) (defsetf rest (x) (v) `(cdr (rplacd ,x ,v))) (defsetf nthcdr (n list) (newval) `(cdr (rplacd (nthcdr (1- ,n) ,list) ,newval))) (defsetf nth %set-nth) (define-setf-method getf (place prop &optional default &environment env) (multiple-value-bind (temps values stores set get) (get-setf-method place env) (let ((newval (il:gensym)) (ptemp (il:gensym)) (def-temp (il:gensym))) (values `(,@temps ,(car stores) ,ptemp ,@(if default `(,def-temp))) `(,@values ,get ,prop ,@(if default `(,default))) `(,newval) `(cond ((null ,(car stores)) (let* ,(list (append stores `((list ,ptemp ,newval)))) ,set) ,newval) (t (il:listput ,(car stores) ,ptemp ,newval))) `(getf ,(car stores) ,ptemp ,@(if default `(,def-temp))))))) (define-setf-method apply (fn &rest args &environment env) (if (and (consp fn) (eq (length fn) 2) (member (first fn) '(function il:function quote) :test #'eq) (symbolp (second fn))) (setq fn (second fn)) (error "Setf of Apply is only defined for function args of form #'symbol.")) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method (cons fn args) env) (il:* il:|;;| "Make sure the place is one that we can handle.") (unless (and (eq (car (last args)) (car (last vals))) (eq (car (last getter)) (car (last dummies))) (eq (car (last setter)) (car (last dummies)))) (error "Apply of ~S not understood as a location for Setf." fn)) (values dummies vals newval `(apply #',(car setter) ,@(cdr setter)) `(apply #',(car getter) ,@(cdr getter))))) (define-setf-method ldb (bytespec place &environment env) "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 place with bits from the low-order end of the new value." (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (let ((btemp (il:gensym)) (gnuval (il:gensym))) (values (cons btemp dummies) (cons bytespec vals) (list gnuval) `(let ((,(car newval) (dpb ,gnuval ,btemp ,getter))) ,setter ,gnuval) `(ldb ,btemp ,getter))))) (define-setf-method mask-field (bytespec place &environment env) "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 place with bits from the corresponding position in the new value." (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place) (let ((btemp (il:gensym)) (gnuval (il:gensym))) (values (cons btemp dummies) (cons bytespec vals) (list gnuval) `(let ((,(car newval) (deposit-field ,gnuval ,btemp ,getter))) ,setter ,gnuval) `(mask-field ,btemp ,getter))))) (define-setf-method char-bit (place bit-name &environment env) "The first argument is any place form acceptable to SETF. Replaces the specified bit of the character in this place with the new value." (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (let ((btemp (il:gensym)) (gnuval (il:gensym))) (values `(,@dummies ,btemp) `(,@vals ,bit-name) (list gnuval) `(let ((,(car newval) (set-char-bit ,getter ,btemp ,gnuval))) ,setter ,gnuval) `(char-bit ,getter ,btemp))))) (define-setf-method the (type place &environment env) (multiple-value-bind (dummies vals newval setter getter) (get-setf-method place env) (values dummies vals newval (subst `(the ,type ,(car newval)) (car newval) setter) `(the ,type ,getter)))) (il:* il:\; "Some IL setfs, for no especially good reason") (defsetf il:gethash il:%set-il-gethash) (defmacro il:%set-il-gethash (key hash-table &optional newvalue) (il:* il:|;;| "SETF inverse for IL:GETHASH. Tricky parts are that args to IL:PUTHASH are in wrong order, and IL:GETHASH might default its second arg (yuck, let's flush that), in which case the third arg is absent and the second is the new value.") (cond ((not newvalue) (il:* il:\; "Defaulted hash table") `(il:puthash ,key ,hash-table)) ((or (il:constantexpressionp newvalue) (and (symbolp newvalue) (symbolp hash-table))) (il:* il:\; "Ok to swap args") `(il:puthash ,key ,newvalue ,hash-table)) (t `(let (il:$$gethash-table) (declare (il:localvars il:$$gethash-table)) (il:puthash ,key (progn (il:setq il:$$gethash-table ,hash-table) ,newvalue) il:$$gethash-table))))) (il:putprops :setf-method-expander il:proptype ignore) (il:putprops :setf-inverse il:proptype ignore) (il:putprops :shared-setf-inverse il:proptype ignore) (il:putprops il:cmlsetf il:filetype :compile-file) (il:putprops il:cmlsetf il:makefile-environment (:readtable "XCL" :package "LISP")) (il:declare\: il:donteval@load il:doeval@compile il:dontcopy il:compilervars (il:addtovar il:nlama ) (il:addtovar il:nlaml ) (il:addtovar il:lama ) ) (il:putprops il:cmlsetf il:copyright ("Venue & Xerox Corporation" 1986 1987 1988 1990)) (il:declare\: il:dontcopy (il:filemap (nil))) il:stop