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