a very big commit cleaning up structs & goops. also applicable structs.
[bpt/guile.git] / libguile / struct.c
1 /* Copyright (C) 1996,1997,1998,1999,2000,2001, 2003, 2004, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 \f
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include "libguile/_scm.h"
25 #include "libguile/async.h"
26 #include "libguile/chars.h"
27 #include "libguile/eval.h"
28 #include "libguile/alist.h"
29 #include "libguile/weaks.h"
30 #include "libguile/hashtab.h"
31 #include "libguile/ports.h"
32 #include "libguile/strings.h"
33 #include "libguile/srfi-13.h"
34
35 #include "libguile/validate.h"
36 #include "libguile/struct.h"
37
38 #include "libguile/eq.h"
39
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43
44 #include "libguile/bdw-gc.h"
45
46 \f
47
48 /* A needlessly obscure test. */
49 #define SCM_LAYOUT_TAILP(X) (((X) & 32) == 0) /* R, W or O */
50
51 static SCM required_vtable_fields = SCM_BOOL_F;
52 static SCM required_applicable_fields = SCM_BOOL_F;
53 static SCM required_applicable_with_setter_fields = SCM_BOOL_F;
54 SCM scm_struct_table = SCM_BOOL_F;
55
56 \f
57 SCM_DEFINE (scm_make_struct_layout, "make-struct-layout", 1, 0, 0,
58 (SCM fields),
59 "Return a new structure layout object.\n\n"
60 "@var{fields} must be a string made up of pairs of characters\n"
61 "strung together. The first character of each pair describes a field\n"
62 "type, the second a field protection. Allowed types are 'p' for\n"
63 "GC-protected Scheme data, 'u' for unprotected binary data, and 's' for\n"
64 "a field that points to the structure itself. Allowed protections\n"
65 "are 'w' for mutable fields, 'h' for hidden fields, 'r' for read-only\n"
66 "fields, and 'o' for opaque fields.\n\n"
67 "Hidden fields are writable, but they will not consume an initializer arg\n"
68 "passed to @code{make-struct}. They are useful to add slots to a struct\n"
69 "in a way that preserves backward-compatibility with existing calls to\n"
70 "@code{make-struct}, especially for derived vtables.\n\n"
71 "The last field protection specification may be capitalized to indicate\n"
72 "that the field is a tail-array.")
73 #define FUNC_NAME s_scm_make_struct_layout
74 {
75 SCM new_sym;
76 scm_t_wchar c;
77
78 SCM_VALIDATE_STRING (1, fields);
79
80 { /* scope */
81 size_t len;
82 int x;
83
84 len = scm_i_string_length (fields);
85 if (len % 2 == 1)
86 SCM_MISC_ERROR ("odd length field specification: ~S",
87 scm_list_1 (fields));
88
89 for (x = 0; x < len; x += 2)
90 {
91 switch (c = scm_i_string_ref (fields, x))
92 {
93 case 'u':
94 case 'p':
95 #if 0
96 case 'i':
97 case 'd':
98 #endif
99 case 's':
100 break;
101 default:
102 SCM_MISC_ERROR ("unrecognized field type: ~S",
103 scm_list_1 (SCM_MAKE_CHAR (c)));
104 }
105
106 switch (c = scm_i_string_ref (fields, x + 1))
107 {
108 case 'w':
109 case 'h':
110 if (scm_i_string_ref (fields, x) == 's')
111 SCM_MISC_ERROR ("self fields not writable", SCM_EOL);
112 case 'r':
113 case 'o':
114 break;
115 case 'R':
116 case 'W':
117 case 'O':
118 if (scm_i_string_ref (fields, x) == 's')
119 SCM_MISC_ERROR ("self fields not allowed in tail array",
120 SCM_EOL);
121 if (x != len - 2)
122 SCM_MISC_ERROR ("tail array field must be last field in layout",
123 SCM_EOL);
124 break;
125 default:
126 SCM_MISC_ERROR ("unrecognized ref specification: ~S",
127 scm_list_1 (SCM_MAKE_CHAR (c)));
128 }
129 #if 0
130 if (scm_i_string_ref (fields, x, 'd'))
131 {
132 if (!scm_i_string_ref (fields, x+2, '-'))
133 SCM_MISC_ERROR ("missing dash field at position ~A",
134 scm_list_1 (scm_from_int (x / 2)));
135 x += 2;
136 goto recheck_ref;
137 }
138 #endif
139 }
140 new_sym = scm_string_to_symbol (fields);
141 }
142 scm_remember_upto_here_1 (fields);
143 return new_sym;
144 }
145 #undef FUNC_NAME
146
147 \f
148
149
150
151 static void
152 scm_struct_init (SCM handle, SCM layout, int tail_elts, SCM inits)
153 {
154 scm_t_wchar prot = 0;
155 int n_fields = scm_i_symbol_length (layout) / 2;
156 int tailp = 0;
157 int i;
158 scm_t_bits *mem = SCM_STRUCT_DATA (handle);
159
160 i = -2;
161 while (n_fields)
162 {
163 if (!tailp)
164 {
165 i += 2;
166 prot = scm_i_symbol_ref (layout, i+1);
167 if (SCM_LAYOUT_TAILP (prot))
168 {
169 tailp = 1;
170 prot = prot == 'R' ? 'r' : prot == 'W' ? 'w' : 'o';
171 *mem++ = tail_elts;
172 n_fields += tail_elts - 1;
173 if (n_fields == 0)
174 break;
175 }
176 }
177 switch (scm_i_symbol_ref (layout, i))
178 {
179 #if 0
180 case 'i':
181 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
182 *mem = 0;
183 else
184 {
185 *mem = scm_to_long (SCM_CAR (inits));
186 inits = SCM_CDR (inits);
187 }
188 break;
189 #endif
190
191 case 'u':
192 if ((prot != 'r' && prot != 'w') || scm_is_null (inits))
193 *mem = 0;
194 else
195 {
196 *mem = scm_to_ulong (SCM_CAR (inits));
197 inits = SCM_CDR (inits);
198 }
199 break;
200
201 case 'p':
202 if ((prot != 'r' && prot != 'w') || scm_is_null (inits))
203 *mem = SCM_UNPACK (SCM_BOOL_F);
204 else
205 {
206 *mem = SCM_UNPACK (SCM_CAR (inits));
207 inits = SCM_CDR (inits);
208 }
209
210 break;
211
212 #if 0
213 case 'd':
214 if ((prot != 'r' && prot != 'w') || inits == SCM_EOL)
215 *((double *)mem) = 0.0;
216 else
217 {
218 *mem = scm_num2dbl (SCM_CAR (inits), "scm_struct_init");
219 inits = SCM_CDR (inits);
220 }
221 fields_desc += 2;
222 break;
223 #endif
224
225 case 's':
226 *mem = SCM_UNPACK (handle);
227 break;
228 }
229
230 n_fields--;
231 mem++;
232 }
233 }
234
235
236 SCM_DEFINE (scm_struct_p, "struct?", 1, 0, 0,
237 (SCM x),
238 "Return @code{#t} iff @var{x} is a structure object, else\n"
239 "@code{#f}.")
240 #define FUNC_NAME s_scm_struct_p
241 {
242 return scm_from_bool(SCM_STRUCTP (x));
243 }
244 #undef FUNC_NAME
245
246 SCM_DEFINE (scm_struct_vtable_p, "struct-vtable?", 1, 0, 0,
247 (SCM x),
248 "Return @code{#t} iff @var{x} is a vtable structure.")
249 #define FUNC_NAME s_scm_struct_vtable_p
250 {
251 return scm_from_bool
252 (SCM_STRUCTP (x)
253 && SCM_STRUCT_VTABLE_FLAG_IS_SET (x, SCM_VTABLE_FLAG_VTABLE));
254 }
255 #undef FUNC_NAME
256
257
258 /* All struct data must be allocated at an address whose bottom three
259 bits are zero. This is because the tag for a struct lives in the
260 bottom three bits of the struct's car, and the upper bits point to
261 the data of its vtable, which is a struct itself. Thus, if the
262 address of that data doesn't end in three zeros, tagging it will
263 destroy the pointer.
264
265 I suppose we should make it clear here that, the data must be 8-byte aligned,
266 *within* the struct, and the struct itself should be 8-byte aligned. In
267 practice we ensure this because the data starts two words into a struct.
268
269 This function allocates an 8-byte aligned block of memory, whose first word
270 points to the given vtable data, then a data pointer, then n_words of data.
271 */
272 SCM
273 scm_alloc_struct (scm_t_bits *vtable_data, int n_words, const char *what)
274 {
275 scm_t_bits ret;
276 ret = (scm_t_bits)scm_gc_malloc (sizeof (scm_t_bits) * (n_words + 2), "struct");
277 /* Now that all platforms support scm_t_uint64, I would think that malloc on
278 all platforms is required to return 8-byte-aligned blocks. This test will
279 let us find out quickly though ;-) */
280 if (ret & 7)
281 abort ();
282 SCM_SET_CELL_WORD_0 (SCM_PACK (ret), (scm_t_bits)vtable_data | scm_tc3_struct);
283 SCM_SET_CELL_WORD_1 (SCM_PACK (ret),
284 (scm_t_bits)SCM_CELL_OBJECT_LOC (SCM_PACK (ret), 2));
285 return SCM_PACK (ret);
286 }
287
288 \f
289 /* Finalization. */
290
291
292 /* Invoke the finalizer of the struct pointed to by PTR. */
293 static void
294 struct_finalizer_trampoline (GC_PTR ptr, GC_PTR unused_data)
295 {
296 SCM obj = PTR2SCM (ptr);
297 scm_t_struct_finalize finalize = SCM_STRUCT_FINALIZER (obj);
298
299 if (finalize)
300 finalize (obj);
301 }
302
303
304
305 \f
306 SCM_DEFINE (scm_make_struct, "make-struct", 2, 0, 1,
307 (SCM vtable, SCM tail_array_size, SCM init),
308 "Create a new structure.\n\n"
309 "@var{type} must be a vtable structure (@pxref{Vtables}).\n\n"
310 "@var{tail-elts} must be a non-negative integer. If the layout\n"
311 "specification indicated by @var{type} includes a tail-array,\n"
312 "this is the number of elements allocated to that array.\n\n"
313 "The @var{init1}, @dots{} are optional arguments describing how\n"
314 "successive fields of the structure should be initialized. Only fields\n"
315 "with protection 'r' or 'w' can be initialized, except for fields of\n"
316 "type 's', which are automatically initialized to point to the new\n"
317 "structure itself. Fields with protection 'o' can not be initialized by\n"
318 "Scheme programs.\n\n"
319 "If fewer optional arguments than initializable fields are supplied,\n"
320 "fields of type 'p' get default value #f while fields of type 'u' are\n"
321 "initialized to 0.\n\n"
322 "For more information, see the documentation for @code{make-vtable-vtable}.")
323 #define FUNC_NAME s_scm_make_struct
324 {
325 SCM layout;
326 size_t basic_size;
327 size_t tail_elts;
328 SCM obj;
329
330 SCM_VALIDATE_VTABLE (1, vtable);
331 SCM_VALIDATE_REST_ARGUMENT (init);
332
333 layout = SCM_VTABLE_LAYOUT (vtable);
334 basic_size = scm_i_symbol_length (layout) / 2;
335 tail_elts = scm_to_size_t (tail_array_size);
336
337 /* A tail array is only allowed if the layout fields string ends in "R",
338 "W" or "O". */
339 if (tail_elts != 0)
340 {
341 SCM layout_str, last_char;
342
343 if (basic_size == 0)
344 {
345 bad_tail:
346 SCM_MISC_ERROR ("tail array not allowed unless layout ends R, W, or O", SCM_EOL);
347 }
348
349 layout_str = scm_symbol_to_string (layout);
350 last_char = scm_string_ref (layout_str,
351 scm_from_size_t (2 * basic_size - 1));
352 if (! SCM_LAYOUT_TAILP (SCM_CHAR (last_char)))
353 goto bad_tail;
354 }
355
356 obj = scm_alloc_struct (SCM_STRUCT_DATA (vtable), basic_size + tail_elts,
357 "struct");
358
359 if (SCM_VTABLE_INSTANCE_FINALIZER (vtable))
360 {
361 /* Register a finalizer for the newly created instance. */
362 GC_finalization_proc prev_finalizer;
363 GC_PTR prev_finalizer_data;
364 GC_REGISTER_FINALIZER_NO_ORDER (SCM2PTR (obj),
365 struct_finalizer_trampoline,
366 NULL,
367 &prev_finalizer,
368 &prev_finalizer_data);
369 }
370
371 scm_struct_init (obj, layout, tail_elts, init);
372
373 /* Verily, what is the deal here, you ask? Basically, we need to know a couple
374 of properties of structures at runtime. For example, "is this structure a
375 vtable of vtables (a metaclass)?"; also, "is this structure applicable?".
376 Both of these questions also imply a certain layout of the structure. So
377 instead of checking the layout at runtime, what we do is pre-verify the
378 layout -- so that at runtime we can just check the applicable flag and
379 dispatch directly to the Scheme procedure in slot 0.
380 */
381 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE)
382 /* only do these checks if the layout was passed as an initarg.
383 something of a hack, but it's for back-compatibility. */
384 && scm_is_true (SCM_VTABLE_LAYOUT (obj)))
385 {
386 /* scm_struct_init will have initialized our layout */
387 SCM olayout;
388
389 /* verify that obj is a valid vtable */
390 if (scm_is_false (scm_symbol_p (SCM_VTABLE_LAYOUT (obj))))
391 scm_misc_error (FUNC_NAME, "invalid layout for new vtable",
392 scm_list_1 (SCM_VTABLE_LAYOUT (obj)));
393
394 /* if obj is a metaclass, verify that its vtable is compatible with the
395 required vtable (class) layout */
396 olayout = scm_symbol_to_string (SCM_VTABLE_LAYOUT (obj));
397 if (scm_is_true (scm_string_eq (olayout, required_vtable_fields,
398 scm_from_size_t (0),
399 scm_string_length (olayout),
400 scm_from_size_t (0),
401 scm_string_length (required_vtable_fields))))
402 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VTABLE);
403
404 /* finally if obj is an applicable class, verify that its vtable is
405 compatible with the required applicable layout */
406 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SETTER_VTABLE))
407 {
408 if (scm_is_false (scm_string_eq (olayout, required_applicable_with_setter_fields,
409 scm_from_size_t (0),
410 scm_from_size_t (4),
411 scm_from_size_t (0),
412 scm_from_size_t (4))))
413 scm_misc_error (FUNC_NAME, "invalid applicable-with-setter struct layout",
414 scm_list_1 (olayout));
415 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE | SCM_VTABLE_FLAG_SETTER);
416 }
417 else if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_APPLICABLE_VTABLE))
418 {
419 if (scm_is_false (scm_string_eq (olayout, required_applicable_fields,
420 scm_from_size_t (0),
421 scm_from_size_t (2),
422 scm_from_size_t (0),
423 scm_from_size_t (2))))
424 scm_misc_error (FUNC_NAME, "invalid applicable struct layout",
425 scm_list_1 (olayout));
426 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_APPLICABLE);
427 }
428 }
429
430 return obj;
431 }
432 #undef FUNC_NAME
433
434
435
436 SCM_DEFINE (scm_make_vtable_vtable, "make-vtable-vtable", 2, 0, 1,
437 (SCM user_fields, SCM tail_array_size, SCM init),
438 "Return a new, self-describing vtable structure.\n\n"
439 "@var{user-fields} is a string describing user defined fields of the\n"
440 "vtable beginning at index @code{vtable-offset-user}\n"
441 "(see @code{make-struct-layout}).\n\n"
442 "@var{tail-size} specifies the size of the tail-array (if any) of\n"
443 "this vtable.\n\n"
444 "@var{init1}, @dots{} are the optional initializers for the fields of\n"
445 "the vtable.\n\n"
446 "Vtables have one initializable system field---the struct printer.\n"
447 "This field comes before the user fields in the initializers passed\n"
448 "to @code{make-vtable-vtable} and @code{make-struct}, and thus works as\n"
449 "a third optional argument to @code{make-vtable-vtable} and a fourth to\n"
450 "@code{make-struct} when creating vtables:\n\n"
451 "If the value is a procedure, it will be called instead of the standard\n"
452 "printer whenever a struct described by this vtable is printed.\n"
453 "The procedure will be called with arguments STRUCT and PORT.\n\n"
454 "The structure of a struct is described by a vtable, so the vtable is\n"
455 "in essence the type of the struct. The vtable is itself a struct with\n"
456 "a vtable. This could go on forever if it weren't for the\n"
457 "vtable-vtables which are self-describing vtables, and thus terminate\n"
458 "the chain.\n\n"
459 "There are several potential ways of using structs, but the standard\n"
460 "one is to use three kinds of structs, together building up a type\n"
461 "sub-system: one vtable-vtable working as the root and one or several\n"
462 "\"types\", each with a set of \"instances\". (The vtable-vtable should be\n"
463 "compared to the class <class> which is the class of itself.)\n\n"
464 "@lisp\n"
465 "(define ball-root (make-vtable-vtable \"pr\" 0))\n\n"
466 "(define (make-ball-type ball-color)\n"
467 " (make-struct ball-root 0\n"
468 " (make-struct-layout \"pw\")\n"
469 " (lambda (ball port)\n"
470 " (format port \"#<a ~A ball owned by ~A>\"\n"
471 " (color ball)\n"
472 " (owner ball)))\n"
473 " ball-color))\n"
474 "(define (color ball) (struct-ref (struct-vtable ball) vtable-offset-user))\n"
475 "(define (owner ball) (struct-ref ball 0))\n\n"
476 "(define red (make-ball-type 'red))\n"
477 "(define green (make-ball-type 'green))\n\n"
478 "(define (make-ball type owner) (make-struct type 0 owner))\n\n"
479 "(define ball (make-ball green 'Nisse))\n"
480 "ball @result{} #<a green ball owned by Nisse>\n"
481 "@end lisp")
482 #define FUNC_NAME s_scm_make_vtable_vtable
483 {
484 SCM fields;
485 SCM layout;
486 size_t basic_size;
487 size_t tail_elts;
488 SCM obj;
489
490 SCM_VALIDATE_STRING (1, user_fields);
491 SCM_VALIDATE_REST_ARGUMENT (init);
492
493 fields = scm_string_append (scm_list_2 (required_vtable_fields,
494 user_fields));
495 layout = scm_make_struct_layout (fields);
496 basic_size = scm_i_symbol_length (layout) / 2;
497 tail_elts = scm_to_size_t (tail_array_size);
498 SCM_CRITICAL_SECTION_START;
499 obj = scm_alloc_struct (NULL, basic_size + tail_elts, "struct");
500 /* magic magic magic */
501 SCM_SET_CELL_WORD_0 (obj, (scm_t_bits)SCM_STRUCT_DATA (obj) | scm_tc3_struct);
502 SCM_CRITICAL_SECTION_END;
503 scm_struct_init (obj, layout, tail_elts, scm_cons (layout, init));
504 SCM_SET_VTABLE_FLAGS (obj, SCM_VTABLE_FLAG_VTABLE);
505 return obj;
506 }
507 #undef FUNC_NAME
508
509
510 static SCM scm_i_vtable_vtable_no_extra_fields;
511
512 SCM_DEFINE (scm_make_vtable, "make-vtable", 1, 1, 0,
513 (SCM fields, SCM printer),
514 "Create a vtable, for creating structures with the given\n"
515 "@var{fields}.\n"
516 "\n"
517 "The optional @var{printer} argument is a function to be called\n"
518 "@code{(@var{printer} struct port)} on the structures created.\n"
519 "It should look at @var{struct} and write to @var{port}.")
520 #define FUNC_NAME s_scm_make_vtable
521 {
522 if (SCM_UNBNDP (printer))
523 printer = SCM_BOOL_F;
524
525 return scm_make_struct (scm_i_vtable_vtable_no_extra_fields, SCM_INUM0,
526 scm_list_2 (scm_make_struct_layout (fields),
527 printer));
528 }
529 #undef FUNC_NAME
530
531
532 /* Return true if S1 and S2 are equal structures, i.e., if their vtable and
533 contents are the same. Field protections are honored. Thus, it is an
534 error to test the equality of structures that contain opaque fields. */
535 SCM
536 scm_i_struct_equalp (SCM s1, SCM s2)
537 #define FUNC_NAME "scm_i_struct_equalp"
538 {
539 SCM vtable1, vtable2, layout;
540 size_t struct_size, field_num;
541
542 SCM_VALIDATE_STRUCT (1, s1);
543 SCM_VALIDATE_STRUCT (2, s2);
544
545 vtable1 = SCM_STRUCT_VTABLE (s1);
546 vtable2 = SCM_STRUCT_VTABLE (s2);
547
548 if (!scm_is_eq (vtable1, vtable2))
549 return SCM_BOOL_F;
550
551 layout = SCM_STRUCT_LAYOUT (s1);
552 struct_size = scm_i_symbol_length (layout) / 2;
553
554 for (field_num = 0; field_num < struct_size; field_num++)
555 {
556 SCM s_field_num;
557 SCM field1, field2;
558
559 /* We have to use `scm_struct_ref ()' here so that fields are accessed
560 consistently, notably wrt. field types and access rights. */
561 s_field_num = scm_from_size_t (field_num);
562 field1 = scm_struct_ref (s1, s_field_num);
563 field2 = scm_struct_ref (s2, s_field_num);
564
565 /* Self-referencing fields (type `s') must be skipped to avoid infinite
566 recursion. */
567 if (!(scm_is_eq (field1, s1) && (scm_is_eq (field2, s2))))
568 if (scm_is_false (scm_equal_p (field1, field2)))
569 return SCM_BOOL_F;
570 }
571
572 /* FIXME: Tail elements should be tested for equality. */
573
574 return SCM_BOOL_T;
575 }
576 #undef FUNC_NAME
577
578
579 \f
580
581
582 SCM_DEFINE (scm_struct_ref, "struct-ref", 2, 0, 0,
583 (SCM handle, SCM pos),
584 "Access the @var{n}th field of @var{struct}.\n\n"
585 "If the field is of type 'p', then it can be set to an arbitrary value.\n\n"
586 "If the field is of type 'u', then it can only be set to a non-negative\n"
587 "integer value small enough to fit in one machine word.")
588 #define FUNC_NAME s_scm_struct_ref
589 {
590 SCM answer = SCM_UNDEFINED;
591 scm_t_bits * data;
592 SCM layout;
593 size_t layout_len;
594 size_t p;
595 scm_t_bits n_fields;
596 scm_t_wchar field_type = 0;
597
598
599 SCM_VALIDATE_STRUCT (1, handle);
600
601 layout = SCM_STRUCT_LAYOUT (handle);
602 data = SCM_STRUCT_DATA (handle);
603 p = scm_to_size_t (pos);
604
605 layout_len = scm_i_symbol_length (layout);
606 n_fields = layout_len / 2;
607 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
608 n_fields += data[n_fields - 1];
609
610 SCM_ASSERT_RANGE(1, pos, p < n_fields);
611
612 if (p * 2 < layout_len)
613 {
614 scm_t_wchar ref;
615 field_type = scm_i_symbol_ref (layout, p * 2);
616 ref = scm_i_symbol_ref (layout, p * 2 + 1);
617 if ((ref != 'r') && (ref != 'w') && (ref != 'h'))
618 {
619 if ((ref == 'R') || (ref == 'W'))
620 field_type = 'u';
621 else
622 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
623 }
624 }
625 else if (scm_i_symbol_ref (layout, layout_len - 1) != 'O')
626 field_type = scm_i_symbol_ref(layout, layout_len - 2);
627 else
628 SCM_MISC_ERROR ("ref denied for field ~A", scm_list_1 (pos));
629
630 switch (field_type)
631 {
632 case 'u':
633 answer = scm_from_ulong (data[p]);
634 break;
635
636 #if 0
637 case 'i':
638 answer = scm_from_long (data[p]);
639 break;
640
641 case 'd':
642 answer = scm_make_real (*((double *)&(data[p])));
643 break;
644 #endif
645
646 case 's':
647 case 'p':
648 answer = SCM_PACK (data[p]);
649 break;
650
651
652 default:
653 SCM_MISC_ERROR ("unrecognized field type: ~S",
654 scm_list_1 (SCM_MAKE_CHAR (field_type)));
655 }
656
657 return answer;
658 }
659 #undef FUNC_NAME
660
661
662 SCM_DEFINE (scm_struct_set_x, "struct-set!", 3, 0, 0,
663 (SCM handle, SCM pos, SCM val),
664 "Set the slot of the structure @var{handle} with index @var{pos}\n"
665 "to @var{val}. Signal an error if the slot can not be written\n"
666 "to.")
667 #define FUNC_NAME s_scm_struct_set_x
668 {
669 scm_t_bits * data;
670 SCM layout;
671 size_t layout_len;
672 size_t p;
673 int n_fields;
674 scm_t_wchar field_type = 0;
675
676 SCM_VALIDATE_STRUCT (1, handle);
677
678 layout = SCM_STRUCT_LAYOUT (handle);
679 data = SCM_STRUCT_DATA (handle);
680 p = scm_to_size_t (pos);
681
682 layout_len = scm_i_symbol_length (layout);
683 n_fields = layout_len / 2;
684 if (SCM_LAYOUT_TAILP (scm_i_symbol_ref (layout, layout_len - 1)))
685 n_fields += data[n_fields - 1];
686
687 SCM_ASSERT_RANGE (1, pos, p < n_fields);
688
689 if (p * 2 < layout_len)
690 {
691 char set_x;
692 field_type = scm_i_symbol_ref (layout, p * 2);
693 set_x = scm_i_symbol_ref (layout, p * 2 + 1);
694 if (set_x != 'w' && set_x != 'h')
695 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
696 }
697 else if (scm_i_symbol_ref (layout, layout_len - 1) == 'W')
698 field_type = scm_i_symbol_ref (layout, layout_len - 2);
699 else
700 SCM_MISC_ERROR ("set! denied for field ~A", scm_list_1 (pos));
701
702 switch (field_type)
703 {
704 case 'u':
705 data[p] = SCM_NUM2ULONG (3, val);
706 break;
707
708 #if 0
709 case 'i':
710 data[p] = SCM_NUM2LONG (3, val);
711 break;
712
713 case 'd':
714 *((double *)&(data[p])) = scm_num2dbl (val, (char *)SCM_ARG3);
715 break;
716 #endif
717
718 case 'p':
719 data[p] = SCM_UNPACK (val);
720 break;
721
722 case 's':
723 SCM_MISC_ERROR ("self fields immutable", SCM_EOL);
724
725 default:
726 SCM_MISC_ERROR ("unrecognized field type: ~S",
727 scm_list_1 (SCM_MAKE_CHAR (field_type)));
728 }
729
730 return val;
731 }
732 #undef FUNC_NAME
733
734
735 SCM_DEFINE (scm_struct_vtable, "struct-vtable", 1, 0, 0,
736 (SCM handle),
737 "Return the vtable structure that describes the type of @var{struct}.")
738 #define FUNC_NAME s_scm_struct_vtable
739 {
740 SCM_VALIDATE_STRUCT (1, handle);
741 return SCM_STRUCT_VTABLE (handle);
742 }
743 #undef FUNC_NAME
744
745
746 SCM_DEFINE (scm_struct_vtable_tag, "struct-vtable-tag", 1, 0, 0,
747 (SCM handle),
748 "Return the vtable tag of the structure @var{handle}.")
749 #define FUNC_NAME s_scm_struct_vtable_tag
750 {
751 SCM_VALIDATE_VTABLE (1, handle);
752 return scm_from_ulong (((unsigned long)SCM_STRUCT_DATA (handle)) >> 3);
753 }
754 #undef FUNC_NAME
755
756 /* {Associating names and classes with vtables}
757 *
758 * The name of a vtable should probably be stored as a slot. This is
759 * a backward compatible solution until agreement has been achieved on
760 * how to associate names with vtables.
761 */
762
763 unsigned long
764 scm_struct_ihashq (SCM obj, unsigned long n, void *closure)
765 {
766 /* The length of the hash table should be a relative prime it's not
767 necessary to shift down the address. */
768 return SCM_UNPACK (obj) % n;
769 }
770
771 SCM
772 scm_struct_create_handle (SCM obj)
773 {
774 SCM handle = scm_hash_fn_create_handle_x (scm_struct_table,
775 obj,
776 SCM_BOOL_F,
777 scm_struct_ihashq,
778 (scm_t_assoc_fn) scm_sloppy_assq,
779 0);
780 if (scm_is_false (SCM_CDR (handle)))
781 SCM_SETCDR (handle, scm_cons (SCM_BOOL_F, SCM_BOOL_F));
782 return handle;
783 }
784
785 SCM_DEFINE (scm_struct_vtable_name, "struct-vtable-name", 1, 0, 0,
786 (SCM vtable),
787 "Return the name of the vtable @var{vtable}.")
788 #define FUNC_NAME s_scm_struct_vtable_name
789 {
790 SCM_VALIDATE_VTABLE (1, vtable);
791 return SCM_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)));
792 }
793 #undef FUNC_NAME
794
795 SCM_DEFINE (scm_set_struct_vtable_name_x, "set-struct-vtable-name!", 2, 0, 0,
796 (SCM vtable, SCM name),
797 "Set the name of the vtable @var{vtable} to @var{name}.")
798 #define FUNC_NAME s_scm_set_struct_vtable_name_x
799 {
800 SCM_VALIDATE_VTABLE (1, vtable);
801 SCM_VALIDATE_SYMBOL (2, name);
802 SCM_SET_STRUCT_TABLE_NAME (SCM_CDR (scm_struct_create_handle (vtable)),
803 name);
804 return SCM_UNSPECIFIED;
805 }
806 #undef FUNC_NAME
807
808
809 \f
810
811 void
812 scm_print_struct (SCM exp, SCM port, scm_print_state *pstate)
813 {
814 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PRINTER (exp))))
815 scm_printer_apply (SCM_STRUCT_PRINTER (exp), exp, port, pstate);
816 else
817 {
818 SCM vtable = SCM_STRUCT_VTABLE (exp);
819 SCM name = scm_struct_vtable_name (vtable);
820 scm_puts ("#<", port);
821 if (scm_is_true (name))
822 {
823 scm_display (name, port);
824 scm_putc (' ', port);
825 }
826 else
827 {
828 if (SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_VTABLE))
829 scm_puts ("vtable:", port);
830 else
831 scm_puts ("struct:", port);
832 scm_uintprint (SCM_UNPACK (vtable), 16, port);
833 scm_putc (' ', port);
834 scm_write (SCM_VTABLE_LAYOUT (vtable), port);
835 scm_putc (' ', port);
836 }
837 scm_uintprint (SCM_UNPACK (exp), 16, port);
838 /* hackety hack */
839 if (SCM_STRUCT_APPLICABLE_P (exp))
840 {
841 if (scm_is_true (SCM_STRUCT_PROCEDURE (exp)))
842 {
843 scm_puts (" proc: ", port);
844 if (scm_is_true (scm_procedure_p (SCM_STRUCT_PROCEDURE (exp))))
845 scm_write (SCM_STRUCT_PROCEDURE (exp), port);
846 else
847 scm_puts ("(not a procedure?)", port);
848 }
849 if (SCM_STRUCT_SETTER_P (exp))
850 {
851 scm_puts (" setter: ", port);
852 scm_write (SCM_STRUCT_SETTER (exp), port);
853 }
854 }
855 scm_putc ('>', port);
856 }
857 }
858
859 void
860 scm_struct_prehistory ()
861 {
862 /* Empty. */
863 }
864
865 void
866 scm_init_struct ()
867 {
868 SCM scm_applicable_struct_vtable_vtable;
869 SCM scm_applicable_struct_with_setter_vtable_vtable;
870
871 GC_REGISTER_DISPLACEMENT (2*sizeof(scm_t_bits)); /* for the self data pointer */
872 GC_REGISTER_DISPLACEMENT (2*sizeof(scm_t_bits)
873 + scm_tc3_struct); /* for the vtable data pointer */
874
875 scm_struct_table = scm_make_weak_key_hash_table (scm_from_int (31));
876 required_vtable_fields = scm_from_locale_string (SCM_VTABLE_BASE_LAYOUT);
877 required_applicable_fields = scm_from_locale_string (SCM_APPLICABLE_BASE_LAYOUT);
878 required_applicable_with_setter_fields = scm_from_locale_string (SCM_APPLICABLE_WITH_SETTER_BASE_LAYOUT);
879
880 scm_i_vtable_vtable_no_extra_fields =
881 scm_make_vtable_vtable (scm_nullstr, SCM_INUM0, SCM_EOL);
882
883 scm_applicable_struct_vtable_vtable =
884 scm_make_struct (scm_i_vtable_vtable_no_extra_fields, SCM_INUM0,
885 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
886 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_vtable_vtable,
887 SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
888 scm_c_define ("<applicable-struct-vtable>", scm_applicable_struct_vtable_vtable);
889
890 scm_applicable_struct_with_setter_vtable_vtable =
891 scm_make_struct (scm_i_vtable_vtable_no_extra_fields, SCM_INUM0,
892 scm_list_1 (scm_make_struct_layout (required_vtable_fields)));
893 SCM_SET_VTABLE_FLAGS (scm_applicable_struct_with_setter_vtable_vtable,
894 SCM_VTABLE_FLAG_APPLICABLE_VTABLE | SCM_VTABLE_FLAG_SETTER_VTABLE);
895 scm_c_define ("<applicable-struct-with-setter-vtable>", scm_applicable_struct_with_setter_vtable_vtable);
896
897 scm_c_define ("vtable-index-layout", scm_from_int (scm_vtable_index_layout));
898 scm_c_define ("vtable-index-printer",
899 scm_from_int (scm_vtable_index_instance_printer));
900 scm_c_define ("vtable-offset-user", scm_from_int (scm_vtable_offset_user));
901 #include "libguile/struct.x"
902 }
903
904 /*
905 Local Variables:
906 c-file-style: "gnu"
907 End:
908 */