merge from 1.8 branch
[bpt/guile.git] / ice-9 / calling.scm
CommitLineData
6a4d3cfd
JB
1;;;; calling.scm --- Calling Conventions
2;;;;
cd5fea8d 3;;;; Copyright (C) 1995, 1996, 1997, 2000, 2001, 2006 Free Software Foundation, Inc.
6a4d3cfd 4;;;;
73be1d9e
MV
5;;;; This library is free software; you can redistribute it and/or
6;;;; modify it under the terms of the GNU Lesser General Public
7;;;; License as published by the Free Software Foundation; either
8;;;; version 2.1 of the License, or (at your option) any later version.
6a4d3cfd 9;;;;
73be1d9e 10;;;; This library is distributed in the hope that it will be useful,
6a4d3cfd 11;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
12;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;;; Lesser General Public License for more details.
6a4d3cfd 14;;;;
73be1d9e
MV
15;;;; You should have received a copy of the GNU Lesser General Public
16;;;; License along with this library; if not, write to the Free Software
92205699 17;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6a4d3cfd
JB
18;;;;
19\f
1a179b03
MD
20(define-module (ice-9 calling)
21 :export-syntax (with-excursion-function
22 with-getter-and-setter
23 with-getter
24 with-delegating-getter-and-setter
25 with-excursion-getter-and-setter
26 with-configuration-getter-and-setter
27 with-delegating-configuration-getter-and-setter
28 let-with-configuration-getter-and-setter))
a6401ee0
JB
29
30;;;;
31;;;
32;;; This file contains a number of macros that support
33;;; common calling conventions.
34
35;;;
36;;; with-excursion-function <vars> proc
37;;; <vars> is an unevaluated list of names that are bound in the caller.
38;;; proc is a procedure, called:
39;;; (proc excursion)
40;;;
41;;; excursion is a procedure isolates all changes to <vars>
42;;; in the dynamic scope of the call to proc. In other words,
43;;; the values of <vars> are saved when proc is entered, and when
44;;; proc returns, those values are restored. Values are also restored
45;;; entering and leaving the call to proc non-locally, such as using
46;;; call-with-current-continuation, error, or throw.
47;;;
1a179b03 48(defmacro with-excursion-function (vars proc)
a6401ee0
JB
49 `(,proc ,(excursion-function-syntax vars)))
50
51
52
53;;; with-getter-and-setter <vars> proc
54;;; <vars> is an unevaluated list of names that are bound in the caller.
55;;; proc is a procedure, called:
56;;; (proc getter setter)
57;;;
58;;; getter and setter are procedures used to access
59;;; or modify <vars>.
60;;;
61;;; setter, called with keywords arguments, modifies the named
62;;; values. If "foo" and "bar" are among <vars>, then:
63;;;
64;;; (setter :foo 1 :bar 2)
65;;; == (set! foo 1 bar 2)
66;;;
67;;; getter, called with just keywords, returns
68;;; a list of the corresponding values. For example,
69;;; if "foo" and "bar" are among the <vars>, then
70;;;
71;;; (getter :foo :bar)
72;;; => (<value-of-foo> <value-of-bar>)
73;;;
74;;; getter, called with no arguments, returns a list of all accepted
75;;; keywords and the corresponding values. If "foo" and "bar" are
76;;; the *only* <vars>, then:
77;;;
78;;; (getter)
79;;; => (:foo <value-of-bar> :bar <value-of-foo>)
80;;;
81;;; The unusual calling sequence of a getter supports too handy
82;;; idioms:
83;;;
84;;; (apply setter (getter)) ;; save and restore
85;;;
86;;; (apply-to-args (getter :foo :bar) ;; fetch and bind
87;;; (lambda (foo bar) ....))
88;;;
89;;; ;; [ "apply-to-args" is just like two-argument "apply" except that it
90;;; ;; takes its arguments in a different order.
91;;;
92;;;
1a179b03 93(defmacro with-getter-and-setter (vars proc)
a6401ee0
JB
94 `(,proc ,@ (getter-and-setter-syntax vars)))
95
96;;; with-getter vars proc
97;;; A short-hand for a call to with-getter-and-setter.
98;;; The procedure is called:
99;;; (proc getter)
100;;;
1a179b03 101(defmacro with-getter (vars proc)
a6401ee0
JB
102 `(,proc ,(car (getter-and-setter-syntax vars))))
103
104
105;;; with-delegating-getter-and-setter <vars> get-delegate set-delegate proc
106;;; Compose getters and setters.
107;;;
108;;; <vars> is an unevaluated list of names that are bound in the caller.
109;;;
110;;; get-delegate is called by the new getter to extend the set of
111;;; gettable variables beyond just <vars>
112;;; set-delegate is called by the new setter to extend the set of
113;;; gettable variables beyond just <vars>
114;;;
115;;; proc is a procedure that is called
116;;; (proc getter setter)
117;;;
1a179b03 118(defmacro with-delegating-getter-and-setter (vars get-delegate set-delegate proc)
a6401ee0
JB
119 `(,proc ,@ (delegating-getter-and-setter-syntax vars get-delegate set-delegate)))
120
121
122;;; with-excursion-getter-and-setter <vars> proc
123;;; <vars> is an unevaluated list of names that are bound in the caller.
124;;; proc is called:
125;;;
126;;; (proc excursion getter setter)
127;;;
128;;; See also:
129;;; with-getter-and-setter
130;;; with-excursion-function
131;;;
1a179b03 132(defmacro with-excursion-getter-and-setter (vars proc)
a6401ee0
JB
133 `(,proc ,(excursion-function-syntax vars)
134 ,@ (getter-and-setter-syntax vars)))
135
136
137(define (excursion-function-syntax vars)
138 (let ((saved-value-names (map gensym vars))
b68c1eed
MD
139 (tmp-var-name (gensym "temp"))
140 (swap-fn-name (gensym "swap"))
141 (thunk-name (gensym "thunk")))
a6401ee0 142 `(lambda (,thunk-name)
63da7567
JB
143 (letrec ((,tmp-var-name #f)
144 (,swap-fn-name
145 (lambda () ,@ (map (lambda (n sn)
146 `(begin (set! ,tmp-var-name ,n)
147 (set! ,n ,sn)
148 (set! ,sn ,tmp-var-name)))
149 vars saved-value-names)))
150 ,@ (map (lambda (sn n) `(,sn ,n)) saved-value-names vars))
151 (dynamic-wind
152 ,swap-fn-name
153 ,thunk-name
154 ,swap-fn-name)))))
a6401ee0
JB
155
156
157(define (getter-and-setter-syntax vars)
b68c1eed
MD
158 (let ((args-name (gensym "args"))
159 (an-arg-name (gensym "an-arg"))
160 (new-val-name (gensym "new-value"))
161 (loop-name (gensym "loop"))
a6401ee0
JB
162 (kws (map symbol->keyword vars)))
163 (list `(lambda ,args-name
164 (let ,loop-name ((,args-name ,args-name))
165 (if (null? ,args-name)
166 ,(if (null? kws)
167 ''()
168 `(let ((all-vals (,loop-name ',kws)))
169 (let ,loop-name ((vals all-vals)
170 (kws ',kws))
171 (if (null? vals)
172 '()
173 `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws)))))))
174 (map (lambda (,an-arg-name)
175 (case ,an-arg-name
176 ,@ (append
177 (map (lambda (kw v) `((,kw) ,v)) kws vars)
178 `((else (throw 'bad-get-option ,an-arg-name))))))
179 ,args-name))))
180
181 `(lambda ,args-name
182 (let ,loop-name ((,args-name ,args-name))
183 (or (null? ,args-name)
184 (null? (cdr ,args-name))
185 (let ((,an-arg-name (car ,args-name))
186 (,new-val-name (cadr ,args-name)))
187 (case ,an-arg-name
188 ,@ (append
189 (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars)
190 `((else (throw 'bad-set-option ,an-arg-name)))))
191 (,loop-name (cddr ,args-name)))))))))
192
193(define (delegating-getter-and-setter-syntax vars get-delegate set-delegate)
b68c1eed
MD
194 (let ((args-name (gensym "args"))
195 (an-arg-name (gensym "an-arg"))
196 (new-val-name (gensym "new-value"))
197 (loop-name (gensym "loop"))
a6401ee0
JB
198 (kws (map symbol->keyword vars)))
199 (list `(lambda ,args-name
200 (let ,loop-name ((,args-name ,args-name))
201 (if (null? ,args-name)
202 (append!
203 ,(if (null? kws)
204 ''()
205 `(let ((all-vals (,loop-name ',kws)))
206 (let ,loop-name ((vals all-vals)
207 (kws ',kws))
208 (if (null? vals)
209 '()
210 `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws)))))))
211 (,get-delegate))
212 (map (lambda (,an-arg-name)
213 (case ,an-arg-name
214 ,@ (append
215 (map (lambda (kw v) `((,kw) ,v)) kws vars)
216 `((else (car (,get-delegate ,an-arg-name)))))))
217 ,args-name))))
218
219 `(lambda ,args-name
220 (let ,loop-name ((,args-name ,args-name))
221 (or (null? ,args-name)
222 (null? (cdr ,args-name))
223 (let ((,an-arg-name (car ,args-name))
224 (,new-val-name (cadr ,args-name)))
225 (case ,an-arg-name
226 ,@ (append
227 (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars)
228 `((else (,set-delegate ,an-arg-name ,new-val-name)))))
229 (,loop-name (cddr ,args-name)))))))))
230
231
232
233
234;;; with-configuration-getter-and-setter <vars-etc> proc
235;;;
236;;; Create a getter and setter that can trigger arbitrary computation.
237;;;
238;;; <vars-etc> is a list of variable specifiers, explained below.
239;;; proc is called:
240;;;
241;;; (proc getter setter)
242;;;
243;;; Each element of the <vars-etc> list is of the form:
244;;;
245;;; (<var> getter-hook setter-hook)
246;;;
247;;; Both hook elements are evaluated; the variable name is not.
248;;; Either hook may be #f or procedure.
249;;;
250;;; A getter hook is a thunk that returns a value for the corresponding
251;;; variable. If omitted (#f is passed), the binding of <var> is
252;;; returned.
253;;;
254;;; A setter hook is a procedure of one argument that accepts a new value
255;;; for the corresponding variable. If omitted, the binding of <var>
256;;; is simply set using set!.
257;;;
1a179b03 258(defmacro with-configuration-getter-and-setter (vars-etc proc)
a6401ee0
JB
259 `((lambda (simpler-get simpler-set body-proc)
260 (with-delegating-getter-and-setter ()
261 simpler-get simpler-set body-proc))
262
263 (lambda (kw)
264 (case kw
265 ,@(map (lambda (v) `((,(symbol->keyword (car v)))
266 ,(cond
267 ((cadr v) => list)
268 (else `(list ,(car v))))))
269 vars-etc)))
270
271 (lambda (kw new-val)
272 (case kw
273 ,@(map (lambda (v) `((,(symbol->keyword (car v)))
274 ,(cond
275 ((caddr v) => (lambda (proc) `(,proc new-val)))
276 (else `(set! ,(car v) new-val)))))
277 vars-etc)))
278
279 ,proc))
280
1a179b03 281(defmacro with-delegating-configuration-getter-and-setter (vars-etc delegate-get delegate-set proc)
a6401ee0
JB
282 `((lambda (simpler-get simpler-set body-proc)
283 (with-delegating-getter-and-setter ()
284 simpler-get simpler-set body-proc))
285
286 (lambda (kw)
287 (case kw
288 ,@(append! (map (lambda (v) `((,(symbol->keyword (car v)))
289 ,(cond
290 ((cadr v) => list)
291 (else `(list ,(car v))))))
292 vars-etc)
293 `((else (,delegate-get kw))))))
294
295 (lambda (kw new-val)
296 (case kw
297 ,@(append! (map (lambda (v) `((,(symbol->keyword (car v)))
298 ,(cond
299 ((caddr v) => (lambda (proc) `(,proc new-val)))
300 (else `(set! ,(car v) new-val)))))
301 vars-etc)
302 `((else (,delegate-set kw new-val))))))
303
304 ,proc))
305
306
307;;; let-configuration-getter-and-setter <vars-etc> proc
308;;;
309;;; This procedure is like with-configuration-getter-and-setter (q.v.)
310;;; except that each element of <vars-etc> is:
311;;;
312;;; (<var> initial-value getter-hook setter-hook)
313;;;
314;;; Unlike with-configuration-getter-and-setter, let-configuration-getter-and-setter
315;;; introduces bindings for the variables named in <vars-etc>.
316;;; It is short-hand for:
317;;;
318;;; (let ((<var1> initial-value-1)
319;;; (<var2> initial-value-2)
320;;; ...)
321;;; (with-configuration-getter-and-setter ((<var1> v1-get v1-set) ...) proc))
322;;;
1a179b03 323(defmacro let-with-configuration-getter-and-setter (vars-etc proc)
a6401ee0
JB
324 `(let ,(map (lambda (v) `(,(car v) ,(cadr v))) vars-etc)
325 (with-configuration-getter-and-setter ,(map (lambda (v) `(,(car v) ,(caddr v) ,(cadddr v))) vars-etc)
326 ,proc)))