* dynwind.c: #include "genio.h"; #include "smob.h"; Implemented a
[bpt/guile.git] / libguile / dynwind.c
1 /* Copyright (C) 1995,1996 Free Software Foundation, Inc.
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
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
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.
40 * If you do not wish that, delete this exception notice. */
41 \f
42
43 #include <stdio.h>
44 #include "_scm.h"
45 #include "eval.h"
46 #include "alist.h"
47 #include "fluids.h"
48 #include "genio.h"
49 #include "smob.h"
50
51 #include "dynwind.h"
52 \f
53
54 /* {Dynamic wind}
55
56 Things that can be on the wind list:
57
58 (enter-proc . leave-proc) dynamic-wind
59 (tag . jmpbuf) catch
60 (tag . lazy-catch) lazy-catch
61 tag is either a symbol or a boolean
62
63 ((fluid ...) . (value ...)) with-fluids
64
65 */
66
67
68
69 SCM_PROC(s_dynamic_wind, "dynamic-wind", 3, 0, 0, scm_dynamic_wind);
70
71 SCM
72 scm_dynamic_wind (thunk1, thunk2, thunk3)
73 SCM thunk1;
74 SCM thunk2;
75 SCM thunk3;
76 {
77 SCM ans;
78 scm_apply (thunk1, SCM_EOL, SCM_EOL);
79 scm_dynwinds = scm_acons (thunk1, thunk3, scm_dynwinds);
80 ans = scm_apply (thunk2, SCM_EOL, SCM_EOL);
81 scm_dynwinds = SCM_CDR (scm_dynwinds);
82 scm_apply (thunk3, SCM_EOL, SCM_EOL);
83 return ans;
84 }
85
86 /* The implementation of a C-callable dynamic-wind,
87 * scm_internal_dynamic_wind, requires packaging of C pointers in a
88 * smob. Objects of this type are pushed onto the dynwind chain.
89 */
90
91 typedef struct guardsmem {
92 scm_guard_t before;
93 scm_guard_t after;
94 void *data;
95 } guardsmem;
96
97 #define SCM_GUARDSMEM(obj) ((guardsmem *) SCM_CDR (obj))
98 #define SCM_BEFORE_GUARD(obj) (SCM_GUARDSMEM (obj)->before)
99 #define SCM_AFTER_GUARD(obj) (SCM_GUARDSMEM (obj)->after)
100 #define SCM_GUARD_DATA(obj) (SCM_GUARDSMEM (obj)->data)
101 #define SCM_GUARDSP(obj) (SCM_CAR (obj) == tc16_guards)
102
103 static long tc16_guards;
104
105 static scm_sizet
106 freeguards (SCM guards)
107 {
108 scm_must_free ((char *) SCM_CDR (guards));
109 return sizeof (guardsmem);
110 }
111
112 static int
113 printguards (SCM exp, SCM port, scm_print_state *pstate)
114 {
115 scm_puts ("#<guards ", port);
116 scm_intprint (SCM_CDR (exp), 16, port);
117 scm_putc ('>', port);
118 return 1;
119 }
120
121 static scm_smobfuns guardsmob = {
122 scm_mark0,
123 freeguards,
124 printguards,
125 0
126 };
127
128 SCM
129 scm_internal_dynamic_wind (scm_guard_t before,
130 scm_inner_t inner,
131 scm_guard_t after,
132 void *inner_data,
133 void *guard_data)
134 {
135 SCM guards, ans;
136 guardsmem *g;
137 before (guard_data);
138 SCM_NEWCELL (guards);
139 SCM_DEFER_INTS;
140 g = (guardsmem *) scm_must_malloc (sizeof (*g), "guards");
141 g->before = before;
142 g->after = after;
143 g->data = guard_data;
144 SCM_SETCDR (guards, g);
145 SCM_SETCAR (guards, tc16_guards);
146 SCM_ALLOW_INTS;
147 scm_dynwinds = scm_acons (guards, SCM_BOOL_F, scm_dynwinds);
148 ans = inner (inner_data);
149 scm_dynwinds = SCM_CDR (scm_dynwinds);
150 after (guard_data);
151 return ans;
152 }
153
154 #ifdef GUILE_DEBUG
155 SCM_PROC (s_wind_chain, "wind-chain", 0, 0, 0, scm_wind_chain);
156
157 SCM
158 scm_wind_chain ()
159 {
160 return scm_dynwinds;
161 }
162 #endif
163
164
165 void
166 scm_dowinds (to, delta)
167 SCM to;
168 long delta;
169 {
170 tail:
171 if (scm_dynwinds == to);
172 else if (0 > delta)
173 {
174 SCM wind_elt;
175 SCM wind_key;
176
177 scm_dowinds (SCM_CDR (to), 1 + delta);
178 wind_elt = SCM_CAR (to);
179 #if 0
180 if (SCM_INUMP (wind_elt))
181 {
182 scm_cross_dynwind_binding_scope (wind_elt, 0);
183 }
184 else
185 #endif
186 {
187 wind_key = SCM_CAR (wind_elt);
188 if (!(SCM_NIMP (wind_key) && SCM_SYMBOLP (wind_key))
189 && (wind_key != SCM_BOOL_F)
190 && (wind_key != SCM_BOOL_T))
191 {
192 if (SCM_NIMP (wind_key) && SCM_CONSP (wind_key))
193 scm_swap_fluids (wind_key, SCM_CDR (wind_elt));
194 else if (SCM_NIMP (wind_key) && SCM_GUARDSP (wind_key))
195 SCM_BEFORE_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
196 else
197 scm_apply (wind_key, SCM_EOL, SCM_EOL);
198 }
199 }
200 scm_dynwinds = to;
201 }
202 else
203 {
204 SCM from;
205 SCM wind_elt;
206 SCM wind_key;
207
208 from = SCM_CDR (SCM_CAR (scm_dynwinds));
209 wind_elt = SCM_CAR (scm_dynwinds);
210 scm_dynwinds = SCM_CDR (scm_dynwinds);
211 #if 0
212 if (SCM_INUMP (wind_elt))
213 {
214 scm_cross_dynwind_binding_scope (wind_elt, 0);
215 }
216 else
217 #endif
218 {
219 wind_key = SCM_CAR (wind_elt);
220 if (!(SCM_NIMP (wind_key) && SCM_SYMBOLP (wind_key))
221 && (wind_key != SCM_BOOL_F)
222 && (wind_key != SCM_BOOL_T))
223 {
224 if (SCM_NIMP (wind_key) && SCM_CONSP (wind_key))
225 scm_swap_fluids_reverse (wind_key, from);
226 else if (SCM_NIMP (wind_key) && SCM_GUARDSP (wind_key))
227 SCM_AFTER_GUARD (wind_key) (SCM_GUARD_DATA (wind_key));
228 else
229 scm_apply (from, SCM_EOL, SCM_EOL);
230 }
231 }
232 delta--;
233 goto tail; /* scm_dowinds(to, delta-1); */
234 }
235 }
236
237
238
239 void
240 scm_init_dynwind ()
241 {
242 tc16_guards = scm_newsmob (&guardsmob);
243 #include "dynwind.x"
244 }