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