* Fix obscure debugger bug - trying to rerun last command when last command
[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"
423 "either a debug object or a continuation).\n"
e3334972 424 "@var{args} must be a list of integers and specifies how the\n"
67941e3c 425 "resulting stack will be narrowed.")
1bbd0b84 426#define FUNC_NAME s_scm_make_stack
782d171c 427{
c014a02e 428 long n, size;
1be6b49c 429 int maxp;
13dcb666 430 scm_t_debug_frame *dframe;
92c2555f 431 scm_t_info_frame *iframe;
c014a02e 432 long offset = 0;
66f45472 433 SCM stack, id;
af45e3b0 434 SCM inner_cut, outer_cut;
f6f88e0d
MD
435
436 /* Extract a pointer to the innermost frame of whatever object
437 scm_make_stack was given. */
13dcb666 438 if (SCM_EQ_P (obj, SCM_BOOL_T))
782d171c 439 {
13dcb666
DH
440 dframe = scm_last_debug_frame;
441 }
442 else if (SCM_DEBUGOBJP (obj))
443 {
444 dframe = SCM_DEBUGOBJ_FRAME (obj);
445 }
446 else if (SCM_CONTINUATIONP (obj))
447 {
448 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_t_contregs))
449 - SCM_BASE (obj));
782d171c 450#ifndef STACK_GROWS_UP
13dcb666 451 offset += SCM_CONTINUATION_LENGTH (obj);
782d171c 452#endif
13dcb666
DH
453 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
454 }
455 else
456 {
457 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
458 /* not reached */
782d171c
MD
459 }
460
f6f88e0d
MD
461 /* Count number of frames. Also get stack id tag and check whether
462 there are more stackframes than we want to record
463 (SCM_BACKTRACE_MAXDEPTH). */
66f45472
MD
464 id = SCM_BOOL_F;
465 maxp = 0;
7115d1e4 466 n = stack_depth (dframe, offset, &id, &maxp);
782d171c
MD
467 size = n * SCM_FRAME_N_SLOTS;
468
f6f88e0d 469 /* Make the stack object. */
92c2555f 470 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (size), SCM_EOL);
66f45472 471 SCM_STACK (stack) -> id = id;
7115d1e4
MD
472 iframe = &SCM_STACK (stack) -> tail[0];
473 SCM_STACK (stack) -> frames = iframe;
7115d1e4 474
f6f88e0d 475 /* Translate the current chain of stack frames into debugging information. */
7c939801
MD
476 n = read_frames (RELOC_FRAME (dframe, offset), offset, n, iframe);
477 SCM_STACK (stack) -> length = n;
7115d1e4 478
f6f88e0d 479 /* Narrow the stack according to the arguments given to scm_make_stack. */
af45e3b0
DH
480 SCM_VALIDATE_REST_ARGUMENT (args);
481 while (n > 0 && !SCM_NULLP (args))
f6f88e0d
MD
482 {
483 inner_cut = SCM_CAR (args);
484 args = SCM_CDR (args);
af45e3b0
DH
485 if (SCM_NULLP (args))
486 {
13dcb666 487 outer_cut = SCM_INUM0;
af45e3b0
DH
488 }
489 else
f6f88e0d
MD
490 {
491 outer_cut = SCM_CAR (args);
492 args = SCM_CDR (args);
493 }
f6f88e0d
MD
494
495 narrow_stack (stack,
496 SCM_INUMP (inner_cut) ? SCM_INUM (inner_cut) : n,
497 SCM_INUMP (inner_cut) ? 0 : inner_cut,
498 SCM_INUMP (outer_cut) ? SCM_INUM (outer_cut) : n,
499 SCM_INUMP (outer_cut) ? 0 : outer_cut);
500
501 n = SCM_STACK (stack) -> length;
502 }
503
7115d1e4 504 if (n > 0)
f6f88e0d
MD
505 {
506 if (maxp)
507 iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW;
508 return stack;
509 }
7115d1e4
MD
510 else
511 return SCM_BOOL_F;
782d171c 512}
1bbd0b84 513#undef FUNC_NAME
782d171c 514
a1ec6916 515SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
1bbd0b84 516 (SCM stack),
b380b885 517 "Return the identifier given to @var{stack} by @code{start-stack}.")
1bbd0b84 518#define FUNC_NAME s_scm_stack_id
66f45472 519{
92c2555f 520 scm_t_debug_frame *dframe;
c014a02e 521 long offset = 0;
9a09deb1 522 if (SCM_EQ_P (stack, SCM_BOOL_T))
7115d1e4 523 {
13dcb666
DH
524 dframe = scm_last_debug_frame;
525 }
526 else if (SCM_DEBUGOBJP (stack))
527 {
528 dframe = SCM_DEBUGOBJ_FRAME (stack);
529 }
530 else if (SCM_CONTINUATIONP (stack))
531 {
532 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (stack) + sizeof (scm_t_contregs))
533 - SCM_BASE (stack));
7115d1e4 534#ifndef STACK_GROWS_UP
13dcb666 535 offset += SCM_CONTINUATION_LENGTH (stack);
7115d1e4 536#endif
13dcb666
DH
537 dframe = RELOC_FRAME (SCM_DFRAME (stack), offset);
538 }
539 else if (SCM_STACKP (stack))
540 {
541 return SCM_STACK (stack) -> id;
7115d1e4 542 }
13dcb666
DH
543 else
544 {
545 SCM_WRONG_TYPE_ARG (1, stack);
546 }
547
7115d1e4 548 while (dframe && !SCM_VOIDFRAMEP (*dframe))
c0ab1b8d 549 dframe = RELOC_FRAME (dframe->prev, offset);
7115d1e4
MD
550 if (dframe && SCM_VOIDFRAMEP (*dframe))
551 return dframe->vect[0].id;
552 return SCM_BOOL_F;
66f45472 553}
1bbd0b84 554#undef FUNC_NAME
66f45472 555
a1ec6916 556SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
13dcb666
DH
557 (SCM stack, SCM index),
558 "Return the @var{index}'th frame from @var{stack}.")
1bbd0b84 559#define FUNC_NAME s_scm_stack_ref
782d171c 560{
13dcb666
DH
561 unsigned long int c_index;
562
563 SCM_VALIDATE_STACK (1, stack);
564 SCM_VALIDATE_INUM (2, index);
565 SCM_ASSERT_RANGE (1, index, SCM_INUM (index) >= 0);
566 c_index = SCM_INUM (index);
567 SCM_ASSERT_RANGE (1, index, c_index < SCM_STACK_LENGTH (stack));
568 return scm_cons (stack, index);
782d171c 569}
1bbd0b84 570#undef FUNC_NAME
782d171c 571
3b3b36dd 572SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
67941e3c
MG
573 (SCM stack),
574 "Return the length of @var{stack}.")
1bbd0b84 575#define FUNC_NAME s_scm_stack_length
782d171c 576{
3b3b36dd 577 SCM_VALIDATE_STACK (1,stack);
782d171c
MD
578 return SCM_MAKINUM (SCM_STACK_LENGTH (stack));
579}
1bbd0b84 580#undef FUNC_NAME
782d171c
MD
581
582/* Frames
583 */
584
a1ec6916 585SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
1bbd0b84 586 (SCM obj),
67941e3c 587 "Return @code{#t} if @var{obj} is a stack frame.")
1bbd0b84 588#define FUNC_NAME s_scm_frame_p
66f45472 589{
0c95b57d 590 return SCM_BOOL(SCM_FRAMEP (obj));
66f45472 591}
1bbd0b84 592#undef FUNC_NAME
66f45472 593
3b3b36dd 594SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
67941e3c
MG
595 (SCM obj),
596 "Return a stack which consists of a single frame, which is the\n"
597 "last stack frame for @var{obj}. @var{obj} must be either a\n"
598 "debug object or a continuation.")
1bbd0b84 599#define FUNC_NAME s_scm_last_stack_frame
782d171c 600{
92c2555f 601 scm_t_debug_frame *dframe;
c014a02e 602 long offset = 0;
7115d1e4 603 SCM stack;
782d171c 604
782d171c 605 if (SCM_DEBUGOBJP (obj))
13dcb666
DH
606 {
607 dframe = SCM_DEBUGOBJ_FRAME (obj);
608 }
5f144b10 609 else if (SCM_CONTINUATIONP (obj))
782d171c 610 {
92c2555f 611 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_t_contregs))
782d171c
MD
612 - SCM_BASE (obj));
613#ifndef STACK_GROWS_UP
bfa974f0 614 offset += SCM_CONTINUATION_LENGTH (obj);
782d171c 615#endif
c0ab1b8d 616 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
782d171c 617 }
3323ad08
JB
618 else
619 {
276dd677
DH
620 SCM_WRONG_TYPE_ARG (1, obj);
621 /* not reached */
3323ad08 622 }
782d171c 623
66f45472 624 if (!dframe || SCM_VOIDFRAMEP (*dframe))
782d171c
MD
625 return SCM_BOOL_F;
626
92c2555f 627 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (SCM_FRAME_N_SLOTS),
c0ab1b8d 628 SCM_EOL);
7115d1e4
MD
629 SCM_STACK (stack) -> length = 1;
630 SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
c0ab1b8d 631 read_frame (dframe, offset,
92c2555f 632 (scm_t_info_frame *) &SCM_STACK (stack) -> frames[0]);
782d171c 633
13dcb666 634 return scm_cons (stack, SCM_INUM0);
782d171c 635}
1bbd0b84 636#undef FUNC_NAME
782d171c 637
3b3b36dd 638SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
67941e3c
MG
639 (SCM frame),
640 "Return the frame number of @var{frame}.")
1bbd0b84 641#define FUNC_NAME s_scm_frame_number
782d171c 642{
3b3b36dd 643 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
644 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame));
645}
1bbd0b84 646#undef FUNC_NAME
782d171c 647
3b3b36dd 648SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
67941e3c
MG
649 (SCM frame),
650 "Return the source of @var{frame}.")
1bbd0b84 651#define FUNC_NAME s_scm_frame_source
782d171c 652{
3b3b36dd 653 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
654 return SCM_FRAME_SOURCE (frame);
655}
1bbd0b84 656#undef FUNC_NAME
782d171c 657
3b3b36dd 658SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
67941e3c
MG
659 (SCM frame),
660 "Return the procedure for @var{frame}, or @code{#f} if no\n"
661 "procedure is associated with @var{frame}.")
1bbd0b84 662#define FUNC_NAME s_scm_frame_procedure
782d171c 663{
3b3b36dd 664 SCM_VALIDATE_FRAME (1,frame);
782d171c 665 return (SCM_FRAME_PROC_P (frame)
afa92d19
TP
666 ? SCM_FRAME_PROC (frame)
667 : SCM_BOOL_F);
782d171c 668}
1bbd0b84 669#undef FUNC_NAME
782d171c 670
3b3b36dd 671SCM_DEFINE (scm_frame_arguments, "frame-arguments", 1, 0, 0,
67941e3c
MG
672 (SCM frame),
673 "Return the arguments of @var{frame}.")
1bbd0b84 674#define FUNC_NAME s_scm_frame_arguments
782d171c 675{
3b3b36dd 676 SCM_VALIDATE_FRAME (1,frame);
782d171c
MD
677 return SCM_FRAME_ARGS (frame);
678}
1bbd0b84 679#undef FUNC_NAME
782d171c 680
3b3b36dd 681SCM_DEFINE (scm_frame_previous, "frame-previous", 1, 0, 0,
67941e3c
MG
682 (SCM frame),
683 "Return the previous frame of @var{frame}, or @code{#f} if\n"
684 "@var{frame} is the first frame in its stack.")
1bbd0b84 685#define FUNC_NAME s_scm_frame_previous
782d171c 686{
13dcb666
DH
687 unsigned long int n;
688 SCM_VALIDATE_FRAME (1, frame);
782d171c
MD
689 n = SCM_INUM (SCM_CDR (frame)) + 1;
690 if (n >= SCM_STACK_LENGTH (SCM_CAR (frame)))
691 return SCM_BOOL_F;
692 else
693 return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n));
694}
1bbd0b84 695#undef FUNC_NAME
782d171c 696
3b3b36dd 697SCM_DEFINE (scm_frame_next, "frame-next", 1, 0, 0,
1bbd0b84 698 (SCM frame),
67941e3c
MG
699 "Return the next frame of @var{frame}, or @code{#f} if\n"
700 "@var{frame} is the last frame in its stack.")
1bbd0b84 701#define FUNC_NAME s_scm_frame_next
782d171c 702{
13dcb666
DH
703 unsigned long int n;
704 SCM_VALIDATE_FRAME (1, frame);
705 n = SCM_INUM (SCM_CDR (frame));
706 if (n == 0)
782d171c
MD
707 return SCM_BOOL_F;
708 else
13dcb666 709 return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n - 1));
782d171c 710}
1bbd0b84 711#undef FUNC_NAME
782d171c 712
3b3b36dd 713SCM_DEFINE (scm_frame_real_p, "frame-real?", 1, 0, 0,
67941e3c
MG
714 (SCM frame),
715 "Return @code{#t} if @var{frame} is a real frame.")
1bbd0b84 716#define FUNC_NAME s_scm_frame_real_p
782d171c 717{
3b3b36dd 718 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 719 return SCM_BOOL(SCM_FRAME_REAL_P (frame));
782d171c 720}
1bbd0b84 721#undef FUNC_NAME
782d171c 722
3b3b36dd 723SCM_DEFINE (scm_frame_procedure_p, "frame-procedure?", 1, 0, 0,
67941e3c
MG
724 (SCM frame),
725 "Return @code{#t} if a procedure is associated with @var{frame}.")
1bbd0b84 726#define FUNC_NAME s_scm_frame_procedure_p
782d171c 727{
3b3b36dd 728 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 729 return SCM_BOOL(SCM_FRAME_PROC_P (frame));
782d171c 730}
1bbd0b84 731#undef FUNC_NAME
782d171c 732
3b3b36dd 733SCM_DEFINE (scm_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0,
67941e3c
MG
734 (SCM frame),
735 "Return @code{#t} if @var{frame} contains evaluated arguments.")
1bbd0b84 736#define FUNC_NAME s_scm_frame_evaluating_args_p
782d171c 737{
3b3b36dd 738 SCM_VALIDATE_FRAME (1,frame);
1bbd0b84 739 return SCM_BOOL(SCM_FRAME_EVAL_ARGS_P (frame));
782d171c 740}
1bbd0b84 741#undef FUNC_NAME
782d171c 742
3b3b36dd 743SCM_DEFINE (scm_frame_overflow_p, "frame-overflow?", 1, 0, 0,
67941e3c
MG
744 (SCM frame),
745 "Return @code{#t} if @var{frame} is an overflow frame.")
1bbd0b84 746#define FUNC_NAME s_scm_frame_overflow_p
782d171c 747{
3b3b36dd 748 SCM_VALIDATE_FRAME (1,frame);
156dcb09 749 return SCM_BOOL(SCM_FRAME_OVERFLOW_P (frame));
782d171c 750}
1bbd0b84 751#undef FUNC_NAME
782d171c
MD
752
753\f
754
755void
756scm_init_stacks ()
757{
66f45472 758 SCM vtable;
c0ab1b8d
JB
759 SCM stack_layout
760 = scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT));
b299f5cd 761 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
92c2555f 762 scm_t_stackype
c0ab1b8d
JB
763 = scm_permanent_object (scm_make_struct (vtable, SCM_INUM0,
764 scm_cons (stack_layout,
765 SCM_EOL)));
92c2555f 766 scm_set_struct_vtable_name_x (scm_t_stackype, scm_str2symbol ("stack"));
8dc9439f 767#ifndef SCM_MAGIC_SNARFER
a0599745 768#include "libguile/stacks.x"
8dc9439f 769#endif
782d171c 770}
89e00824
ML
771
772/*
773 Local Variables:
774 c-file-style: "gnu"
775 End:
776*/