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