2001-12-08 Stefan Jahn <stefan@lkcc.org>
[bpt/guile.git] / libguile / stacks.c
CommitLineData
782d171c 1/* Representation of stack frame debug information
13dcb666 2 * Copyright (C) 1996,1997,2000,2001 Free Software Foundation
782d171c
MD
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; see the file COPYING. If not, write to
82892bed
JB
16 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307 USA
782d171c
MD
18 *
19 * As a special exception, the Free Software Foundation gives permission
20 * for additional uses of the text contained in its release of GUILE.
21 *
22 * The exception is that, if you link the GUILE library with other files
23 * to produce an executable, this does not by itself cause the
24 * resulting executable to be covered by the GNU General Public License.
25 * Your use of that executable is in no way restricted on account of
26 * linking the GUILE library code into it.
27 *
28 * This exception does not however invalidate any other reasons why
29 * the executable file might be covered by the GNU General Public License.
30 *
31 * This exception applies only to the code released by the
32 * Free Software Foundation under the name GUILE. If you copy
33 * code from other Free Software Foundation releases into a copy of
34 * GUILE, as the General Public License permits, the exception does
35 * not apply to the code that you add in this way. To avoid misleading
36 * anyone as to the status of such modified files, you must delete
37 * this exception notice from them.
38 *
39 * If you write modifications of your own for GUILE, it is your choice
40 * whether to permit this exception to apply to your modifications.
41 * If you do not wish that, delete this exception notice.
42 *
43 * The author can be reached at djurfeldt@nada.kth.se
82892bed 44 * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
1bbd0b84 45
1bbd0b84 46
782d171c
MD
47\f
48
a0599745
MD
49#include "libguile/_scm.h"
50#include "libguile/eval.h"
51#include "libguile/debug.h"
52#include "libguile/continuations.h"
53#include "libguile/struct.h"
54#include "libguile/macros.h"
55#include "libguile/procprop.h"
56#include "libguile/modules.h"
57#include "libguile/root.h"
58#include "libguile/strings.h"
59
60#include "libguile/validate.h"
61#include "libguile/stacks.h"
782d171c
MD
62
63\f
64/* {Frames and stacks}
65 *
66 * The debugging evaluator creates debug frames on the stack. These
67 * are linked from the innermost frame and outwards. The last frame
68 * created can always be accessed as SCM_LAST_DEBUG_FRAME.
69 * Continuations contain a pointer to the innermost debug frame on the
70 * continuation stack.
71 *
72 * Each debug frame contains a set of flags and information about one
73 * or more stack frames. The case of multiple frames occurs due to
74 * tail recursion. The maximal number of stack frames which can be
75 * recorded in one debug frame can be set dynamically with the debug
76 * option FRAMES.
77 *
78 * Stack frame information is of two types: eval information (the
79 * expression being evaluated and its environment) and apply
80 * information (the procedure being applied and its arguments). A
81 * stack frame normally corresponds to an eval/apply pair, but macros
82 * and special forms (which are implemented as macros in Guile) only
83 * have eval information and apply calls leads to apply only frames.
84 *
85 * Since we want to record the total stack information and later
86 * manipulate this data at the scheme level in the debugger, we need
87 * to transform it into a new representation. In the following code
88 * section you'll find the functions implementing this data type.
89 *
90 * Representation:
91 *
7115d1e4 92 * The stack is represented as a struct with an id slot and a tail
92c2555f 93 * array of scm_t_info_frame structs.
782d171c
MD
94 *
95 * A frame is represented as a pair where the car contains a stack and
96 * the cdr an inum. The inum is an index to the first SCM value of
92c2555f 97 * the scm_t_info_frame struct.
782d171c
MD
98 *
99 * Stacks
100 * Constructor
101 * make-stack
7115d1e4
MD
102 * Selectors
103 * stack-id
782d171c
MD
104 * stack-ref
105 * Inspector
106 * stack-length
107 *
108 * Frames
109 * Constructor
110 * last-stack-frame
111 * Selectors
112 * frame-number
113 * frame-source
114 * frame-procedure
115 * frame-arguments
116 * frame-previous
117 * frame-next
118 * Predicates
119 * frame-real?
120 * frame-procedure?
121 * frame-evaluating-args?
7115d1e4 122 * frame-overflow? */
782d171c
MD
123
124\f
125
126/* Some auxiliary functions for reading debug frames off the stack.
127 */
128
c0ab1b8d 129/* Stacks often contain pointers to other items on the stack; for
92c2555f 130 example, each scm_t_debug_frame structure contains a pointer to the
c0ab1b8d
JB
131 next frame out. When we capture a continuation, we copy the stack
132 into the heap, and just leave all the pointers unchanged. This
133 makes it simple to restore the continuation --- just copy the stack
134 back! However, if we retrieve a pointer from the heap copy to
135 another item that was originally on the stack, we have to add an
136 offset to the pointer to discover the new referent.
137
138 If PTR is a pointer retrieved from a continuation, whose original
139 target was on the stack, and OFFSET is the appropriate offset from
140 the original stack to the continuation, then RELOC_MUMBLE (PTR,
141 OFFSET) is a pointer to the copy in the continuation of the
142 original referent, cast to an scm_debug_MUMBLE *. */
143#define RELOC_INFO(ptr, offset) \
92c2555f 144 ((scm_t_debug_info *) ((SCM_STACKITEM *) (ptr) + (offset)))
c0ab1b8d 145#define RELOC_FRAME(ptr, offset) \
92c2555f 146 ((scm_t_debug_frame *) ((SCM_STACKITEM *) (ptr) + (offset)))
c0ab1b8d
JB
147
148
782d171c
MD
149/* Count number of debug info frames on a stack, beginning with
150 * DFRAME. OFFSET is used for relocation of pointers when the stack
151 * is read from a continuation.
152 */
92c2555f
MV
153static scm_t_bits
154stack_depth (scm_t_debug_frame *dframe,long offset,SCM *id,int *maxp)
782d171c 155{
c014a02e
ML
156 long n;
157 long max_depth = SCM_BACKTRACE_MAXDEPTH;
782d171c 158 for (n = 0;
66f45472 159 dframe && !SCM_VOIDFRAMEP (*dframe) && n < max_depth;
c0ab1b8d 160 dframe = RELOC_FRAME (dframe->prev, offset))
782d171c
MD
161 {
162 if (SCM_EVALFRAMEP (*dframe))
163 {
92c2555f 164 scm_t_debug_info * info = RELOC_INFO (dframe->info, offset);
782d171c
MD
165 n += (info - dframe->vect) / 2 + 1;
166 /* Data in the apply part of an eval info frame comes from previous
92c2555f 167 stack frame if the scm_t_debug_info vector is overflowed. */
782d171c
MD
168 if ((((info - dframe->vect) & 1) == 0)
169 && SCM_OVERFLOWP (*dframe)
170 && !SCM_UNBNDP (info[1].a.proc))
171 ++n;
172 }
173 else
174 ++n;
175 }
66f45472
MD
176 if (dframe && SCM_VOIDFRAMEP (*dframe))
177 *id = dframe->vect[0].id;
178 else if (dframe)
782d171c
MD
179 *maxp = 1;
180 return n;
181}
182
183/* Read debug info from DFRAME into IFRAME.
184 */
782d171c 185static void
92c2555f 186read_frame (scm_t_debug_frame *dframe,long offset,scm_t_info_frame *iframe)
782d171c 187{
92c2555f 188 scm_t_bits flags = SCM_UNPACK (SCM_INUM0); /* UGh. */
782d171c
MD
189 if (SCM_EVALFRAMEP (*dframe))
190 {
92c2555f 191 scm_t_debug_info * info = RELOC_INFO (dframe->info, offset);
782d171c
MD
192 if ((info - dframe->vect) & 1)
193 {
194 /* Debug.vect ends with apply info. */
195 --info;
54778cd3 196 if (!SCM_UNBNDP (info[1].a.proc))
782d171c
MD
197 {
198 flags |= SCM_FRAMEF_PROC;
199 iframe->proc = info[1].a.proc;
200 iframe->args = info[1].a.args;
201 if (!SCM_ARGS_READY_P (*dframe))
202 flags |= SCM_FRAMEF_EVAL_ARGS;
203 }
204 }
6629eb1c 205 iframe->source = scm_make_memoized (info[0].e.exp, info[0].e.env);
782d171c
MD
206 }
207 else
208 {
209 flags |= SCM_FRAMEF_PROC;
210 iframe->proc = dframe->vect[0].a.proc;
211 iframe->args = dframe->vect[0].a.args;
212 }
213 iframe->flags = flags;
214}
215
7a13c3ae
MD
216/* Look up the first body form of the apply closure. We'll use this
217 below to prevent it from being displayed.
218*/
219static SCM
220get_applybody ()
221{
86d31dfe
MV
222 SCM var = scm_sym2var (scm_sym_apply, SCM_BOOL_F, SCM_BOOL_F);
223 if (SCM_VARIABLEP (var) && SCM_CLOSUREP (SCM_VARIABLE_REF (var)))
224 return SCM_CADR (SCM_CODE (SCM_VARIABLE_REF (var)));
7a13c3ae
MD
225 else
226 return SCM_UNDEFINED;
227}
7115d1e4
MD
228
229#define NEXT_FRAME(iframe, n, quit) \
d3a6bc94 230do { \
13dcb666 231 if (SCM_MEMOIZEDP (iframe->source) \
54778cd3 232 && SCM_EQ_P (SCM_MEMOIZED_EXP (iframe->source), applybody)) \
7a13c3ae
MD
233 { \
234 iframe->source = SCM_BOOL_F; \
235 if (SCM_FALSEP (iframe->proc)) \
236 { \
237 --iframe; \
238 ++n; \
239 } \
240 } \
7115d1e4
MD
241 ++iframe; \
242 if (--n == 0) \
243 goto quit; \
d3a6bc94 244} while (0)
7115d1e4
MD
245
246
92c2555f 247/* Fill the scm_t_info_frame vector IFRAME with data from N stack frames
7a13c3ae
MD
248 * starting with the first stack frame represented by debug frame
249 * DFRAME.
250 */
251
92c2555f
MV
252static scm_t_bits
253read_frames (scm_t_debug_frame *dframe,long offset,long n,scm_t_info_frame *iframes)
782d171c 254{
92c2555f
MV
255 scm_t_info_frame *iframe = iframes;
256 scm_t_debug_info *info;
7a13c3ae 257 static SCM applybody = SCM_UNDEFINED;
782d171c 258
7a13c3ae
MD
259 /* The value of applybody has to be setup after r4rs.scm has executed. */
260 if (SCM_UNBNDP (applybody))
261 applybody = get_applybody ();
782d171c 262 for (;
66f45472 263 dframe && !SCM_VOIDFRAMEP (*dframe) && n > 0;
c0ab1b8d 264 dframe = RELOC_FRAME (dframe->prev, offset))
782d171c
MD
265 {
266 read_frame (dframe, offset, iframe);
267 if (SCM_EVALFRAMEP (*dframe))
268 {
6629eb1c
MD
269 /* If current frame is a macro during expansion, we should
270 skip the previously recorded macro transformer
271 application frame. */
272 if (SCM_MACROEXPP (*dframe) && iframe > iframes)
7c939801
MD
273 {
274 *(iframe - 1) = *iframe;
275 --iframe;
276 }
c0ab1b8d 277 info = RELOC_INFO (dframe->info, offset);
782d171c
MD
278 if ((info - dframe->vect) & 1)
279 --info;
280 /* Data in the apply part of an eval info frame comes from
13dcb666
DH
281 previous stack frame if the scm_t_debug_info vector is
282 overflowed. */
782d171c
MD
283 else if (SCM_OVERFLOWP (*dframe)
284 && !SCM_UNBNDP (info[1].a.proc))
285 {
7115d1e4 286 NEXT_FRAME (iframe, n, quit);
f1267706 287 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
782d171c
MD
288 iframe->proc = info[1].a.proc;
289 iframe->args = info[1].a.args;
290 }
291 if (SCM_OVERFLOWP (*dframe))
292 iframe->flags |= SCM_FRAMEF_OVERFLOW;
293 info -= 2;
7115d1e4 294 NEXT_FRAME (iframe, n, quit);
782d171c
MD
295 while (info >= dframe->vect)
296 {
297 if (!SCM_UNBNDP (info[1].a.proc))
298 {
f1267706 299 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
782d171c
MD
300 iframe->proc = info[1].a.proc;
301 iframe->args = info[1].a.args;
302 }
303 else
f1267706 304 iframe->flags = SCM_UNPACK (SCM_INUM0);
782d171c
MD
305 iframe->source = scm_make_memoized (info[0].e.exp,
306 info[0].e.env);
307 info -= 2;
7115d1e4 308 NEXT_FRAME (iframe, n, quit);
782d171c
MD
309 }
310 }
54778cd3 311 else if (SCM_EQ_P (iframe->proc, scm_f_gsubr_apply))
7c939801
MD
312 /* Skip gsubr apply frames. */
313 continue;
782d171c
MD
314 else
315 {
7115d1e4 316 NEXT_FRAME (iframe, n, quit);
782d171c
MD
317 }
318 quit:
319 if (iframe > iframes)
320 (iframe - 1) -> flags |= SCM_FRAMEF_REAL;
321 }
7c939801 322 return iframe - iframes; /* Number of frames actually read */
782d171c
MD
323}
324
c3a6c6f9
MD
325/* Narrow STACK by cutting away stackframes (mutatingly).
326 *
327 * Inner frames (most recent) are cut by advancing the frames pointer.
328 * Outer frames are cut by decreasing the recorded length.
329 *
330 * Cut maximally INNER inner frames and OUTER outer frames using
331 * the keys INNER_KEY and OUTER_KEY.
332 *
333 * Frames are cut away starting at the end points and moving towards
334 * the center of the stack. The key is normally compared to the
335 * operator in application frames. Frames up to and including the key
336 * are cut.
337 *
338 * If INNER_KEY is #t a different scheme is used for inner frames:
339 *
340 * Frames up to but excluding the first source frame originating from
341 * a user module are cut, except for possible application frames
342 * between the user frame and the last system frame previously
343 * encountered.
344 */
345
7115d1e4 346static void
c014a02e 347narrow_stack (SCM stack,long inner,SCM inner_key,long outer,SCM outer_key)
7115d1e4 348{
92c2555f 349 scm_t_stack *s = SCM_STACK (stack);
13dcb666 350 unsigned long int i;
c014a02e 351 long n = s->length;
7115d1e4
MD
352
353 /* Cut inner part. */
9a09deb1 354 if (SCM_EQ_P (inner_key, SCM_BOOL_T))
c3a6c6f9 355 {
13dcb666 356 /* Cut all frames up to user module code */
c3a6c6f9
MD
357 for (i = 0; inner; ++i, --inner)
358 {
359 SCM m = s->frames[i].source;
13dcb666
DH
360 if (SCM_MEMOIZEDP (m)
361 && !SCM_IMP (SCM_MEMOIZED_ENV (m))
9bba1435 362 && SCM_FALSEP (scm_system_module_env_p (SCM_MEMOIZED_ENV (m))))
c3a6c6f9
MD
363 {
364 /* Back up in order to include any non-source frames */
13dcb666 365 while (i > 0)
c3a6c6f9 366 {
13dcb666
DH
367 m = s->frames[i - 1].source;
368 if (SCM_MEMOIZEDP (m))
369 break;
370
371 m = s->frames[i - 1].proc;
372 if (!SCM_FALSEP (scm_procedure_p (m))
373 && !SCM_FALSEP (scm_procedure_property
374 (m, scm_sym_system_procedure)))
375 break;
376
c3a6c6f9
MD
377 --i;
378 ++inner;
379 }
380 break;
381 }
382 }
383 }
384 else
385 /* Use standard cutting procedure. */
386 {
387 for (i = 0; inner; --inner)
fee7ef83 388 if (SCM_EQ_P (s->frames[i++].proc, inner_key))
c3a6c6f9
MD
389 break;
390 }
7115d1e4
MD
391 s->frames = &s->frames[i];
392 n -= i;
393
394 /* Cut outer part. */
395 for (; n && outer; --outer)
fee7ef83 396 if (SCM_EQ_P (s->frames[--n].proc, outer_key))
7115d1e4
MD
397 break;
398
399 s->length = n;
400}
401
782d171c
MD
402\f
403
404/* Stacks
405 */
406
92c2555f 407SCM scm_t_stackype;
66f45472 408
a1ec6916 409SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
1bbd0b84 410 (SCM obj),
b380b885 411 "Return @code{#t} if @var{obj} is a calling stack.")
1bbd0b84 412#define FUNC_NAME s_scm_stack_p
66f45472 413{
0c95b57d 414 return SCM_BOOL(SCM_STACKP (obj));
66f45472 415}
1bbd0b84 416#undef FUNC_NAME
66f45472 417
af45e3b0
DH
418SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
419 (SCM obj, SCM args),
67941e3c
MG
420 "Create a new stack. If @var{obj} is @code{#t}, the current\n"
421 "evaluation stack is used for creating the stack frames,\n"
422 "otherwise the frames are taken from @var{obj} (which must be\n"
baffb19f
NJ
423 "either a debug object or a continuation).\n\n"
424 "@var{args} should be a list containing any combination of\n"
425 "integer, procedure and @code{#t} values.\n\n"
426 "These values specify various ways of cutting away uninteresting\n"
427 "stack frames from the top and bottom of the stack that\n"
428 "@code{make-stack} returns. They come in pairs like this:\n"
429 "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
430 "@var{outer_cut_2} @dots{})}.\n\n"
431 "Each @var{inner_cut_N} can be @code{#t}, an integer, or a\n"
432 "procedure. @code{#t} means to cut away all frames up to but\n"
433 "excluding the first user module frame. An integer means to cut\n"
434 "away exactly that number of frames. A procedure means to cut\n"
435 "away all frames up to but excluding the application frame whose\n"
436 "procedure matches the specified one.\n\n"
437 "Each @var{outer_cut_N} can be an integer or a procedure. An\n"
438 "integer means to cut away that number of frames. A procedure\n"
439 "means to cut away frames down to but excluding the application\n"
440 "frame whose procedure matches the specified one.\n\n"
441 "If the @var{outer_cut_N} of the last pair is missing, it is\n"
442 "taken as 0.")
1bbd0b84 443#define FUNC_NAME s_scm_make_stack
782d171c 444{
c014a02e 445 long n, size;
1be6b49c 446 int maxp;
13dcb666 447 scm_t_debug_frame *dframe;
92c2555f 448 scm_t_info_frame *iframe;
c014a02e 449 long offset = 0;
66f45472 450 SCM stack, id;
af45e3b0 451 SCM inner_cut, outer_cut;
f6f88e0d
MD
452
453 /* Extract a pointer to the innermost frame of whatever object
454 scm_make_stack was given. */
13dcb666 455 if (SCM_EQ_P (obj, SCM_BOOL_T))
782d171c 456 {
13dcb666
DH
457 dframe = scm_last_debug_frame;
458 }
459 else if (SCM_DEBUGOBJP (obj))
460 {
461 dframe = SCM_DEBUGOBJ_FRAME (obj);
462 }
463 else if (SCM_CONTINUATIONP (obj))
464 {
465 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_t_contregs))
466 - SCM_BASE (obj));
782d171c 467#ifndef STACK_GROWS_UP
13dcb666 468 offset += SCM_CONTINUATION_LENGTH (obj);
782d171c 469#endif
13dcb666
DH
470 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
471 }
472 else
473 {
474 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
475 /* not reached */
782d171c
MD
476 }
477
f6f88e0d
MD
478 /* Count number of frames. Also get stack id tag and check whether
479 there are more stackframes than we want to record
480 (SCM_BACKTRACE_MAXDEPTH). */
66f45472
MD
481 id = SCM_BOOL_F;
482 maxp = 0;
7115d1e4 483 n = stack_depth (dframe, offset, &id, &maxp);
782d171c
MD
484 size = n * SCM_FRAME_N_SLOTS;
485
f6f88e0d 486 /* Make the stack object. */
92c2555f 487 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (size), SCM_EOL);
66f45472 488 SCM_STACK (stack) -> id = id;
7115d1e4
MD
489 iframe = &SCM_STACK (stack) -> tail[0];
490 SCM_STACK (stack) -> frames = iframe;
7115d1e4 491
f6f88e0d 492 /* Translate the current chain of stack frames into debugging information. */
7c939801
MD
493 n = read_frames (RELOC_FRAME (dframe, offset), offset, n, iframe);
494 SCM_STACK (stack) -> length = n;
7115d1e4 495
f6f88e0d 496 /* Narrow the stack according to the arguments given to scm_make_stack. */
af45e3b0
DH
497 SCM_VALIDATE_REST_ARGUMENT (args);
498 while (n > 0 && !SCM_NULLP (args))
f6f88e0d
MD
499 {
500 inner_cut = SCM_CAR (args);
501 args = SCM_CDR (args);
af45e3b0
DH
502 if (SCM_NULLP (args))
503 {
13dcb666 504 outer_cut = SCM_INUM0;
af45e3b0
DH
505 }
506 else
f6f88e0d
MD
507 {
508 outer_cut = SCM_CAR (args);
509 args = SCM_CDR (args);
510 }
f6f88e0d
MD
511
512 narrow_stack (stack,
513 SCM_INUMP (inner_cut) ? SCM_INUM (inner_cut) : n,
514 SCM_INUMP (inner_cut) ? 0 : inner_cut,
515 SCM_INUMP (outer_cut) ? SCM_INUM (outer_cut) : n,
516 SCM_INUMP (outer_cut) ? 0 : outer_cut);
517
518 n = SCM_STACK (stack) -> length;
519 }
520
7115d1e4 521 if (n > 0)
f6f88e0d
MD
522 {
523 if (maxp)
524 iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW;
525 return stack;
526 }
7115d1e4
MD
527 else
528 return SCM_BOOL_F;
782d171c 529}
1bbd0b84 530#undef FUNC_NAME
782d171c 531
a1ec6916 532SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
1bbd0b84 533 (SCM stack),
b380b885 534 "Return the identifier given to @var{stack} by @code{start-stack}.")
1bbd0b84 535#define FUNC_NAME s_scm_stack_id
66f45472 536{
92c2555f 537 scm_t_debug_frame *dframe;
c014a02e 538 long offset = 0;
9a09deb1 539 if (SCM_EQ_P (stack, SCM_BOOL_T))
7115d1e4 540 {
13dcb666
DH
541 dframe = scm_last_debug_frame;
542 }
543 else if (SCM_DEBUGOBJP (stack))
544 {
545 dframe = SCM_DEBUGOBJ_FRAME (stack);
546 }
547 else if (SCM_CONTINUATIONP (stack))
548 {
549 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (stack) + sizeof (scm_t_contregs))
550 - SCM_BASE (stack));
7115d1e4 551#ifndef STACK_GROWS_UP
13dcb666 552 offset += SCM_CONTINUATION_LENGTH (stack);
7115d1e4 553#endif
13dcb666
DH
554 dframe = RELOC_FRAME (SCM_DFRAME (stack), offset);
555 }
556 else if (SCM_STACKP (stack))
557 {
558 return SCM_STACK (stack) -> id;
7115d1e4 559 }
13dcb666
DH
560 else
561 {
562 SCM_WRONG_TYPE_ARG (1, stack);
563 }
564
7115d1e4 565 while (dframe && !SCM_VOIDFRAMEP (*dframe))
c0ab1b8d 566 dframe = RELOC_FRAME (dframe->prev, offset);
7115d1e4
MD
567 if (dframe && SCM_VOIDFRAMEP (*dframe))
568 return dframe->vect[0].id;
569 return SCM_BOOL_F;
66f45472 570}
1bbd0b84 571#undef FUNC_NAME
66f45472 572
a1ec6916 573SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
13dcb666
DH
574 (SCM stack, SCM index),
575 "Return the @var{index}'th frame from @var{stack}.")
1bbd0b84 576#define FUNC_NAME s_scm_stack_ref
782d171c 577{
13dcb666
DH
578 unsigned long int c_index;
579
580 SCM_VALIDATE_STACK (1, stack);
581 SCM_VALIDATE_INUM (2, index);
582 SCM_ASSERT_RANGE (1, index, SCM_INUM (index) >= 0);
583 c_index = SCM_INUM (index);
584 SCM_ASSERT_RANGE (1, index, c_index < SCM_STACK_LENGTH (stack));
585 return scm_cons (stack, index);
782d171c 586}
1bbd0b84 587#undef FUNC_NAME
782d171c 588
3b3b36dd 589SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
67941e3c
MG
590 (SCM stack),
591 "Return the length of @var{stack}.")
1bbd0b84 592#define FUNC_NAME s_scm_stack_length
782d171c 593{
3b3b36dd 594 SCM_VALIDATE_STACK (1,stack);
782d171c
MD
595 return SCM_MAKINUM (SCM_STACK_LENGTH (stack));
596}
1bbd0b84 597#undef FUNC_NAME
782d171c
MD
598
599/* Frames
600 */
601
a1ec6916 602SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
1bbd0b84 603 (SCM obj),
67941e3c 604 "Return @code{#t} if @var{obj} is a stack frame.")
1bbd0b84 605#define FUNC_NAME s_scm_frame_p
66f45472 606{
0c95b57d 607 return SCM_BOOL(SCM_FRAMEP (obj));
66f45472 608}
1bbd0b84 609#undef FUNC_NAME
66f45472 610
3b3b36dd 611SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
67941e3c
MG
612 (SCM obj),
613 "Return a stack which consists of a single frame, which is the\n"
614 "last stack frame for @var{obj}. @var{obj} must be either a\n"
615 "debug object or a continuation.")
1bbd0b84 616#define FUNC_NAME s_scm_last_stack_frame
782d171c 617{
92c2555f 618 scm_t_debug_frame *dframe;
c014a02e 619 long offset = 0;
7115d1e4 620 SCM stack;
782d171c 621
782d171c 622 if (SCM_DEBUGOBJP (obj))
13dcb666
DH
623 {
624 dframe = SCM_DEBUGOBJ_FRAME (obj);
625 }
5f144b10 626 else if (SCM_CONTINUATIONP (obj))
782d171c 627 {
92c2555f 628 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_t_contregs))
782d171c
MD
629 - SCM_BASE (obj));
630#ifndef STACK_GROWS_UP
bfa974f0 631 offset += SCM_CONTINUATION_LENGTH (obj);
782d171c 632#endif
c0ab1b8d 633 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
782d171c 634 }
3323ad08
JB
635 else
636 {
276dd677
DH
637 SCM_WRONG_TYPE_ARG (1, obj);
638 /* not reached */
3323ad08 639 }
782d171c 640
66f45472 641 if (!dframe || SCM_VOIDFRAMEP (*dframe))
782d171c
MD
642 return SCM_BOOL_F;
643
92c2555f 644 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (SCM_FRAME_N_SLOTS),
c0ab1b8d 645 SCM_EOL);
7115d1e4
MD
646 SCM_STACK (stack) -> length = 1;
647 SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
c0ab1b8d 648 read_frame (dframe, offset,
92c2555f 649 (scm_t_info_frame *) &SCM_STACK (stack) -> frames[0]);
782d171c 650
13dcb666 651 return scm_cons (stack, SCM_INUM0);
782d171c 652}
1bbd0b84 653#undef FUNC_NAME
782d171c 654
3b3b36dd 655SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
67941e3c
MG
656 (SCM frame),
657 "Return the frame number of @var{frame}.")
1bbd0b84 658#define FUNC_NAME s_scm_frame_number
782d171c 659{
3b3b36dd 660 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
661 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame));
662}
1bbd0b84 663#undef FUNC_NAME
782d171c 664
3b3b36dd 665SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
67941e3c
MG
666 (SCM frame),
667 "Return the source of @var{frame}.")
1bbd0b84 668#define FUNC_NAME s_scm_frame_source
782d171c 669{
3b3b36dd 670 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
671 return SCM_FRAME_SOURCE (frame);
672}
1bbd0b84 673#undef FUNC_NAME
782d171c 674
3b3b36dd 675SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
67941e3c
MG
676 (SCM frame),
677 "Return the procedure for @var{frame}, or @code{#f} if no\n"
678 "procedure is associated with @var{frame}.")
1bbd0b84 679#define FUNC_NAME s_scm_frame_procedure
782d171c 680{
3b3b36dd 681 SCM_VALIDATE_FRAME (1,frame);
782d171c 682 return (SCM_FRAME_PROC_P (frame)
afa92d19
TP
683 ? SCM_FRAME_PROC (frame)
684 : SCM_BOOL_F);
782d171c 685}
1bbd0b84 686#undef FUNC_NAME
782d171c 687
3b3b36dd 688SCM_DEFINE (scm_frame_arguments, "frame-arguments", 1, 0, 0,
67941e3c
MG
689 (SCM frame),
690 "Return the arguments of @var{frame}.")
1bbd0b84 691#define FUNC_NAME s_scm_frame_arguments
782d171c 692{
3b3b36dd 693 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
694 return SCM_FRAME_ARGS (frame);
695}
1bbd0b84 696#undef FUNC_NAME
782d171c 697
3b3b36dd 698SCM_DEFINE (scm_frame_previous, "frame-previous", 1, 0, 0,
67941e3c
MG
699 (SCM frame),
700 "Return the previous frame of @var{frame}, or @code{#f} if\n"
701 "@var{frame} is the first frame in its stack.")
1bbd0b84 702#define FUNC_NAME s_scm_frame_previous
782d171c 703{
13dcb666
DH
704 unsigned long int n;
705 SCM_VALIDATE_FRAME (1, frame);
782d171c
MD
706 n = SCM_INUM (SCM_CDR (frame)) + 1;
707 if (n >= SCM_STACK_LENGTH (SCM_CAR (frame)))
708 return SCM_BOOL_F;
709 else
710 return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n));
711}
1bbd0b84 712#undef FUNC_NAME
782d171c 713
3b3b36dd 714SCM_DEFINE (scm_frame_next, "frame-next", 1, 0, 0,
1bbd0b84 715 (SCM frame),
67941e3c
MG
716 "Return the next frame of @var{frame}, or @code{#f} if\n"
717 "@var{frame} is the last frame in its stack.")
1bbd0b84 718#define FUNC_NAME s_scm_frame_next
782d171c 719{
13dcb666
DH
720 unsigned long int n;
721 SCM_VALIDATE_FRAME (1, frame);
722 n = SCM_INUM (SCM_CDR (frame));
723 if (n == 0)
782d171c
MD
724 return SCM_BOOL_F;
725 else
13dcb666 726 return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n - 1));
782d171c 727}
1bbd0b84 728#undef FUNC_NAME
782d171c 729
3b3b36dd 730SCM_DEFINE (scm_frame_real_p, "frame-real?", 1, 0, 0,
67941e3c
MG
731 (SCM frame),
732 "Return @code{#t} if @var{frame} is a real frame.")
1bbd0b84 733#define FUNC_NAME s_scm_frame_real_p
782d171c 734{
3b3b36dd 735 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 736 return SCM_BOOL(SCM_FRAME_REAL_P (frame));
782d171c 737}
1bbd0b84 738#undef FUNC_NAME
782d171c 739
3b3b36dd 740SCM_DEFINE (scm_frame_procedure_p, "frame-procedure?", 1, 0, 0,
67941e3c
MG
741 (SCM frame),
742 "Return @code{#t} if a procedure is associated with @var{frame}.")
1bbd0b84 743#define FUNC_NAME s_scm_frame_procedure_p
782d171c 744{
3b3b36dd 745 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 746 return SCM_BOOL(SCM_FRAME_PROC_P (frame));
782d171c 747}
1bbd0b84 748#undef FUNC_NAME
782d171c 749
3b3b36dd 750SCM_DEFINE (scm_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0,
67941e3c
MG
751 (SCM frame),
752 "Return @code{#t} if @var{frame} contains evaluated arguments.")
1bbd0b84 753#define FUNC_NAME s_scm_frame_evaluating_args_p
782d171c 754{
3b3b36dd 755 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 756 return SCM_BOOL(SCM_FRAME_EVAL_ARGS_P (frame));
782d171c 757}
1bbd0b84 758#undef FUNC_NAME
782d171c 759
3b3b36dd 760SCM_DEFINE (scm_frame_overflow_p, "frame-overflow?", 1, 0, 0,
67941e3c
MG
761 (SCM frame),
762 "Return @code{#t} if @var{frame} is an overflow frame.")
1bbd0b84 763#define FUNC_NAME s_scm_frame_overflow_p
782d171c 764{
3b3b36dd 765 SCM_VALIDATE_FRAME (1,frame);
156dcb09 766 return SCM_BOOL(SCM_FRAME_OVERFLOW_P (frame));
782d171c 767}
1bbd0b84 768#undef FUNC_NAME
782d171c
MD
769
770\f
771
772void
773scm_init_stacks ()
774{
66f45472 775 SCM vtable;
c0ab1b8d
JB
776 SCM stack_layout
777 = scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT));
b299f5cd 778 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
92c2555f 779 scm_t_stackype
c0ab1b8d
JB
780 = scm_permanent_object (scm_make_struct (vtable, SCM_INUM0,
781 scm_cons (stack_layout,
782 SCM_EOL)));
92c2555f 783 scm_set_struct_vtable_name_x (scm_t_stackype, scm_str2symbol ("stack"));
8dc9439f 784#ifndef SCM_MAGIC_SNARFER
a0599745 785#include "libguile/stacks.x"
8dc9439f 786#endif
782d171c 787}
89e00824
ML
788
789/*
790 Local Variables:
791 c-file-style: "gnu"
792 End:
793*/