* print.h (SCM_PRINT_STATE_P, SCM_COERCE_OPORT): New macros.
[bpt/guile.git] / libguile / root.c
CommitLineData
0f2d19dd
JB
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
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. */
0f2d19dd
JB
41\f
42
43#include <stdio.h>
44#include "_scm.h"
20e6290e 45#include "stackchk.h"
d564d753
MD
46#include "dynwind.h"
47#include "eval.h"
48#include "genio.h"
49#include "smob.h"
50#include "pairs.h"
51#include "throw.h"
d9dfcf80 52#include "fluids.h"
0f2d19dd 53
20e6290e 54#include "root.h"
0f2d19dd
JB
55\f
56
57SCM scm_sys_protects[SCM_NUM_PROTECTS];
d564d753
MD
58
59long scm_tc16_root;
60
61#ifndef USE_THREADS
62struct scm_root_state *scm_root;
63#endif
0f2d19dd
JB
64
65\f
66
d564d753
MD
67static SCM mark_root SCM_P ((SCM));
68
69static SCM
70mark_root (root)
71 SCM root;
72{
73 scm_root_state *s = SCM_ROOT_STATE (root);
74 SCM_SETGC8MARK (root);
75 scm_gc_mark (s->rootcont);
76 scm_gc_mark (s->dynwinds);
77 scm_gc_mark (s->continuation_stack);
78 scm_gc_mark (s->continuation_stack_ptr);
79 scm_gc_mark (s->progargs);
80 scm_gc_mark (s->exitval);
81 scm_gc_mark (s->cur_inp);
82 scm_gc_mark (s->cur_outp);
83 scm_gc_mark (s->cur_errp);
84 scm_gc_mark (s->def_inp);
85 scm_gc_mark (s->def_outp);
86 scm_gc_mark (s->def_errp);
d9dfcf80 87 scm_gc_mark (s->fluids);
dc19d1d2 88 scm_gc_mark (s->top_level_lookup_closure_var);
d564d753 89 scm_gc_mark (s->system_transformer);
5aab5d96 90 scm_gc_mark (s->the_last_stack_var);
d564d753
MD
91 return SCM_ROOT_STATE (root) -> parent;
92}
0f2d19dd 93
d564d753
MD
94static scm_sizet free_root SCM_P ((SCM));
95
96static scm_sizet
97free_root (root)
98 SCM root;
99{
100 scm_must_free ((char *) SCM_ROOT_STATE (root));
101 return sizeof (scm_root_state);
102}
103
104static int print_root SCM_P ((SCM exp, SCM port, scm_print_state *pstate));
105
106static int
107print_root (exp, port, pstate)
108 SCM exp;
109 SCM port;
110 scm_print_state *pstate;
111{
112 scm_gen_puts (scm_regular_string, "#<root ", port);
113 scm_intprint(SCM_SEQ (SCM_ROOT_STATE (exp) -> rootcont), 16, port);
114 scm_gen_putc('>', port);
115 return 1;
116}
117
118static scm_smobfuns root_smob =
119{
120 mark_root,
121 free_root,
122 print_root,
123 0
124};
125
126\f
127
128SCM
129scm_make_root (parent)
130 SCM parent;
131{
132 SCM root;
133 scm_root_state *root_state;
134
135 root_state = (scm_root_state *) scm_must_malloc (sizeof (scm_root_state),
136 "scm_make_root");
137 if (SCM_NIMP (parent) && SCM_ROOTP (parent))
138 {
139 memcpy (root_state, SCM_ROOT_STATE (parent), sizeof (scm_root_state));
d9dfcf80 140 scm_copy_fluids (root_state);
d564d753
MD
141 root_state->parent = parent;
142 }
143 else
144 {
145 root_state->parent = SCM_BOOL_F;
146 }
147 SCM_NEWCELL (root);
148 SCM_REDEFER_INTS;
149 SCM_SETCAR (root, scm_tc16_root);
150 SCM_SETCDR (root, root_state);
151 root_state->handle = root;
152 SCM_REALLOW_INTS;
153 return root;
154}
155
1cc91f1b 156/* {call-with-dynamic-root}
d564d753
MD
157 *
158 * Suspending the current thread to evaluate a thunk on the
159 * same C stack but under a new root.
160 *
1cc91f1b 161 * Calls to call-with-dynamic-root return exactly once (unless
d564d753
MD
162 * the process is somehow exitted).
163 */
164
650fa1ab
JB
165/* Some questions about cwdr:
166
167 Couldn't the body just be a closure? Do we really need to pass
168 args through to it?
169
170 The semantics are a lot like catch's; in fact, we call
171 scm_internal_catch to take care of that part of things. Wouldn't
172 it be cleaner to say that uncaught throws just disappear into the
173 ether (or print a message to stderr), and let the caller use catch
174 themselves if they want to?
175
176 -JimB */
177
d564d753
MD
178#if 0
179SCM scm_exitval; /* INUM with return value */
180#endif
181static int n_dynamic_roots = 0;
182
650fa1ab
JB
183
184/* cwdr fills out one of these structures, and then passes a pointer
816a6f06
JB
185 to it through scm_internal_catch to the cwdr_body function, to tell
186 it how to behave.
650fa1ab
JB
187
188 A cwdr is a lot like a catch, except there is no tag (all
189 exceptions are caught), and the body procedure takes the arguments
190 passed to cwdr as A1 and ARGS. */
191
192struct cwdr_body_data {
650fa1ab
JB
193 /* Arguments to pass to the cwdr body function. */
194 SCM a1, args;
195
196 /* Scheme procedure to use as body of cwdr. */
197 SCM body_proc;
f032b8a8
JB
198
199 /* Scheme handler function to establish. */
200 SCM handler;
650fa1ab
JB
201};
202
203
204/* Invoke the body of a cwdr, assuming that the throw handler has
205 already been set up. DATA points to a struct set up by cwdr that
816a6f06
JB
206 says what proc to call, and what args to apply it to.
207
208 With a little thought, we could replace this with scm_body_thunk,
209 but I don't want to mess with that at the moment. */
650fa1ab 210static SCM
f032b8a8 211cwdr_inner_body (void *data, SCM jmpbuf)
650fa1ab
JB
212{
213 struct cwdr_body_data *c = (struct cwdr_body_data *) data;
214
215 return scm_apply (c->body_proc, c->a1, c->args);
216}
217
218
f032b8a8
JB
219/* Invoke the body of a cwdr, assuming that the last-ditch handler has
220 been established. The structure DATA points to must live on the
221 stack, or else it won't be found by the GC. Establish the user's
222 handler, and pass control to cwdr_inner_body, which will invoke the
223 users' body. Maybe the user has a nice body. */
224static SCM
225cwdr_outer_body (void *data, SCM jmpbuf)
226{
227 struct cwdr_body_data *c = (struct cwdr_body_data *) data;
228
229 return scm_internal_catch (SCM_BOOL_T,
beec890e 230 cwdr_inner_body, c,
f032b8a8
JB
231 scm_handle_by_proc, &c->handler);
232}
d564d753
MD
233
234/* This is the basic code for new root creation.
235 *
236 * WARNING! The order of actions in this routine is in many ways
237 * critical. E. g., it is essential that an error doesn't leave Guile
650fa1ab 238 * in a messed up state. */
d564d753
MD
239
240static SCM
f032b8a8 241cwdr (SCM proc, SCM a1, SCM args, SCM handler, SCM_STACKITEM *stack_start)
d564d753
MD
242{
243 int old_ints_disabled = scm_ints_disabled;
8938d022 244 SCM old_rootcont, old_winds;
d564d753
MD
245 SCM answer;
246
d564d753
MD
247 /* Create a fresh root continuation.
248 */
249 {
250 SCM new_rootcont;
251 SCM_NEWCELL (new_rootcont);
252 SCM_REDEFER_INTS;
253 SCM_SETJMPBUF (new_rootcont,
0db18cf4 254 scm_must_malloc ((long) sizeof (scm_contregs),
d564d753 255 "inferior root continuation"));
a6c64c3c 256 SCM_SETCAR (new_rootcont, scm_tc7_contin);
d564d753
MD
257 SCM_DYNENV (new_rootcont) = SCM_EOL;
258 SCM_BASE (new_rootcont) = stack_start;
8938d022 259 SCM_SEQ (new_rootcont) = ++n_dynamic_roots;
d564d753
MD
260#ifdef DEBUG_EXTENSIONS
261 SCM_DFRAME (new_rootcont) = 0;
262#endif
8938d022
MD
263 old_rootcont = scm_rootcont;
264 scm_rootcont = new_rootcont;
d564d753
MD
265 SCM_REALLOW_INTS;
266 }
267
8938d022
MD
268 /* Exit caller's dynamic state.
269 */
270 old_winds = scm_dynwinds;
271 scm_dowinds (SCM_EOL, scm_ilength (scm_dynwinds));
d564d753 272#ifdef DEBUG_EXTENSIONS
308277cb 273 SCM_DFRAME (old_rootcont) = scm_last_debug_frame;
8938d022 274 scm_last_debug_frame = 0;
d564d753 275#endif
d564d753 276
f032b8a8
JB
277 /* Catch absolutely all errors. We actually use
278 scm_handle_by_message_noexit here, and then install HANDLER in
279 cwdr_outer_body, because HANDLER might encounter errors itself. */
650fa1ab
JB
280 {
281 struct cwdr_body_data c;
282
283 c.a1 = a1;
284 c.args = args;
285 c.body_proc = proc;
f032b8a8 286 c.handler = handler;
650fa1ab 287
816a6f06 288 answer = scm_internal_catch (SCM_BOOL_T,
f032b8a8
JB
289 cwdr_outer_body, &c,
290 scm_handle_by_message_noexit, 0);
650fa1ab 291 }
d564d753
MD
292
293 scm_dowinds (old_winds, - scm_ilength (old_winds));
294 SCM_REDEFER_INTS;
d564d753 295#ifdef DEBUG_EXTENSIONS
308277cb 296 scm_last_debug_frame = SCM_DFRAME (old_rootcont);
d564d753 297#endif
308277cb 298 scm_rootcont = old_rootcont;
d564d753
MD
299 SCM_REALLOW_INTS;
300 scm_ints_disabled = old_ints_disabled;
301 return answer;
302}
303
304
8938d022 305SCM_PROC(s_call_with_dynamic_root, "call-with-dynamic-root", 2, 0, 0, scm_call_with_dynamic_root);
d564d753 306SCM
8938d022 307scm_call_with_dynamic_root (thunk, handler)
d564d753
MD
308 SCM thunk;
309 SCM handler;
d564d753
MD
310{
311 SCM_STACKITEM stack_place;
312
8938d022 313 return cwdr (thunk, SCM_EOL, SCM_EOL, handler, &stack_place);
d564d753
MD
314}
315
316SCM_PROC(s_dynamic_root, "dynamic-root", 0, 0, 0, scm_dynamic_root);
d564d753
MD
317SCM
318scm_dynamic_root ()
d564d753
MD
319{
320 return scm_ulong2num (SCM_SEQ (scm_root->rootcont));
321}
322
d564d753 323SCM
8938d022 324scm_apply_with_dynamic_root (proc, a1, args, handler)
d564d753
MD
325 SCM proc;
326 SCM a1;
327 SCM args;
1cc91f1b 328 SCM handler;
d564d753
MD
329{
330 SCM_STACKITEM stack_place;
8938d022 331 return cwdr (proc, a1, args, handler, &stack_place);
d564d753 332}
0f2d19dd
JB
333
334\f
335
336/* Call thunk(closure) underneath a top-level error handler.
337 * If an error occurs, pass the exitval through err_filter and return it.
338 * If no error occurs, return the value of thunk.
339 */
340
341
342#ifdef _UNICOS
343typedef int setjmp_type;
344#else
345typedef long setjmp_type;
346#endif
347
348
1cc91f1b 349
0f2d19dd
JB
350SCM
351scm_call_catching_errors (thunk, err_filter, closure)
352 SCM (*thunk)();
353 SCM (*err_filter)();
d564d753 354 void *closure;
0f2d19dd
JB
355{
356 SCM answer;
357 setjmp_type i;
faa6b3df 358#ifdef DEBUG_EXTENSIONS
8938d022 359 SCM_DFRAME (scm_rootcont) = scm_last_debug_frame;
faa6b3df 360#endif
0f2d19dd 361 i = setjmp (SCM_JMPBUF (scm_rootcont));
faa6b3df 362 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
0f2d19dd
JB
363 if (!i)
364 {
365 scm_gc_heap_lock = 0;
366 answer = thunk (closure);
367 }
368 else
369 {
370 scm_gc_heap_lock = 1;
371 answer = err_filter (scm_exitval, closure);
372 }
373 return answer;
374}
375
d564d753
MD
376void
377scm_init_root ()
378{
379 scm_tc16_root = scm_newsmob (&root_smob);
380#include "root.x"
381}