* *.[ch]: Whitespace changes -- added space after SCM_VALIDATE_*
[bpt/guile.git] / libguile / throw.c
CommitLineData
d90ca38d 1/* Copyright (C) 1995, 1996, 1997, 1998 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
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
48#include "_scm.h"
20e6290e
JB
49#include "genio.h"
50#include "smob.h"
51#include "alist.h"
52#include "eval.h"
1a36eef2 53#include "eq.h"
20e6290e 54#include "dynwind.h"
e82afdb8 55#include "backtrace.h"
20e6290e
JB
56#ifdef DEBUG_EXTENSIONS
57#include "debug.h"
58#endif
59#include "continuations.h"
7f759d79 60#include "stackchk.h"
95384717 61#include "stacks.h"
b6609fc7 62#include "fluids.h"
0f2d19dd 63
1bbd0b84 64#include "scm_validate.h"
20e6290e 65#include "throw.h"
0f2d19dd 66
32f7b3a1 67\f
74229f75 68/* the jump buffer data structure */
0f2d19dd
JB
69static int scm_tc16_jmpbuffer;
70
d3a6bc94 71#define SCM_JMPBUFP(O) (SCM_NIMP(O) && (SCM_TYP16(O) == scm_tc16_jmpbuffer))
0f2d19dd 72#define JBACTIVE(O) (SCM_CAR (O) & (1L << 16L))
898a256f
MD
73#define ACTIVATEJB(O) (SCM_SETOR_CAR (O, (1L << 16L)))
74#define DEACTIVATEJB(O) (SCM_SETAND_CAR (O, ~(1L << 16L)))
0f2d19dd 75
e137c6b3
MD
76#ifndef DEBUG_EXTENSIONS
77#define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (O) )
78#define SETJBJMPBUF SCM_SETCDR
79#else
08b5b88c 80#define SCM_JBDFRAME(O) ((scm_debug_frame*)SCM_CAR (SCM_CDR (O)) )
0f2d19dd 81#define JBJMPBUF(O) ((jmp_buf*)SCM_CDR (SCM_CDR (O)) )
898a256f 82#define SCM_SETJBDFRAME(O,X) SCM_SETCAR (SCM_CDR (O), (SCM)(X))
0f2d19dd 83#define SETJBJMPBUF(O,X) SCM_SETCDR(SCM_CDR (O), X)
e137c6b3 84
faa6b3df 85static scm_sizet
1bbd0b84 86freejb (SCM jbsmob)
e137c6b3
MD
87{
88 scm_must_free ((char *) SCM_CDR (jbsmob));
89 return sizeof (scm_cell);
90}
0f2d19dd
JB
91#endif
92
0f2d19dd 93static int
1bbd0b84 94printjb (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 95{
b7f3516f
TT
96 scm_puts ("#<jmpbuffer ", port);
97 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
0f2d19dd 98 scm_intprint((SCM) JBJMPBUF(exp), 16, port);
b7f3516f 99 scm_putc ('>', port);
0f2d19dd
JB
100 return 1 ;
101}
102
0f2d19dd 103
0f2d19dd 104static SCM
1bbd0b84 105make_jmpbuf (void)
0f2d19dd
JB
106{
107 SCM answer;
7f759d79 108 SCM_REDEFER_INTS;
0f2d19dd 109 {
e137c6b3
MD
110#ifdef DEBUG_EXTENSIONS
111 char *mem = scm_must_malloc (sizeof (scm_cell), "jb");
e137c6b3 112#endif
23a62151
MD
113#ifdef DEBUG_EXTENSIONS
114 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, mem);
115#else
116 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, 0);
117#endif
11702758
MD
118 SETJBJMPBUF(answer, (jmp_buf *)0);
119 DEACTIVATEJB(answer);
0f2d19dd 120 }
7f759d79 121 SCM_REALLOW_INTS;
0f2d19dd
JB
122 return answer;
123}
124
74229f75 125\f
18eadcbe 126/* scm_internal_catch (the guts of catch) */
74229f75 127
0f2d19dd
JB
128struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
129{
130 jmp_buf buf; /* must be first */
131 SCM throw_tag;
132 SCM retval;
133};
134
650fa1ab
JB
135
136/* scm_internal_catch is the guts of catch. It handles all the
137 mechanics of setting up a catch target, invoking the catch body,
138 and perhaps invoking the handler if the body does a throw.
139
140 The function is designed to be usable from C code, but is general
141 enough to implement all the semantics Guile Scheme expects from
142 throw.
143
144 TAG is the catch tag. Typically, this is a symbol, but this
145 function doesn't actually care about that.
146
147 BODY is a pointer to a C function which runs the body of the catch;
148 this is the code you can throw from. We call it like this:
816a6f06 149 BODY (BODY_DATA, JMPBUF)
650fa1ab 150 where:
816a6f06
JB
151 BODY_DATA is just the BODY_DATA argument we received; we pass it
152 through to BODY as its first argument. The caller can make
153 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
154 JMPBUF is the Scheme jmpbuf object corresponding to this catch,
155 which we have just created and initialized.
156
157 HANDLER is a pointer to a C function to deal with a throw to TAG,
158 should one occur. We call it like this:
86327304 159 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 160 where
816a6f06
JB
161 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
162 same idea as BODY_DATA above.
86327304
JB
163 THROWN_TAG is the tag that the user threw to; usually this is
164 TAG, but it could be something else if TAG was #t (i.e., a
165 catch-all), or the user threw to a jmpbuf.
650fa1ab 166 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 167 function, after the tag.
650fa1ab 168
3eed3475
JB
169 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
170 is just a pointer we pass through to HANDLER. We don't actually
171 use either of those pointers otherwise ourselves. The idea is
172 that, if our caller wants to communicate something to BODY or
173 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
174 HANDLER can then use. Think of it as a way to make BODY and
175 HANDLER closures, not just functions; MUMBLE_DATA points to the
176 enclosed variables.
177
178 Of course, it's up to the caller to make sure that any data a
179 MUMBLE_DATA needs is protected from GC. A common way to do this is
180 to make MUMBLE_DATA a pointer to data stored in an automatic
181 structure variable; since the collector must scan the stack for
182 references anyway, this assures that any references in MUMBLE_DATA
183 will be found. */
650fa1ab 184
0f2d19dd 185SCM
6e8d25a6 186scm_internal_catch (SCM tag, scm_catch_body_t body, void *body_data, scm_catch_handler_t handler, void *handler_data)
0f2d19dd
JB
187{
188 struct jmp_buf_and_retval jbr;
189 SCM jmpbuf;
190 SCM answer;
191
11702758 192 jmpbuf = make_jmpbuf ();
0f2d19dd
JB
193 answer = SCM_EOL;
194 scm_dynwinds = scm_acons (tag, jmpbuf, scm_dynwinds);
195 SETJBJMPBUF(jmpbuf, &jbr.buf);
196#ifdef DEBUG_EXTENSIONS
e68b42c1 197 SCM_SETJBDFRAME(jmpbuf, scm_last_debug_frame);
0f2d19dd
JB
198#endif
199 if (setjmp (jbr.buf))
200 {
201 SCM throw_tag;
202 SCM throw_args;
203
7f759d79
MD
204#ifdef STACK_CHECKING
205 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
206#endif
207 SCM_REDEFER_INTS;
0f2d19dd
JB
208 DEACTIVATEJB (jmpbuf);
209 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 210 SCM_REALLOW_INTS;
0f2d19dd
JB
211 throw_args = jbr.retval;
212 throw_tag = jbr.throw_tag;
213 jbr.throw_tag = SCM_EOL;
214 jbr.retval = SCM_EOL;
816a6f06 215 answer = handler (handler_data, throw_tag, throw_args);
0f2d19dd
JB
216 }
217 else
218 {
219 ACTIVATEJB (jmpbuf);
492960a4 220 answer = body (body_data);
7f759d79 221 SCM_REDEFER_INTS;
0f2d19dd
JB
222 DEACTIVATEJB (jmpbuf);
223 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 224 SCM_REALLOW_INTS;
0f2d19dd
JB
225 }
226 return answer;
227}
228
650fa1ab 229
18eadcbe
JB
230\f
231/* scm_internal_lazy_catch (the guts of lazy catching) */
232
233/* The smob tag for lazy_catch smobs. */
234static long tc16_lazy_catch;
235
236/* This is the structure we put on the wind list for a lazy catch. It
237 stores the handler function to call, and the data pointer to pass
238 through to it. It's not a Scheme closure, but it is a function
239 with data, so the term "closure" is appropriate in its broader
240 sense.
241
242 (We don't need anything like this in the "eager" catch code,
243 because the same C frame runs both the body and the handler.) */
244struct lazy_catch {
245 scm_catch_handler_t handler;
246 void *handler_data;
247};
248
249/* Strictly speaking, we could just pass a zero for our print
250 function, because we don't need to print them. They should never
251 appear in normal data structures, only in the wind list. However,
252 it might be nice for debugging someday... */
253static int
254print_lazy_catch (SCM closure, SCM port, scm_print_state *pstate)
255{
256 struct lazy_catch *c = (struct lazy_catch *) SCM_CDR (closure);
257 char buf[200];
258
259 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
260 (long) c->handler, (long) c->handler_data);
b7f3516f 261 scm_puts (buf, port);
18eadcbe
JB
262
263 return 1;
264}
265
18eadcbe
JB
266
267/* Given a pointer to a lazy catch structure, return a smob for it,
268