Reorder arrays.test
[bpt/guile.git] / libguile / throw.c
CommitLineData
1773bc7d 1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
0f2d19dd 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
0f2d19dd 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
0f2d19dd
JB
24
25#include <stdio.h>
27646f41 26#include <unistdio.h>
a0599745
MD
27#include "libguile/_scm.h"
28#include "libguile/smob.h"
a0599745
MD
29#include "libguile/eval.h"
30#include "libguile/eq.h"
416f26c7 31#include "libguile/control.h"
e10cf6b9 32#include "libguile/deprecation.h"
a0599745 33#include "libguile/backtrace.h"
a0599745 34#include "libguile/debug.h"
a0599745
MD
35#include "libguile/stackchk.h"
36#include "libguile/stacks.h"
37#include "libguile/fluids.h"
38#include "libguile/ports.h"
a0599745 39#include "libguile/validate.h"
416f26c7 40#include "libguile/vm.h"
a0599745 41#include "libguile/throw.h"
9de87eea 42#include "libguile/init.h"
a2c40dc7 43#include "libguile/strings.h"
0f2d19dd 44
22fc179a
HWN
45#include "libguile/private-options.h"
46
47
416f26c7
AW
48/* Pleasantly enough, the guts of catch are defined in Scheme, in terms of
49 prompt, abort, and the %exception-handler fluid. This file just provides
50 shims so that it's easy to have catch functionality from C.
0f2d19dd 51
416f26c7
AW
52 All of these function names and prototypes carry a fair bit of historical
53 baggage. */
c209c88e 54
0f2d19dd 55
416f26c7
AW
56#define CACHE_VAR(var,name) \
57 static SCM var = SCM_BOOL_F; \
58 if (scm_is_false (var)) \
59 { \
60 var = scm_module_variable (scm_the_root_module (), \
9179e8a5 61 scm_from_latin1_symbol (name)); \
416f26c7
AW
62 if (scm_is_false (var)) \
63 abort (); \
64 }
0f2d19dd 65
416f26c7
AW
66\f
67
68SCM
69scm_catch (SCM key, SCM thunk, SCM handler)
0f2d19dd 70{
416f26c7
AW
71 CACHE_VAR (var, "catch");
72
73 return scm_call_3 (scm_variable_ref (var), key, thunk, handler);
0f2d19dd
JB
74}
75
416f26c7
AW
76SCM
77scm_catch_with_pre_unwind_handler (SCM key, SCM thunk, SCM handler,
78 SCM pre_unwind_handler)
0f2d19dd 79{
416f26c7
AW
80 if (SCM_UNBNDP (pre_unwind_handler))
81 return scm_catch (key, thunk, handler);
82 else
83 {
84 CACHE_VAR (var, "catch");
85
86 return scm_call_4 (scm_variable_ref (var), key, thunk, handler,
87 pre_unwind_handler);
88 }
0f2d19dd
JB
89}
90
416f26c7
AW
91SCM
92scm_with_throw_handler (SCM key, SCM thunk, SCM handler)
93{
94 CACHE_VAR (var, "with-throw-handler");
95
96 return scm_call_3 (scm_variable_ref (var), key, thunk, handler);
97}
74229f75 98
416f26c7
AW
99SCM
100scm_throw (SCM key, SCM args)
0f2d19dd 101{
416f26c7
AW
102 CACHE_VAR (var, "throw");
103
104 return scm_apply_1 (scm_variable_ref (var), key, args);
105}
106
107\f
0f2d19dd 108
416f26c7 109/* Now some support for C bodies and catch handlers */
650fa1ab 110
416f26c7 111static scm_t_bits tc16_catch_closure;
43e01b1e 112
416f26c7
AW
113enum {
114 CATCH_CLOSURE_BODY,
115 CATCH_CLOSURE_HANDLER
43e01b1e
NJ
116};
117
416f26c7
AW
118static SCM
119make_catch_body_closure (scm_t_catch_body body, void *body_data)
120{
121 SCM ret;
122 SCM_NEWSMOB2 (ret, tc16_catch_closure, body, body_data);
123 SCM_SET_SMOB_FLAGS (ret, CATCH_CLOSURE_BODY);
124 return ret;
125}
126
127static SCM
128make_catch_handler_closure (scm_t_catch_handler handler, void *handler_data)
129{
130 SCM ret;
131 SCM_NEWSMOB2 (ret, tc16_catch_closure, handler, handler_data);
132 SCM_SET_SMOB_FLAGS (ret, CATCH_CLOSURE_HANDLER);
133 return ret;
134}
43e01b1e 135
416f26c7
AW
136static SCM
137apply_catch_closure (SCM clo, SCM args)
138{
139 void *data = (void*)SCM_SMOB_DATA_2 (clo);
650fa1ab 140
416f26c7
AW
141 switch (SCM_SMOB_FLAGS (clo))
142 {
143 case CATCH_CLOSURE_BODY:
144 {
145 scm_t_catch_body body = (void*)SCM_SMOB_DATA (clo);
146 return body (data);
147 }
148 case CATCH_CLOSURE_HANDLER:
149 {
150 scm_t_catch_handler handler = (void*)SCM_SMOB_DATA (clo);
151 return handler (data, scm_car (args), scm_cdr (args));
152 }
153 default:
154 abort ();
155 }
156}
650fa1ab 157
416f26c7 158/* TAG is the catch tag. Typically, this is a symbol, but this
650fa1ab
JB
159 function doesn't actually care about that.
160
161 BODY is a pointer to a C function which runs the body of the catch;
162 this is the code you can throw from. We call it like this:
19b27fa2 163 BODY (BODY_DATA)
650fa1ab 164 where:
816a6f06
JB
165 BODY_DATA is just the BODY_DATA argument we received; we pass it
166 through to BODY as its first argument. The caller can make
167 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
168
169 HANDLER is a pointer to a C function to deal with a throw to TAG,
170 should one occur. We call it like this:
86327304 171 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 172 where
816a6f06
JB
173 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
174 same idea as BODY_DATA above.
86327304
JB
175 THROWN_TAG is the tag that the user threw to; usually this is
176 TAG, but it could be something else if TAG was #t (i.e., a
177 catch-all), or the user threw to a jmpbuf.
650fa1ab 178 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 179 function, after the tag.
650fa1ab 180
3eed3475
JB
181 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
182 is just a pointer we pass through to HANDLER. We don't actually
183 use either of those pointers otherwise ourselves. The idea is
184 that, if our caller wants to communicate something to BODY or
185 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
186 HANDLER can then use. Think of it as a way to make BODY and
187 HANDLER closures, not just functions; MUMBLE_DATA points to the
188 enclosed variables.
189
190 Of course, it's up to the caller to make sure that any data a
191 MUMBLE_DATA needs is protected from GC. A common way to do this is
192 to make MUMBLE_DATA a pointer to data stored in an automatic
193 structure variable; since the collector must scan the stack for
194 references anyway, this assures that any references in MUMBLE_DATA
195 will be found. */
650fa1ab 196
0f2d19dd 197SCM
43e01b1e
NJ
198scm_c_catch (SCM tag,
199 scm_t_catch_body body, void *body_data,
200 scm_t_catch_handler handler, void *handler_data,
201 scm_t_catch_handler pre_unwind_handler, void *pre_unwind_handler_data)
0f2d19dd 202{
416f26c7
AW
203 SCM sbody, shandler, spre_unwind_handler;
204
205 sbody = make_catch_body_closure (body, body_data);
206 shandler = make_catch_handler_closure (handler, handler_data);
207 if (pre_unwind_handler)
208 spre_unwind_handler = make_catch_handler_closure (pre_unwind_handler,
209 pre_unwind_handler_data);
0f2d19dd 210 else
416f26c7
AW
211 spre_unwind_handler = SCM_UNDEFINED;
212
213 return scm_catch_with_pre_unwind_handler (tag, sbody, shandler,
214 spre_unwind_handler);
0f2d19dd
JB
215}
216
43e01b1e
NJ
217SCM
218scm_internal_catch (SCM tag,
219 scm_t_catch_body body, void *body_data,
220 scm_t_catch_handler handler, void *handler_data)
221{
416f26c7
AW
222 return scm_c_catch (tag,
223 body, body_data,
224 handler, handler_data,
225 NULL, NULL);
18eadcbe
JB
226}
227
18eadcbe 228
18eadcbe 229SCM
43e01b1e
NJ
230scm_c_with_throw_handler (SCM tag,
231 scm_t_catch_body body,
232 void *body_data,
233 scm_t_catch_handler handler,
234 void *handler_data,
235 int lazy_catch_p)
18eadcbe 236{
416f26c7 237 SCM sbody, shandler;
18eadcbe 238
e10cf6b9
AW
239 if (lazy_catch_p)
240 scm_c_issue_deprecation_warning
241 ("The LAZY_CATCH_P argument to `scm_c_with_throw_handler' is no longer.\n"
242 "supported. Instead the handler will be invoked from within the dynamic\n"
243 "context of the corresponding `throw'.\n"
244 "\nTHIS COULD CHANGE YOUR PROGRAM'S BEHAVIOR.\n\n"
245 "Please modify your program to pass 0 as the LAZY_CATCH_P argument,\n"
246 "and adapt it (if necessary) to expect to be within the dynamic context\n"
247 "of the throw.");
248
416f26c7
AW
249 sbody = make_catch_body_closure (body, body_data);
250 shandler = make_catch_handler_closure (handler, handler_data);
251
252 return scm_with_throw_handler (tag, sbody, shandler);
18eadcbe
JB
253}
254
95384717 255\f
95384717 256/* body and handler functions for use with any of the above catch variants */
18eadcbe 257
816a6f06 258/* This is a body function you can pass to scm_internal_catch if you
492960a4 259 want the body to be like Scheme's `catch' --- a thunk.
650fa1ab 260
74229f75
JB
261 BODY_DATA is a pointer to a scm_body_thunk_data structure, which
262 contains the Scheme procedure to invoke as the body, and the tag
492960a4 263 we're catching. */
650fa1ab 264
816a6f06 265SCM
6e8d25a6 266scm_body_thunk (void *body_data)
650fa1ab 267{
816a6f06 268 struct scm_body_thunk_data *c = (struct scm_body_thunk_data *) body_data;
650fa1ab 269
fdc28395 270 return scm_call_0 (c->body_proc);
650fa1ab
JB
271}
272
273
74229f75 274/* This is a handler function you can pass to scm_internal_catch if
4dd8323f
JB
275 you want the handler to act like Scheme's catch: (throw TAG ARGS ...)
276 applies a handler procedure to (TAG ARGS ...).
74229f75
JB
277
278 If the user does a throw to this catch, this function runs a
816a6f06
JB
279 handler procedure written in Scheme. HANDLER_DATA is a pointer to
280 an SCM variable holding the Scheme procedure object to invoke. It
74229f75
JB
281 ought to be a pointer to an automatic variable (i.e., one living on
282 the stack), or the procedure object should be otherwise protected
283 from GC. */
816a6f06 284SCM
6e8d25a6 285scm_handle_by_proc (void *handler_data, SCM tag, SCM throw_args)
650fa1ab 286{
816a6f06 287 SCM *handler_proc_p = (SCM *) handler_data;
650fa1ab 288
fdc28395 289 return scm_apply_1 (*handler_proc_p, tag, throw_args);
650fa1ab
JB
290}
291
1345df5d
MV
292/* SCM_HANDLE_BY_PROC_CATCHING_ALL is like SCM_HANDLE_BY_PROC but
293 catches all throws that the handler might emit itself. The handler
294 used for these `secondary' throws is SCM_HANDLE_BY_MESSAGE_NO_EXIT. */
295
296struct hbpca_data {
297 SCM proc;
298 SCM args;
299};
300
301static SCM
6e8d25a6 302hbpca_body (void *body_data)
1345df5d
MV
303{
304 struct hbpca_data *data = (struct hbpca_data *)body_data;
fdc28395 305 return scm_apply_0 (data->proc, data->args);
1345df5d
MV
306}
307
308SCM
6e8d25a6 309scm_handle_by_proc_catching_all (void *handler_data, SCM tag, SCM throw_args)
1345df5d
MV
310{
311 SCM *handler_proc_p = (SCM *) handler_data;
312 struct hbpca_data data;
313 data.proc = *handler_proc_p;
314 data.args = scm_cons (tag, throw_args);
315
316 return scm_internal_catch (SCM_BOOL_T,
317 hbpca_body, &data,
318 scm_handle_by_message_noexit, NULL);
319}
650fa1ab 320
f032b8a8
JB
321/* Derive the an exit status from the arguments to (quit ...). */
322int
6e8d25a6 323scm_exit_status (SCM args)
f032b8a8 324{
58e68be4 325 if (scm_is_pair (args))
f032b8a8
JB
326 {
327 SCM cqa = SCM_CAR (args);
328
e11e83f3
MV
329 if (scm_is_integer (cqa))
330 return (scm_to_int (cqa));
7888309b 331 else if (scm_is_false (cqa))
4765b28f 332 return EXIT_FAILURE;
58e68be4
AW
333 else
334 return EXIT_SUCCESS;
f032b8a8 335 }
58e68be4
AW
336 else if (scm_is_null (args))
337 return EXIT_SUCCESS;
338 else
339 /* A type error. Strictly speaking we shouldn't get here. */
340 return EXIT_FAILURE;
f032b8a8
JB
341}
342
74229f75 343
e0c70a8b
AW
344static int
345should_print_backtrace (SCM tag, SCM stack)
346{
347 return SCM_BACKTRACE_P
348 && scm_is_true (stack)
349 && scm_initialized_p
350 /* It's generally not useful to print backtraces for errors reading
351 or expanding code in these fallback catch statements. */
352 && !scm_is_eq (tag, scm_from_latin1_symbol ("read-error"))
353 && !scm_is_eq (tag, scm_from_latin1_symbol ("syntax-error"));
354}
355
f032b8a8
JB
356static void
357handler_message (void *handler_data, SCM tag, SCM args)
e68b42c1 358{
e0c70a8b 359 SCM p, stack, frame;
650fa1ab 360
e0c70a8b 361 p = scm_current_error_port ();
39d41afe
AW
362 /* Usually we get here via a throw to a catch-all. In that case
363 there is the throw frame active, and the catch closure, so narrow by
364 two frames. It is possible for a user to invoke
365 scm_handle_by_message directly, though, so it could be this
366 narrows too much. We'll have to see how this works out in
367 practice. */
368 stack = scm_make_stack (SCM_BOOL_T, scm_list_1 (scm_from_int (2)));
e0c70a8b 369 frame = scm_is_true (stack) ? scm_stack_ref (stack, SCM_INUM0) : SCM_BOOL_F;
eeb48bc2 370
e0c70a8b 371 if (should_print_backtrace (tag, stack))
74229f75 372 {
0607ebbf 373 scm_puts_unlocked ("Backtrace:\n", p);
e0c70a8b
AW
374 scm_display_backtrace_with_highlights (stack, p,
375 SCM_BOOL_F, SCM_BOOL_F,
376 SCM_EOL);
377 scm_newline (p);
74229f75 378 }
f64056d1 379
e0c70a8b 380 scm_print_exception (p, frame, tag, args);
f032b8a8
JB
381}
382
383
384/* This is a handler function to use if you want scheme to print a
385 message and die. Useful for dealing with throws to uncaught keys
386 at the top level.
387
388 At boot time, we establish a catch-all that uses this as its handler.
389 1) If the user wants something different, they can use (catch #t
390 ...) to do what they like.
391 2) Outside the context of a read-eval-print loop, there isn't
392 anything else good to do; libguile should not assume the existence
393 of a read-eval-print loop.
394 3) Given that we shouldn't do anything complex, it's much more
395 robust to do it in C code.
396
397 HANDLER_DATA, if non-zero, is assumed to be a char * pointing to a
398 message header to print; if zero, we use "guile" instead. That
399 text is followed by a colon, then the message described by ARGS. */
400
5a2a5407
DH
401/* Dirk:FIXME:: The name of the function should make clear that the
402 * application gets terminated.
403 */
404
f032b8a8 405SCM
6e8d25a6 406scm_handle_by_message (void *handler_data, SCM tag, SCM args)
f032b8a8 407{
4a655e50 408 if (scm_is_true (scm_eq_p (tag, scm_from_latin1_symbol ("quit"))))
9de87eea 409 exit (scm_exit_status (args));
f032b8a8
JB
410
411 handler_message (handler_data, tag, args);
9de87eea 412 scm_i_pthread_exit (NULL);
23f2b9a3
KR
413
414 /* this point not reached, but suppress gcc warning about no return value
415 in case scm_i_pthread_exit isn't marked as "noreturn" (which seemed not
416 to be the case on cygwin for instance) */
417 return SCM_BOOL_F;
74229f75
JB
418}
419
420
f032b8a8
JB
421/* This is just like scm_handle_by_message, but it doesn't exit; it
422 just returns #f. It's useful in cases where you don't really know
423 enough about the body to handle things in a better way, but don't
424 want to let throws fall off the bottom of the wind list. */
425SCM
6e8d25a6 426scm_handle_by_message_noexit (void *handler_data, SCM tag, SCM args)
74229f75 427{
4a655e50 428 if (scm_is_true (scm_eq_p (tag, scm_from_latin1_symbol ("quit"))))
9de87eea
MV
429 exit (scm_exit_status (args));
430
f032b8a8
JB
431 handler_message (handler_data, tag, args);
432
433 return SCM_BOOL_F;
e68b42c1
MD
434}
435
3eed3475 436
e158e4f4 437SCM
e81d98ec 438scm_handle_by_throw (void *handler_data SCM_UNUSED, SCM tag, SCM args)
e158e4f4
MD
439{
440 scm_ithrow (tag, args, 1);
441 return SCM_UNSPECIFIED; /* never returns */
442}
443
43e01b1e 444SCM
36c40440 445scm_ithrow (SCM key, SCM args, int no_return SCM_UNUSED)
ad310508 446{
416f26c7 447 return scm_throw (key, args);
ad310508
MD
448}
449
416f26c7
AW
450/* Unfortunately we have to support catch and throw before boot-9 has, um,
451 booted. So here are lame versions, which will get replaced with their scheme
452 equivalents. */
c6a32a2c
AW
453
454SCM_SYMBOL (sym_pre_init_catch_tag, "%pre-init-catch-tag");
455
416f26c7
AW
456static SCM
457pre_init_catch (SCM tag, SCM thunk, SCM handler, SCM pre_unwind_handler)
0f2d19dd 458{
4fcbc1b0
AW
459 struct scm_vm *vp;
460 volatile SCM v_handler;
9ede013f 461 SCM res;
9ede013f 462 scm_t_dynstack *dynstack = &SCM_I_CURRENT_THREAD->dynstack;
9d381ba4 463 scm_i_jmp_buf registers;
492960a4 464
416f26c7
AW
465 /* Only handle catch-alls without pre-unwind handlers */
466 if (!SCM_UNBNDP (pre_unwind_handler))
467 abort ();
468 if (scm_is_false (scm_eqv_p (tag, SCM_BOOL_T)))
d6580119 469 abort ();
43e01b1e 470
9ede013f
AW
471 /* These two are volatile, so we know we can access them after a
472 nonlocal return to the setjmp. */
e7f9abab 473 vp = scm_the_vm ();
9ede013f 474 v_handler = handler;
43e01b1e 475
9ede013f 476 /* Push the prompt onto the dynamic stack. */
9d381ba4 477 scm_dynstack_push_prompt (dynstack,
c6cd692f
AW
478 SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY
479 | SCM_F_DYNSTACK_PROMPT_PUSH_NARGS,
9d381ba4 480 sym_pre_init_catch_tag,
4fcbc1b0
AW
481 vp->fp - vp->stack_base,
482 vp->sp - vp->stack_base,
483 vp->ip,
9d381ba4
AW
484 &registers);
485
486 if (SCM_I_SETJMP (registers))
416f26c7
AW
487 {
488 /* nonlocal exit */
4fcbc1b0
AW
489 SCM args;
490 /* vp is not volatile */
e7f9abab 491 vp = scm_the_vm ();
4fcbc1b0 492 args = scm_i_prompt_pop_abort_args_x (vp);
416f26c7 493 /* cdr past the continuation */
9ede013f 494 return scm_apply_0 (v_handler, scm_cdr (args));
11702758 495 }
3eed3475 496
416f26c7 497 res = scm_call_0 (thunk);
9ede013f 498 scm_dynstack_pop (dynstack);
346e4402 499
416f26c7 500 return res;
0f2d19dd
JB
501}
502
5a588521
AW
503static int
504find_pre_init_catch (void)
505{
9ede013f 506 if (scm_dynstack_find_prompt (&SCM_I_CURRENT_THREAD->dynstack,
9d381ba4
AW
507 sym_pre_init_catch_tag,
508 NULL, NULL, NULL, NULL, NULL))
9ede013f 509 return 1;
5a588521
AW
510
511 return 0;
512}
513
416f26c7 514static SCM
5a588521 515pre_init_throw (SCM k, SCM args)
416f26c7 516{
5a588521 517 if (find_pre_init_catch ())
1773bc7d 518 return scm_abort_to_prompt_star (sym_pre_init_catch_tag, scm_cons (k, args));
5a588521
AW
519 else
520 {
cd4f274c
AW
521 static int error_printing_error = 0;
522 static int error_printing_fallback = 0;
523
524 if (error_printing_fallback)
525 fprintf (stderr, "\nFailed to print exception.\n");
526 else if (error_printing_error)
527 {
528 fprintf (stderr, "\nError while printing exception:\n");
529 error_printing_fallback = 1;
530 fprintf (stderr, "Key: ");
531 scm_write (k, scm_current_error_port ());
532 fprintf (stderr, ", args: ");
533 scm_write (args, scm_current_error_port ());
534 scm_newline (scm_current_error_port ());
535 }
536 else
537 {
538 fprintf (stderr, "Throw without catch before boot:\n");
539 error_printing_error = 1;
540 scm_handle_by_message_noexit (NULL, k, args);
541 }
542
e7450642
AW
543 fprintf (stderr, "Aborting.\n");
544 abort ();
5a588521
AW
545 return SCM_BOOL_F; /* not reached */
546 }
416f26c7 547}
0f2d19dd 548
0f2d19dd
JB
549void
550scm_init_throw ()
0f2d19dd 551{
416f26c7
AW
552 tc16_catch_closure = scm_make_smob_type ("catch-closure", 0);
553 scm_set_smob_apply (tc16_catch_closure, apply_catch_closure, 0, 0, 1);
e841c3e0 554
416f26c7 555 scm_c_define ("catch", scm_c_make_gsubr ("catch", 3, 1, 0, pre_init_catch));
5a588521 556 scm_c_define ("throw", scm_c_make_gsubr ("throw", 1, 0, 1, pre_init_throw));
e841c3e0 557
a0599745 558#include "libguile/throw.x"
0f2d19dd 559}
89e00824
ML
560
561/*
562 Local Variables:
563 c-file-style: "gnu"
564 End:
565*/