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