*** empty log message ***
[bpt/guile.git] / libguile / dynwind.c
CommitLineData
e81d98ec 1/* Copyright (C) 1995,1996,1998,1999,2000,2001 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84 41
1bbd0b84 42
0f2d19dd
JB
43\f
44
a0599745
MD
45#include "libguile/_scm.h"
46#include "libguile/eval.h"
47#include "libguile/alist.h"
48#include "libguile/fluids.h"
49#include "libguile/ports.h"
50#include "libguile/smob.h"
0f2d19dd 51
a0599745 52#include "libguile/dynwind.h"
0f2d19dd
JB
53\f
54
55/* {Dynamic wind}
b3460a50
MV
56
57 Things that can be on the wind list:
58
59 (enter-proc . leave-proc) dynamic-wind
60 (tag . jmpbuf) catch
61 (tag . lazy-catch) lazy-catch
62 tag is either a symbol or a boolean
63
64 ((fluid ...) . (value ...)) with-fluids
65
66*/
0f2d19dd
JB
67
68
69
3b3b36dd 70SCM_DEFINE (scm_dynamic_wind, "dynamic-wind", 3, 0, 0,
1e6808ea
MG
71 (SCM in_guard, SCM thunk, SCM out_guard),
72 "All three arguments must be 0-argument procedures.\n"
73 "@var{in_guard} is called, then @var{thunk}, then\n"
74 "@var{out_guard}.\n"
75 "\n"
76 "If, any time during the execution of @var{thunk}, the\n"
77 "continuation of the @code{dynamic_wind} expression is escaped\n"
78 "non-locally, @var{out_guard} is called. If the continuation of\n"
79 "the dynamic-wind is re-entered, @var{in_guard} is called. Thus\n"
80 "@var{in_guard} and @var{out_guard} may be called any number of\n"
81 "times.\n"
82 "@lisp\n"
b380b885 83 "(define x 'normal-binding)\n"
1e6808ea 84 "@result{} x\n"
b380b885
MD
85 "(define a-cont (call-with-current-continuation \n"
86 " (lambda (escape)\n"
87 " (let ((old-x x))\n"
88 " (dynamic-wind\n"
89 " ;; in-guard:\n"
90 " ;;\n"
1e6808ea
MG
91 " (lambda () (set! x 'special-binding))\n"
92 "\n"
b380b885
MD
93 " ;; thunk\n"
94 " ;;\n"
95 " (lambda () (display x) (newline)\n"
96 " (call-with-current-continuation escape)\n"
97 " (display x) (newline)\n"
1e6808ea
MG
98 " x)\n"
99 "\n"
b380b885
MD
100 " ;; out-guard:\n"
101 " ;;\n"
1e6808ea
MG
102 " (lambda () (set! x old-x)))))))\n"
103 "\n"
b380b885
MD
104 ";; Prints: \n"
105 "special-binding\n"
106 ";; Evaluates to:\n"
1e6808ea 107 "@result{} a-cont\n"
b380b885 108 "x\n"
1e6808ea 109 "@result{} normal-binding\n"
b380b885
MD
110 "(a-cont #f)\n"
111 ";; Prints:\n"
112 "special-binding\n"
113 ";; Evaluates to:\n"
1e6808ea 114 "@result{} a-cont ;; the value of the (define a-cont...)\n"
b380b885 115 "x\n"
1e6808ea 116 "@result{} normal-binding\n"
b380b885
MD
117 "a-cont\n"
118 "@result{} special-binding\n"
1e6808ea 119 "@end lisp")
1bbd0b84 120#define FUNC_NAME s_scm_dynamic_wind
0f2d19dd
JB
121{
122 SCM ans;
1e6808ea
MG
123 SCM_ASSERT (SCM_NFALSEP (scm_thunk_p (out_guard)),
124 out_guard,
1bbd0b84 125 SCM_ARG3, FUNC_NAME);
fdc28395 126 scm_call_0 (in_guard);
1e6808ea 127 scm_dynwinds = scm_acons (in_guard, out_guard, scm_dynwinds);
fdc28395 128 ans = scm_call_0 (thunk);
0f2d19dd 129 scm_dynwinds = SCM_CDR (scm_dynwinds);
fdc28395 130 scm_call_0 (out_guard);
0f2d19dd
JB
131 return ans;
132}
1bbd0b84 133#undef FUNC_NAME
0f2d19dd 134
3346a90f
MD
135/* The implementation of a C-callable dynamic-wind,
136 * scm_internal_dynamic_wind, requires packaging of C pointers in a
137 * smob. Objects of this type are pushed onto the dynwind chain.
138 */
139
e841c3e0 140#define SCM_GUARDSP(obj) SCM_TYP16_PREDICATE (tc16_guards, obj)
92c2555f
MV
141#define SCM_BEFORE_GUARD(obj) ((scm_t_guard) SCM_CELL_WORD (obj, 1))
142#define SCM_AFTER_GUARD(obj) ((scm_t_guard) SCM_CELL_WORD (obj, 2))
bd47429e 143#define SCM_GUARD_DATA(obj) ((void *) SCM_CELL_WORD (obj, 3))
3346a90f 144
92c2555f 145static scm_t_bits tc16_guards;
3346a90f 146
3346a90f 147static int
e81d98ec 148guards_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
3346a90f
MD
149{
150 scm_puts ("#<guards ", port);
f1267706 151 scm_intprint (SCM_UNPACK (SCM_CDR (exp)), 16, port);
3346a90f
MD
152 scm_putc ('>', port);
153 return 1;
154}
155
3346a90f 156SCM
92c2555f
MV
157scm_internal_dynamic_wind (scm_t_guard before,
158 scm_t_inner inner,
159 scm_t_guard after,
3346a90f
MD
160 void *inner_data,
161 void *guard_data)
162{
163 SCM guards, ans;
3346a90f 164 before (guard_data);
92c2555f
MV
165 SCM_NEWSMOB3 (guards, tc16_guards, (scm_t_bits) before,
166 (scm_t_bits) after, (scm_t_bits) guard_data);
3346a90f
MD
167 scm_dynwinds = scm_acons (guards, SCM_BOOL_F, scm_dynwinds);
168 ans = inner (inner_data);
169 scm_dynwinds = SCM_CDR (scm_dynwinds);
170 after (guard_data);
171 return ans;
172}
1cc91f1b 173
c2654ef0 174#ifdef GUILE_DEBUG
a1ec6916 175SCM_DEFINE (scm_wind_chain, "wind-chain", 0, 0, 0,
1bbd0b84 176 (),
156149ad
MG
177 "Return the current wind chain. The wind chain contains all\n"
178 "information required by @code{dynamic-wind} to call its\n"
179 "argument thunks when entering/exiting its scope.")
1bbd0b84 180#define FUNC_NAME s_scm_wind_chain
c2654ef0
MD
181{
182 return scm_dynwinds;
183}
1bbd0b84 184#undef FUNC_NAME
c2654ef0
MD
185#endif
186
6778caf9 187static void
904a077d 188scm_swap_bindings (SCM vars, SCM vals)
6778caf9
MD
189{
190 SCM tmp;
191 while (SCM_NIMP (vals))
192 {
904a077d
MV
193 tmp = SCM_VARIABLE_REF (SCM_CAR (vars));
194 SCM_VARIABLE_SET (SCM_CAR (vars), SCM_CAR (vals));
6778caf9 195 SCM_SETCAR (vals, tmp);
904a077d 196 vars = SCM_CDR (vars);
6778caf9
MD
197 vals = SCM_CDR (vals);
198 }
199}
c2654ef0 200
0f2d19dd 201void
c014a02e 202scm_dowinds (SCM to, long delta)
0f2d19dd
JB
203{
204 tail:
843524cc 205 if (SCM_EQ_P (to, scm_dynwinds));
1be6b49c 206 else if (delta < 0)
0f2d19dd
JB
207 {
208 SCM wind_elt;
209 SCM wind_key;
210
211 scm_dowinds (SCM_CDR (to), 1 + delta);
212 wind_elt = SCM_CAR (to);
213#if 0
214 if (SCM_INUMP (wind_elt))
215 {
216 scm_cross_dynwind_binding_scope (wind_elt, 0);
217 }
218 else
219#endif
220 {
221 wind_key = SCM_CAR (wind_elt);
904a077d 222 /* key = #t | symbol | thunk | list of variables | list of fluids */
6778caf9 223 if (SCM_NIMP (wind_key))
b3460a50 224 {
904a077d
MV
225 if (SCM_CONSP (wind_key))
226 {
227 if (SCM_VARIABLEP (SCM_CAR (wind_key)))
228 scm_swap_bindings (wind_key, SCM_CDR (wind_elt));
229 else if (SCM_FLUIDP (SCM_CAR (wind_key)))
230 scm_swap_fluids (wind_key, SCM_CDR (wind_elt));
231 }
4725c298
MD
232 else if (SCM_GUARDSP (wind_key))
233 SCM_BEFORE_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
234 else if (SCM_TYP3 (wind_key) == scm_tc3_closure)
fdc28395 235 scm_call_0 (wind_key);
b3460a50 236 }
0f2d19dd
JB
237 }
238 scm_dynwinds = to;
239 }
240 else
241 {
242 SCM from;
243 SCM wind_elt;
244 SCM wind_key;
245
246 from = SCM_CDR (SCM_CAR (scm_dynwinds));
247 wind_elt = SCM_CAR (scm_dynwinds);
248 scm_dynwinds = SCM_CDR (scm_dynwinds);
249#if 0
250 if (SCM_INUMP (wind_elt))
251 {
252 scm_cross_dynwind_binding_scope (wind_elt, 0);
253 }
254 else
255#endif
256 {
257 wind_key = SCM_CAR (wind_elt);
6778caf9 258 if (SCM_NIMP (wind_key))
b3460a50 259 {
904a077d
MV
260 if (SCM_CONSP (wind_key))
261 {
262 if (SCM_VARIABLEP (SCM_CAR (wind_key)))
263 scm_swap_bindings (wind_key, SCM_CDR (wind_elt));
264 else if (SCM_FLUIDP (SCM_CAR (wind_key)))
265 scm_swap_fluids_reverse (wind_key, SCM_CDR (wind_elt));
266 }
4725c298
MD
267 else if (SCM_GUARDSP (wind_key))
268 SCM_AFTER_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
269 else if (SCM_TYP3 (wind_key) == scm_tc3_closure)
fdc28395 270 scm_call_0 (from);
b3460a50 271 }
0f2d19dd
JB
272 }
273 delta--;
274 goto tail; /* scm_dowinds(to, delta-1); */
275 }
276}
277
278
1cc91f1b 279
0f2d19dd
JB
280void
281scm_init_dynwind ()
0f2d19dd 282{
e841c3e0
KN
283 tc16_guards = scm_make_smob_type ("guards", 0);
284 scm_set_smob_print (tc16_guards, guards_print);
8dc9439f 285#ifndef SCM_MAGIC_SNARFER
a0599745 286#include "libguile/dynwind.x"
8dc9439f 287#endif
0f2d19dd 288}
89e00824
ML
289
290/*
291 Local Variables:
292 c-file-style: "gnu"
293 End:
294*/