home *** CD-ROM | disk | FTP | other *** search
- ;;;
- ;;; SETF.L - Copyright (c) 1986 by David Morein
- ;;;
- ;;; This file contains all code relevent to SETF and DEFSETF.
- ;;;
- (pdq /sys/cmd)
- ;;;
- (global 'setf 'get-setf-method 'define-setf-method)
- ;;;
- ;;; SETF is taken from Steele, p107. It is an implementation
- ;;; of a subset of the SETF standard.
- ;;;
- (defmacro setf (reference value)
- (multiple-value-bind (vars vals stores store-form access-form)
- (get-setf-method reference)
- `(let* ,(mapcar 'list
- (append vars stores)
- (append vals (list value)))
- ,store-form)))
- ;;;
- ;;; GET-SETF-METHOD - retrieves the quintuple constituting
- ;;; the setf method for FORM. If FORM is atomic (i.e., a symbol),
- ;;; then a method is computed for it by ATOMIC-METHOD; otherwise
- ;;; the method generator corresponding to FORM is retrieved
- ;;; from the property list of SETF, and evaluated to produce
- ;;; a method. The property list of SETF is organized by access-fn;
- ;;; under each function name is a value which is the method generator
- ;;; for that function.
- ;;;
- (defun get-setf-method (reference)
- (if (atom reference)
- (atomic-method reference)
- (progn
- (setq let-vars
- (mapcar 'list
- (get 'setf-lambda-lists (car reference))
- (mapcar 'quote (cdr reference))))
- (eval (eval
- `(let ,let-vars ,(get 'setf (car reference))))))))
- ;;;
- ;;; ATOMIC-METHOD - standard setf method for an atomic reference
- ;;;
- (defmacro atomic-method (variable)
- `(if (symbolp ,variable)
- (let ((store-variable ',(gensym)))
- (values
- '()
- '()
- '(store-variable)
- '(setq ,variable store-variable)
- '(,variable)))
- (err "***> SETF: constant cannot be setq'd.")))
- ;;;
- ;;; DEFINE-SETF-METHOD - stores the setf method for a
- ;;; generalized variable reference.
- ;;;
- (defmacro define-setf-method (access-fn lambda-list &rest body)
- `(progn
- (putprop 'setf-lambda-lists ',lambda-list ',access-fn)
- (putprop 'setf ',body ',access-fn)))
- ;;;
- ;;; METHOD-BROWSE - constructs a sample method for a generalized
- ;;; variable reference, and displays it. For example,
- ;;; (METHOD-BROWSE '(car y)) might produce the output:
- ;;;
- ;;; reference = (CAR _Y)
- ;;; vars = (G9)
- ;;; vals = (_Y)
- ;;; stores = (G10)
- ;;; store-form = (PROGN (RPLACA G9 G10) G10)
- ;;; access-form = (CAR G9)
- ;;;
- (defun method-browse (reference)
- (multiple-value-bind (vars vals stores store-form access-form)
- (get-setf-method reference)
- (princ "reference = ") (print reference) (terpri)
- (princ "vars = ") (print vars) (terpri)
- (princ "vals = ") (print vals) (terpri)
- (princ "stores = ") (print stores) (terpri)
- (princ "store-form = ") (print store-form) (terpri)
- (princ "access-form = ") (print access-form) (terpri)
- ))
- ;;;
- ;;; some methods for common functions:
- ;;;
- ;;; the following example is from Steele, p106
- ;;;
- (define-setf-method ldb (bytespec int)
- (multiple-value-bind (temps vals stores store-form access-form)
- (get-setf-method int) ;get SETF method for int.
- (let ((btemp (gensym)) ;temp var for byte specifier.
- (store (gensym)) ;temp var for byte to store.
- (stemp (first stores))) ;temp var for int to store.
- ;; Return the SETF method for LDB as five values.
- (values (cons btemp temps) ;temporary variables.
- (cons bytespec vals) ;value forms.
- (list store) ;store variables.
- `(let ((,stemp (dpb ,store ,btemp ,access-form)))
- ,store-form
- ,store) ;storing form.
- `(ldb ,btemp ,access-form) ;accessing form.
- ))))
-
- ;;;
- ;;; other SETF methods:
- ;;;
- ;;; method for CAR
- ;;;
- (define-setf-method car (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca ,store-var1 ,store-var2) ,store-var2)
- '(car ,store-var1))))
- ;;;
- ;;; method for CDR
- ;;;
- (define-setf-method cdr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd ,store-var1 ,store-var2) ,store-var2)
- '(cdr ,store-var1))))
- ;;;
- ;;; method for CAAR
- ;;;
- (define-setf-method caar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (car ,store-var1) ,store-var2) ,store-var2)
- '(caar ,store-var1))))
- ;;;
- ;;; method for CADR
- ;;;
- (define-setf-method cadr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (cdr ,store-var1) ,store-var2) ,store-var2)
- '(cadr ,store-var1))))
- ;;;
- ;;; method for CDAR
- ;;;
- (define-setf-method cdar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (car ,store-var1) ,store-var2) ,store-var2)
- '(cdar ,store-var1))))
- ;;;
- ;;; method for CDDR
- ;;;
- (define-setf-method cddr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (cdr ,store-var1) ,store-var2) ,store-var2)
- '(cddr ,store-var1))))
- ;;;
- ;;; method for CAAAR
- ;;;
- (define-setf-method caaar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (caar ,store-var1) ,store-var2) ,store-var2)
- '(caaar ,store-var1))))
- ;;;
- ;;; method for CAADR
- ;;;
- (define-setf-method caadr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (cadr ,store-var1) ,store-var2) ,store-var2)
- '(caadr ,store-var1))))
- ;;;
- ;;; method for CADAR
- ;;;
- (define-setf-method cadar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (cdar ,store-var1) ,store-var2) ,store-var2)
- '(cadar ,store-var1))))
- ;;;
- ;;; method for CADDR
- ;;;
- (define-setf-method caddr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplaca (cddr ,store-var1) ,store-var2) ,store-var2)
- '(caddr ,store-var1))))
- ;;;
- ;;; method for CDAAR
- ;;;
- (define-setf-method cdaar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (caar ,store-var1) ,store-var2) ,store-var2)
- '(cdaar ,store-var1))))
- ;;;
- ;;; method for CDADR
- ;;;
- (define-setf-method cdadr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (cadr ,store-var1) ,store-var2) ,store-var2)
- '(cdadr ,store-var1))))
- ;;;
- ;;; method for CDDAR
- ;;;
- (define-setf-method cddar (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (cdar ,store-var1) ,store-var2) ,store-var2)
- '(cddar ,store-var1))))
- ;;;
- ;;;
- ;;; method for CDDDR
- ;;;
- (define-setf-method cdddr (x)
- (let ((store-var1 (gensym)) (store-var2 (gensym)))
- `(values
- ',(list store-var1)
- '(,x)
- ',(list store-var2)
- '(progn (rplacd (cddr ,store-var1) ,store-var2) ,store-var2)
- '(cdddr ,store-var1))))
- ;;;
- (popd) ;return to original directory
-