Lots of fixes with respect to strict typing.
[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 "smob.h"
50#include "alist.h"
51#include "eval.h"
1a36eef2 52#include "eq.h"
20e6290e 53#include "dynwind.h"
e82afdb8 54#include "backtrace.h"
20e6290e
JB
55#ifdef DEBUG_EXTENSIONS
56#include "debug.h"
57#endif
58#include "continuations.h"
7f759d79 59#include "stackchk.h"
95384717 60#include "stacks.h"
b6609fc7 61#include "fluids.h"
f04d8caf 62#include "ports.h"
0f2d19dd 63
b6791b2e 64#include "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
c209c88e
GB
71#define SCM_JMPBUFP(OBJ) (SCM_NIMP(OBJ) && (SCM_TYP16(OBJ) == scm_tc16_jmpbuffer))
72
4260a7fc 73#define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
c209c88e
GB
74#define ACTIVATEJB(OBJ) (SCM_SETOR_CAR (OBJ, (1L << 16L)))
75#define DEACTIVATEJB(OBJ) (SCM_SETAND_CAR (OBJ, ~(1L << 16L)))
0f2d19dd 76
e137c6b3 77#ifndef DEBUG_EXTENSIONS
4260a7fc
DH
78#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
79#define SETJBJMPBUF(x,v) (SCM_SET_CELL_WORD_1 ((x), (v)))
e137c6b3 80#else
4260a7fc
DH
81#define SCM_JBDFRAME(x) ((scm_debug_frame *) SCM_CELL_WORD_0 (SCM_CDR (x)))
82#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (SCM_CDR (OBJ)))
83#define SCM_SETJBDFRAME(OBJ,X) (SCM_SET_CELL_WORD_0 (SCM_CDR (OBJ), (X)))
84#define SETJBJMPBUF(OBJ,X) (SCM_SET_CELL_WORD_1 (SCM_CDR (OBJ), (X)))
e137c6b3 85
faa6b3df 86static scm_sizet
1bbd0b84 87freejb (SCM jbsmob)
e137c6b3 88{
4260a7fc 89 scm_must_free ((char *) SCM_CELL_WORD_1 (jbsmob));
e137c6b3
MD
90 return sizeof (scm_cell);
91}
0f2d19dd
JB
92#endif
93
0f2d19dd 94static int
1bbd0b84 95printjb (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 96{
b7f3516f
TT
97 scm_puts ("#<jmpbuffer ", port);
98 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
4260a7fc 99 scm_intprint((long) JBJMPBUF (exp), 16, port);
c209c88e 100
b7f3516f 101 scm_putc ('>', port);
0f2d19dd
JB
102 return 1 ;
103}
104
0f2d19dd 105
0f2d19dd 106static SCM
1bbd0b84 107make_jmpbuf (void)
0f2d19dd
JB
108{
109 SCM answer;
7f759d79 110 SCM_REDEFER_INTS;
0f2d19dd 111 {
e137c6b3
MD
112#ifdef DEBUG_EXTENSIONS
113 char *mem = scm_must_malloc (sizeof (scm_cell), "jb");
e137c6b3 114#endif
23a62151
MD
115#ifdef DEBUG_EXTENSIONS
116 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, mem);
117#else
118 SCM_NEWSMOB (answer, scm_tc16_jmpbuffer, 0);
119#endif
11702758
MD
120 SETJBJMPBUF(answer, (jmp_buf *)0);
121 DEACTIVATEJB(answer);
0f2d19dd 122 }
7f759d79 123 SCM_REALLOW_INTS;
0f2d19dd
JB
124 return answer;
125}
126
74229f75 127\f
18eadcbe 128/* scm_internal_catch (the guts of catch) */
74229f75 129
0f2d19dd
JB
130struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
131{
132 jmp_buf buf; /* must be first */
133 SCM throw_tag;
134 SCM retval;
135};
136
650fa1ab
JB
137
138/* scm_internal_catch is the guts of catch. It handles all the
139 mechanics of setting up a catch target, invoking the catch body,
140 and perhaps invoking the handler if the body does a throw.
141
142 The function is designed to be usable from C code, but is general
143 enough to implement all the semantics Guile Scheme expects from
144 throw.
145
146 TAG is the catch tag. Typically, this is a symbol, but this
147 function doesn't actually care about that.
148
149 BODY is a pointer to a C function which runs the body of the catch;
150 this is the code you can throw from. We call it like this:
19b27fa2 151 BODY (BODY_DATA)
650fa1ab 152 where:
816a6f06
JB
153 BODY_DATA is just the BODY_DATA argument we received; we pass it
154 through to BODY as its first argument. The caller can make
155 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
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{
4260a7fc 256 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (closure);
18eadcbe
JB
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