Merge from mvo-vcell-cleanup-1-branch.
[bpt/guile.git] / libguile / stacks.c
1 /* Representation of stack frame debug information
2 * Copyright (C) 1996,1997, 2000 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 /* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
47 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
48
49 \f
50
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"
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 *
94 * The stack is represented as a struct with an id slot and a tail
95 * array of scm_info_frame structs.
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
104 * Selectors
105 * stack-id
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?
124 * frame-overflow? */
125
126 \f
127
128 /* Some auxiliary functions for reading debug frames off the stack.
129 */
130
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
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 */
155 static int
156 stack_depth (scm_debug_frame *dframe,long offset,SCM *id,int *maxp)
157 {
158 int n;
159 int max_depth = SCM_BACKTRACE_MAXDEPTH;
160 for (n = 0;
161 dframe && !SCM_VOIDFRAMEP (*dframe) && n < max_depth;
162 dframe = RELOC_FRAME (dframe->prev, offset))
163 {
164 if (SCM_EVALFRAMEP (*dframe))
165 {
166 scm_debug_info * info = RELOC_INFO (dframe->info, offset);
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 }
178 if (dframe && SCM_VOIDFRAMEP (*dframe))
179 *id = dframe->vect[0].id;
180 else if (dframe)
181 *maxp = 1;
182 return n;
183 }
184
185 /* Read debug info from DFRAME into IFRAME.
186 */
187 static void
188 read_frame (scm_debug_frame *dframe,long offset,scm_info_frame *iframe)
189 {
190 scm_bits_t flags = SCM_UNPACK (SCM_INUM0); /* UGh. */
191 if (SCM_EVALFRAMEP (*dframe))
192 {
193 scm_debug_info * info = RELOC_INFO (dframe->info, offset);
194 if ((info - dframe->vect) & 1)
195 {
196 /* Debug.vect ends with apply info. */
197 --info;
198 if (!SCM_UNBNDP (info[1].a.proc))
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 }
207 iframe->source = scm_make_memoized (info[0].e.exp, info[0].e.env);
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
218 /* Look up the first body form of the apply closure. We'll use this
219 below to prevent it from being displayed.
220 */
221 static SCM
222 get_applybody ()
223 {
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)));
227 else
228 return SCM_UNDEFINED;
229 }
230
231 #define NEXT_FRAME(iframe, n, quit) \
232 do { \
233 if (SCM_NIMP (iframe->source) \
234 && SCM_EQ_P (SCM_MEMOIZED_EXP (iframe->source), applybody)) \
235 { \
236 iframe->source = SCM_BOOL_F; \
237 if (SCM_FALSEP (iframe->proc)) \
238 { \
239 --iframe; \
240 ++n; \
241 } \
242 } \
243 ++iframe; \
244 if (--n == 0) \
245 goto quit; \
246 } while (0)
247
248
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
254 static int
255 read_frames (scm_debug_frame *dframe,long offset,int n,scm_info_frame *iframes)
256 {
257 scm_info_frame *iframe = iframes;
258 scm_debug_info *info;
259 static SCM applybody = SCM_UNDEFINED;
260
261 /* The value of applybody has to be setup after r4rs.scm has executed. */
262 if (SCM_UNBNDP (applybody))
263 applybody = get_applybody ();
264 for (;
265 dframe && !SCM_VOIDFRAMEP (*dframe) && n > 0;
266 dframe = RELOC_FRAME (dframe->prev, offset))
267 {
268 read_frame (dframe, offset, iframe);
269 if (SCM_EVALFRAMEP (*dframe))
270 {
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)
275 {
276 *(iframe - 1) = *iframe;
277 --iframe;
278 }
279 info = RELOC_INFO (dframe->info, offset);
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 {
287 NEXT_FRAME (iframe, n, quit);
288 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
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;
295 NEXT_FRAME (iframe, n, quit);
296 while (info >= dframe->vect)
297 {
298 if (!SCM_UNBNDP (info[1].a.proc))
299 {
300 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
301 iframe->proc = info[1].a.proc;
302 iframe->args = info[1].a.args;
303 }
304 else
305 iframe->flags = SCM_UNPACK (SCM_INUM0);
306 iframe->source = scm_make_memoized (info[0].e.exp,
307 info[0].e.env);
308 info -= 2;
309 NEXT_FRAME (iframe, n, quit);
310 }
311 }
312 else if (SCM_EQ_P (iframe->proc, scm_f_gsubr_apply))
313 /* Skip gsubr apply frames. */
314 continue;
315 else
316 {
317 NEXT_FRAME (iframe, n, quit);
318 }
319 quit:
320 if (iframe > iframes)
321 (iframe - 1) -> flags |= SCM_FRAMEF_REAL;
322 }
323 return iframe - iframes; /* Number of frames actually read */
324 }
325
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
347 static void
348 narrow_stack (SCM stack,int inner,SCM inner_key,int outer,SCM outer_key)
349 {
350 scm_stack *s = SCM_STACK (stack);
351 int i;
352 int n = s->length;
353
354 /* Cut inner part. */
355 if (SCM_EQ_P (inner_key, SCM_BOOL_T))
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;
361 if ( SCM_MEMOIZEDP (m)
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
367 && !((m = s->frames[i - 1].source, SCM_MEMOIZEDP (m))
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)
384 if (SCM_EQ_P (s->frames[i++].proc, inner_key))
385 break;
386 }
387 s->frames = &s->frames[i];
388 n -= i;
389
390 /* Cut outer part. */
391 for (; n && outer; --outer)
392 if (SCM_EQ_P (s->frames[--n].proc, outer_key))
393 break;
394
395 s->length = n;
396 }
397
398 \f
399
400 /* Stacks
401 */
402
403 SCM scm_stack_type;
404
405 SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
406 (SCM obj),
407 "Return @code{#t} if @var{obj} is a calling stack.")
408 #define FUNC_NAME s_scm_stack_p
409 {
410 return SCM_BOOL(SCM_STACKP (obj));
411 }
412 #undef FUNC_NAME
413
414 SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
415 (SCM obj, SCM args),
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"
420 "@var{args} must be a list of integers and specifies how the\n"
421 "resulting stack will be narrowed.")
422 #define FUNC_NAME s_scm_make_stack
423 {
424 int n, maxp, size;
425 scm_debug_frame *dframe = scm_last_debug_frame;
426 scm_info_frame *iframe;
427 long offset = 0;
428 SCM stack, id;
429 SCM inner_cut, outer_cut;
430
431 /* Extract a pointer to the innermost frame of whatever object
432 scm_make_stack was given. */
433 /* just use dframe == scm_last_debug_frame
434 (from initialization of dframe, above) if obj is #t */
435 if (!SCM_EQ_P (obj, SCM_BOOL_T))
436 {
437 SCM_ASSERT (SCM_NIMP (obj), obj, SCM_ARG1, FUNC_NAME);
438 if (SCM_DEBUGOBJP (obj))
439 dframe = (scm_debug_frame *) SCM_DEBUGOBJ_FRAME (obj);
440 else if (SCM_CONTINUATIONP (obj))
441 {
442 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_contregs))
443 - SCM_BASE (obj));
444 #ifndef STACK_GROWS_UP
445 offset += SCM_CONTINUATION_LENGTH (obj);
446 #endif
447 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
448 }
449 else
450 {
451 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
452 /* not reached */
453 }
454 }
455
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). */
459 id = SCM_BOOL_F;
460 maxp = 0;
461 n = stack_depth (dframe, offset, &id, &maxp);
462 size = n * SCM_FRAME_N_SLOTS;
463
464 /* Make the stack object. */
465 stack = scm_make_struct (scm_stack_type, SCM_MAKINUM (size), SCM_EOL);
466 SCM_STACK (stack) -> id = id;
467 iframe = &SCM_STACK (stack) -> tail[0];
468 SCM_STACK (stack) -> frames = iframe;
469
470 /* Translate the current chain of stack frames into debugging information. */
471 n = read_frames (RELOC_FRAME (dframe, offset), offset, n, iframe);
472 SCM_STACK (stack) -> length = n;
473
474 /* Narrow the stack according to the arguments given to scm_make_stack. */
475 SCM_VALIDATE_REST_ARGUMENT (args);
476 while (n > 0 && !SCM_NULLP (args))
477 {
478 inner_cut = SCM_CAR (args);
479 args = SCM_CDR (args);
480 if (SCM_NULLP (args))
481 {
482 outer_cut = SCM_INUM0;
483 }
484 else
485 {
486 outer_cut = SCM_CAR (args);
487 args = SCM_CDR (args);
488 }
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
499 if (n > 0)
500 {
501 if (maxp)
502 iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW;
503 return stack;
504 }
505 else
506 return SCM_BOOL_F;
507 }
508 #undef FUNC_NAME
509
510 SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
511 (SCM stack),
512 "Return the identifier given to @var{stack} by @code{start-stack}.")
513 #define FUNC_NAME s_scm_stack_id
514 {
515 scm_debug_frame *dframe;
516 long offset = 0;
517 if (SCM_EQ_P (stack, SCM_BOOL_T))
518 dframe = scm_last_debug_frame;
519 else
520 {
521 SCM_VALIDATE_NIM (1,stack);
522 if (SCM_DEBUGOBJP (stack))
523 dframe = (scm_debug_frame *) SCM_DEBUGOBJ_FRAME (stack);
524 else if (SCM_CONTINUATIONP (stack))
525 {
526 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (stack) + sizeof (scm_contregs))
527 - SCM_BASE (stack));
528 #ifndef STACK_GROWS_UP
529 offset += SCM_CONTINUATION_LENGTH (stack);
530 #endif
531 dframe = RELOC_FRAME (SCM_DFRAME (stack), offset);
532 }
533 else if (SCM_STACKP (stack))
534 return SCM_STACK (stack) -> id;
535 else
536 SCM_WRONG_TYPE_ARG (1, stack);
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
546 SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
547 (SCM stack, SCM i),
548 "Return the @var{i}'th frame from @var{stack}.")
549 #define FUNC_NAME s_scm_stack_ref
550 {
551 SCM_VALIDATE_STACK (1,stack);
552 SCM_VALIDATE_INUM (2,i);
553 SCM_ASSERT_RANGE (1,i,
554 SCM_INUM (i) >= 0 &&
555 SCM_INUM (i) < SCM_STACK_LENGTH (stack));
556 return scm_cons (stack, i);
557 }
558 #undef FUNC_NAME
559
560 SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
561 (SCM stack),
562 "Return the length of @var{stack}.")
563 #define FUNC_NAME s_scm_stack_length
564 {
565 SCM_VALIDATE_STACK (1,stack);
566 return SCM_MAKINUM (SCM_STACK_LENGTH (stack));
567 }
568 #undef FUNC_NAME
569
570 /* Frames
571 */
572
573 SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
574 (SCM obj),
575 "Return @code{#t} if @var{obj} is a stack frame.")
576 #define FUNC_NAME s_scm_frame_p
577 {
578 return SCM_BOOL(SCM_FRAMEP (obj));
579 }
580 #undef FUNC_NAME
581
582 SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
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.")
587 #define FUNC_NAME s_scm_last_stack_frame
588 {
589 scm_debug_frame *dframe;
590 long offset = 0;
591 SCM stack;
592
593 SCM_VALIDATE_NIM (1,obj);
594 if (SCM_DEBUGOBJP (obj))
595 dframe = (scm_debug_frame *) SCM_DEBUGOBJ_FRAME (obj);
596 else if (SCM_CONTINUATIONP (obj))
597 {
598 offset = ((SCM_STACKITEM *) ((char *) SCM_CONTREGS (obj) + sizeof (scm_contregs))
599 - SCM_BASE (obj));
600 #ifndef STACK_GROWS_UP
601 offset += SCM_CONTINUATION_LENGTH (obj);
602 #endif
603 dframe = RELOC_FRAME (SCM_DFRAME (obj), offset);
604 }
605 else
606 {
607 SCM_WRONG_TYPE_ARG (1, obj);
608 /* not reached */
609 }
610
611 if (!dframe || SCM_VOIDFRAMEP (*dframe))
612 return SCM_BOOL_F;
613
614 stack = scm_make_struct (scm_stack_type, SCM_MAKINUM (SCM_FRAME_N_SLOTS),
615 SCM_EOL);
616 SCM_STACK (stack) -> length = 1;
617 SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
618 read_frame (dframe, offset,
619 (scm_info_frame *) &SCM_STACK (stack) -> frames[0]);
620
621 return scm_cons (stack, SCM_INUM0);;
622 }
623 #undef FUNC_NAME
624
625 SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
626 (SCM frame),
627 "Return the frame number of @var{frame}.")
628 #define FUNC_NAME s_scm_frame_number
629 {
630 SCM_VALIDATE_FRAME (1,frame);
631 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame));
632 }
633 #undef FUNC_NAME
634
635 SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
636 (SCM frame),
637 "Return the source of @var{frame}.")
638 #define FUNC_NAME s_scm_frame_source
639 {
640 SCM_VALIDATE_FRAME (1,frame);
641 return SCM_FRAME_SOURCE (frame);
642 }
643 #undef FUNC_NAME
644
645 SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
646 (SCM frame),
647 "Return the procedure for @var{frame}, or @code{#f} if no\n"
648 "procedure is associated with @var{frame}.")
649 #define FUNC_NAME s_scm_frame_procedure
650 {
651 SCM_VALIDATE_FRAME (1,frame);
652 return (SCM_FRAME_PROC_P (frame)
653 ? SCM_FRAME_PROC (frame)
654 : SCM_BOOL_F);
655 }
656 #undef FUNC_NAME
657
658 SCM_DEFINE (scm_frame_arguments, "frame-arguments", 1, 0, 0,
659 (SCM frame),
660 "Return the arguments of @var{frame}.")
661 #define FUNC_NAME s_scm_frame_arguments
662 {
663 SCM_VALIDATE_FRAME (1,frame);
664 return SCM_FRAME_ARGS (frame);
665 }
666 #undef FUNC_NAME
667
668 SCM_DEFINE (scm_frame_previous, "frame-previous", 1, 0, 0,
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.")
672 #define FUNC_NAME s_scm_frame_previous
673 {
674 int n;
675 SCM_VALIDATE_FRAME (1,frame);
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 }
682 #undef FUNC_NAME
683
684 SCM_DEFINE (scm_frame_next, "frame-next", 1, 0, 0,
685 (SCM frame),
686 "Return the next frame of @var{frame}, or @code{#f} if\n"
687 "@var{frame} is the last frame in its stack.")
688 #define FUNC_NAME s_scm_frame_next
689 {
690 int n;
691 SCM_VALIDATE_FRAME (1,frame);
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 }
698 #undef FUNC_NAME
699
700 SCM_DEFINE (scm_frame_real_p, "frame-real?", 1, 0, 0,
701 (SCM frame),
702 "Return @code{#t} if @var{frame} is a real frame.")
703 #define FUNC_NAME s_scm_frame_real_p
704 {
705 SCM_VALIDATE_FRAME (1,frame);
706 return SCM_BOOL(SCM_FRAME_REAL_P (frame));
707 }
708 #undef FUNC_NAME
709
710 SCM_DEFINE (scm_frame_procedure_p, "frame-procedure?", 1, 0, 0,
711 (SCM frame),
712 "Return @code{#t} if a procedure is associated with @var{frame}.")
713 #define FUNC_NAME s_scm_frame_procedure_p
714 {
715 SCM_VALIDATE_FRAME (1,frame);
716 return SCM_BOOL(SCM_FRAME_PROC_P (frame));
717 }
718 #undef FUNC_NAME
719
720 SCM_DEFINE (scm_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0,
721 (SCM frame),
722 "Return @code{#t} if @var{frame} contains evaluated arguments.")
723 #define FUNC_NAME s_scm_frame_evaluating_args_p
724 {
725 SCM_VALIDATE_FRAME (1,frame);
726 return SCM_BOOL(SCM_FRAME_EVAL_ARGS_P (frame));
727 }
728 #undef FUNC_NAME
729
730 SCM_DEFINE (scm_frame_overflow_p, "frame-overflow?", 1, 0, 0,
731 (SCM frame),
732 "Return @code{#t} if @var{frame} is an overflow frame.")
733 #define FUNC_NAME s_scm_frame_overflow_p
734 {
735 SCM_VALIDATE_FRAME (1,frame);
736 return SCM_BOOL(SCM_FRAME_OVERFLOW_P (frame));
737 }
738 #undef FUNC_NAME
739
740 \f
741
742 void
743 scm_init_stacks ()
744 {
745 SCM vtable;
746 SCM stack_layout
747 = scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT));
748 vtable = scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
749 scm_stack_type
750 = scm_permanent_object (scm_make_struct (vtable, SCM_INUM0,
751 scm_cons (stack_layout,
752 SCM_EOL)));
753 scm_set_struct_vtable_name_x (scm_stack_type, scm_str2symbol ("stack"));
754 #ifndef SCM_MAGIC_SNARFER
755 #include "libguile/stacks.x"
756 #endif
757 }
758
759 /*
760 Local Variables:
761 c-file-style: "gnu"
762 End:
763 */