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