* extracted the tests from exceptions.test into eval.test and syntax.test.
[bpt/guile.git] / libguile / struct.c
CommitLineData
8dee1541 1/* Copyright (C) 1996, 97, 98, 99, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
a0599745
MD
48#include "libguile/_scm.h"
49#include "libguile/chars.h"
50#include "libguile/eval.h"
51#include "libguile/alist.h"
52#include "libguile/weaks.h"
53#include "libguile/hashtab.h"
54#include "libguile/ports.h"
55#include "libguile/strings.h"
56
57#include "libguile/validate.h"
58#include "libguile/struct.h"
0f2d19dd 59
95b88819
GH
60#ifdef HAVE_STRING_H
61#include <string.h>
62#endif
63
0f2d19dd
JB
64\f
65
66static SCM required_vtable_fields = SCM_BOOL_F;
98d5f601 67SCM scm_struct_table;
0f2d19dd
JB
68
69\f
a1ec6916 70SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
1bbd0b84 71 (SCM fields),
b380b885 72 "Return a new structure layout object.\n\n"
7c31152f 73 "@var{fields} must be a string made up of pairs of characters\n"
b380b885
MD
74 "strung together. The first character of each pair describes a field\n"
75 "type, the second a field protection. Allowed types are 'p' for\n"
76 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
04323af4 77 "a field that points to the structure itself. Allowed protections\n"
b380b885
MD
78 "are 'w' for mutable fields, 'r' for read-only fields, and 'o' for opaque \n"
79 "fields. The last field protection specification may be capitalized to\n"
80 "indicate that the field is a tail-array.")
1bbd0b84 81#define FUNC_NAME s_scm_make_struct_layout
0f2d19dd
JB
82{
83 SCM new_sym;
d1ca2c64 84 SCM_VALIDATE_STRING (1, fields);
1bbd0b84 85 { /* scope */
0f2d19dd
JB
86 char * field_desc;
87 int len;
88 int x;
89
d1ca2c64 90 len = SCM_STRING_LENGTH (fields);
34f0f2b8 91 field_desc = SCM_STRING_CHARS (fields);
1bbd0b84 92 SCM_ASSERT (!(len & 1), fields, "odd length field specification", FUNC_NAME);
0f2d19dd
JB
93
94 for (x = 0; x < len; x += 2)
95 {
96 switch (field_desc[x])
97 {
98 case 'u':
99 case 'p':
100#if 0
101 case 'i':
102 case 'd':
103#endif
104 case 's':
105 break;
106 default:
7866a09b 107 SCM_ASSERT (0, SCM_MAKE_CHAR (field_desc[x]) , "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
108 }
109
110 switch (field_desc[x + 1])
111 {
112 case 'w':
7866a09b 113 SCM_ASSERT (field_desc[x] != 's', SCM_MAKE_CHAR (field_desc[x + 1]),
1bbd0b84 114 "self fields not writable", FUNC_NAME);
0f2d19dd
JB
115
116 case 'r':
117 case 'o':
118 break;
2c36c351
MD
119 case 'R':
120 case 'W':
121 case 'O':
7866a09b 122 SCM_ASSERT (field_desc[x] != 's', SCM_MAKE_CHAR (field_desc[x + 1]),
2c36c351 123 "self fields not allowed in tail array",
1bbd0b84 124 FUNC_NAME);
7866a09b 125 SCM_ASSERT (x == len - 2, SCM_MAKE_CHAR (field_desc[x + 1]),
2c36c351 126 "tail array field must be last field in layout",
1bbd0b84 127 FUNC_NAME);
2c36c351 128 break;
0f2d19dd 129 default:
7866a09b 130 SCM_ASSERT (0, SCM_MAKE_CHAR (field_desc[x]) , "unrecognized ref specification", FUNC_NAME);
0f2d19dd
JB
131 }
132#if 0
133 if (field_desc[x] == 'd')
134 {
1bbd0b84 135 SCM_ASSERT (field_desc[x + 2] == '-', SCM_MAKINUM (x / 2), "missing dash field", FUNC_NAME);
0f2d19dd
JB
136 x += 2;
137 goto recheck_ref;
138 }
139#endif
140 }
38ae064c 141 new_sym = scm_mem2symbol (field_desc, len);
0f2d19dd
JB
142 }
143 return scm_return_first (new_sym, fields);
144}
1bbd0b84 145#undef FUNC_NAME
0f2d19dd
JB
146
147\f
148
149
1cc91f1b 150
f7620510
DH
151static void
152scm_struct_init (SCM handle, SCM layout, scm_bits_t * mem, int tail_elts, SCM inits)
0f2d19dd 153{
a002f1a2 154 unsigned char * fields_desc = (unsigned char *) SCM_SYMBOL_CHARS (layout) - 2;
35de7ebe 155 unsigned char prot = 0;
bfa974f0 156 int n_fields = SCM_SYMBOL_LENGTH (layout) / 2;
2c36c351 157 int tailp = 0;
d8c40b9f 158
0f2d19dd
JB
159 while (n_fields)
160 {
2c36c351
MD
161 if (!tailp)
162 {
163 fields_desc += 2;
164 prot = fields_desc[1];
165 if (SCM_LAYOUT_TAILP (prot))
166 {
167 tailp = 1;
168 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
d8c40b9f 169 *mem++ = tail_elts;
2c36c351
MD
170 n_fields += tail_elts - 1;
171 if (n_fields == 0)
172 break;
173 }
174 }
175
0f2d19dd
JB
176 switch (*fields_desc)
177 {
178#if 0
179 case 'i':
2c36c351 180 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
181 *mem = 0;
182 else
183 {
a5bfe84d 184 *mem = scm_num2long (SCM_CAR (inits), SCM_ARGn, "scm_struct_init");
0f2d19dd
JB
185 inits = SCM_CDR (inits);
186 }
187 break;
188#endif
189
190 case 'u':
54778cd3 191 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
0f2d19dd
JB
192 *mem = 0;
193 else
194 {
d8c40b9f
DH
195 *mem = scm_num2ulong (SCM_CAR (inits),
196 SCM_ARGn,
197 "scm_struct_init");
0f2d19dd
JB
198 inits = SCM_CDR (inits);
199 }
200 break;
201
202 case 'p':
54778cd3 203 if ((prot != 'r' && prot != 'w') || SCM_NULLP (inits))
d8c40b9f 204 *mem = SCM_UNPACK (SCM_BOOL_F);
0f2d19dd
JB
205 else
206 {
d8c40b9f 207 *mem = SCM_UNPACK (SCM_CAR (inits));
0f2d19dd
JB
208 inits = SCM_CDR (inits);
209 }
210
211 break;
212
213#if 0
214 case 'd':
2c36c351 215 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
0f2d19dd
JB
216 *((double *)mem) = 0.0;
217 else
218 {
a5bfe84d 219 *mem = scm_num2dbl (SCM_CAR (inits), "scm_struct_init");
0f2d19dd
JB
220 inits = SCM_CDR (inits);
221 }
222 fields_desc += 2;
223 break;
224#endif
225
226 case 's':
d8c40b9f 227 *mem = SCM_UNPACK (handle);
0f2d19dd
JB
228 break;
229 }
230
0f2d19dd
JB
231 n_fields--;
232 mem++;
233 }
234}
235
236
a1ec6916 237SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
1bbd0b84 238 (SCM x),
b380b885 239 "Return #t iff @var{obj} is a structure object, else #f.")
1bbd0b84 240#define FUNC_NAME s_scm_struct_p
0f2d19dd 241{
0c95b57d 242 return SCM_BOOL(SCM_STRUCTP (x));
0f2d19dd 243}
1bbd0b84 244#undef FUNC_NAME
0f2d19dd 245
a1ec6916 246SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
1bbd0b84 247 (SCM x),
b380b885 248 "Return #t iff obj is a vtable structure.")
1bbd0b84 249#define FUNC_NAME s_scm_struct_vtable_p
0f2d19dd
JB
250{
251 SCM layout;
d8c40b9f 252 scm_bits_t * mem;
0f2d19dd
JB
253
254 if (!SCM_STRUCTP (x))
255 return SCM_BOOL_F;
256
257 layout = SCM_STRUCT_LAYOUT (x);
258
bfa974f0 259 if (SCM_SYMBOL_LENGTH (layout) < SCM_STRING_LENGTH (required_vtable_fields))
0f2d19dd
JB
260 return SCM_BOOL_F;
261
a002f1a2 262 if (strncmp (SCM_SYMBOL_CHARS (layout), SCM_STRING_CHARS (required_vtable_fields),
bfa974f0 263 SCM_STRING_LENGTH (required_vtable_fields)))
0f2d19dd
JB
264 return SCM_BOOL_F;
265
266 mem = SCM_STRUCT_DATA (x);
267
268 if (mem[1] != 0)
269 return SCM_BOOL_F;
270
d8c40b9f 271 return SCM_BOOL (SCM_SYMBOLP (SCM_PACK (mem[0])));
0f2d19dd 272}
1bbd0b84 273#undef FUNC_NAME
0f2d19dd 274
14d1400f
JB
275
276/* All struct data must be allocated at an address whose bottom three
277 bits are zero. This is because the tag for a struct lives in the
278 bottom three bits of the struct's car, and the upper bits point to
279 the data of its vtable, which is a struct itself. Thus, if the
280 address of that data doesn't end in three zeros, tagging it will
281 destroy the pointer.
282
283 This function allocates a block of memory, and returns a pointer at
284 least scm_struct_n_extra_words words into the block. Furthermore,
285 it guarantees that that pointer's least three significant bits are
286 all zero.
287
288 The argument n_words should be the number of words that should
289 appear after the returned address. (That is, it shouldn't include
290 scm_struct_n_extra_words.)
291
292 This function initializes the following fields of the struct:
293
ad196599 294 scm_struct_i_ptr --- the actual start of the block of memory; the
14d1400f
JB
295 address you should pass to 'free' to dispose of the block.
296 This field allows us to both guarantee that the returned
297 address is divisible by eight, and allow the GC to free the
298 block.
299
300 scm_struct_i_n_words --- the number of words allocated to the
301 block, including the extra fields. This is used by the GC.
302
14d1400f
JB
303 Ugh. */
304
305
c8045e8d 306scm_bits_t *
a5bfe84d 307scm_alloc_struct (int n_words, int n_extra, char *who)
14d1400f 308{
c8045e8d
DH
309 int size = sizeof (scm_bits_t) * (n_words + n_extra) + 7;
310 void * block = scm_must_malloc (size, who);
14d1400f
JB
311
312 /* Adjust the pointer to hide the extra words. */
c8045e8d 313 scm_bits_t * p = (scm_bits_t *) block + n_extra;
14d1400f
JB
314
315 /* Adjust it even further so it's aligned on an eight-byte boundary. */
c8045e8d 316 p = (scm_bits_t *) (((scm_bits_t) p + 7) & ~7);
14d1400f 317
ad196599 318 /* Initialize a few fields as described above. */
c8045e8d
DH
319 p[scm_struct_i_free] = (scm_bits_t) scm_struct_free_standard;
320 p[scm_struct_i_ptr] = (scm_bits_t) block;
321 p[scm_struct_i_n_words] = n_words;
ad196599 322 p[scm_struct_i_flags] = 0;
14d1400f
JB
323
324 return p;
325}
326
97056309 327scm_sizet
c8045e8d 328scm_struct_free_0 (scm_bits_t * vtable, scm_bits_t * data)
ad196599
MD
329{
330 return 0;
331}
332
97056309 333scm_sizet
c8045e8d 334scm_struct_free_light (scm_bits_t * vtable, scm_bits_t * data)
ad196599 335{
cfe66b72 336 scm_must_free (data);
c8045e8d 337 return vtable [scm_struct_i_size] & ~SCM_STRUCTF_MASK;
ad196599
MD
338}
339
97056309 340scm_sizet
c8045e8d 341scm_struct_free_standard (scm_bits_t * vtable, scm_bits_t * data)
ad196599 342{
c8045e8d
DH
343 size_t n = (data[scm_struct_i_n_words] + scm_struct_n_extra_words)
344 * sizeof (scm_bits_t) + 7;
cfe66b72 345 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
346 return n;
347}
348
97056309 349scm_sizet
c8045e8d 350scm_struct_free_entity (scm_bits_t * vtable, scm_bits_t * data)
ad196599 351{
c8045e8d
DH
352 size_t n = (data[scm_struct_i_n_words] + scm_struct_entity_n_extra_words)
353 * sizeof (scm_bits_t) + 7;
cfe66b72 354 scm_must_free ((void *) data[scm_struct_i_ptr]);
ad196599
MD
355 return n;
356}
14d1400f 357
08c880a3
MD
358static void *
359scm_struct_gc_init (void *dummy1, void *dummy2, void *dummy3)
360{
361 scm_structs_to_free = SCM_EOL;
362 return 0;
363}
364
365static void *
366scm_free_structs (void *dummy1, void *dummy2, void *dummy3)
367{
368 SCM newchain = scm_structs_to_free;
369 do
370 {
371 /* Mark vtables in GC chain. GC mark set means delay freeing. */
372 SCM chain = newchain;
373 while (SCM_NNULLP (chain))
374 {
375 SCM vtable = SCM_STRUCT_VTABLE (chain);
376 if (SCM_STRUCT_GC_CHAIN (vtable) != 0 && vtable != chain)
377 SCM_SETGCMARK (vtable);
378 chain = SCM_STRUCT_GC_CHAIN (chain);
379 }
380 /* Free unmarked structs. */
381 chain = newchain;
382 newchain = SCM_EOL;
383 while (SCM_NNULLP (chain))
384 {
385 SCM obj = chain;
386 chain = SCM_STRUCT_GC_CHAIN (chain);
387 if (SCM_GCMARKP (obj))
388 {
389 SCM_CLRGCMARK (obj);
390 SCM_SET_STRUCT_GC_CHAIN (obj, newchain);
391 newchain = obj;
392 }
393 else
394 {
395 scm_bits_t word0 = SCM_CELL_WORD_0 (obj) - scm_tc3_cons_gloc;
396 /* access as struct */
397 scm_bits_t * vtable_data = (scm_bits_t *) word0;
398 scm_bits_t * data = (scm_bits_t *) SCM_UNPACK (SCM_CDR (obj));
399 scm_struct_free_t free_struct_data
400 = ((scm_struct_free_t) vtable_data[scm_struct_i_free]);
401 SCM_SET_CELL_TYPE (obj, scm_tc_free_cell);
402 free_struct_data (vtable_data, data);
403 }
404 }
405 }
406 while (SCM_NNULLP (newchain));
407 return 0;
408}
409
a1ec6916 410SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
1bbd0b84 411 (SCM vtable, SCM tail_array_size, SCM init),
b380b885 412 "Create a new structure.\n\n"
1bee0e70 413 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
b380b885
MD
414 "@var{tail-elts} must be a non-negative integer. If the layout\n"
415 "specification indicated by @var{type} includes a tail-array,\n"
416 "this is the number of elements allocated to that array.\n\n"
6386e25c 417 "The @var{init1}, @dots{} are optional arguments describing how\n"
04323af4
MD
418 "successive fields of the structure should be initialized. Only fields\n"
419 "with protection 'r' or 'w' can be initialized, except for fields of\n"
420 "type 's', which are automatically initialized to point to the new\n"
421 "structure itself; fields with protection 'o' can not be initialized by\n"
422 "Scheme programs.\n\n"
423 "If fewer optional arguments than initializable fields are supplied,\n"
424 "fields of type 'p' get default value #f while fields of type 'u' are\n"
425 "initialized to 0.\n\n"
426 "Structs are currently the basic representation for record-like data\n"
427 "structures in Guile. The plan is to eventually replace them with a\n"
428 "new representation which will at the same time be easier to use and\n"
429 "more powerful.\n\n"
6386e25c 430 "For more information, see the documentation for @code{make-vtable-vtable}.")
1bbd0b84 431#define FUNC_NAME s_scm_make_struct
0f2d19dd
JB
432{
433 SCM layout;
434 int basic_size;
435 int tail_elts;
c8045e8d 436 scm_bits_t * data;
0f2d19dd
JB
437 SCM handle;
438
3b3b36dd
GB
439 SCM_VALIDATE_VTABLE (1,vtable);
440 SCM_VALIDATE_INUM (2,tail_array_size);
af45e3b0 441 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd 442
d8c40b9f 443 layout = SCM_PACK (SCM_STRUCT_DATA (vtable) [scm_vtable_index_layout]);
bfa974f0 444 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 445 tail_elts = SCM_INUM (tail_array_size);
08c880a3 446 SCM_NEWCELL2 (handle);
0f2d19dd 447 SCM_DEFER_INTS;
d8c40b9f 448 if (SCM_STRUCT_DATA (vtable)[scm_struct_i_flags] & SCM_STRUCTF_ENTITY)
a5bfe84d
MD
449 {
450 data = scm_alloc_struct (basic_size + tail_elts,
98d5f601 451 scm_struct_entity_n_extra_words,
a5bfe84d 452 "make-struct");
c8045e8d
DH
453 data[scm_struct_i_procedure] = SCM_UNPACK (SCM_BOOL_F);
454 data[scm_struct_i_setter] = SCM_UNPACK (SCM_BOOL_F);
a5bfe84d
MD
455 }
456 else
457 data = scm_alloc_struct (basic_size + tail_elts,
458 scm_struct_n_extra_words,
459 "make-struct");
54778cd3 460 SCM_SET_CELL_WORD_1 (handle, data);
08c880a3 461 SCM_SET_STRUCT_GC_CHAIN (handle, 0);
f7620510 462 scm_struct_init (handle, layout, data, tail_elts, init);
c8045e8d 463 SCM_SET_CELL_WORD_0 (handle, (scm_bits_t) SCM_STRUCT_DATA (vtable) + scm_tc3_cons_gloc);
0f2d19dd
JB
464 SCM_ALLOW_INTS;
465 return handle;
466}
1bbd0b84 467#undef FUNC_NAME
0f2d19dd
JB
468
469
470
a1ec6916 471SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
04323af4 472 (SCM user_fields, SCM tail_array_size, SCM init),
b380b885 473 "Return a new, self-describing vtable structure.\n\n"
04323af4
MD
474 "@var{user-fields} is a string describing user defined fields of the\n"
475 "vtable beginning at index @code{vtable-offset-user}\n"
476 "(see @code{make-struct-layout}).\n\n"
b380b885
MD
477 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
478 "this vtable.\n\n"
6386e25c 479 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
04323af4
MD
480 "the vtable.\n\n"
481 "Vtables have one initializable system field---the struct printer.\n"
482 "This field comes before the user fields in the initializers passed\n"
483 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
484 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
485 "@code{make-struct} when creating vtables:\n\n"
486 "If the value is a procedure, it will be called instead of the standard\n"
487 "printer whenever a struct described by this vtable is printed.\n"
488 "The procedure will be called with arguments STRUCT and PORT.\n\n"
489 "The structure of a struct is described by a vtable, so the vtable is\n"
490 "in essence the type of the struct. The vtable is itself a struct with\n"
491 "a vtable. This could go on forever if it weren't for the\n"
29b4f9fb 492 "vtable-vtables which are self-describing vtables, and thus terminate\n"
04323af4
MD
493 "the chain.\n\n"
494 "There are several potential ways of using structs, but the standard\n"
495 "one is to use three kinds of structs, together building up a type\n"
496 "sub-system: one vtable-vtable working as the root and one or several\n"
497 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
29b4f9fb 498 "compared to the class <class> which is the class of itself.)\n\n"
b380b885 499 "@example\n"
04323af4
MD
500 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
501 "(define (make-ball-type ball-color)\n"
502 " (make-struct ball-root 0\n"
503 " (make-struct-layout \"pw\")\n"
504 " (lambda (ball port)\n"
505 " (format port \"#<a ~A ball owned by ~A>\"\n"
506 " (color ball)\n"
507 " (owner ball)))\n"
508 " ball-color))\n"
509 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
510 "(define (owner ball) (struct-ref ball 0))\n\n"
511 "(define red (make-ball-type 'red))\n"
512 "(define green (make-ball-type 'green))\n\n"
513 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
514 "(define ball (make-ball green 'Nisse))\n"
515 "ball @result{} #<a green ball owned by Nisse>\n"
e3239868 516 "@end example\n")
1bbd0b84 517#define FUNC_NAME s_scm_make_vtable_vtable
0f2d19dd
JB
518{
519 SCM fields;
520 SCM layout;
521 int basic_size;
522 int tail_elts;
c8045e8d 523 scm_bits_t * data;
0f2d19dd
JB
524 SCM handle;
525
d1ca2c64 526 SCM_VALIDATE_STRING (1, user_fields);
04323af4 527 SCM_VALIDATE_INUM (2, tail_array_size);
af45e3b0 528 SCM_VALIDATE_REST_ARGUMENT (init);
0f2d19dd
JB
529
530 fields = scm_string_append (scm_listify (required_vtable_fields,
04323af4 531 user_fields,
0f2d19dd
JB
532 SCM_UNDEFINED));
533 layout = scm_make_struct_layout (fields);
bfa974f0 534 basic_size = SCM_SYMBOL_LENGTH (layout) / 2;
0f2d19dd 535 tail_elts = SCM_INUM (tail_array_size);
08c880a3 536 SCM_NEWCELL2 (handle);
0f2d19dd 537 SCM_DEFER_INTS;
a5bfe84d
MD
538 data = scm_alloc_struct (basic_size + tail_elts,
539 scm_struct_n_extra_words,
540 "make-vtable-vtable");
54778cd3 541 SCM_SET_CELL_WORD_1 (handle, data);
08c880a3 542 SCM_SET_STRUCT_GC_CHAIN (handle, 0);
f7620510
DH
543 data [scm_vtable_index_layout] = SCM_UNPACK (layout);
544 scm_struct_init (handle, layout, data, tail_elts, scm_cons (layout, init));
c8045e8d 545 SCM_SET_CELL_WORD_0 (handle, (scm_bits_t) data + scm_tc3_cons_gloc);
0f2d19dd
JB
546 SCM_ALLOW_INTS;
547 return handle;
548}
1bbd0b84 549#undef FUNC_NAME
0f2d19dd
JB
550
551\f
552
553
a1ec6916 554SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
1bbd0b84 555 (SCM handle, SCM pos),
b380b885
MD
556 "@deffnx primitive struct-set! struct n value\n"
557 "Access (or modify) the @var{n}th field of @var{struct}.\n\n"
558 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
559 "If the field is of type 'u', then it can only be set to a non-negative\n"
560 "integer value small enough to fit in one machine word.")
1bbd0b84 561#define FUNC_NAME s_scm_struct_ref
0f2d19dd 562{
5e840c2e 563 SCM answer = SCM_UNDEFINED;
d8c40b9f 564 scm_bits_t * data;
0f2d19dd
JB
565 SCM layout;
566 int p;
4d45e7b6 567 scm_bits_t n_fields;
e51fe79c
DH
568 char * fields_desc;
569 char field_type = 0;
0f2d19dd
JB
570
571
3b3b36dd
GB
572 SCM_VALIDATE_STRUCT (1,handle);
573 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
574
575 layout = SCM_STRUCT_LAYOUT (handle);
576 data = SCM_STRUCT_DATA (handle);
577 p = SCM_INUM (pos);
578
e51fe79c 579 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 580 n_fields = data[scm_struct_i_n_words];
2c36c351 581
c751e5e3 582 SCM_ASSERT_RANGE(1,pos, p < n_fields);
0f2d19dd 583
bfa974f0 584 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 585 {
e51fe79c 586 char ref;
2c36c351
MD
587 field_type = fields_desc[p * 2];
588 ref = fields_desc[p * 2 + 1];
589 if ((ref != 'r') && (ref != 'w'))
590 {
591 if ((ref == 'R') || (ref == 'W'))
592 field_type = 'u';
593 else
1bbd0b84 594 SCM_ASSERT (0, pos, "ref denied", FUNC_NAME);
2c36c351
MD
595 }
596 }
bfa974f0
DH
597 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] != 'O')
598 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351
MD
599 else
600 {
1bbd0b84 601 SCM_ASSERT (0, pos, "ref denied", FUNC_NAME);
35de7ebe 602 abort ();
2c36c351
MD
603 }
604
0f2d19dd
JB
605 switch (field_type)
606 {
607 case 'u':
d8c40b9f 608 answer = scm_ulong2num (data[p]);
0f2d19dd
JB
609 break;
610
611#if 0
612 case 'i':
613 answer = scm_long2num (data[p]);
614 break;
615
616 case 'd':
f8de44c1 617 answer = scm_make_real (*((double *)&(data[p])));
0f2d19dd
JB
618 break;
619#endif
620
621 case 's':
622 case 'p':
d8c40b9f 623 answer = SCM_PACK (data[p]);
0f2d19dd
JB
624 break;
625
626
627 default:
7866a09b 628 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
629 break;
630 }
631
632 return answer;
633}
1bbd0b84 634#undef FUNC_NAME
0f2d19dd
JB
635
636
a1ec6916 637SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
1bbd0b84 638 (SCM handle, SCM pos, SCM val),
e3239868
DH
639 "Set the slot of the structure @var{handle} with index @var{pos}\n"
640 "to @var{val}. Signal an error if the slot can not be written\n"
641 "to.")
1bbd0b84 642#define FUNC_NAME s_scm_struct_set_x
0f2d19dd 643{
d8c40b9f 644 scm_bits_t * data;
0f2d19dd
JB
645 SCM layout;
646 int p;
647 int n_fields;
e51fe79c
DH
648 char * fields_desc;
649 char field_type = 0;
0f2d19dd 650
3b3b36dd
GB
651 SCM_VALIDATE_STRUCT (1,handle);
652 SCM_VALIDATE_INUM (2,pos);
0f2d19dd
JB
653
654 layout = SCM_STRUCT_LAYOUT (handle);
655 data = SCM_STRUCT_DATA (handle);
656 p = SCM_INUM (pos);
657
e51fe79c 658 fields_desc = SCM_SYMBOL_CHARS (layout);
d8c40b9f 659 n_fields = data[scm_struct_i_n_words];
0f2d19dd 660
c751e5e3 661 SCM_ASSERT_RANGE (1,pos, p < n_fields);
0f2d19dd 662
bfa974f0 663 if (p * 2 < SCM_SYMBOL_LENGTH (layout))
2c36c351 664 {
e51fe79c 665 char set_x;
2c36c351
MD
666 field_type = fields_desc[p * 2];
667 set_x = fields_desc [p * 2 + 1];
668 if (set_x != 'w')
1bbd0b84 669 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
2c36c351 670 }
bfa974f0
DH
671 else if (fields_desc[SCM_SYMBOL_LENGTH (layout) - 1] == 'W')
672 field_type = fields_desc[SCM_SYMBOL_LENGTH (layout) - 2];
2c36c351
MD
673 else
674 {
1bbd0b84 675 SCM_ASSERT (0, pos, "set_x denied", FUNC_NAME);
35de7ebe 676 abort ();
2c36c351
MD
677 }
678
0f2d19dd
JB
679 switch (field_type)
680 {
681 case 'u':
d8c40b9f 682 data[p] = SCM_NUM2ULONG (3, val);
0f2d19dd
JB
683 break;
684
685#if 0
686 case 'i':
1bbd0b84 687 data[p] = SCM_NUM2LONG (3,val);
0f2d19dd
JB
688 break;
689
690 case 'd':
691 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
692 break;
693#endif
694
695 case 'p':
d8c40b9f 696 data[p] = SCM_UNPACK (val);
0f2d19dd
JB
697 break;
698
699 case 's':
7866a09b 700 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "self fields immutable", FUNC_NAME);
0f2d19dd
JB
701 break;
702
703 default:
7866a09b 704 SCM_ASSERT (0, SCM_MAKE_CHAR (field_type), "unrecognized field type", FUNC_NAME);
0f2d19dd
JB
705 break;
706 }
707
708 return val;
709}
1bbd0b84 710#undef FUNC_NAME
0f2d19dd
JB
711
712
a1ec6916 713SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
1bbd0b84 714 (SCM handle),
b380b885 715 "Return the vtable structure that describes the type of @var{struct}.")
1bbd0b84 716#define FUNC_NAME s_scm_struct_vtable
0f2d19dd 717{
3b3b36dd 718 SCM_VALIDATE_STRUCT (1,handle);
0f2d19dd
JB
719 return SCM_STRUCT_VTABLE (handle);
720}
1bbd0b84 721#undef FUNC_NAME
0f2d19dd
JB
722
723
a1ec6916 724SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
1bbd0b84 725 (SCM handle),
e3239868 726 "Return the vtable tag of the structure @var{handle}.")
1bbd0b84 727#define FUNC_NAME s_scm_struct_vtable_tag
0f2d19dd 728{
3b3b36dd 729 SCM_VALIDATE_VTABLE (1,handle);
ad196599 730 return scm_long2num ((long) SCM_STRUCT_DATA (handle) >> 3);
98d5f601 731}
1bbd0b84 732#undef FUNC_NAME
98d5f601
MD
733
734/* {Associating names and classes with vtables}
735 *
736 * The name of a vtable should probably be stored as a slot. This is
737 * a backward compatible solution until agreement has been achieved on
738 * how to associate names with vtables.
739 */
740
741unsigned int
742scm_struct_ihashq (SCM obj, unsigned int n)
743{
ad196599
MD
744 /* The length of the hash table should be a relative prime it's not
745 necessary to shift down the address. */
f1267706 746 return SCM_UNPACK (obj) % n;
98d5f601
MD
747}
748
749SCM
750scm_struct_create_handle (SCM obj)
751{
752 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
753 obj,
754 SCM_BOOL_F,
755 scm_struct_ihashq,
756 scm_sloppy_assq,
757 0);
758 if (SCM_FALSEP (SCM_CDR (handle)))
759 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
760 return handle;
761}
762
a1ec6916 763SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
1bbd0b84 764 (SCM vtable),
e3239868 765 "Return the name of the vtable @var{vtable}.")
1bbd0b84 766#define FUNC_NAME s_scm_struct_vtable_name
98d5f601 767{
3b3b36dd 768 SCM_VALIDATE_VTABLE (1,vtable);
98d5f601
MD
769 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
770}
1bbd0b84 771#undef FUNC_NAME
98d5f601 772
a1ec6916 773SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
1bbd0b84 774 (SCM vtable, SCM name),
e3239868 775 "Set the name of the vtable @var{vtable} to @var{name}.")
1bbd0b84 776#define FUNC_NAME s_scm_set_struct_vtable_name_x
98d5f601 777{
3b3b36dd
GB
778 SCM_VALIDATE_VTABLE (1,vtable);
779 SCM_VALIDATE_SYMBOL (2,name);
98d5f601
MD
780 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
781 name);
782 return SCM_UNSPECIFIED;
0f2d19dd 783}
1bbd0b84 784#undef FUNC_NAME
0f2d19dd
JB
785
786
787\f
788
bafcafb2 789void
1bbd0b84 790scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
bafcafb2 791{
4bfdf158
MD
792 if (SCM_NFALSEP (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
793 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
794 else
bafcafb2 795 {
a1ae1799
MD
796 SCM vtable = SCM_STRUCT_VTABLE (exp);
797 SCM name = scm_struct_vtable_name (vtable);
798 scm_puts ("#<", port);
799 if (SCM_NFALSEP (name))
800 scm_display (name, port);
801 else
802 scm_puts ("struct", port);
803 scm_putc (' ', port);
54778cd3 804 scm_intprint (SCM_UNPACK (vtable), 16, port);
b7f3516f 805 scm_putc (':', port);
54778cd3 806 scm_intprint (SCM_UNPACK (exp), 16, port);
b7f3516f 807 scm_putc ('>', port);
bafcafb2 808 }
bafcafb2 809}
1cc91f1b 810
08c880a3
MD
811void
812scm_struct_prehistory ()
813{
814 scm_c_hook_add (&scm_before_mark_c_hook, scm_struct_gc_init, 0, 0);
815 scm_c_hook_add (&scm_after_sweep_c_hook, scm_free_structs, 0, 0);
816}
817
0f2d19dd
JB
818void
819scm_init_struct ()
0f2d19dd 820{
98d5f601
MD
821 scm_struct_table
822 = scm_permanent_object (scm_make_weak_key_hash_table (SCM_MAKINUM (31)));
7c31152f 823 required_vtable_fields = scm_makfrom0str ("pruosrpw");
0f2d19dd 824 scm_permanent_object (required_vtable_fields);
4bfdf158
MD
825 scm_sysintern ("vtable-index-layout", SCM_MAKINUM (scm_vtable_index_layout));
826 scm_sysintern ("vtable-index-vtable", SCM_MAKINUM (scm_vtable_index_vtable));
827 scm_sysintern ("vtable-index-printer", SCM_MAKINUM (scm_vtable_index_printer));
828 scm_sysintern ("vtable-offset-user", SCM_MAKINUM (scm_vtable_offset_user));
8dc9439f 829#ifndef SCM_MAGIC_SNARFER
a0599745 830#include "libguile/struct.x"
8dc9439f 831#endif
0f2d19dd 832}
89e00824
ML
833
834/*
835 Local Variables:
836 c-file-style: "gnu"
837 End:
838*/