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