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