* Explain cutting args for `make-stack'.
[bpt/guile.git] / libguile / stacks.c
1 /* Representation of stack frame debug information
2 * Copyright (C) 1996,1997,2000,2001 Free Software Foundation
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
16 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307 USA
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
44 * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
45
46
47 \f
48
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"
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 *
92 * The stack is represented as a struct with an id slot and a tail
93 * array of scm_t_info_frame structs.
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
97 * the scm_t_info_frame struct.
98 *
99 * Stacks
100 * Constructor
101 * make-stack
102 * Selectors
103 * stack-id
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?
122 * frame-overflow? */
123
124 \f
125
126 /* Some auxiliary functions for reading debug frames off the stack.
127 */
128
129 /* Stacks often contain pointers to other items on the stack; for
130 example, each scm_t_debug_frame structure contains a pointer to the
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) \
144 ((scm_t_debug_info *) ((SCM_STACKITEM *) (ptr) + (offset)))
145 #define RELOC_FRAME(ptr, offset) \
146 ((scm_t_debug_frame *) ((SCM_STACKITEM *) (ptr) + (offset)))
147
148
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 */
153 static scm_t_bits
154 stack_depth (scm_t_debug_frame *dframe,long offset,SCM *id,int *maxp)
155 {
156 long n;
157 long max_depth = SCM_BACKTRACE_MAXDEPTH;
158 for (n = 0;
159 dframe && !SCM_VOIDFRAMEP (*dframe) && n < max_depth;
160 dframe = RELOC_FRAME (dframe->prev, offset))
161 {
162 if (SCM_EVALFRAMEP (*dframe))
163 {
164 scm_t_debug_info * info = RELOC_INFO (dframe->info, offset);
165 n += (info - dframe->vect) / 2 + 1;
166 /* Data in the apply part of an eval info frame comes from previous
167 stack frame if the scm_t_debug_info vector is overflowed. */
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 }
176 if (dframe && SCM_VOIDFRAMEP (*dframe))
177 *id = dframe->vect[0].id;
178 else if (dframe)
179 *maxp = 1;
180 return n;
181 }
182
183 /* Read debug info from DFRAME into IFRAME.
184 */
185 static void
186 read_frame (scm_t_debug_frame *dframe,long offset,scm_t_info_frame *iframe)
187 {
188 scm_t_bits flags = SCM_UNPACK (SCM_INUM0); /* UGh. */
189 if (SCM_EVALFRAMEP (*dframe))
190 {
191 scm_t_debug_info * info = RELOC_INFO (dframe->info, offset);
192 if ((info - dframe->vect) & 1)
193 {
194 /* Debug.vect ends with apply info. */
195 --info;
196 if (!SCM_UNBNDP (info[1].a.proc))
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 }
205 iframe->source = scm_make_memoized (info[0].e.exp, info[0].e.env);
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
216 /* Look up the first body form of the apply closure. We'll use this
217 below to prevent it from being displayed.
218 */
219 static SCM
220 get_applybody ()
221 {
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)));
225 else
226 return SCM_UNDEFINED;
227 }
228
229 #define NEXT_FRAME(iframe, n, quit) \
230 do { \
231 if (SCM_MEMOIZEDP (iframe->source) \
232 && SCM_EQ_P (SCM_MEMOIZED_EXP (iframe->source), applybody)) \
233 { \
234 iframe->source = SCM_BOOL_F; \
235 if (SCM_FALSEP (iframe->proc)) \
236 { \
237 --iframe; \
238 ++n; \
239 } \
240 } \
241 ++iframe; \
242 if (--n == 0) \
243 goto quit; \
244 } while (0)
245
246
247 /* Fill the scm_t_info_frame vector IFRAME with data from N stack frames
248 * starting with the first stack frame represented by debug frame
249 * DFRAME.
250 */
251
252 static scm_t_bits
253 read_frames (scm_t_debug_frame *dframe,long offset,long n,scm_t_info_frame *iframes)
254 {
255 scm_t_info_frame *iframe = iframes;
256 scm_t_debug_info *info;
257 static SCM applybody = SCM_UNDEFINED;
258
259 /* The value of applybody has to be setup after r4rs.scm has executed. */
260 if (SCM_UNBNDP (applybody))
261 applybody = get_applybody ();
262 for (;
263 dframe && !SCM_VOIDFRAMEP (*dframe) && n > 0;
264 dframe = RELOC_FRAME (dframe->prev, offset))
265 {
266 read_frame (dframe, offset, iframe);
267 if (SCM_EVALFRAMEP (*dframe))
268 {
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)
273 {
274 *(iframe - 1) = *iframe;
275 --iframe;
276 }
277 info = RELOC_INFO (dframe->info, offset);
278 if ((info - dframe->vect) & 1)
279 --info;
280 /* Data in the apply part of an eval info frame comes from
281 previous stack frame if the scm_t_debug_info vector is
282 overflowed. */
283 else if (SCM_OVERFLOWP (*dframe)
284 && !SCM_UNBNDP (info[1].a.proc))
285 {
286 NEXT_FRAME (iframe, n, quit);
287 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
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;
294 NEXT_FRAME (iframe, n, quit);
295 while (info >= dframe->vect)
296 {
297 if (!SCM_UNBNDP (info[1].a.proc))
298 {
299 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
300 iframe->proc = info[1].a.proc;
301 iframe->args = info[1].a.args;
302 }
303 else
304 iframe->flags = SCM_UNPACK (SCM_INUM0);
305 iframe->source = scm_make_memoized (info[0].e.exp,
306 info[0].e.env);
307 info -= 2;
308 NEXT_FRAME (iframe, n, quit);
309 }
310 }
311 else if (SCM_EQ_P (iframe->proc, scm_f_gsubr_apply))
312 /* Skip gsubr apply frames. */
313 continue;
314 else
315 {
316 NEXT_FRAME (iframe, n, quit);
317 }
318 quit:
319 if (iframe > iframes)
320 (iframe - 1) -> flags |= SCM_FRAMEF_REAL;
321 }
322 return iframe - iframes; /* Number of frames actually read */
323 }
324
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
346 static void
347 narrow_stack (SCM stack,long inner,SCM inner_key,long outer,SCM outer_key)
348 {
349 scm_t_stack *s = SCM_STACK (stack);
350 unsigned long int i;
351 long n = s->length;
352
353 /* Cut inner part. */
354 if (SCM_EQ_P (inner_key, SCM_BOOL_T))
355 {
356 /* Cut all frames up to user module code */
357 for (i = 0; inner; ++i, --inner)
358 {
359 SCM m = s->frames[i].source;
360 if (SCM_MEMOIZEDP (m)
361 && !SCM_IMP (SCM_MEMOIZED_ENV (m))
362 && SCM_FALSEP (scm_system_module_env_p (SCM_MEMOIZED_ENV (m))))
363 {
364 /* Back up in order to include any non-source frames */
365 while (i > 0)
366 {
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
377 --i;
378 ++inner;
379 }
380 break;
381 }
382 }
383 }
384 else
385 /* Use standard cutting procedure. */
386 {
387 for (i = 0; inner; --inner)
388 if (SCM_EQ_P (s->frames[i++].proc, inner_key))
389 break;
390 }
391 s->frames = &s->frames[i];
392 n -= i;
393
394 /* Cut outer part. */
395 for (; n && outer; --outer)
396 if (SCM_EQ_P (s->frames[--n].proc, outer_key))
397 break;
398
399 s->length = n;
400 }
401
402 \f
403
404 /* Stacks
405 */
406
407 SCM scm_t_stackype;
408
409 SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
410 (SCM obj),
411 "Return @code{#t} if @var{obj} is a calling stack.")
412 #define FUNC_NAME s_scm_stack_p
413 {
414 return SCM_BOOL(SCM_STACKP (obj));
415 }
416 #undef FUNC_NAME
417
418 SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
419 (SCM obj, SCM args),
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\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.")
443 #define FUNC_NAME s_scm_make_stack
444 {
445 long n, size;
446 int maxp;
447 scm_t_debug_frame *dframe;
448 scm_t_info_frame *iframe;
449 long offset = 0;
450 SCM stack, id;
451 SCM inner_cut, outer_cut;
452
453 /* Extract a pointer to the innermost frame of whatever object
454 scm_make_stack was given. */
455 if (SCM_EQ_P (obj, SCM_BOOL_T))
456 {
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));
467 #ifndef STACK_GROWS_UP
468 offset += SCM_CONTINUATION_LENGTH (obj);
469 #endif
470 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
471 }
472 else
473 {
474 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
475 /* not reached */
476 }
477
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). */
481 id = SCM_BOOL_F;
482 maxp = 0;
483 n = stack_depth (dframe, offset, &id, &maxp);
484 size = n * SCM_FRAME_N_SLOTS;
485
486 /* Make the stack object. */
487 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (size), SCM_EOL);
488 SCM_STACK (stack) -> id = id;
489 iframe = &SCM_STACK (stack) -> tail[0];
490 SCM_STACK (stack) -> frames = iframe;
491
492 /* Translate the current chain of stack frames into debugging information. */
493 n = read_frames (RELOC_FRAME (dframe, offset), offset, n, iframe);
494 SCM_STACK (stack) -> length = n;
495
496 /* Narrow the stack according to the arguments given to scm_make_stack. */
497 SCM_VALIDATE_REST_ARGUMENT (args);
498 while (n > 0 && !SCM_NULLP (args))
499 {
500 inner_cut = SCM_CAR (args);
501 args = SCM_CDR (args);
502 if (SCM_NULLP (args))
503 {
504 outer_cut = SCM_INUM0;
505 }
506 else
507 {
508 outer_cut = SCM_CAR (args);
509 args = SCM_CDR (args);
510 }
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
521 if (n > 0)
522 {
523 if (maxp)
524 iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW;
525 return stack;
526 }
527 else
528 return SCM_BOOL_F;
529 }
530 #undef FUNC_NAME
531
532 SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
533 (SCM stack),
534 "Return the identifier given to @var{stack} by @code{start-stack}.")
535 #define FUNC_NAME s_scm_stack_id
536 {
537 scm_t_debug_frame *dframe;
538 long offset = 0;
539 if (SCM_EQ_P (stack, SCM_BOOL_T))
540 {
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));
551 #ifndef STACK_GROWS_UP
552 offset += SCM_CONTINUATION_LENGTH (stack);
553 #endif
554 dframe = RELOC_FRAME (SCM_DFRAME (stack), offset);
555 }
556 else if (SCM_STACKP (stack))
557 {
558 return SCM_STACK (stack) -> id;
559 }
560 else
561 {
562 SCM_WRONG_TYPE_ARG (1, stack);
563 }
564
565 while (dframe && !SCM_VOIDFRAMEP (*dframe))
566 dframe = RELOC_FRAME (dframe->prev, offset);
567 if (dframe && SCM_VOIDFRAMEP (*dframe))
568 return dframe->vect[0].id;
569 return SCM_BOOL_F;
570 }
571 #undef FUNC_NAME
572
573 SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
574 (SCM stack, SCM index),
575 "Return the @var{index}'th frame from @var{stack}.")
576 #define FUNC_NAME s_scm_stack_ref
577 {
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);
586 }
587 #undef FUNC_NAME
588
589 SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
590 (SCM stack),
591 "Return the length of @var{stack}.")
592 #define FUNC_NAME s_scm_stack_length
593 {
594 SCM_VALIDATE_STACK (1,stack);
595 return SCM_MAKINUM (SCM_STACK_LENGTH (stack));
596 }
597 #undef FUNC_NAME
598
599 /* Frames
600 */
601
602 SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
603 (SCM obj),
604 "Return @code{#t} if @var{obj} is a stack frame.")
605 #define FUNC_NAME s_scm_frame_p
606 {
607 return SCM_BOOL(SCM_FRAMEP (obj));
608 }
609 #undef FUNC_NAME
610
611 SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
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.")
616 #define FUNC_NAME s_scm_last_stack_frame
617 {
618 scm_t_debug_frame *dframe;
619 long offset = 0;
620 SCM stack;
621
622 if (SCM_DEBUGOBJP (obj))
623 {
624 dframe = SCM_DEBUGOBJ_FRAME (obj);
625 }
626 else if (SCM_CONTINUATIONP (obj))
627 {
628 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_t_contregs))
629 - SCM_BASE (obj));
630 #ifndef STACK_GROWS_UP
631 offset += SCM_CONTINUATION_LENGTH (obj);
632 #endif
633 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
634 }
635 else
636 {
637 SCM_WRONG_TYPE_ARG (1, obj);
638 /* not reached */
639 }
640
641 if (!dframe || SCM_VOIDFRAMEP (*dframe))
642 return SCM_BOOL_F;
643
644 stack = scm_make_struct (scm_t_stackype, SCM_MAKINUM (SCM_FRAME_N_SLOTS),
645 SCM_EOL);
646 SCM_STACK (stack) -> length = 1;
647 SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
648 read_frame (dframe, offset,
649 (scm_t_info_frame *) &SCM_STACK (stack) -> frames[0]);
650
651 return scm_cons (stack, SCM_INUM0);
652 }
653 #undef FUNC_NAME
654
655 SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
656 (SCM frame),
657 "Return the frame number of @var{frame}.")
658 #define FUNC_NAME s_scm_frame_number
659 {
660 SCM_VALIDATE_FRAME (1,frame);
661 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame));
662 }
663 #undef FUNC_NAME
664
665 SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
666 (SCM frame),
667 "Return the source of @var{frame}.")
668 #define FUNC_NAME s_scm_frame_source
669 {
670 SCM_VALIDATE_FRAME (1,frame);
671 return SCM_FRAME_SOURCE (frame);
672 }
673 #undef FUNC_NAME
674
675 SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
676 (SCM frame),
677 "Return the procedure for @var{frame}, or @code{#f} if no\n"
678 "procedure is associated with @var{frame}.")
679 #define FUNC_NAME s_scm_frame_procedure
680 {
681 SCM_VALIDATE_FRAME (1,frame);
682 return (SCM_FRAME_PROC_P (frame)
683 ? SCM_FRAME_PROC (frame)
684 : SCM_BOOL_F);
685 }
686 #undef FUNC_NAME
687
688 SCM_DEFINE (scm_frame_arguments, "frame-arguments", 1, 0, 0,
689 (SCM frame),
690 "Return the arguments of @var{frame}.")
691 #define FUNC_NAME s_scm_frame_arguments
692 {
693 SCM_VALIDATE_FRAME (1,frame);
694 return SCM_FRAME_ARGS (frame);
695 }
696 #undef FUNC_NAME
697
698 SCM_DEFINE (scm_frame_previous, "frame-previous", 1, 0, 0,
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.")
702 #define FUNC_NAME s_scm_frame_previous
703 {
704 unsigned long int n;
705 SCM_VALIDATE_FRAME (1, frame);
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 }
712 #undef FUNC_NAME
713
714 SCM_DEFINE (scm_frame_next, "frame-next", 1, 0, 0,
715 (SCM frame),
716 "Return the next frame of @var{frame}, or @code{#f} if\n"
717 "@var{frame} is the last frame in its stack.")
718 #define FUNC_NAME s_scm_frame_next
719 {
720 unsigned long int n;
721 SCM_VALIDATE_FRAME (1, frame);
722 n = SCM_INUM (SCM_CDR (frame));
723 if (n == 0)
724 return SCM_BOOL_F;
725 else
726 return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n - 1));
727 }
728 #undef FUNC_NAME
729
730 SCM_DEFINE (scm_frame_real_p, "frame-real?", 1, 0, 0,
731 (SCM frame),
732 "Return @code{#t} if @var{frame} is a real frame.")
733 #define FUNC_NAME s_scm_frame_real_p
734 {
735 SCM_VALIDATE_FRAME (1,frame);
736 return SCM_BOOL(SCM_FRAME_REAL_P (frame));
737 }
738 #undef FUNC_NAME
739
740 SCM_DEFINE (scm_frame_procedure_p, "frame-procedure?", 1, 0, 0,
741 (SCM frame),
742 "Return @code{#t} if a procedure is associated with @var{frame}.")
743 #define FUNC_NAME s_scm_frame_procedure_p
744 {
745 SCM_VALIDATE_FRAME (1,frame);
746 return SCM_BOOL(SCM_FRAME_PROC_P (frame));
747 }
748 #undef FUNC_NAME
749
750 SCM_DEFINE (scm_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0,
751 (SCM frame),
752 "Return @code{#t} if @var{frame} contains evaluated arguments.")
753 #define FUNC_NAME s_scm_frame_evaluating_args_p
754 {
755 SCM_VALIDATE_FRAME (1,frame);
756 return SCM_BOOL(SCM_FRAME_EVAL_ARGS_P (frame));
757 }
758 #undef FUNC_NAME
759
760 SCM_DEFINE (scm_frame_overflow_p, "frame-overflow?", 1, 0, 0,
761 (SCM frame),
762 "Return @code{#t} if @var{frame} is an overflow frame.")
763 #define FUNC_NAME s_scm_frame_overflow_p
764 {
765 SCM_VALIDATE_FRAME (1,frame);
766 return SCM_BOOL(SCM_FRAME_OVERFLOW_P (frame));
767 }
768 #undef FUNC_NAME
769
770 \f
771
772 void
773 scm_init_stacks ()
774 {
775 SCM vtable;
776 SCM stack_layout
777 = scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT));
778 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
779 scm_t_stackype
780 = scm_permanent_object (scm_make_struct (vtable, SCM_INUM0,
781 scm_cons (stack_layout,
782 SCM_EOL)));
783 scm_set_struct_vtable_name_x (scm_t_stackype, scm_str2symbol ("stack"));
784 #ifndef SCM_MAGIC_SNARFER
785 #include "libguile/stacks.x"
786 #endif
787 }
788
789 /*
790 Local Variables:
791 c-file-style: "gnu"
792 End:
793 */