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