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