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