Commit | Line | Data |
---|---|---|
aa3f6951 | 1 | /* A stack holds a frame chain |
8de051da | 2 | * Copyright (C) 1996,1997,2000,2001, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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 | 26 | #include "libguile/_scm.h" |
06dcb9df | 27 | #include "libguile/control.h" |
a0599745 MD |
28 | #include "libguile/eval.h" |
29 | #include "libguile/debug.h" | |
30 | #include "libguile/continuations.h" | |
31 | #include "libguile/struct.h" | |
32 | #include "libguile/macros.h" | |
33 | #include "libguile/procprop.h" | |
34 | #include "libguile/modules.h" | |
35 | #include "libguile/root.h" | |
36 | #include "libguile/strings.h" | |
b1b942b7 AW |
37 | #include "libguile/vm.h" /* to capture vm stacks */ |
38 | #include "libguile/frames.h" /* vm frames */ | |
a0599745 MD |
39 | |
40 | #include "libguile/validate.h" | |
41 | #include "libguile/stacks.h" | |
22fc179a HWN |
42 | #include "libguile/private-options.h" |
43 | ||
782d171c | 44 | |
06dcb9df AW |
45 | static SCM scm_sys_stacks; |
46 | ||
782d171c | 47 | \f |
aa3f6951 | 48 | /* {Stacks} |
782d171c | 49 | * |
aa3f6951 AW |
50 | * The stack is represented as a struct that holds a frame. The frame itself is |
51 | * linked to the next frame, or #f. | |
782d171c MD |
52 | * |
53 | * Stacks | |
54 | * Constructor | |
55 | * make-stack | |
7115d1e4 MD |
56 | * Selectors |
57 | * stack-id | |
782d171c MD |
58 | * stack-ref |
59 | * Inspector | |
60 | * stack-length | |
aa3f6951 | 61 | */ |
782d171c MD |
62 | |
63 | \f | |
64 | ||
aa3f6951 | 65 | /* Count number of debug info frames on a stack, beginning with FRAME. |
782d171c | 66 | */ |
b1b942b7 | 67 | static long |
3b14dd2f | 68 | stack_depth (enum scm_vm_frame_kind kind, const struct scm_frame *frame) |
782d171c | 69 | { |
3b14dd2f AW |
70 | struct scm_frame tmp; |
71 | long n = 1; | |
72 | memcpy (&tmp, frame, sizeof tmp); | |
73 | while (scm_c_frame_previous (kind, &tmp)) | |
93dbc31b | 74 | ++n; |
782d171c MD |
75 | return n; |
76 | } | |
77 | ||
c3a6c6f9 MD |
78 | /* Narrow STACK by cutting away stackframes (mutatingly). |
79 | * | |
80 | * Inner frames (most recent) are cut by advancing the frames pointer. | |
81 | * Outer frames are cut by decreasing the recorded length. | |
82 | * | |
83 | * Cut maximally INNER inner frames and OUTER outer frames using | |
84 | * the keys INNER_KEY and OUTER_KEY. | |
85 | * | |
86 | * Frames are cut away starting at the end points and moving towards | |
87 | * the center of the stack. The key is normally compared to the | |
88 | * operator in application frames. Frames up to and including the key | |
89 | * are cut. | |
90 | * | |
91 | * If INNER_KEY is #t a different scheme is used for inner frames: | |
92 | * | |
93 | * Frames up to but excluding the first source frame originating from | |
94 | * a user module are cut, except for possible application frames | |
95 | * between the user frame and the last system frame previously | |
96 | * encountered. | |
97 | */ | |
98 | ||
0bca90aa | 99 | static scm_t_ptrdiff |
06dcb9df AW |
100 | find_prompt (SCM key) |
101 | { | |
0bca90aa | 102 | scm_t_ptrdiff fp_offset; |
9ede013f AW |
103 | |
104 | if (!scm_dynstack_find_prompt (&SCM_I_CURRENT_THREAD->dynstack, key, | |
0bca90aa | 105 | NULL, &fp_offset, NULL, NULL, NULL)) |
9ede013f AW |
106 | scm_misc_error ("make-stack", "Prompt tag not found while narrowing stack", |
107 | scm_list_1 (key)); | |
108 | ||
0bca90aa | 109 | return fp_offset; |
06dcb9df AW |
110 | } |
111 | ||
3b14dd2f AW |
112 | static long |
113 | narrow_stack (long len, enum scm_vm_frame_kind kind, struct scm_frame *frame, | |
114 | SCM inner_cut, SCM outer_cut) | |
7115d1e4 | 115 | { |
de0233af AW |
116 | /* Resolve procedure cuts to address ranges, if possible. If the |
117 | debug information has been stripped, this might not be | |
118 | possible. */ | |
119 | if (scm_is_true (scm_program_p (inner_cut))) | |
120 | { | |
121 | SCM addr_range = scm_program_address_range (inner_cut); | |
122 | if (scm_is_pair (addr_range)) | |
123 | inner_cut = addr_range; | |
124 | } | |
125 | if (scm_is_true (scm_program_p (outer_cut))) | |
126 | { | |
127 | SCM addr_range = scm_program_address_range (outer_cut); | |
128 | if (scm_is_pair (addr_range)) | |
129 | outer_cut = addr_range; | |
130 | } | |
131 | ||
7115d1e4 | 132 | /* Cut inner part. */ |
99d7688b | 133 | if (scm_is_true (scm_procedure_p (inner_cut))) |
c3a6c6f9 | 134 | { |
06dcb9df | 135 | /* Cut until the given procedure is seen. */ |
99d7688b | 136 | for (; len ;) |
aa3f6951 | 137 | { |
3b14dd2f | 138 | SCM proc = scm_c_frame_closure (kind, frame); |
aa3f6951 | 139 | len--; |
3b14dd2f | 140 | scm_c_frame_previous (kind, frame); |
99d7688b | 141 | if (scm_is_eq (proc, inner_cut)) |
06dcb9df | 142 | break; |
aa3f6951 | 143 | } |
c3a6c6f9 | 144 | } |
de0233af AW |
145 | else if (scm_is_pair (inner_cut) |
146 | && scm_is_integer (scm_car (inner_cut)) | |
147 | && scm_is_integer (scm_cdr (inner_cut))) | |
148 | { | |
149 | /* Cut until an IP within the given range is found. */ | |
150 | scm_t_uintptr low_pc, high_pc, pc; | |
151 | ||
152 | low_pc = scm_to_uintptr_t (scm_car (inner_cut)); | |
153 | high_pc = scm_to_uintptr_t (scm_cdr (inner_cut)); | |
154 | ||
155 | for (; len ;) | |
156 | { | |
157 | pc = (scm_t_uintptr) frame->ip; | |
158 | len--; | |
159 | scm_c_frame_previous (kind, frame); | |
160 | if (low_pc <= pc && pc < high_pc) | |
161 | break; | |
162 | } | |
163 | } | |
99d7688b | 164 | else if (scm_is_integer (inner_cut)) |
c3a6c6f9 | 165 | { |
06dcb9df | 166 | /* Cut specified number of frames. */ |
99d7688b NL |
167 | long inner = scm_to_int (inner_cut); |
168 | ||
06dcb9df | 169 | for (; inner && len; --inner) |
aa3f6951 | 170 | { |
aa3f6951 | 171 | len--; |
3b14dd2f | 172 | scm_c_frame_previous (kind, frame); |
aa3f6951 | 173 | } |
c3a6c6f9 | 174 | } |
99d7688b NL |
175 | else |
176 | { | |
177 | /* Cut until the given prompt tag is seen. */ | |
0bca90aa | 178 | scm_t_ptrdiff fp_offset = find_prompt (inner_cut); |
3b14dd2f AW |
179 | for (; len; len--, scm_c_frame_previous (kind, frame)) |
180 | if (fp_offset == frame->fp_offset) | |
99d7688b NL |
181 | break; |
182 | } | |
aa3f6951 | 183 | |
7115d1e4 | 184 | /* Cut outer part. */ |
99d7688b | 185 | if (scm_is_true (scm_procedure_p (outer_cut))) |
aa3f6951 | 186 | { |
3b14dd2f AW |
187 | long i, new_len; |
188 | struct scm_frame tmp; | |
189 | ||
190 | memcpy (&tmp, frame, sizeof tmp); | |
191 | ||
06dcb9df | 192 | /* Cut until the given procedure is seen. */ |
3b14dd2f AW |
193 | for (new_len = i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp)) |
194 | if (scm_is_eq (scm_c_frame_closure (kind, &tmp), outer_cut)) | |
195 | new_len = i; | |
196 | ||
de0233af AW |
197 | len = new_len; |
198 | } | |
199 | else if (scm_is_pair (outer_cut) | |
200 | && scm_is_integer (scm_car (outer_cut)) | |
201 | && scm_is_integer (scm_cdr (outer_cut))) | |
202 | { | |
203 | /* Cut until an IP within the given range is found. */ | |
204 | scm_t_uintptr low_pc, high_pc, pc; | |
205 | long i, new_len; | |
206 | struct scm_frame tmp; | |
207 | ||
208 | low_pc = scm_to_uintptr_t (scm_car (outer_cut)); | |
209 | high_pc = scm_to_uintptr_t (scm_cdr (outer_cut)); | |
210 | ||
211 | memcpy (&tmp, frame, sizeof tmp); | |
212 | ||
213 | /* Cut until the given procedure is seen. */ | |
214 | for (new_len = i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp)) | |
215 | { | |
216 | pc = (scm_t_uintptr) tmp.ip; | |
217 | if (low_pc <= pc && pc < high_pc) | |
218 | new_len = i; | |
219 | } | |
220 | ||
3b14dd2f | 221 | len = new_len; |
06dcb9df | 222 | } |
99d7688b NL |
223 | else if (scm_is_integer (outer_cut)) |
224 | { | |
225 | /* Cut specified number of frames. */ | |
226 | long outer = scm_to_int (outer_cut); | |
227 | ||
228 | if (outer < len) | |
229 | len -= outer; | |
230 | else | |
231 | len = 0; | |
232 | } | |
233 | else | |
06dcb9df | 234 | { |
99d7688b | 235 | /* Cut until the given prompt tag is seen. */ |
3b14dd2f AW |
236 | long i; |
237 | struct scm_frame tmp; | |
0bca90aa | 238 | scm_t_ptrdiff fp_offset = find_prompt (outer_cut); |
3b14dd2f AW |
239 | |
240 | memcpy (&tmp, frame, sizeof tmp); | |
241 | ||
242 | for (i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp)) | |
243 | if (tmp.fp_offset == fp_offset) | |
244 | break; | |
245 | ||
246 | if (i < len) | |
247 | len = i; | |
248 | else | |
249 | len = 0; | |
06dcb9df | 250 | } |
7115d1e4 | 251 | |
3b14dd2f | 252 | return len; |
7115d1e4 MD |
253 | } |
254 | ||
782d171c MD |
255 | \f |
256 | ||
257 | /* Stacks | |
258 | */ | |
259 | ||
762e289a | 260 | SCM scm_stack_type; |
66f45472 | 261 | |
a1ec6916 | 262 | SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0, |
1bbd0b84 | 263 | (SCM obj), |
b380b885 | 264 | "Return @code{#t} if @var{obj} is a calling stack.") |
1bbd0b84 | 265 | #define FUNC_NAME s_scm_stack_p |
66f45472 | 266 | { |
7888309b | 267 | return scm_from_bool(SCM_STACKP (obj)); |
66f45472 | 268 | } |
1bbd0b84 | 269 | #undef FUNC_NAME |
66f45472 | 270 | |
af45e3b0 DH |
271 | SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1, |
272 | (SCM obj, SCM args), | |
67941e3c MG |
273 | "Create a new stack. If @var{obj} is @code{#t}, the current\n" |
274 | "evaluation stack is used for creating the stack frames,\n" | |
275 | "otherwise the frames are taken from @var{obj} (which must be\n" | |
06dcb9df AW |
276 | "a continuation or a frame object).\n" |
277 | "\n" | |
baffb19f | 278 | "@var{args} should be a list containing any combination of\n" |
de0233af AW |
279 | "integer, procedure, address range, prompt tag and @code{#t}\n" |
280 | "values.\n" | |
06dcb9df | 281 | "\n" |
baffb19f NJ |
282 | "These values specify various ways of cutting away uninteresting\n" |
283 | "stack frames from the top and bottom of the stack that\n" | |
284 | "@code{make-stack} returns. They come in pairs like this:\n" | |
285 | "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n" | |
06dcb9df AW |
286 | "@var{outer_cut_2} @dots{})}.\n" |
287 | "\n" | |
de0233af AW |
288 | "Each @var{inner_cut_i} can be an integer, a procedure, an\n" |
289 | "address range, or a prompt tag. An integer means to cut away\n" | |
290 | "exactly that number of frames. A procedure means to cut\n" | |
291 | "away all frames up to but excluding the frame whose procedure\n" | |
292 | "matches the specified one. An address range is a pair of\n" | |
293 | "integers indicating the low and high addresses of a procedure's\n" | |
294 | "code, and is the same as cutting away to a procedure (though\n" | |
295 | "with less work). Anything else is interpreted as a prompt tag\n" | |
296 | "which cuts away all frames that are inside a prompt with the\n" | |
297 | "given tag.\n" | |
06dcb9df | 298 | "\n" |
de0233af AW |
299 | "Each @var{outer_cut_i} can be an integer, a procedure, an\n" |
300 | "address range, or a prompt tag. An integer means to cut away\n" | |
301 | "that number of frames. A procedure means to cut away frames\n" | |
302 | "down to but excluding the frame whose procedure matches the\n" | |
303 | "specified one. An address range is the same, but with the\n" | |
304 | "procedure's code specified as an address range. Anything else\n" | |
305 | "is taken to be a prompt tag, which cuts away all frames that are\n" | |
306 | "outside a prompt with the given tag.\n" | |
06dcb9df | 307 | "\n" |
de0233af AW |
308 | "If the @var{outer_cut_i} of the last pair is missing, it is\n" |
309 | "taken as 0.") | |
1bbd0b84 | 310 | #define FUNC_NAME s_scm_make_stack |
782d171c | 311 | { |
aa3f6951 | 312 | long n; |
af45e3b0 | 313 | SCM inner_cut, outer_cut; |
3b14dd2f AW |
314 | enum scm_vm_frame_kind kind; |
315 | struct scm_frame frame; | |
f6f88e0d MD |
316 | |
317 | /* Extract a pointer to the innermost frame of whatever object | |
318 | scm_make_stack was given. */ | |
bc36d050 | 319 | if (scm_is_eq (obj, SCM_BOOL_T)) |
782d171c | 320 | { |
aa3f6951 AW |
321 | SCM cont; |
322 | struct scm_vm_cont *c; | |
323 | ||
9ede013f | 324 | cont = scm_i_capture_current_stack (); |
8de051da | 325 | c = SCM_VM_CONT_DATA (cont); |
3b14dd2f AW |
326 | |
327 | kind = SCM_VM_FRAME_KIND_CONT; | |
328 | frame.stack_holder = c; | |
329 | frame.fp_offset = (c->fp + c->reloc) - c->stack_base; | |
330 | frame.sp_offset = (c->sp + c->reloc) - c->stack_base; | |
331 | frame.ip = c->ra; | |
13dcb666 | 332 | } |
b1b942b7 | 333 | else if (SCM_VM_FRAME_P (obj)) |
3b14dd2f AW |
334 | { |
335 | kind = SCM_VM_FRAME_KIND (obj); | |
336 | memcpy (&frame, SCM_VM_FRAME_DATA (obj), sizeof frame); | |
337 | } | |
13dcb666 | 338 | else if (SCM_CONTINUATIONP (obj)) |
06dcb9df AW |
339 | /* FIXME: Narrowing to prompt tags should narrow with respect to the prompts |
340 | that were in place when the continuation was captured. */ | |
3b14dd2f AW |
341 | { |
342 | kind = SCM_VM_FRAME_KIND_CONT; | |
343 | if (!scm_i_continuation_to_frame (obj, &frame)) | |
344 | return SCM_BOOL_F; | |
345 | } | |
4cfa92d6 AW |
346 | else if (SCM_PROGRAM_P (obj) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (obj)) |
347 | { | |
348 | kind = SCM_VM_FRAME_KIND_CONT; | |
349 | if (!scm_i_vm_cont_to_frame (SCM_PROGRAM_FREE_VARIABLE_REF (obj, 0), | |
350 | &frame)) | |
351 | return SCM_BOOL_F; | |
352 | } | |
13dcb666 DH |
353 | else |
354 | { | |
355 | SCM_WRONG_TYPE_ARG (SCM_ARG1, obj); | |
356 | /* not reached */ | |
782d171c MD |
357 | } |
358 | ||
3b14dd2f AW |
359 | /* Skip initial boot frame, if any. This is possible if the frame |
360 | originates from a captured continuation. */ | |
361 | if (SCM_PROGRAM_P (scm_c_frame_closure (kind, &frame)) | |
362 | && SCM_PROGRAM_IS_BOOT (scm_c_frame_closure (kind, &frame)) | |
363 | && !scm_c_frame_previous (kind, &frame)) | |
14aa25e4 AW |
364 | return SCM_BOOL_F; |
365 | ||
f6f88e0d MD |
366 | /* Count number of frames. Also get stack id tag and check whether |
367 | there are more stackframes than we want to record | |
368 | (SCM_BACKTRACE_MAXDEPTH). */ | |
3b14dd2f | 369 | n = stack_depth (kind, &frame); |
782d171c | 370 | |
f6f88e0d | 371 | /* Narrow the stack according to the arguments given to scm_make_stack. */ |
af45e3b0 | 372 | SCM_VALIDATE_REST_ARGUMENT (args); |
d2e53ed6 | 373 | while (n > 0 && !scm_is_null (args)) |
f6f88e0d MD |
374 | { |
375 | inner_cut = SCM_CAR (args); | |
376 | args = SCM_CDR (args); | |
d2e53ed6 | 377 | if (scm_is_null (args)) |
af45e3b0 | 378 | { |
13dcb666 | 379 | outer_cut = SCM_INUM0; |
af45e3b0 DH |
380 | } |
381 | else | |
f6f88e0d MD |
382 | { |
383 | outer_cut = SCM_CAR (args); | |
384 | args = SCM_CDR (args); | |
385 | } | |
f6f88e0d | 386 | |
3b14dd2f | 387 | n = narrow_stack (n, kind, &frame, inner_cut, outer_cut); |
f6f88e0d MD |
388 | } |
389 | ||
7115d1e4 | 390 | if (n > 0) |
3b14dd2f AW |
391 | { |
392 | /* Make the stack object. */ | |
393 | SCM stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL); | |
394 | SCM_SET_STACK_LENGTH (stack, n); | |
395 | SCM_SET_STACK_ID (stack, scm_stack_id (obj)); | |
396 | SCM_SET_STACK_FRAME (stack, scm_c_make_frame (kind, &frame)); | |
397 | return stack; | |
398 | } | |
7115d1e4 MD |
399 | else |
400 | return SCM_BOOL_F; | |
782d171c | 401 | } |
1bbd0b84 | 402 | #undef FUNC_NAME |
782d171c | 403 | |
a1ec6916 | 404 | SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0, |
1bbd0b84 | 405 | (SCM stack), |
b380b885 | 406 | "Return the identifier given to @var{stack} by @code{start-stack}.") |
1bbd0b84 | 407 | #define FUNC_NAME s_scm_stack_id |
66f45472 | 408 | { |
06dcb9df AW |
409 | if (scm_is_eq (stack, SCM_BOOL_T) |
410 | /* FIXME: frame case assumes frame still live on the stack, and no | |
411 | intervening start-stack. Hmm... */ | |
412 | || SCM_VM_FRAME_P (stack)) | |
7115d1e4 | 413 | { |
06dcb9df AW |
414 | /* Fetch most recent start-stack tag. */ |
415 | SCM stacks = scm_fluid_ref (scm_sys_stacks); | |
416 | return scm_is_pair (stacks) ? scm_caar (stacks) : SCM_BOOL_F; | |
13dcb666 DH |
417 | } |
418 | else if (SCM_CONTINUATIONP (stack)) | |
06dcb9df AW |
419 | /* FIXME: implement me */ |
420 | return SCM_BOOL_F; | |
4cfa92d6 AW |
421 | else if (SCM_PROGRAM_P (stack) && SCM_PROGRAM_IS_PARTIAL_CONTINUATION (stack)) |
422 | /* FIXME: implement me */ | |
423 | return SCM_BOOL_F; | |
13dcb666 DH |
424 | else |
425 | { | |
14aa25e4 AW |
426 | SCM_WRONG_TYPE_ARG (SCM_ARG1, stack); |
427 | /* not reached */ | |
13dcb666 | 428 | } |
66f45472 | 429 | } |
1bbd0b84 | 430 | #undef FUNC_NAME |
66f45472 | 431 | |
a1ec6916 | 432 | SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0, |
13dcb666 DH |
433 | (SCM stack, SCM index), |
434 | "Return the @var{index}'th frame from @var{stack}.") | |
1bbd0b84 | 435 | #define FUNC_NAME s_scm_stack_ref |
782d171c | 436 | { |
13dcb666 | 437 | unsigned long int c_index; |
aa3f6951 | 438 | SCM frame; |
13dcb666 DH |
439 | |
440 | SCM_VALIDATE_STACK (1, stack); | |
a55c2b68 | 441 | c_index = scm_to_unsigned_integer (index, 0, SCM_STACK_LENGTH(stack)-1); |
aa3f6951 AW |
442 | frame = SCM_STACK_FRAME (stack); |
443 | while (c_index--) | |
93dbc31b | 444 | frame = scm_frame_previous (frame); |
aa3f6951 | 445 | return frame; |
782d171c | 446 | } |
1bbd0b84 | 447 | #undef FUNC_NAME |
782d171c | 448 | |
3b3b36dd | 449 | SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0, |
67941e3c MG |
450 | (SCM stack), |
451 | "Return the length of @var{stack}.") | |
1bbd0b84 | 452 | #define FUNC_NAME s_scm_stack_length |
782d171c | 453 | { |
34d19ef6 | 454 | SCM_VALIDATE_STACK (1, stack); |
aa3f6951 | 455 | return scm_from_long (SCM_STACK_LENGTH (stack)); |
782d171c | 456 | } |
1bbd0b84 | 457 | #undef FUNC_NAME |
782d171c MD |
458 | |
459 | \f | |
460 | ||
461 | void | |
462 | scm_init_stacks () | |
463 | { | |
06dcb9df AW |
464 | scm_sys_stacks = scm_make_fluid (); |
465 | scm_c_define ("%stacks", scm_sys_stacks); | |
466 | ||
f39448c5 AW |
467 | scm_stack_type = scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT), |
468 | SCM_UNDEFINED); | |
cc95e00a | 469 | scm_set_struct_vtable_name_x (scm_stack_type, |
4a655e50 | 470 | scm_from_latin1_symbol ("stack")); |
a0599745 | 471 | #include "libguile/stacks.x" |
782d171c | 472 | } |
89e00824 ML |
473 | |
474 | /* | |
475 | Local Variables: | |
476 | c-file-style: "gnu" | |
477 | End: | |
478 | */ |