1 | ;;; setf.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2003-2006 Peter Graves |
---|
4 | ;;; $Id: setf.lisp 14036 2012-08-01 11:53:36Z ehuelsmann $ |
---|
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 | (in-package #:system) |
---|
33 | |
---|
34 | (defun get-setf-method-inverse (form inverse setf-function) |
---|
35 | (let ((new-var (gensym)) |
---|
36 | (vars nil) |
---|
37 | (vals nil)) |
---|
38 | (dolist (x (cdr form)) |
---|
39 | (push (gensym) vars) |
---|
40 | (push x vals)) |
---|
41 | (setq vals (nreverse vals)) |
---|
42 | (values vars vals (list new-var) |
---|
43 | (if setf-function |
---|
44 | `(,@inverse ,new-var ,@vars) |
---|
45 | (if (functionp (car inverse)) |
---|
46 | `(funcall ,@inverse ,@vars ,new-var) |
---|
47 | `(,@inverse ,@vars ,new-var))) |
---|
48 | `(,(car form) ,@vars)))) |
---|
49 | |
---|
50 | ;;; If a macro, expand one level and try again. If not, go for the |
---|
51 | ;;; SETF function. |
---|
52 | (defun expand-or-get-setf-inverse (form environment) |
---|
53 | (multiple-value-bind (expansion expanded) |
---|
54 | (macroexpand-1 form environment) |
---|
55 | (if expanded |
---|
56 | (get-setf-expansion expansion environment) |
---|
57 | (get-setf-method-inverse form `(funcall #'(setf ,(car form))) |
---|
58 | t)))) |
---|
59 | |
---|
60 | (defun get-setf-expansion (form &optional environment) |
---|
61 | ; ### FIXME: resolving here causes functions to be loaded at |
---|
62 | ; Macro expansion time instead of upon their first call! |
---|
63 | ; Discussion to be had on the mailing list. |
---|
64 | ; EH 2012-08-01 |
---|
65 | ; (when (and (consp form) |
---|
66 | ; (autoloadp (%car form))) |
---|
67 | ; (resolve (%car form))) |
---|
68 | (let (temp) |
---|
69 | (cond ((symbolp form) |
---|
70 | (multiple-value-bind (expansion expanded) |
---|
71 | (macroexpand-1 form environment) |
---|
72 | (if expanded |
---|
73 | (get-setf-expansion expansion environment) |
---|
74 | (let ((new-var (gensym))) |
---|
75 | (values nil nil (list new-var) |
---|
76 | `(setq ,form ,new-var) form))))) |
---|
77 | ((setq temp (get (car form) 'setf-inverse)) |
---|
78 | (get-setf-method-inverse form `(,temp) nil)) |
---|
79 | ((setq temp (get (car form) 'setf-expander)) |
---|
80 | (funcall temp form environment)) |
---|
81 | (t |
---|
82 | (expand-or-get-setf-inverse form environment))))) |
---|
83 | |
---|
84 | (defmacro setf (&rest args &environment environment) |
---|
85 | (let ((numargs (length args))) |
---|
86 | (cond |
---|
87 | ((= numargs 2) |
---|
88 | (let ((place (first args)) |
---|
89 | (value-form (second args))) |
---|
90 | (if (atom place) |
---|
91 | `(setq ,place ,value-form) |
---|
92 | (progn |
---|
93 | ; ### FIXME: resolving here causes functions to be loaded at |
---|
94 | ; Macro expansion time instead of upon their first call! |
---|
95 | ; Discussion to be had on the mailing list. |
---|
96 | ; EH 2012-08-01 |
---|
97 | ; (when (symbolp (%car place)) |
---|
98 | ; (resolve (%car place))) |
---|
99 | (multiple-value-bind (dummies vals store-vars setter getter) |
---|
100 | (get-setf-expansion place environment) |
---|
101 | (let ((inverse (get (car place) 'setf-inverse))) |
---|
102 | (if (and inverse (eq inverse (car setter))) |
---|
103 | (if (functionp inverse) |
---|
104 | `(funcall ,inverse ,@(cdr place) ,value-form) |
---|
105 | `(,inverse ,@(cdr place) ,value-form)) |
---|
106 | (if (or (null store-vars) (cdr store-vars)) |
---|
107 | `(let* (,@(mapcar #'list dummies vals)) |
---|
108 | (multiple-value-bind ,store-vars ,value-form |
---|
109 | ,setter)) |
---|
110 | `(let* (,@(mapcar #'list dummies vals) |
---|
111 | ,(list (car store-vars) value-form)) |
---|
112 | ,setter))))))))) |
---|
113 | ((oddp numargs) |
---|
114 | (error "Odd number of arguments to SETF.")) |
---|
115 | (t |
---|
116 | (do ((a args (cddr a)) (l nil)) |
---|
117 | ((null a) `(progn ,@(nreverse l))) |
---|
118 | (setq l (cons (list 'setf (car a) (cadr a)) l))))))) |
---|
119 | |
---|
120 | ;;; Redefined in define-modify-macro.lisp. |
---|
121 | (defmacro incf (place &optional (delta 1)) |
---|
122 | `(setf ,place (+ ,place ,delta))) |
---|
123 | |
---|
124 | ;;; Redefined in define-modify-macro.lisp. |
---|
125 | (defmacro decf (place &optional (delta 1)) |
---|
126 | `(setf ,place (- ,place ,delta))) |
---|
127 | |
---|
128 | ;; (defsetf subseq (sequence start &optional (end nil)) (v) |
---|
129 | ;; `(progn (replace ,sequence ,v :start1 ,start :end1 ,end) |
---|
130 | ;; ,v)) |
---|
131 | (defun %set-subseq (sequence start &rest rest) |
---|
132 | (let ((end nil) v) |
---|
133 | (ecase (length rest) |
---|
134 | (1 |
---|
135 | (setq v (car rest))) |
---|
136 | (2 |
---|
137 | (setq end (car rest) |
---|
138 | v (cadr rest)))) |
---|
139 | (progn |
---|
140 | (replace sequence v :start1 start :end1 end) |
---|
141 | v))) |
---|
142 | |
---|
143 | (defun %define-setf-macro (name expander inverse doc) |
---|
144 | (declare (ignore doc)) ; FIXME |
---|
145 | (when inverse |
---|
146 | (put name 'setf-inverse inverse)) |
---|
147 | (when expander |
---|
148 | (put name 'setf-expander expander)) |
---|
149 | name) |
---|
150 | |
---|
151 | (defmacro defsetf (access-function update-function) |
---|
152 | `(eval-when (:load-toplevel :compile-toplevel :execute) |
---|
153 | (put ',access-function 'setf-inverse ',update-function))) |
---|
154 | |
---|
155 | (defun %set-caar (x v) (set-car (car x) v)) |
---|
156 | (defun %set-cadr (x v) (set-car (cdr x) v)) |
---|
157 | (defun %set-cdar (x v) (set-cdr (car x) v)) |
---|
158 | (defun %set-cddr (x v) (set-cdr (cdr x) v)) |
---|
159 | (defun %set-caaar (x v) (set-car (caar x) v)) |
---|
160 | (defun %set-cadar (x v) (set-car (cdar x) v)) |
---|
161 | (defun %set-cdaar (x v) (set-cdr (caar x) v)) |
---|
162 | (defun %set-cddar (x v) (set-cdr (cdar x) v)) |
---|
163 | (defun %set-caadr (x v) (set-car (cadr x) v)) |
---|
164 | (defun %set-caddr (x v) (set-car (cddr x) v)) |
---|
165 | (defun %set-cdadr (x v) (set-cdr (cadr x) v)) |
---|
166 | (defun %set-cdddr (x v) (set-cdr (cddr x) v)) |
---|
167 | (defun %set-caaaar (x v) (set-car (caaar x) v)) |
---|
168 | (defun %set-cadaar (x v) (set-car (cdaar x) v)) |
---|
169 | (defun %set-cdaaar (x v) (set-cdr (caaar x) v)) |
---|
170 | (defun %set-cddaar (x v) (set-cdr (cdaar x) v)) |
---|
171 | (defun %set-caadar (x v) (set-car (cadar x) v)) |
---|
172 | (defun %set-caddar (x v) (set-car (cddar x) v)) |
---|
173 | (defun %set-cdadar (x v) (set-cdr (cadar x) v)) |
---|
174 | (defun %set-cdddar (x v) (set-cdr (cddar x) v)) |
---|
175 | (defun %set-caaadr (x v) (set-car (caadr x) v)) |
---|
176 | (defun %set-cadadr (x v) (set-car (cdadr x) v)) |
---|
177 | (defun %set-cdaadr (x v) (set-cdr (caadr x) v)) |
---|
178 | (defun %set-cddadr (x v) (set-cdr (cdadr x) v)) |
---|
179 | (defun %set-caaddr (x v) (set-car (caddr x) v)) |
---|
180 | (defun %set-cadddr (x v) (set-car (cdddr x) v)) |
---|
181 | (defun %set-cdaddr (x v) (set-cdr (caddr x) v)) |
---|
182 | (defun %set-cddddr (x v) (set-cdr (cdddr x) v)) |
---|
183 | |
---|
184 | (defsetf car set-car) |
---|
185 | (defsetf cdr set-cdr) |
---|
186 | (defsetf caar %set-caar) |
---|
187 | (defsetf cadr %set-cadr) |
---|
188 | (defsetf cdar %set-cdar) |
---|
189 | (defsetf cddr %set-cddr) |
---|
190 | (defsetf caaar %set-caaar) |
---|
191 | (defsetf cadar %set-cadar) |
---|
192 | (defsetf cdaar %set-cdaar) |
---|
193 | (defsetf cddar %set-cddar) |
---|
194 | (defsetf caadr %set-caadr) |
---|
195 | (defsetf caddr %set-caddr) |
---|
196 | (defsetf cdadr %set-cdadr) |
---|
197 | (defsetf cdddr %set-cdddr) |
---|
198 | (defsetf caaaar %set-caaaar) |
---|
199 | (defsetf cadaar %set-cadaar) |
---|
200 | (defsetf cdaaar %set-cdaaar) |
---|
201 | (defsetf cddaar %set-cddaar) |
---|
202 | (defsetf caadar %set-caadar) |
---|
203 | (defsetf caddar %set-caddar) |
---|
204 | (defsetf cdadar %set-cdadar) |
---|
205 | (defsetf cdddar %set-cdddar) |
---|
206 | (defsetf caaadr %set-caaadr) |
---|
207 | (defsetf cadadr %set-cadadr) |
---|
208 | (defsetf cdaadr %set-cdaadr) |
---|
209 | (defsetf cddadr %set-cddadr) |
---|
210 | (defsetf caaddr %set-caaddr) |
---|
211 | (defsetf cadddr %set-cadddr) |
---|
212 | (defsetf cdaddr %set-cdaddr) |
---|
213 | (defsetf cddddr %set-cddddr) |
---|
214 | |
---|
215 | (defsetf first set-car) |
---|
216 | (defsetf second %set-cadr) |
---|
217 | (defsetf third %set-caddr) |
---|
218 | (defsetf fourth %set-cadddr) |
---|
219 | (defun %set-fifth (x v) (set-car (cddddr x) v)) |
---|
220 | (defsetf fifth %set-fifth) |
---|
221 | (defun %set-sixth (x v) (set-car (cdr (cddddr x)) v)) |
---|
222 | (defsetf sixth %set-sixth) |
---|
223 | (defun %set-seventh (x v) (set-car (cddr (cddddr x)) v)) |
---|
224 | (defsetf seventh %set-seventh) |
---|
225 | (defun %set-eighth (x v) (set-car (cdddr (cddddr x)) v)) |
---|
226 | (defsetf eighth %set-eighth) |
---|
227 | (defun %set-ninth (x v) (set-car (cddddr (cddddr x)) v)) |
---|
228 | (defsetf ninth %set-ninth) |
---|
229 | (defun %set-tenth (x v) (set-car (cdr (cddddr (cddddr x))) v)) |
---|
230 | (defsetf tenth %set-tenth) |
---|
231 | |
---|
232 | (defsetf rest set-cdr) |
---|
233 | ;;Redefined in extensible-sequences-base.lisp |
---|
234 | (defsetf elt %set-elt) |
---|
235 | (defsetf nth %set-nth) |
---|
236 | (defsetf svref svset) |
---|
237 | (defsetf fill-pointer %set-fill-pointer) |
---|
238 | (defsetf subseq %set-subseq) |
---|
239 | (defsetf symbol-value set) |
---|
240 | (defsetf symbol-function %set-symbol-function) |
---|
241 | (defsetf symbol-plist %set-symbol-plist) |
---|
242 | (defsetf get put) |
---|
243 | (defsetf gethash puthash) |
---|
244 | (defsetf char set-char) |
---|
245 | (defsetf schar set-schar) |
---|
246 | (defsetf logical-pathname-translations %set-logical-pathname-translations) |
---|
247 | (defsetf readtable-case %set-readtable-case) |
---|
248 | |
---|
249 | (defsetf function-info %set-function-info) |
---|
250 | |
---|
251 | (defsetf stream-external-format %set-stream-external-format) |
---|
252 | |
---|
253 | (defsetf structure-ref structure-set) |
---|