1;;; define-modify-macro.lisp 2;;; 3;;; Copyright (C) 2003-2005 Peter Graves 4;;; $Id$ 5;;; 6;;; This program is free software; you can redistribute it and/or 7;;; modify it under the terms of the GNU General Public License 8;;; as published by the Free Software Foundation; either version 2 9;;; of the License, or (at your option) any later version. 10;;; 11;;; This program is distributed in the hope that it will be useful, 12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of 13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14;;; GNU General Public License for more details. 15;;; 16;;; You should have received a copy of the GNU General Public License 17;;; along with this program; if not, write to the Free Software 18;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 19;;; 20;;; As a special exception, the copyright holders of this library give you 21;;; permission to link this library with independent modules to produce an 22;;; executable, regardless of the license terms of these independent 23;;; modules, and to copy and distribute the resulting executable under 24;;; terms of your choice, provided that you also meet, for each linked 25;;; independent module, the terms and conditions of the license of that 26;;; module. An independent module is a module which is not derived from 27;;; or based on this library. If you modify this library, you may extend 28;;; this exception to your version of the library, but you are not 29;;; obligated to do so. If you do not wish to do so, delete this 30;;; exception statement from your version. 31 32;;; Adapted from SBCL. 33 34(in-package #:system) 35 36;; FIXME See section 5.1.3. 37(defmacro define-modify-macro (name lambda-list function &optional doc-string) 38 "Creates a new read-modify-write macro like PUSH or INCF." 39 (let ((other-args nil) 40 (rest-arg nil) 41 (env (gensym)) 42 (reference (gensym))) 43 ;; Parse out the variable names and &REST arg from the lambda list. 44 (do ((ll lambda-list (cdr ll)) 45 (arg nil)) 46 ((null ll)) 47 (setq arg (car ll)) 48 (cond ((eq arg '&optional)) 49 ((eq arg '&rest) 50 (if (symbolp (cadr ll)) 51 (setq rest-arg (cadr ll)) 52 (error "Non-symbol &REST arg in definition of ~S." name)) 53 (if (null (cddr ll)) 54 (return nil) 55 (error "Illegal stuff after &REST argument in DEFINE-MODIFY-MACRO."))) 56 ((memq arg '(&key &allow-other-keys &aux)) 57 (error "~S not allowed in DEFINE-MODIFY-MACRO lambda list." arg)) 58 ((symbolp arg) 59 (push arg other-args)) 60 ((and (listp arg) (symbolp (car arg))) 61 (push (car arg) other-args)) 62 (t (error "Illegal stuff in DEFINE-MODIFY-MACRO lambda list.")))) 63 (setq other-args (nreverse other-args)) 64 `(eval-when (:compile-toplevel :load-toplevel :execute) 65 (defmacro ,name (,reference ,@lambda-list &environment ,env) 66 ,doc-string 67 (multiple-value-bind (dummies vals newval setter getter) 68 (get-setf-expansion ,reference ,env) 69 (do ((d dummies (cdr d)) 70 (v vals (cdr v)) 71 (let-list nil (cons (list (car d) (car v)) let-list))) 72 ((null d) 73 (push (list (car newval) 74 ,(if rest-arg 75 `(list* ',function getter ,@other-args ,rest-arg) 76 `(list ',function getter ,@other-args))) 77 let-list) 78 `(let* ,(nreverse let-list) 79 ,setter)))))))) 80 81(define-modify-macro incf-complex (&optional (delta 1)) + 82 "The first argument is some location holding a number. This number is 83 incremented by the second argument, DELTA, which defaults to 1.") 84 85(define-modify-macro decf-complex (&optional (delta 1)) - 86 "The first argument is some location holding a number. This number is 87 decremented by the second argument, DELTA, which defaults to 1.") 88 89(defmacro incf (place &optional (delta 1)) 90 (cond ((symbolp place) 91 (cond ((constantp delta) 92 `(setq ,place (+ ,place ,delta))) 93 (t 94 ;; See section 5.1.3. 95 (let ((temp (gensym))) 96 `(let ((,temp ,delta)) 97 (setq ,place (+ ,place ,temp))))))) 98 ((and (consp place) (eq (car place) 'THE)) 99 (let ((res (gensym))) 100 `(let ((,res (the ,(second place) (+ ,place ,delta)))) 101 (setf ,(third place) ,res)))) 102 (t 103 `(incf-complex ,place ,delta)))) 104 105(defmacro decf (place &optional (delta 1)) 106 (cond ((symbolp place) 107 (cond ((constantp delta) 108 `(setq ,place (- ,place ,delta))) 109 (t 110 ;; See section 5.1.3. 111 (let ((temp (gensym))) 112 `(let ((,temp ,delta)) 113 (setq ,place (- ,place ,temp))))))) 114 ((and (consp place) (eq (car place) 'THE)) 115 (let ((res (gensym))) 116 `(let ((,res (the ,(second place) (- ,place ,delta)))) 117 (setf ,(third place) ,res)))) 118 (t 119 `(decf-complex ,place ,delta)))) 120