Rename scm_tc7_rtl_program to scm_tc7_program
[bpt/guile.git] / libguile / goops.c
1 /* Copyright (C) 1998,1999,2000,2001,2002,2003,2004,2008,2009,2010,2011,2012,2013
2 * Free Software Foundation, Inc.
3 *
4 * This library is free software; you can redistribute it and/or
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.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
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
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
18 */
19 \f
20
21 /* This software is a derivative work of other copyrighted softwares; the
22 * copyright notices of these softwares are placed in the file COPYRIGHTS
23 *
24 * This file is based upon stklos.c from the STk distribution by
25 * Erick Gallesio <eg@unice.fr>.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <stdio.h>
33
34 #include "libguile/_scm.h"
35 #include "libguile/alist.h"
36 #include "libguile/async.h"
37 #include "libguile/chars.h"
38 #include "libguile/debug.h"
39 #include "libguile/dynl.h"
40 #include "libguile/dynwind.h"
41 #include "libguile/eval.h"
42 #include "libguile/gsubr.h"
43 #include "libguile/hashtab.h"
44 #include "libguile/keywords.h"
45 #include "libguile/macros.h"
46 #include "libguile/modules.h"
47 #include "libguile/ports.h"
48 #include "libguile/procprop.h"
49 #include "libguile/programs.h"
50 #include "libguile/random.h"
51 #include "libguile/root.h"
52 #include "libguile/smob.h"
53 #include "libguile/strings.h"
54 #include "libguile/strports.h"
55 #include "libguile/vectors.h"
56 #include "libguile/vm.h"
57
58 #include "libguile/validate.h"
59 #include "libguile/goops.h"
60
61 #define SPEC_OF(x) SCM_SLOT (x, scm_si_specializers)
62
63 /* Port classes */
64 #define SCM_IN_PCLASS_INDEX 0
65 #define SCM_OUT_PCLASS_INDEX SCM_I_MAX_PORT_TYPE_COUNT
66 #define SCM_INOUT_PCLASS_INDEX (2 * SCM_I_MAX_PORT_TYPE_COUNT)
67
68 /* this file is a mess. in theory, though, we shouldn't have many SCM references
69 -- most of the references should be to vars. */
70
71 static SCM var_slot_unbound = SCM_BOOL_F;
72 static SCM var_slot_missing = SCM_BOOL_F;
73 static SCM var_compute_cpl = SCM_BOOL_F;
74 static SCM var_no_applicable_method = SCM_BOOL_F;
75 static SCM var_change_class = SCM_BOOL_F;
76
77 SCM_SYMBOL (sym_slot_unbound, "slot-unbound");
78 SCM_SYMBOL (sym_slot_missing, "slot-missing");
79 SCM_SYMBOL (sym_compute_cpl, "compute-cpl");
80 SCM_SYMBOL (sym_no_applicable_method, "no-applicable-method");
81 SCM_SYMBOL (sym_memoize_method_x, "memoize-method!");
82 SCM_SYMBOL (sym_change_class, "change-class");
83
84 SCM_VARIABLE (scm_var_make_extended_generic, "make-extended-generic");
85
86
87 /* Class redefinition protocol:
88
89 A class is represented by a heap header h1 which points to a
90 malloc:ed memory block m1.
91
92 When a new version of a class is created, a new header h2 and
93 memory block m2 are allocated. The headers h1 and h2 then switch
94 pointers so that h1 refers to m2 and h2 to m1. In this way, names
95 bound to h1 will point to the new class at the same time as h2 will
96 be a handle which the GC will use to free m1.
97
98 The `redefined' slot of m1 will be set to point to h1. An old
99 instance will have its class pointer (the CAR of the heap header)
100 pointing to m1. The non-immediate `redefined'-slot in m1 indicates
101 the class modification and the new class pointer can be found via
102 h1.
103 */
104
105 #define TEST_CHANGE_CLASS(obj, class) \
106 { \
107 class = SCM_CLASS_OF (obj); \
108 if (scm_is_true (SCM_OBJ_CLASS_REDEF (obj))) \
109 { \
110 scm_change_object_class (obj, class, SCM_OBJ_CLASS_REDEF (obj));\
111 class = SCM_CLASS_OF (obj); \
112 } \
113 }
114
115 #define NXT_MTHD_METHODS(m) (SCM_VELTS (m)[1])
116 #define NXT_MTHD_ARGS(m) (SCM_VELTS (m)[2])
117
118 #define SCM_GOOPS_UNBOUND SCM_UNBOUND
119 #define SCM_GOOPS_UNBOUNDP(x) (scm_is_eq (x, SCM_GOOPS_UNBOUND))
120
121 static int goops_loaded_p = 0;
122 static scm_t_rstate *goops_rstate;
123
124 /* These variables are filled in by the object system when loaded. */
125 SCM scm_class_boolean, scm_class_char, scm_class_pair;
126 SCM scm_class_procedure, scm_class_string, scm_class_symbol;
127 SCM scm_class_primitive_generic;
128 SCM scm_class_vector, scm_class_null;
129 SCM scm_class_integer, scm_class_real, scm_class_complex, scm_class_fraction;
130 SCM scm_class_unknown;
131 SCM scm_class_top, scm_class_object, scm_class_class;
132 SCM scm_class_applicable;
133 SCM scm_class_applicable_struct, scm_class_applicable_struct_with_setter;
134 SCM scm_class_generic, scm_class_generic_with_setter;
135 SCM scm_class_accessor;
136 SCM scm_class_extended_generic, scm_class_extended_generic_with_setter;
137 SCM scm_class_extended_accessor;
138 SCM scm_class_method;
139 SCM scm_class_accessor_method;
140 SCM scm_class_procedure_class;
141 SCM scm_class_applicable_struct_class;
142 SCM scm_class_number, scm_class_list;
143 SCM scm_class_keyword;
144 SCM scm_class_port, scm_class_input_output_port;
145 SCM scm_class_input_port, scm_class_output_port;
146 SCM scm_class_foreign_slot;
147 SCM scm_class_self, scm_class_protected;
148 SCM scm_class_hidden, scm_class_opaque, scm_class_read_only;
149 SCM scm_class_protected_hidden, scm_class_protected_opaque, scm_class_protected_read_only;
150 SCM scm_class_scm;
151 SCM scm_class_int, scm_class_float, scm_class_double;
152
153 static SCM class_foreign;
154 static SCM class_hashtable;
155 static SCM class_fluid;
156 static SCM class_dynamic_state;
157 static SCM class_frame;
158 static SCM class_vm;
159 static SCM class_vm_cont;
160 static SCM class_bytevector;
161 static SCM class_uvec;
162 static SCM class_array;
163 static SCM class_bitvector;
164
165 static SCM vtable_class_map = SCM_BOOL_F;
166
167 /* Port classes. Allocate 3 times the maximum number of port types so that
168 input ports, output ports, and in/out ports can be stored at different
169 offsets. See `SCM_IN_PCLASS_INDEX' et al. */
170 SCM scm_port_class[3 * SCM_I_MAX_PORT_TYPE_COUNT];
171
172 /* SMOB classes. */
173 SCM scm_smob_class[SCM_I_MAX_SMOB_TYPE_COUNT];
174
175 SCM scm_no_applicable_method;
176
177 SCM_SYMBOL (scm_sym_define_public, "define-public");
178
179 static SCM scm_make_unbound (void);
180 static SCM scm_unbound_p (SCM obj);
181 static SCM scm_assert_bound (SCM value, SCM obj);
182 static SCM scm_at_assert_bound_ref (SCM obj, SCM index);
183 static SCM scm_sys_goops_loaded (void);
184 static SCM scm_make_extended_class_from_symbol (SCM type_name_sym,
185 int applicablep);
186
187
188 SCM
189 scm_i_define_class_for_vtable (SCM vtable)
190 {
191 SCM class;
192
193 scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
194 if (scm_is_false (vtable_class_map))
195 vtable_class_map = scm_c_make_weak_table (0, SCM_WEAK_TABLE_KIND_KEY);
196 scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
197
198 if (scm_is_false (scm_struct_vtable_p (vtable)))
199 abort ();
200
201 class = scm_weak_table_refq (vtable_class_map, vtable, SCM_BOOL_F);
202
203 if (scm_is_false (class))
204 {
205 if (SCM_UNPACK (scm_class_class))
206 {
207 SCM name = SCM_VTABLE_NAME (vtable);
208 if (!scm_is_symbol (name))
209 name = scm_string_to_symbol (scm_nullstr);
210
211 class = scm_make_extended_class_from_symbol
212 (name, SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_APPLICABLE));
213 }
214 else
215 /* `create_struct_classes' will fill this in later. */
216 class = SCM_BOOL_F;
217
218 /* Don't worry about races. This only happens when creating a
219 vtable, which happens by definition in one thread. */
220 scm_weak_table_putq_x (vtable_class_map, vtable, class);
221 }
222
223 return class;
224 }
225
226 /* This function is used for efficient type dispatch. */
227 SCM_DEFINE (scm_class_of, "class-of", 1, 0, 0,
228 (SCM x),
229 "Return the class of @var{x}.")
230 #define FUNC_NAME s_scm_class_of
231 {
232 switch (SCM_ITAG3 (x))
233 {
234 case scm_tc3_int_1:
235 case scm_tc3_int_2:
236 return scm_class_integer;
237
238 case scm_tc3_imm24:
239 if (SCM_CHARP (x))
240 return scm_class_char;
241 else if (scm_is_bool (x))
242 return scm_class_boolean;
243 else if (scm_is_null (x))
244 return scm_class_null;
245 else
246 return scm_class_unknown;
247
248 case scm_tc3_cons:
249 switch (SCM_TYP7 (x))
250 {
251 case scm_tcs_cons_nimcar:
252 return scm_class_pair;
253 case scm_tc7_symbol:
254 return scm_class_symbol;
255 case scm_tc7_vector:
256 case scm_tc7_wvect:
257 return scm_class_vector;
258 case scm_tc7_pointer:
259 return class_foreign;
260 case scm_tc7_hashtable:
261 return class_hashtable;
262 case scm_tc7_fluid:
263 return class_fluid;
264 case scm_tc7_dynamic_state:
265 return class_dynamic_state;
266 case scm_tc7_frame:
267 return class_frame;
268 case scm_tc7_vm:
269 return class_vm;
270 case scm_tc7_vm_cont:
271 return class_vm_cont;
272 case scm_tc7_bytevector:
273 if (SCM_BYTEVECTOR_ELEMENT_TYPE (x) == SCM_ARRAY_ELEMENT_TYPE_VU8)
274 return class_bytevector;
275 else
276 return class_uvec;
277 case scm_tc7_array:
278 return class_array;
279 case scm_tc7_bitvector:
280 return class_bitvector;
281 case scm_tc7_string:
282 return scm_class_string;
283 case scm_tc7_number:
284 switch SCM_TYP16 (x) {
285 case scm_tc16_big:
286 return scm_class_integer;
287 case scm_tc16_real:
288 return scm_class_real;
289 case scm_tc16_complex:
290 return scm_class_complex;
291 case scm_tc16_fraction:
292 return scm_class_fraction;
293 }
294 case scm_tc7_program:
295 if (SCM_PROGRAM_IS_PRIMITIVE_GENERIC (x)
296 && SCM_UNPACK (*SCM_SUBR_GENERIC (x)))
297 return scm_class_primitive_generic;
298 else
299 return scm_class_procedure;
300
301 case scm_tc7_smob:
302 {
303 scm_t_bits type = SCM_TYP16 (x);
304 if (type != scm_tc16_port_with_ps)
305 return scm_smob_class[SCM_TC2SMOBNUM (type)];
306 x = SCM_PORT_WITH_PS_PORT (x);
307 /* fall through to ports */
308 }
309 case scm_tc7_port:
310 return scm_port_class[(SCM_WRTNG & SCM_CELL_WORD_0 (x)
311 ? (SCM_RDNG & SCM_CELL_WORD_0 (x)
312 ? SCM_INOUT_PCLASS_INDEX | SCM_PTOBNUM (x)
313 : SCM_OUT_PCLASS_INDEX | SCM_PTOBNUM (x))
314 : SCM_IN_PCLASS_INDEX | SCM_PTOBNUM (x))];
315 case scm_tcs_struct:
316 if (SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_GOOPS_VALID)
317 return SCM_CLASS_OF (x);
318 else if (SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_GOOPS)
319 {
320 /* Goops object */
321 if (! scm_is_false (SCM_OBJ_CLASS_REDEF (x)))
322 scm_change_object_class (x,
323 SCM_CLASS_OF (x), /* old */
324 SCM_OBJ_CLASS_REDEF (x)); /* new */
325 return SCM_CLASS_OF (x);
326 }
327 else
328 return scm_i_define_class_for_vtable (SCM_CLASS_OF (x));
329 default:
330 if (scm_is_pair (x))
331 return scm_class_pair;
332 else
333 return scm_class_unknown;
334 }
335
336 case scm_tc3_struct:
337 case scm_tc3_tc7_1:
338 case scm_tc3_tc7_2:
339 /* case scm_tc3_unused: */
340 /* Never reached */
341 break;
342 }
343 return scm_class_unknown;
344 }
345 #undef FUNC_NAME
346
347 /******************************************************************************
348 *
349 * Compute-cpl
350 *
351 * This version doesn't fully handle multiple-inheritance. It serves
352 * only for booting classes and will be overloaded in Scheme
353 *
354 ******************************************************************************/
355
356 static SCM
357 map (SCM (*proc) (SCM), SCM ls)
358 {
359 if (scm_is_null (ls))
360 return ls;
361 else
362 {
363 SCM res = scm_cons (proc (SCM_CAR (ls)), SCM_EOL);
364 SCM h = res;
365 ls = SCM_CDR (ls);
366 while (scm_is_pair (ls))
367 {
368 SCM_SETCDR (h, scm_cons (proc (SCM_CAR (ls)), SCM_EOL));
369 h = SCM_CDR (h);
370 ls = SCM_CDR (ls);
371 }
372 return res;
373 }
374 }
375
376 static SCM
377 filter_cpl (SCM ls)
378 {
379 SCM res = SCM_EOL;
380 while (scm_is_pair (ls))
381 {
382 SCM el = SCM_CAR (ls);
383 if (scm_is_false (scm_c_memq (el, res)))
384 res = scm_cons (el, res);
385 ls = SCM_CDR (ls);
386 }
387 return res;
388 }
389
390 static SCM
391 compute_cpl (SCM class)
392 {
393 if (goops_loaded_p)
394 return scm_call_1 (SCM_VARIABLE_REF (var_compute_cpl), class);
395 else
396 {
397 SCM supers = SCM_SLOT (class, scm_si_direct_supers);
398 SCM ls = scm_append (scm_acons (class, supers,
399 map (compute_cpl, supers)));
400 return scm_reverse_x (filter_cpl (ls), SCM_EOL);
401 }
402 }
403
404 /******************************************************************************
405 *
406 * compute-slots
407 *
408 ******************************************************************************/
409
410 static SCM
411 remove_duplicate_slots (SCM l, SCM res, SCM slots_already_seen)
412 {
413 SCM tmp;
414
415 if (!scm_is_pair (l))
416 return res;
417
418 tmp = SCM_CAAR (l);
419 if (!scm_is_symbol (tmp))
420 scm_misc_error ("%compute-slots", "bad slot name ~S", scm_list_1 (tmp));
421
422 if (scm_is_false (scm_c_memq (tmp, slots_already_seen))) {
423 res = scm_cons (SCM_CAR (l), res);
424 slots_already_seen = scm_cons (tmp, slots_already_seen);
425 }
426
427 return remove_duplicate_slots (SCM_CDR (l), res, slots_already_seen);
428 }
429
430 static void
431 check_cpl (SCM slots, SCM bslots)
432 {
433 for (; scm_is_pair (bslots); bslots = SCM_CDR (bslots))
434 if (scm_is_true (scm_assq (SCM_CAAR (bslots), slots)))
435 scm_misc_error ("init-object", "a predefined <class> inherited "
436 "field cannot be redefined", SCM_EOL);
437 }
438
439 static SCM
440 build_class_class_slots (void);
441
442 static SCM
443 build_slots_list (SCM dslots, SCM cpl)
444 {
445 SCM bslots, class_slots;
446 int classp;
447 SCM res = dslots;
448
449 class_slots = SCM_EOL;
450 classp = scm_is_true (scm_memq (scm_class_class, cpl));
451
452 if (classp)
453 {
454 bslots = build_class_class_slots ();
455 check_cpl (res, bslots);
456 }
457 else
458 bslots = SCM_EOL;
459
460 if (scm_is_pair (cpl))
461 {
462 for (cpl = SCM_CDR (cpl); scm_is_pair (cpl); cpl = SCM_CDR (cpl))
463 {
464 SCM new_slots = SCM_SLOT (SCM_CAR (cpl),
465 scm_si_direct_slots);
466 if (classp)
467 {
468 if (!scm_is_eq (SCM_CAR (cpl), scm_class_class))
469 check_cpl (new_slots, bslots);
470 else
471 {
472 /* Move class slots to the head of the list. */
473 class_slots = new_slots;
474 continue;
475 }
476 }
477 res = scm_append (scm_list_2 (new_slots, res));
478 }
479 }
480 else
481 scm_misc_error ("%compute-slots", "malformed cpl argument in "
482 "build_slots_list", SCM_EOL);
483
484 /* make sure to add the <class> slots to the head of the list */
485 if (classp)
486 res = scm_append (scm_list_2 (class_slots, res));
487
488 /* res contains a list of slots. Remove slots which appears more than once */
489 return remove_duplicate_slots (scm_reverse (res), SCM_EOL, SCM_EOL);
490 }
491
492 static SCM
493 maplist (SCM ls)
494 {
495 SCM orig = ls;
496 while (!scm_is_null (ls))
497 {
498 if (!scm_is_pair (ls))
499 scm_misc_error ("%compute-slots", "malformed ls argument in "
500 "maplist", SCM_EOL);
501 if (!scm_is_pair (SCM_CAR (ls)))
502 SCM_SETCAR (ls, scm_cons (SCM_CAR (ls), SCM_EOL));
503 ls = SCM_CDR (ls);
504 }
505 return orig;
506 }
507
508
509 SCM_DEFINE (scm_sys_compute_slots, "%compute-slots", 1, 0, 0,
510 (SCM class),
511 "Return a list consisting of the names of all slots belonging to\n"
512 "class @var{class}, i. e. the slots of @var{class} and of all of\n"
513 "its superclasses.")
514 #define FUNC_NAME s_scm_sys_compute_slots
515 {
516 SCM_VALIDATE_CLASS (1, class);
517 return build_slots_list (SCM_SLOT (class, scm_si_direct_slots),
518 SCM_SLOT (class, scm_si_cpl));
519 }
520 #undef FUNC_NAME
521
522
523 /******************************************************************************
524 *
525 * compute-getters-n-setters
526 *
527 * This version doesn't handle slot options. It serves only for booting
528 * classes and will be overloaded in Scheme.
529 *
530 ******************************************************************************/
531
532 SCM_KEYWORD (k_init_value, "init-value");
533 SCM_KEYWORD (k_init_thunk, "init-thunk");
534
535 static SCM
536 compute_getters_n_setters (SCM slots)
537 {
538 SCM res = SCM_EOL;
539 SCM *cdrloc = &res;
540 long i = 0;
541
542 for ( ; !scm_is_null (slots); slots = SCM_CDR (slots))
543 {
544 SCM init = SCM_BOOL_F;
545 SCM options = SCM_CDAR (slots);
546 if (!scm_is_null (options))
547 {
548 init = scm_get_keyword (k_init_value, options, SCM_PACK (0));
549 if (SCM_UNPACK (init))
550 {
551 init = scm_primitive_eval (scm_list_3 (scm_sym_lambda,
552 SCM_EOL,
553 scm_list_2 (scm_sym_quote,
554 init)));
555 }
556 else
557 init = scm_get_keyword (k_init_thunk, options, SCM_BOOL_F);
558 }
559 *cdrloc = scm_cons (scm_cons (SCM_CAAR (slots),
560 scm_cons (init,
561 scm_from_int (i++))),
562 SCM_EOL);
563 cdrloc = SCM_CDRLOC (*cdrloc);
564 }
565 return res;
566 }
567
568 /******************************************************************************
569 *
570 * initialize-object
571 *
572 ******************************************************************************/
573
574 /*fixme* Manufacture keywords in advance */
575 SCM
576 scm_i_get_keyword (SCM key, SCM l, long len, SCM default_value, const char *subr)
577 {
578 long i;
579
580 for (i = 0; i != len; i += 2)
581 {
582 SCM obj = SCM_CAR (l);
583
584 if (!scm_is_keyword (obj))
585 scm_misc_error (subr, "bad keyword: ~S", scm_list_1 (obj));
586 else if (scm_is_eq (obj, key))
587 return SCM_CADR (l);
588 else
589 l = SCM_CDDR (l);
590 }
591
592 return default_value;
593 }
594
595
596 SCM_DEFINE (scm_get_keyword, "get-keyword", 3, 0, 0,
597 (SCM key, SCM l, SCM default_value),
598 "Determine an associated value for the keyword @var{key} from\n"
599 "the list @var{l}. The list @var{l} has to consist of an even\n"
600 "number of elements, where, starting with the first, every\n"
601 "second element is a keyword, followed by its associated value.\n"
602 "If @var{l} does not hold a value for @var{key}, the value\n"
603 "@var{default_value} is returned.")
604 #define FUNC_NAME s_scm_get_keyword
605 {
606 long len;
607
608 SCM_ASSERT (scm_is_keyword (key), key, SCM_ARG1, FUNC_NAME);
609 len = scm_ilength (l);
610 if (len < 0 || len % 2 == 1)
611 scm_misc_error (FUNC_NAME, "Bad keyword-value list: ~S", scm_list_1 (l));
612
613 return scm_i_get_keyword (key, l, len, default_value, FUNC_NAME);
614 }
615 #undef FUNC_NAME
616
617
618 SCM_KEYWORD (k_init_keyword, "init-keyword");
619
620 static SCM get_slot_value (SCM class, SCM obj, SCM slotdef);
621 static SCM set_slot_value (SCM class, SCM obj, SCM slotdef, SCM value);
622
623 SCM_DEFINE (scm_sys_initialize_object, "%initialize-object", 2, 0, 0,
624 (SCM obj, SCM initargs),
625 "Initialize the object @var{obj} with the given arguments\n"
626 "@var{initargs}.")
627 #define FUNC_NAME s_scm_sys_initialize_object
628 {
629 SCM tmp, get_n_set, slots;
630 SCM class = SCM_CLASS_OF (obj);
631 long n_initargs;
632
633 SCM_VALIDATE_INSTANCE (1, obj);
634 n_initargs = scm_ilength (initargs);
635 SCM_ASSERT ((n_initargs & 1) == 0, initargs, SCM_ARG2, FUNC_NAME);
636
637 get_n_set = SCM_SLOT (class, scm_si_getters_n_setters);
638 slots = SCM_SLOT (class, scm_si_slots);
639
640 /* See for each slot how it must be initialized */
641 for (;
642 !scm_is_null (slots);
643 get_n_set = SCM_CDR (get_n_set), slots = SCM_CDR (slots))
644 {
645 SCM slot_name = SCM_CAR (slots);
646 SCM slot_value = SCM_PACK (0);
647
648 if (!scm_is_null (SCM_CDR (slot_name)))
649 {
650 /* This slot admits (perhaps) to be initialized at creation time */
651 long n = scm_ilength (SCM_CDR (slot_name));
652 if (n & 1) /* odd or -1 */
653 SCM_MISC_ERROR ("class contains bogus slot definition: ~S",
654 scm_list_1 (slot_name));
655 tmp = scm_i_get_keyword (k_init_keyword,
656 SCM_CDR (slot_name),
657 n,
658 SCM_PACK (0),
659 FUNC_NAME);
660 slot_name = SCM_CAR (slot_name);
661 if (SCM_UNPACK (tmp))
662 {
663 /* an initarg was provided for this slot */
664 if (!scm_is_keyword (tmp))
665 SCM_MISC_ERROR ("initarg must be a keyword. It was ~S",
666 scm_list_1 (tmp));
667 slot_value = scm_i_get_keyword (tmp,
668 initargs,
669 n_initargs,
670 SCM_PACK (0),
671 FUNC_NAME);
672 }
673 }
674
675 if (SCM_UNPACK (slot_value))
676 /* set slot to provided value */
677 set_slot_value (class, obj, SCM_CAR (get_n_set), slot_value);
678 else
679 {
680 /* set slot to its :init-form if it exists */
681 tmp = SCM_CADAR (get_n_set);
682 if (scm_is_true (tmp))
683 {
684 slot_value = get_slot_value (class, obj, SCM_CAR (get_n_set));
685 if (SCM_GOOPS_UNBOUNDP (slot_value))
686 set_slot_value (class,
687 obj,
688 SCM_CAR (get_n_set),
689 scm_call_0 (tmp));
690 }
691 }
692 }
693
694 return obj;
695 }
696 #undef FUNC_NAME
697
698 /* NOTE: The following macros are interdependent with code
699 * in goops.scm:compute-getters-n-setters
700 */
701 #define SCM_GNS_INSTANCE_ALLOCATED_P(gns) \
702 (SCM_I_INUMP (SCM_CDDR (gns)) \
703 || (scm_is_pair (SCM_CDDR (gns)) \
704 && scm_is_pair (SCM_CDDDR (gns)) \
705 && scm_is_pair (SCM_CDDDDR (gns))))
706 #define SCM_GNS_INDEX(gns) \
707 (SCM_I_INUMP (SCM_CDDR (gns)) \
708 ? SCM_I_INUM (SCM_CDDR (gns)) \
709 : scm_to_long (SCM_CAR (SCM_CDDDDR (gns))))
710 #define SCM_GNS_SIZE(gns) \
711 (SCM_I_INUMP (SCM_CDDR (gns)) \
712 ? 1 \
713 : scm_to_long (SCM_CADR (SCM_CDDDDR (gns))))
714
715 SCM_KEYWORD (k_class, "class");
716 SCM_KEYWORD (k_allocation, "allocation");
717 SCM_KEYWORD (k_instance, "instance");
718
719 SCM_DEFINE (scm_sys_prep_layout_x, "%prep-layout!", 1, 0, 0,
720 (SCM class),
721 "")
722 #define FUNC_NAME s_scm_sys_prep_layout_x
723 {
724 SCM slots, getters_n_setters, nfields;
725 unsigned long int n, i;
726 char *s;
727 SCM layout;
728
729 SCM_VALIDATE_INSTANCE (1, class);
730 slots = SCM_SLOT (class, scm_si_slots);
731 getters_n_setters = SCM_SLOT (class, scm_si_getters_n_setters);
732 nfields = SCM_SLOT (class, scm_si_nfields);
733 if (!SCM_I_INUMP (nfields) || SCM_I_INUM (nfields) < 0)
734 SCM_MISC_ERROR ("bad value in nfields slot: ~S",
735 scm_list_1 (nfields));
736 n = 2 * SCM_I_INUM (nfields);
737 if (n < sizeof (SCM_CLASS_CLASS_LAYOUT) - 1
738 && SCM_SUBCLASSP (class, scm_class_class))
739 SCM_MISC_ERROR ("class object doesn't have enough fields: ~S",
740 scm_list_1 (nfields));
741
742 layout = scm_i_make_string (n, &s, 0);
743 i = 0;
744 while (scm_is_pair (getters_n_setters))
745 {
746 if (SCM_GNS_INSTANCE_ALLOCATED_P (SCM_CAR (getters_n_setters)))
747 {
748 SCM type;
749 int len, index, size;
750 char p, a;
751
752 if (i >= n || !scm_is_pair (slots))
753 goto inconsistent;
754
755 /* extract slot type */
756 len = scm_ilength (SCM_CDAR (slots));
757 type = scm_i_get_keyword (k_class, SCM_CDAR (slots),
758 len, SCM_BOOL_F, FUNC_NAME);
759 /* determine slot GC protection and access mode */
760 if (scm_is_false (type))
761 {
762 p = 'p';
763 a = 'w';
764 }
765 else
766 {
767 if (!SCM_CLASSP (type))
768 SCM_MISC_ERROR ("bad slot class", SCM_EOL);
769 else if (SCM_SUBCLASSP (type, scm_class_foreign_slot))
770 {
771 if (SCM_SUBCLASSP (type, scm_class_self))
772 p = 's';
773 else if (SCM_SUBCLASSP (type, scm_class_protected))
774 p = 'p';
775 else
776 p = 'u';
777
778 if (SCM_SUBCLASSP (type, scm_class_opaque))
779 a = 'o';
780 else if (SCM_SUBCLASSP (type, scm_class_read_only))
781 a = 'r';
782 else if (SCM_SUBCLASSP (type, scm_class_hidden))
783 a = 'h';
784 else
785 a = 'w';
786 }
787 else
788 {
789 p = 'p';
790 a = 'w';
791 }
792 }
793
794 index = SCM_GNS_INDEX (SCM_CAR (getters_n_setters));
795 if (index != (i >> 1))
796 goto inconsistent;
797 size = SCM_GNS_SIZE (SCM_CAR (getters_n_setters));
798 while (size)
799 {
800 s[i++] = p;
801 s[i++] = a;
802 --size;
803 }
804 }
805 slots = SCM_CDR (slots);
806 getters_n_setters = SCM_CDR (getters_n_setters);
807 }
808 if (!scm_is_null (slots))
809 {
810 inconsistent:
811 SCM_MISC_ERROR ("inconsistent getters-n-setters", SCM_EOL);
812 }
813 SCM_SET_VTABLE_LAYOUT (class, scm_string_to_symbol (layout));
814 return SCM_UNSPECIFIED;
815 }
816 #undef FUNC_NAME
817
818 static void prep_hashsets (SCM);
819
820 SCM_DEFINE (scm_sys_inherit_magic_x, "%inherit-magic!", 2, 0, 0,
821 (SCM class, SCM dsupers),
822 "")
823 #define FUNC_NAME s_scm_sys_inherit_magic_x
824 {
825 SCM_VALIDATE_INSTANCE (1, class);
826 scm_i_struct_inherit_vtable_magic (SCM_CLASS_OF (class), class);
827 SCM_SET_CLASS_FLAGS (class, SCM_CLASSF_GOOPS_OR_VALID);
828
829 prep_hashsets (class);
830
831 return SCM_UNSPECIFIED;
832 }
833 #undef FUNC_NAME
834
835 static void
836 prep_hashsets (SCM class)
837 {
838 unsigned int i;
839
840 for (i = 0; i < 8; ++i)
841 SCM_SET_HASHSET (class, i, scm_c_uniform32 (goops_rstate));
842 }
843
844 /******************************************************************************/
845
846 SCM
847 scm_basic_basic_make_class (SCM class, SCM name, SCM dsupers, SCM dslots)
848 {
849 SCM z, cpl, slots, nfields, g_n_s;
850
851 /* Allocate one instance */
852 z = scm_make_struct (class, SCM_INUM0, SCM_EOL);
853
854 /* Initialize its slots */
855 SCM_SET_SLOT (z, scm_si_direct_supers, dsupers);
856 cpl = compute_cpl (z);
857 slots = build_slots_list (maplist (dslots), cpl);
858 nfields = scm_from_int (scm_ilength (slots));
859 g_n_s = compute_getters_n_setters (slots);
860
861 SCM_SET_SLOT (z, scm_vtable_index_name, name);
862 SCM_SET_SLOT (z, scm_si_direct_slots, dslots);
863 SCM_SET_SLOT (z, scm_si_direct_subclasses, SCM_EOL);
864 SCM_SET_SLOT (z, scm_si_direct_methods, SCM_EOL);
865 SCM_SET_SLOT (z, scm_si_cpl, cpl);
866 SCM_SET_SLOT (z, scm_si_slots, slots);
867 SCM_SET_SLOT (z, scm_si_nfields, nfields);
868 SCM_SET_SLOT (z, scm_si_getters_n_setters, g_n_s);
869 SCM_SET_SLOT (z, scm_si_redefined, SCM_BOOL_F);
870
871 /* Add this class in the direct-subclasses slot of dsupers */
872 {
873 SCM tmp;
874 for (tmp = dsupers; !scm_is_null (tmp); tmp = SCM_CDR (tmp))
875 SCM_SET_SLOT (SCM_CAR (tmp), scm_si_direct_subclasses,
876 scm_cons (z, SCM_SLOT (SCM_CAR (tmp),
877 scm_si_direct_subclasses)));
878 }
879
880 return z;
881 }
882
883 SCM
884 scm_basic_make_class (SCM class, SCM name, SCM dsupers, SCM dslots)
885 {
886 SCM z = scm_basic_basic_make_class (class, name, dsupers, dslots);
887 scm_sys_prep_layout_x (z);
888 scm_sys_inherit_magic_x (z, dsupers);
889 return z;
890 }
891
892 /******************************************************************************/
893
894 SCM_SYMBOL (sym_layout, "layout");
895 SCM_SYMBOL (sym_flags, "flags");
896 SCM_SYMBOL (sym_self, "%self");
897 SCM_SYMBOL (sym_instance_finalizer, "instance-finalizer");
898 SCM_SYMBOL (sym_reserved_0, "%reserved-0");
899 SCM_SYMBOL (sym_reserved_1, "%reserved-1");
900 SCM_SYMBOL (sym_print, "print");
901 SCM_SYMBOL (sym_procedure, "procedure");
902 SCM_SYMBOL (sym_setter, "setter");
903 SCM_SYMBOL (sym_redefined, "redefined");
904 SCM_SYMBOL (sym_h0, "h0");
905 SCM_SYMBOL (sym_h1, "h1");
906 SCM_SYMBOL (sym_h2, "h2");
907 SCM_SYMBOL (sym_h3, "h3");
908 SCM_SYMBOL (sym_h4, "h4");
909 SCM_SYMBOL (sym_h5, "h5");
910 SCM_SYMBOL (sym_h6, "h6");
911 SCM_SYMBOL (sym_h7, "h7");
912 SCM_SYMBOL (sym_name, "name");
913 SCM_SYMBOL (sym_direct_supers, "direct-supers");
914 SCM_SYMBOL (sym_direct_slots, "direct-slots");
915 SCM_SYMBOL (sym_direct_subclasses, "direct-subclasses");
916 SCM_SYMBOL (sym_direct_methods, "direct-methods");
917 SCM_SYMBOL (sym_cpl, "cpl");
918 SCM_SYMBOL (sym_default_slot_definition_class, "default-slot-definition-class");
919 SCM_SYMBOL (sym_slots, "slots");
920 SCM_SYMBOL (sym_getters_n_setters, "getters-n-setters");
921 SCM_SYMBOL (sym_nfields, "nfields");
922
923
924 static SCM
925 build_class_class_slots (void)
926 {
927 /* has to be kept in sync with SCM_VTABLE_BASE_LAYOUT and
928 SCM_CLASS_CLASS_LAYOUT */
929 return scm_list_n (
930 scm_list_3 (sym_layout, k_class, scm_class_protected_read_only),
931 scm_list_3 (sym_flags, k_class, scm_class_hidden),
932 scm_list_3 (sym_self, k_class, scm_class_self),
933 scm_list_3 (sym_instance_finalizer, k_class, scm_class_hidden),
934 scm_list_1 (sym_print),
935 scm_list_3 (sym_name, k_class, scm_class_protected_hidden),
936 scm_list_3 (sym_reserved_0, k_class, scm_class_hidden),
937 scm_list_3 (sym_reserved_1, k_class, scm_class_hidden),
938 scm_list_1 (sym_redefined),
939 scm_list_3 (sym_h0, k_class, scm_class_int),
940 scm_list_3 (sym_h1, k_class, scm_class_int),
941 scm_list_3 (sym_h2, k_class, scm_class_int),
942 scm_list_3 (sym_h3, k_class, scm_class_int),
943 scm_list_3 (sym_h4, k_class, scm_class_int),
944 scm_list_3 (sym_h5, k_class, scm_class_int),
945 scm_list_3 (sym_h6, k_class, scm_class_int),
946 scm_list_3 (sym_h7, k_class, scm_class_int),
947 scm_list_1 (sym_direct_supers),
948 scm_list_1 (sym_direct_slots),
949 scm_list_1 (sym_direct_subclasses),
950 scm_list_1 (sym_direct_methods),
951 scm_list_1 (sym_cpl),
952 scm_list_1 (sym_default_slot_definition_class),
953 scm_list_1 (sym_slots),
954 scm_list_1 (sym_getters_n_setters),
955 scm_list_1 (sym_nfields),
956 SCM_UNDEFINED);
957 }
958
959 static void
960 create_basic_classes (void)
961 {
962 /* SCM slots_of_class = build_class_class_slots (); */
963
964 /**** <class> ****/
965 SCM cs = scm_from_locale_string (SCM_CLASS_CLASS_LAYOUT);
966 SCM name = scm_from_latin1_symbol ("<class>");
967 scm_class_class = scm_i_make_vtable_vtable (cs);
968 SCM_SET_CLASS_FLAGS (scm_class_class, (SCM_CLASSF_GOOPS_OR_VALID
969 | SCM_CLASSF_METACLASS));
970
971 SCM_SET_SLOT (scm_class_class, scm_vtable_index_name, name);
972 SCM_SET_SLOT (scm_class_class, scm_si_direct_supers, SCM_EOL); /* will be changed */
973 /* SCM_SET_SLOT (scm_class_class, scm_si_direct_slots, slots_of_class); */
974 SCM_SET_SLOT (scm_class_class, scm_si_direct_subclasses, SCM_EOL);
975 SCM_SET_SLOT (scm_class_class, scm_si_direct_methods, SCM_EOL);
976 SCM_SET_SLOT (scm_class_class, scm_si_cpl, SCM_EOL); /* will be changed */
977 /* SCM_SET_SLOT (scm_class_class, scm_si_slots, slots_of_class); */
978 SCM_SET_SLOT (scm_class_class, scm_si_nfields, scm_from_int (SCM_N_CLASS_SLOTS));
979 /* SCM_SET_SLOT (scm_class_class, scm_si_getters_n_setters,
980 compute_getters_n_setters (slots_of_class)); */
981 SCM_SET_SLOT (scm_class_class, scm_si_redefined, SCM_BOOL_F);
982
983 prep_hashsets (scm_class_class);
984
985 scm_module_define (scm_module_goops, name, scm_class_class);
986
987 /**** <top> ****/
988 name = scm_from_latin1_symbol ("<top>");
989 scm_class_top = scm_basic_make_class (scm_class_class, name,
990 SCM_EOL, SCM_EOL);
991
992 scm_module_define (scm_module_goops, name, scm_class_top);
993
994 /**** <object> ****/
995 name = scm_from_latin1_symbol ("<object>");
996 scm_class_object = scm_basic_make_class (scm_class_class, name,
997 scm_list_1 (scm_class_top), SCM_EOL);
998
999 scm_module_define (scm_module_goops, name, scm_class_object);
1000
1001 /* <top> <object> and <class> were partially initialized. Correct them here */
1002 SCM_SET_SLOT (scm_class_object, scm_si_direct_subclasses, scm_list_1 (scm_class_class));
1003
1004 SCM_SET_SLOT (scm_class_class, scm_si_direct_supers, scm_list_1 (scm_class_object));
1005 SCM_SET_SLOT (scm_class_class, scm_si_cpl, scm_list_3 (scm_class_class, scm_class_object, scm_class_top));
1006 }
1007
1008 /******************************************************************************/
1009
1010 SCM_DEFINE (scm_instance_p, "instance?", 1, 0, 0,
1011 (SCM obj),
1012 "Return @code{#t} if @var{obj} is an instance.")
1013 #define FUNC_NAME s_scm_instance_p
1014 {
1015 return scm_from_bool (SCM_INSTANCEP (obj));
1016 }
1017 #undef FUNC_NAME
1018
1019
1020 /******************************************************************************
1021 *
1022 * Meta object accessors
1023 *
1024 ******************************************************************************/
1025 SCM_DEFINE (scm_class_name, "class-name", 1, 0, 0,
1026 (SCM obj),
1027 "Return the class name of @var{obj}.")
1028 #define FUNC_NAME s_scm_class_name
1029 {
1030 SCM_VALIDATE_CLASS (1, obj);
1031 return scm_slot_ref (obj, sym_name);
1032 }
1033 #undef FUNC_NAME
1034
1035 SCM_DEFINE (scm_class_direct_supers, "class-direct-supers", 1, 0, 0,
1036 (SCM obj),
1037 "Return the direct superclasses of the class @var{obj}.")
1038 #define FUNC_NAME s_scm_class_direct_supers
1039 {
1040 SCM_VALIDATE_CLASS (1, obj);
1041 return scm_slot_ref (obj, sym_direct_supers);
1042 }
1043 #undef FUNC_NAME
1044
1045 SCM_DEFINE (scm_class_direct_slots, "class-direct-slots", 1, 0, 0,
1046 (SCM obj),
1047 "Return the direct slots of the class @var{obj}.")
1048 #define FUNC_NAME s_scm_class_direct_slots
1049 {
1050 SCM_VALIDATE_CLASS (1, obj);
1051 return scm_slot_ref (obj, sym_direct_slots);
1052 }
1053 #undef FUNC_NAME
1054
1055 SCM_DEFINE (scm_class_direct_subclasses, "class-direct-subclasses", 1, 0, 0,
1056 (SCM obj),
1057 "Return the direct subclasses of the class @var{obj}.")
1058 #define FUNC_NAME s_scm_class_direct_subclasses
1059 {
1060 SCM_VALIDATE_CLASS (1, obj);
1061 return scm_slot_ref(obj, sym_direct_subclasses);
1062 }
1063 #undef FUNC_NAME
1064
1065 SCM_DEFINE (scm_class_direct_methods, "class-direct-methods", 1, 0, 0,
1066 (SCM obj),
1067 "Return the direct methods of the class @var{obj}")
1068 #define FUNC_NAME s_scm_class_direct_methods
1069 {
1070 SCM_VALIDATE_CLASS (1, obj);
1071 return scm_slot_ref (obj, sym_direct_methods);
1072 }
1073 #undef FUNC_NAME
1074
1075 SCM_DEFINE (scm_class_precedence_list, "class-precedence-list", 1, 0, 0,
1076 (SCM obj),
1077 "Return the class precedence list of the class @var{obj}.")
1078 #define FUNC_NAME s_scm_class_precedence_list
1079 {
1080 SCM_VALIDATE_CLASS (1, obj);
1081 return scm_slot_ref (obj, sym_cpl);
1082 }
1083 #undef FUNC_NAME
1084
1085 SCM_DEFINE (scm_class_slots, "class-slots", 1, 0, 0,
1086 (SCM obj),
1087 "Return the slot list of the class @var{obj}.")
1088 #define FUNC_NAME s_scm_class_slots
1089 {
1090 SCM_VALIDATE_CLASS (1, obj);
1091 return scm_slot_ref (obj, sym_slots);
1092 }
1093 #undef FUNC_NAME
1094
1095 SCM_DEFINE (scm_generic_function_name, "generic-function-name", 1, 0, 0,
1096 (SCM obj),
1097 "Return the name of the generic function @var{obj}.")
1098 #define FUNC_NAME s_scm_generic_function_name
1099 {
1100 SCM_VALIDATE_GENERIC (1, obj);
1101 return scm_procedure_property (obj, scm_sym_name);
1102 }
1103 #undef FUNC_NAME
1104
1105 SCM_SYMBOL (sym_methods, "methods");
1106 SCM_SYMBOL (sym_extended_by, "extended-by");
1107 SCM_SYMBOL (sym_extends, "extends");
1108
1109 static
1110 SCM fold_downward_gf_methods (SCM method_lists, SCM gf)
1111 {
1112 SCM gfs = scm_slot_ref (gf, sym_extended_by);
1113 method_lists = scm_cons (scm_slot_ref (gf, sym_methods), method_lists);
1114 while (!scm_is_null (gfs))
1115 {
1116 method_lists = fold_downward_gf_methods (method_lists, SCM_CAR (gfs));
1117 gfs = SCM_CDR (gfs);
1118 }
1119 return method_lists;
1120 }
1121
1122 static
1123 SCM fold_upward_gf_methods (SCM method_lists, SCM gf)
1124 {
1125 if (SCM_IS_A_P (gf, scm_class_extended_generic))
1126 {
1127 SCM gfs = scm_slot_ref (gf, sym_extends);
1128 while (!scm_is_null (gfs))
1129 {
1130 SCM methods = scm_slot_ref (SCM_CAR (gfs), sym_methods);
1131 method_lists = fold_upward_gf_methods (scm_cons (methods,
1132 method_lists),
1133 SCM_CAR (gfs));
1134 gfs = SCM_CDR (gfs);
1135 }
1136 }
1137 return method_lists;
1138 }
1139
1140 SCM_DEFINE (scm_generic_function_methods, "generic-function-methods", 1, 0, 0,
1141 (SCM obj),
1142 "Return the methods of the generic function @var{obj}.")
1143 #define FUNC_NAME s_scm_generic_function_methods
1144 {
1145 SCM methods;
1146 SCM_VALIDATE_GENERIC (1, obj);
1147 methods = fold_upward_gf_methods (SCM_EOL, obj);
1148 methods = fold_downward_gf_methods (methods, obj);
1149 return scm_append (methods);
1150 }
1151 #undef FUNC_NAME
1152
1153 SCM_DEFINE (scm_method_generic_function, "method-generic-function", 1, 0, 0,
1154 (SCM obj),
1155 "Return the generic function for the method @var{obj}.")
1156 #define FUNC_NAME s_scm_method_generic_function
1157 {
1158 SCM_VALIDATE_METHOD (1, obj);
1159 return scm_slot_ref (obj, scm_from_latin1_symbol ("generic-function"));
1160 }
1161 #undef FUNC_NAME
1162
1163 SCM_DEFINE (scm_method_specializers, "method-specializers", 1, 0, 0,
1164 (SCM obj),
1165 "Return specializers of the method @var{obj}.")
1166 #define FUNC_NAME s_scm_method_specializers
1167 {
1168 SCM_VALIDATE_METHOD (1, obj);
1169 return scm_slot_ref (obj, scm_from_latin1_symbol ("specializers"));
1170 }
1171 #undef FUNC_NAME
1172
1173 SCM_DEFINE (scm_method_procedure, "method-procedure", 1, 0, 0,
1174 (SCM obj),
1175 "Return the procedure of the method @var{obj}.")
1176 #define FUNC_NAME s_scm_method_procedure
1177 {
1178 SCM_VALIDATE_METHOD (1, obj);
1179 return scm_slot_ref (obj, sym_procedure);
1180 }
1181 #undef FUNC_NAME
1182
1183 /******************************************************************************
1184 *
1185 * S l o t a c c e s s
1186 *
1187 ******************************************************************************/
1188
1189 SCM_DEFINE (scm_make_unbound, "make-unbound", 0, 0, 0,
1190 (),
1191 "Return the unbound value.")
1192 #define FUNC_NAME s_scm_make_unbound
1193 {
1194 return SCM_GOOPS_UNBOUND;
1195 }
1196 #undef FUNC_NAME
1197
1198 SCM_DEFINE (scm_unbound_p, "unbound?", 1, 0, 0,
1199 (SCM obj),
1200 "Return @code{#t} if @var{obj} is unbound.")
1201 #define FUNC_NAME s_scm_unbound_p
1202 {
1203 return SCM_GOOPS_UNBOUNDP (obj) ? SCM_BOOL_T : SCM_BOOL_F;
1204 }
1205 #undef FUNC_NAME
1206
1207 SCM_DEFINE (scm_assert_bound, "assert-bound", 2, 0, 0,
1208 (SCM value, SCM obj),
1209 "Return @var{value} if it is bound, and invoke the\n"
1210 "@var{slot-unbound} method of @var{obj} if it is not.")
1211 #define FUNC_NAME s_scm_assert_bound
1212 {
1213 if (SCM_GOOPS_UNBOUNDP (value))
1214 return scm_call_1 (SCM_VARIABLE_REF (var_slot_unbound), obj);
1215 return value;
1216 }
1217 #undef FUNC_NAME
1218
1219 SCM_DEFINE (scm_at_assert_bound_ref, "@assert-bound-ref", 2, 0, 0,
1220 (SCM obj, SCM index),
1221 "Like @code{assert-bound}, but use @var{index} for accessing\n"
1222 "the value from @var{obj}.")
1223 #define FUNC_NAME s_scm_at_assert_bound_ref
1224 {
1225 SCM value = SCM_SLOT (obj, scm_to_int (index));
1226 if (SCM_GOOPS_UNBOUNDP (value))
1227 return scm_call_1 (SCM_VARIABLE_REF (var_slot_unbound), obj);
1228 return value;
1229 }
1230 #undef FUNC_NAME
1231
1232 SCM_DEFINE (scm_sys_fast_slot_ref, "%fast-slot-ref", 2, 0, 0,
1233 (SCM obj, SCM index),
1234 "Return the slot value with index @var{index} from @var{obj}.")
1235 #define FUNC_NAME s_scm_sys_fast_slot_ref
1236 {
1237 scm_t_bits i;
1238
1239 SCM_VALIDATE_INSTANCE (1, obj);
1240 i = scm_to_unsigned_integer (index, 0,
1241 SCM_I_INUM (SCM_SLOT (SCM_CLASS_OF (obj),
1242 scm_si_nfields))
1243 - 1);
1244 return SCM_SLOT (obj, i);
1245 }
1246 #undef FUNC_NAME
1247
1248 SCM_DEFINE (scm_sys_fast_slot_set_x, "%fast-slot-set!", 3, 0, 0,
1249 (SCM obj, SCM index, SCM value),
1250 "Set the slot with index @var{index} in @var{obj} to\n"
1251 "@var{value}.")
1252 #define FUNC_NAME s_scm_sys_fast_slot_set_x
1253 {
1254 scm_t_bits i;
1255
1256 SCM_VALIDATE_INSTANCE (1, obj);
1257 i = scm_to_unsigned_integer (index, 0,
1258 SCM_I_INUM (SCM_SLOT (SCM_CLASS_OF (obj),
1259 scm_si_nfields))
1260 - 1);
1261
1262 SCM_SET_SLOT (obj, i, value);
1263
1264 return SCM_UNSPECIFIED;
1265 }
1266 #undef FUNC_NAME
1267
1268
1269 \f
1270 /** Utilities **/
1271
1272 /* In the future, this function will return the effective slot
1273 * definition associated with SLOT_NAME. Now it just returns some of
1274 * the information which will be stored in the effective slot
1275 * definition.
1276 */
1277
1278 static SCM
1279 slot_definition_using_name (SCM class, SCM slot_name)
1280 {
1281 register SCM slots = SCM_SLOT (class, scm_si_getters_n_setters);
1282 for (; !scm_is_null (slots); slots = SCM_CDR (slots))
1283 if (scm_is_eq (SCM_CAAR (slots), slot_name))
1284 return SCM_CAR (slots);
1285 return SCM_BOOL_F;
1286 }
1287
1288 static SCM
1289 get_slot_value (SCM class SCM_UNUSED, SCM obj, SCM slotdef)
1290 #define FUNC_NAME "%get-slot-value"
1291 {
1292 SCM access = SCM_CDDR (slotdef);
1293 /* Two cases here:
1294 * - access is an integer (the offset of this slot in the slots vector)
1295 * - otherwise (car access) is the getter function to apply
1296 *
1297 * Instances have never more than SCM_MOST_POSITIVE_FIXNUM slots, so
1298 * we can just assume fixnums here.
1299 */
1300 if (SCM_I_INUMP (access))
1301 /* Don't poke at the slots directly, because scm_struct_ref handles the
1302 access bits for us. */
1303 return scm_struct_ref (obj, access);
1304 else
1305 return scm_call_1 (SCM_CAR (access), obj);
1306 }
1307 #undef FUNC_NAME
1308
1309 static SCM
1310 get_slot_value_using_name (SCM class, SCM obj, SCM slot_name)
1311 {
1312 SCM slotdef = slot_definition_using_name (class, slot_name);
1313 if (scm_is_true (slotdef))
1314 return get_slot_value (class, obj, slotdef);
1315 else
1316 return scm_call_3 (SCM_VARIABLE_REF (var_slot_missing), class, obj, slot_name);
1317 }
1318
1319 static SCM
1320 set_slot_value (SCM class SCM_UNUSED, SCM obj, SCM slotdef, SCM value)
1321 #define FUNC_NAME "%set-slot-value"
1322 {
1323 SCM access = SCM_CDDR (slotdef);
1324 /* Two cases here:
1325 * - access is an integer (the offset of this slot in the slots vector)
1326 * - otherwise (cadr access) is the setter function to apply
1327 *
1328 * Instances have never more than SCM_MOST_POSITIVE_FIXNUM slots, so
1329 * we can just assume fixnums here.
1330 */
1331 if (SCM_I_INUMP (access))
1332 /* obey permissions bits via going through struct-set! */
1333 scm_struct_set_x (obj, access, value);
1334 else
1335 /* ((cadr l) obj value) */
1336 scm_call_2 (SCM_CADR (access), obj, value);
1337 return SCM_UNSPECIFIED;
1338 }
1339 #undef FUNC_NAME
1340
1341 static SCM
1342 set_slot_value_using_name (SCM class, SCM obj, SCM slot_name, SCM value)
1343 {
1344 SCM slotdef = slot_definition_using_name (class, slot_name);
1345 if (scm_is_true (slotdef))
1346 return set_slot_value (class, obj, slotdef, value);
1347 else
1348 return scm_call_4 (SCM_VARIABLE_REF (var_slot_missing), class, obj, slot_name, value);
1349 }
1350
1351 static SCM
1352 test_slot_existence (SCM class SCM_UNUSED, SCM obj, SCM slot_name)
1353 {
1354 register SCM l;
1355
1356 for (l = SCM_ACCESSORS_OF (obj); !scm_is_null (l); l = SCM_CDR (l))
1357 if (scm_is_eq (SCM_CAAR (l), slot_name))
1358 return SCM_BOOL_T;
1359
1360 return SCM_BOOL_F;
1361 }
1362
1363 /* ======================================== */
1364
1365 SCM_DEFINE (scm_slot_ref_using_class, "slot-ref-using-class", 3, 0, 0,
1366 (SCM class, SCM obj, SCM slot_name),
1367 "")
1368 #define FUNC_NAME s_scm_slot_ref_using_class
1369 {
1370 SCM res;
1371
1372 SCM_VALIDATE_CLASS (1, class);
1373 SCM_VALIDATE_INSTANCE (2, obj);
1374 SCM_VALIDATE_SYMBOL (3, slot_name);
1375
1376 res = get_slot_value_using_name (class, obj, slot_name);
1377 if (SCM_GOOPS_UNBOUNDP (res))
1378 return scm_call_3 (SCM_VARIABLE_REF (var_slot_unbound), class, obj, slot_name);
1379 return res;
1380 }
1381 #undef FUNC_NAME
1382
1383
1384 SCM_DEFINE (scm_slot_set_using_class_x, "slot-set-using-class!", 4, 0, 0,
1385 (SCM class, SCM obj, SCM slot_name, SCM value),
1386 "")
1387 #define FUNC_NAME s_scm_slot_set_using_class_x
1388 {
1389 SCM_VALIDATE_CLASS (1, class);
1390 SCM_VALIDATE_INSTANCE (2, obj);
1391 SCM_VALIDATE_SYMBOL (3, slot_name);
1392
1393 return set_slot_value_using_name (class, obj, slot_name, value);
1394 }
1395 #undef FUNC_NAME
1396
1397
1398 SCM_DEFINE (scm_slot_bound_using_class_p, "slot-bound-using-class?", 3, 0, 0,
1399 (SCM class, SCM obj, SCM slot_name),
1400 "")
1401 #define FUNC_NAME s_scm_slot_bound_using_class_p
1402 {
1403 SCM_VALIDATE_CLASS (1, class);
1404 SCM_VALIDATE_INSTANCE (2, obj);
1405 SCM_VALIDATE_SYMBOL (3, slot_name);
1406
1407 return (SCM_GOOPS_UNBOUNDP (get_slot_value_using_name (class, obj, slot_name))
1408 ? SCM_BOOL_F
1409 : SCM_BOOL_T);
1410 }
1411 #undef FUNC_NAME
1412
1413 SCM_DEFINE (scm_slot_exists_using_class_p, "slot-exists-using-class?", 3, 0, 0,
1414 (SCM class, SCM obj, SCM slot_name),
1415 "")
1416 #define FUNC_NAME s_scm_slot_exists_using_class_p
1417 {
1418 SCM_VALIDATE_CLASS (1, class);
1419 SCM_VALIDATE_INSTANCE (2, obj);
1420 SCM_VALIDATE_SYMBOL (3, slot_name);
1421 return test_slot_existence (class, obj, slot_name);
1422 }
1423 #undef FUNC_NAME
1424
1425
1426 /* ======================================== */
1427
1428 SCM_DEFINE (scm_slot_ref, "slot-ref", 2, 0, 0,
1429 (SCM obj, SCM slot_name),
1430 "Return the value from @var{obj}'s slot with the name\n"
1431 "@var{slot_name}.")
1432 #define FUNC_NAME s_scm_slot_ref
1433 {
1434 SCM res, class;
1435
1436 SCM_VALIDATE_INSTANCE (1, obj);
1437 TEST_CHANGE_CLASS (obj, class);
1438
1439 res = get_slot_value_using_name (class, obj, slot_name);
1440 if (SCM_GOOPS_UNBOUNDP (res))
1441 return scm_call_3 (SCM_VARIABLE_REF (var_slot_unbound), class, obj, slot_name);
1442 return res;
1443 }
1444 #undef FUNC_NAME
1445
1446 SCM_DEFINE (scm_slot_set_x, "slot-set!", 3, 0, 0,
1447 (SCM obj, SCM slot_name, SCM value),
1448 "Set the slot named @var{slot_name} of @var{obj} to @var{value}.")
1449 #define FUNC_NAME s_scm_slot_set_x
1450 {
1451 SCM class;
1452
1453 SCM_VALIDATE_INSTANCE (1, obj);
1454 TEST_CHANGE_CLASS(obj, class);
1455
1456 return set_slot_value_using_name (class, obj, slot_name, value);
1457 }
1458 #undef FUNC_NAME
1459
1460 const char *scm_s_slot_set_x = s_scm_slot_set_x;
1461
1462 SCM_DEFINE (scm_slot_bound_p, "slot-bound?", 2, 0, 0,
1463 (SCM obj, SCM slot_name),
1464 "Return @code{#t} if the slot named @var{slot_name} of @var{obj}\n"
1465 "is bound.")
1466 #define FUNC_NAME s_scm_slot_bound_p
1467 {
1468 SCM class;
1469
1470 SCM_VALIDATE_INSTANCE (1, obj);
1471 TEST_CHANGE_CLASS(obj, class);
1472
1473 return (SCM_GOOPS_UNBOUNDP (get_slot_value_using_name (class,
1474 obj,
1475 slot_name))
1476 ? SCM_BOOL_F
1477 : SCM_BOOL_T);
1478 }
1479 #undef FUNC_NAME
1480
1481 SCM_DEFINE (scm_slot_exists_p, "slot-exists?", 2, 0, 0,
1482 (SCM obj, SCM slot_name),
1483 "Return @code{#t} if @var{obj} has a slot named @var{slot_name}.")
1484 #define FUNC_NAME s_scm_slot_exists_p
1485 {
1486 SCM class;
1487
1488 SCM_VALIDATE_INSTANCE (1, obj);
1489 SCM_VALIDATE_SYMBOL (2, slot_name);
1490 TEST_CHANGE_CLASS (obj, class);
1491
1492 return test_slot_existence (class, obj, slot_name);
1493 }
1494 #undef FUNC_NAME
1495
1496
1497 /******************************************************************************
1498 *
1499 * %allocate-instance (the low level instance allocation primitive)
1500 *
1501 ******************************************************************************/
1502
1503 static void clear_method_cache (SCM);
1504
1505 SCM_DEFINE (scm_sys_allocate_instance, "%allocate-instance", 2, 0, 0,
1506 (SCM class, SCM initargs),
1507 "Create a new instance of class @var{class} and initialize it\n"
1508 "from the arguments @var{initargs}.")
1509 #define FUNC_NAME s_scm_sys_allocate_instance
1510 {
1511 SCM obj;
1512 scm_t_signed_bits n, i;
1513 SCM layout;
1514
1515 SCM_VALIDATE_CLASS (1, class);
1516
1517 /* FIXME: duplicates some of scm_make_struct. */
1518
1519 n = SCM_I_INUM (SCM_SLOT (class, scm_si_nfields));
1520 obj = scm_i_alloc_struct (SCM_STRUCT_DATA (class), n);
1521
1522 layout = SCM_VTABLE_LAYOUT (class);
1523
1524 /* Set all SCM-holding slots to unbound */
1525 for (i = 0; i < n; i++)
1526 {
1527 scm_t_wchar c = scm_i_symbol_ref (layout, i*2);
1528 if (c == 'p')
1529 SCM_STRUCT_DATA (obj)[i] = SCM_UNPACK (SCM_GOOPS_UNBOUND);
1530 else if (c == 's')
1531 SCM_STRUCT_DATA (obj)[i] = SCM_UNPACK (obj);
1532 else
1533 SCM_STRUCT_DATA (obj)[i] = 0;
1534 }
1535
1536 if (SCM_CLASS_FLAGS (class) & SCM_CLASSF_PURE_GENERIC)
1537 clear_method_cache (obj);
1538
1539 return obj;
1540 }
1541 #undef FUNC_NAME
1542
1543 SCM_DEFINE (scm_sys_set_object_setter_x, "%set-object-setter!", 2, 0, 0,
1544 (SCM obj, SCM setter),
1545 "")
1546 #define FUNC_NAME s_scm_sys_set_object_setter_x
1547 {
1548 SCM_ASSERT (SCM_STRUCTP (obj)
1549 && (SCM_OBJ_CLASS_FLAGS (obj) & SCM_CLASSF_PURE_GENERIC),
1550 obj,
1551 SCM_ARG1,
1552 FUNC_NAME);
1553 SCM_SET_GENERIC_SETTER (obj, setter);
1554 return SCM_UNSPECIFIED;
1555 }
1556 #undef FUNC_NAME
1557
1558 /******************************************************************************
1559 *
1560 * %modify-instance (used by change-class to modify in place)
1561 *
1562 ******************************************************************************/
1563
1564 SCM_DEFINE (scm_sys_modify_instance, "%modify-instance", 2, 0, 0,
1565 (SCM old, SCM new),
1566 "")
1567 #define FUNC_NAME s_scm_sys_modify_instance
1568 {
1569 SCM_VALIDATE_INSTANCE (1, old);
1570 SCM_VALIDATE_INSTANCE (2, new);
1571
1572 /* Exchange the data contained in old and new. We exchange rather than
1573 * scratch the old value with new to be correct with GC.
1574 * See "Class redefinition protocol above".
1575 */
1576 SCM_CRITICAL_SECTION_START;
1577 {
1578 scm_t_bits word0, word1;
1579 word0 = SCM_CELL_WORD_0 (old);
1580 word1 = SCM_CELL_WORD_1 (old);
1581 SCM_SET_CELL_WORD_0 (old, SCM_CELL_WORD_0 (new));
1582 SCM_SET_CELL_WORD_1 (old, SCM_CELL_WORD_1 (new));
1583 SCM_SET_CELL_WORD_0 (new, word0);
1584 SCM_SET_CELL_WORD_1 (new, word1);
1585 }
1586 SCM_CRITICAL_SECTION_END;
1587 return SCM_UNSPECIFIED;
1588 }
1589 #undef FUNC_NAME
1590
1591 SCM_DEFINE (scm_sys_modify_class, "%modify-class", 2, 0, 0,
1592 (SCM old, SCM new),
1593 "")
1594 #define FUNC_NAME s_scm_sys_modify_class
1595 {
1596 SCM_VALIDATE_CLASS (1, old);
1597 SCM_VALIDATE_CLASS (2, new);
1598
1599 SCM_CRITICAL_SECTION_START;
1600 {
1601 scm_t_bits word0, word1;
1602 word0 = SCM_CELL_WORD_0 (old);
1603 word1 = SCM_CELL_WORD_1 (old);
1604 SCM_SET_CELL_WORD_0 (old, SCM_CELL_WORD_0 (new));
1605 SCM_SET_CELL_WORD_1 (old, SCM_CELL_WORD_1 (new));
1606 SCM_STRUCT_DATA (old)[scm_vtable_index_self] = SCM_UNPACK (old);
1607 SCM_SET_CELL_WORD_0 (new, word0);
1608 SCM_SET_CELL_WORD_1 (new, word1);
1609 SCM_STRUCT_DATA (new)[scm_vtable_index_self] = SCM_UNPACK (new);
1610 }
1611 SCM_CRITICAL_SECTION_END;
1612 return SCM_UNSPECIFIED;
1613 }
1614 #undef FUNC_NAME
1615
1616 SCM_DEFINE (scm_sys_invalidate_class, "%invalidate-class", 1, 0, 0,
1617 (SCM class),
1618 "")
1619 #define FUNC_NAME s_scm_sys_invalidate_class
1620 {
1621 SCM_VALIDATE_CLASS (1, class);
1622 SCM_CLEAR_CLASS_FLAGS (class, SCM_CLASSF_GOOPS_VALID);
1623 return SCM_UNSPECIFIED;
1624 }
1625 #undef FUNC_NAME
1626
1627 /* When instances change class, they finally get a new body, but
1628 * before that, they go through purgatory in hell. Odd as it may
1629 * seem, this data structure saves us from eternal suffering in
1630 * infinite recursions.
1631 */
1632
1633 static scm_t_bits **hell;
1634 static long n_hell = 1; /* one place for the evil one himself */
1635 static long hell_size = 4;
1636 static SCM hell_mutex;
1637
1638 static long
1639 burnin (SCM o)
1640 {
1641 long i;
1642 for (i = 1; i < n_hell; ++i)
1643 if (SCM_STRUCT_DATA (o) == hell[i])
1644 return i;
1645 return 0;
1646 }
1647
1648 static void
1649 go_to_hell (void *o)
1650 {
1651 SCM obj = *(SCM*)o;
1652 scm_lock_mutex (hell_mutex);
1653 if (n_hell >= hell_size)
1654 {
1655 hell_size *= 2;
1656 hell = scm_realloc (hell, hell_size * sizeof(*hell));
1657 }
1658 hell[n_hell++] = SCM_STRUCT_DATA (obj);
1659 scm_unlock_mutex (hell_mutex);
1660 }
1661
1662 static void
1663 go_to_heaven (void *o)
1664 {
1665 SCM obj = *(SCM*)o;
1666 scm_lock_mutex (hell_mutex);
1667 hell[burnin (obj)] = hell[--n_hell];
1668 scm_unlock_mutex (hell_mutex);
1669 }
1670
1671
1672 SCM_SYMBOL (scm_sym_change_class, "change-class");
1673
1674 static SCM
1675 purgatory (SCM obj, SCM new_class)
1676 {
1677 return scm_call_2 (SCM_VARIABLE_REF (var_change_class), obj, new_class);
1678 }
1679
1680 /* This function calls the generic function change-class for all
1681 * instances which aren't currently undergoing class change.
1682 */
1683
1684 void
1685 scm_change_object_class (SCM obj, SCM old_class SCM_UNUSED, SCM new_class)
1686 {
1687 if (!burnin (obj))
1688 {
1689 scm_dynwind_begin (SCM_F_DYNWIND_REWINDABLE);
1690 scm_dynwind_rewind_handler (go_to_hell, &obj, SCM_F_WIND_EXPLICITLY);
1691 scm_dynwind_unwind_handler (go_to_heaven, &obj, SCM_F_WIND_EXPLICITLY);
1692 purgatory (obj, new_class);
1693 scm_dynwind_end ();
1694 }
1695 }
1696
1697 /******************************************************************************
1698 *
1699 * GGGG FFFFF
1700 * G F
1701 * G GG FFF
1702 * G G F
1703 * GGG E N E R I C F U N C T I O N S
1704 *
1705 * This implementation provides
1706 * - generic functions (with class specializers)
1707 * - multi-methods
1708 * - next-method
1709 * - a hard-coded MOP for standard gf, which can be overloaded for non-std gf
1710 *
1711 ******************************************************************************/
1712
1713 SCM_KEYWORD (k_name, "name");
1714
1715 SCM_GLOBAL_SYMBOL (scm_sym_args, "args");
1716
1717
1718 SCM_SYMBOL (sym_delayed_compile, "delayed-compile");
1719 static SCM
1720 make_dispatch_procedure (SCM gf)
1721 {
1722 static SCM var = SCM_BOOL_F;
1723 if (scm_is_false (var))
1724 var = scm_module_variable (scm_c_resolve_module ("oop goops dispatch"),
1725 sym_delayed_compile);
1726 return scm_call_1 (SCM_VARIABLE_REF (var), gf);
1727 }
1728
1729 static void
1730 clear_method_cache (SCM gf)
1731 {
1732 SCM_SET_GENERIC_DISPATCH_PROCEDURE (gf, make_dispatch_procedure (gf));
1733 SCM_CLEAR_GENERIC_EFFECTIVE_METHODS (gf);
1734 }
1735
1736 SCM_DEFINE (scm_sys_invalidate_method_cache_x, "%invalidate-method-cache!", 1, 0, 0,
1737 (SCM gf),
1738 "")
1739 #define FUNC_NAME s_scm_sys_invalidate_method_cache_x
1740 {
1741 SCM_ASSERT (SCM_PUREGENERICP (gf), gf, SCM_ARG1, FUNC_NAME);
1742 clear_method_cache (gf);
1743 return SCM_UNSPECIFIED;
1744 }
1745 #undef FUNC_NAME
1746
1747 SCM_DEFINE (scm_generic_capability_p, "generic-capability?", 1, 0, 0,
1748 (SCM proc),
1749 "")
1750 #define FUNC_NAME s_scm_generic_capability_p
1751 {
1752 SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
1753 proc, SCM_ARG1, FUNC_NAME);
1754 return (SCM_PRIMITIVE_GENERIC_P (proc) ? SCM_BOOL_T : SCM_BOOL_F);
1755 }
1756 #undef FUNC_NAME
1757
1758 SCM_DEFINE (scm_enable_primitive_generic_x, "enable-primitive-generic!", 0, 0, 1,
1759 (SCM subrs),
1760 "")
1761 #define FUNC_NAME s_scm_enable_primitive_generic_x
1762 {
1763 SCM_VALIDATE_REST_ARGUMENT (subrs);
1764 while (!scm_is_null (subrs))
1765 {
1766 SCM subr = SCM_CAR (subrs);
1767 SCM_ASSERT (SCM_PRIMITIVE_GENERIC_P (subr), subr, SCM_ARGn, FUNC_NAME);
1768 SCM_SET_SUBR_GENERIC (subr,
1769 scm_make (scm_list_3 (scm_class_generic,
1770 k_name,
1771 SCM_SUBR_NAME (subr))));
1772 subrs = SCM_CDR (subrs);
1773 }
1774 return SCM_UNSPECIFIED;
1775 }
1776 #undef FUNC_NAME
1777
1778 SCM_DEFINE (scm_set_primitive_generic_x, "set-primitive-generic!", 2, 0, 0,
1779 (SCM subr, SCM generic),
1780 "")
1781 #define FUNC_NAME s_scm_set_primitive_generic_x
1782 {
1783 SCM_ASSERT (SCM_PRIMITIVE_GENERIC_P (subr), subr, SCM_ARG1, FUNC_NAME);
1784 SCM_ASSERT (SCM_PUREGENERICP (generic), generic, SCM_ARG2, FUNC_NAME);
1785 SCM_SET_SUBR_GENERIC (subr, generic);
1786 return SCM_UNSPECIFIED;
1787 }
1788 #undef FUNC_NAME
1789
1790 SCM_DEFINE (scm_primitive_generic_generic, "primitive-generic-generic", 1, 0, 0,
1791 (SCM subr),
1792 "")
1793 #define FUNC_NAME s_scm_primitive_generic_generic
1794 {
1795 if (SCM_PRIMITIVE_GENERIC_P (subr))
1796 {
1797 if (!SCM_UNPACK (*SCM_SUBR_GENERIC (subr)))
1798 scm_enable_primitive_generic_x (scm_list_1 (subr));
1799 return *SCM_SUBR_GENERIC (subr);
1800 }
1801 SCM_WRONG_TYPE_ARG (SCM_ARG1, subr);
1802 }
1803 #undef FUNC_NAME
1804
1805 typedef struct t_extension {
1806 struct t_extension *next;
1807 SCM extended;
1808 SCM extension;
1809 } t_extension;
1810
1811
1812 /* Hint for `scm_gc_malloc ()' et al. when allocating `t_extension'
1813 objects. */
1814 static const char extension_gc_hint[] = "GOOPS extension";
1815
1816 static t_extension *extensions = 0;
1817
1818 void
1819 scm_c_extend_primitive_generic (SCM extended, SCM extension)
1820 {
1821 if (goops_loaded_p)
1822 {
1823 SCM gf, gext;
1824 if (!SCM_UNPACK (*SCM_SUBR_GENERIC (extended)))
1825 scm_enable_primitive_generic_x (scm_list_1 (extended));
1826 gf = *SCM_SUBR_GENERIC (extended);
1827 gext = scm_call_2 (SCM_VARIABLE_REF (scm_var_make_extended_generic),
1828 gf,
1829 SCM_SUBR_NAME (extension));
1830 SCM_SET_SUBR_GENERIC (extension, gext);
1831 }
1832 else
1833 {
1834 t_extension *e = scm_gc_malloc (sizeof (t_extension),
1835 extension_gc_hint);
1836 t_extension **loc = &extensions;
1837 /* Make sure that extensions are placed before their own
1838 * extensions in the extensions list. O(N^2) algorithm, but
1839 * extensions of primitive generics are rare.
1840 */
1841 while (*loc && !scm_is_eq (extension, (*loc)->extended))
1842 loc = &(*loc)->next;
1843 e->next = *loc;
1844 e->extended = extended;
1845 e->extension = extension;
1846 *loc = e;
1847 }
1848 }
1849
1850 static void
1851 setup_extended_primitive_generics ()
1852 {
1853 while (extensions)
1854 {
1855 t_extension *e = extensions;
1856 scm_c_extend_primitive_generic (e->extended, e->extension);
1857 extensions = e->next;
1858 }
1859 }
1860
1861 /* Dirk:FIXME:: In all of these scm_wta_dispatch_* routines it is
1862 * assumed that 'gf' is zero if uninitialized. It would be cleaner if
1863 * some valid SCM value like SCM_BOOL_F or SCM_UNDEFINED were chosen.
1864 */
1865
1866 SCM
1867 scm_wta_dispatch_0 (SCM gf, const char *subr)
1868 {
1869 if (!SCM_UNPACK (gf))
1870 scm_error_num_args_subr (subr);
1871
1872 return scm_call_0 (gf);
1873 }
1874
1875 SCM
1876 scm_wta_dispatch_1 (SCM gf, SCM a1, int pos, const char *subr)
1877 {
1878 if (!SCM_UNPACK (gf))
1879 scm_wrong_type_arg (subr, pos, a1);
1880
1881 return scm_call_1 (gf, a1);
1882 }
1883
1884 SCM
1885 scm_wta_dispatch_2 (SCM gf, SCM a1, SCM a2, int pos, const char *subr)
1886 {
1887 if (!SCM_UNPACK (gf))
1888 scm_wrong_type_arg (subr, pos, (pos == SCM_ARG1) ? a1 : a2);
1889
1890 return scm_call_2 (gf, a1, a2);
1891 }
1892
1893 SCM
1894 scm_wta_dispatch_n (SCM gf, SCM args, int pos, const char *subr)
1895 {
1896 if (!SCM_UNPACK (gf))
1897 scm_wrong_type_arg (subr, pos, scm_list_ref (args, scm_from_int (pos)));
1898
1899 return scm_apply_0 (gf, args);
1900 }
1901
1902 /******************************************************************************
1903 *
1904 * Protocol for calling a generic fumction
1905 * This protocol is roughly equivalent to (parameter are a little bit different
1906 * for efficiency reasons):
1907 *
1908 * + apply-generic (gf args)
1909 * + compute-applicable-methods (gf args ...)
1910 * + sort-applicable-methods (methods args)
1911 * + apply-methods (gf methods args)
1912 *
1913 * apply-methods calls make-next-method to build the "continuation" of a a
1914 * method. Applying a next-method will call apply-next-method which in
1915 * turn will call apply again to call effectively the following method.
1916 *
1917 ******************************************************************************/
1918
1919 static int
1920 applicablep (SCM actual, SCM formal)
1921 {
1922 /* We already know that the cpl is well formed. */
1923 return scm_is_true (scm_c_memq (formal, SCM_SLOT (actual, scm_si_cpl)));
1924 }
1925
1926 static int
1927 more_specificp (SCM m1, SCM m2, SCM const *targs)
1928 {
1929 register SCM s1, s2;
1930 register long i;
1931 /*
1932 * Note:
1933 * m1 and m2 can have != length (i.e. one can be one element longer than the
1934 * other when we have a dotted parameter list). For instance, with the call
1935 * (M 1)
1936 * with
1937 * (define-method M (a . l) ....)
1938 * (define-method M (a) ....)
1939 *
1940 * we consider that the second method is more specific.
1941 *
1942 * BTW, targs is an array of types. We don't need it's size since
1943 * we already know that m1 and m2 are applicable (no risk to go past
1944 * the end of this array).
1945 *
1946 */
1947 for (i=0, s1=SPEC_OF(m1), s2=SPEC_OF(m2); ; i++, s1=SCM_CDR(s1), s2=SCM_CDR(s2)) {
1948 if (scm_is_null(s1)) return 1;
1949 if (scm_is_null(s2)) return 0;
1950 if (!scm_is_eq (SCM_CAR(s1), SCM_CAR(s2))) {
1951 register SCM l, cs1 = SCM_CAR(s1), cs2 = SCM_CAR(s2);
1952
1953 for (l = SCM_SLOT (targs[i], scm_si_cpl); ; l = SCM_CDR(l)) {
1954 if (scm_is_eq (cs1, SCM_CAR (l)))
1955 return 1;
1956 if (scm_is_eq (cs2, SCM_CAR (l)))
1957 return 0;
1958 }
1959 return 0;/* should not occur! */
1960 }
1961 }
1962 return 0; /* should not occur! */
1963 }
1964
1965 #define BUFFSIZE 32 /* big enough for most uses */
1966
1967 static SCM
1968 scm_i_vector2list (SCM l, long len)
1969 {
1970 long j;
1971 SCM z = scm_c_make_vector (len, SCM_UNDEFINED);
1972
1973 for (j = 0; j < len; j++, l = SCM_CDR (l)) {
1974 SCM_SIMPLE_VECTOR_SET (z, j, SCM_CAR (l));
1975 }
1976 return z;
1977 }
1978
1979 static SCM
1980 sort_applicable_methods (SCM method_list, long size, SCM const *targs)
1981 {
1982 long i, j, incr;
1983 SCM *v, vector = SCM_EOL;
1984 SCM buffer[BUFFSIZE];
1985 SCM save = method_list;
1986 scm_t_array_handle handle;
1987
1988 /* For reasonably sized method_lists we can try to avoid all the
1989 * consing and reorder the list in place...
1990 * This idea is due to David McClain <Dave_McClain@msn.com>
1991 */
1992 if (size <= BUFFSIZE)
1993 {
1994 for (i = 0; i < size; i++)
1995 {
1996 buffer[i] = SCM_CAR (method_list);
1997 method_list = SCM_CDR (method_list);
1998 }
1999 v = buffer;
2000 }
2001 else
2002 {
2003 /* Too many elements in method_list to keep everything locally */
2004 vector = scm_i_vector2list (save, size);
2005 v = scm_vector_writable_elements (vector, &handle, NULL, NULL);
2006 }
2007
2008 /* Use a simple shell sort since it is generally faster than qsort on
2009 * small vectors (which is probably mostly the case when we have to
2010 * sort a list of applicable methods).
2011 */
2012 for (incr = size / 2; incr; incr /= 2)
2013 {
2014 for (i = incr; i < size; i++)
2015 {
2016 for (j = i - incr; j >= 0; j -= incr)
2017 {
2018 if (more_specificp (v[j], v[j+incr], targs))
2019 break;
2020 else
2021 {
2022 SCM tmp = v[j + incr];
2023 v[j + incr] = v[j];
2024 v[j] = tmp;
2025 }
2026 }
2027 }
2028 }
2029
2030 if (size <= BUFFSIZE)
2031 {
2032 /* We did it in locally, so restore the original list (reordered) in-place */
2033 for (i = 0, method_list = save; i < size; i++, v++)
2034 {
2035 SCM_SETCAR (method_list, *v);
2036 method_list = SCM_CDR (method_list);
2037 }
2038 return save;
2039 }
2040
2041 /* If we are here, that's that we did it the hard way... */
2042 scm_array_handle_release (&handle);
2043 return scm_vector_to_list (vector);
2044 }
2045
2046 SCM
2047 scm_compute_applicable_methods (SCM gf, SCM args, long len, int find_method_p)
2048 {
2049 register long i;
2050 long count = 0;
2051 SCM l, fl, applicable = SCM_EOL;
2052 SCM save = args;
2053 SCM buffer[BUFFSIZE];
2054 SCM const *types;
2055 SCM *p;
2056 SCM tmp = SCM_EOL;
2057 scm_t_array_handle handle;
2058
2059 /* Build the list of arguments types */
2060 if (len >= BUFFSIZE)
2061 {
2062 tmp = scm_c_make_vector (len, SCM_UNDEFINED);
2063 types = p = scm_vector_writable_elements (tmp, &handle, NULL, NULL);
2064
2065 /*
2066 note that we don't have to work to reset the generation
2067 count. TMP is a new vector anyway, and it is found
2068 conservatively.
2069 */
2070 }
2071 else
2072 types = p = buffer;
2073
2074 for ( ; !scm_is_null (args); args = SCM_CDR (args))
2075 *p++ = scm_class_of (SCM_CAR (args));
2076
2077 /* Build a list of all applicable methods */
2078 for (l = scm_generic_function_methods (gf); !scm_is_null (l); l = SCM_CDR (l))
2079 {
2080 fl = SPEC_OF (SCM_CAR (l));
2081 for (i = 0; ; i++, fl = SCM_CDR (fl))
2082 {
2083 if (SCM_INSTANCEP (fl)
2084 /* We have a dotted argument list */
2085 || (i >= len && scm_is_null (fl)))
2086 { /* both list exhausted */
2087 applicable = scm_cons (SCM_CAR (l), applicable);
2088 count += 1;
2089 break;
2090 }
2091 if (i >= len
2092 || scm_is_null (fl)
2093 || !applicablep (types[i], SCM_CAR (fl)))
2094 break;
2095 }
2096 }
2097
2098 if (len >= BUFFSIZE)
2099 scm_array_handle_release (&handle);
2100
2101 if (count == 0)
2102 {
2103 if (find_method_p)
2104 return SCM_BOOL_F;
2105 scm_call_2 (SCM_VARIABLE_REF (var_no_applicable_method), gf, save);
2106 /* if we are here, it's because no-applicable-method hasn't signaled an error */
2107 return SCM_BOOL_F;
2108 }
2109
2110 return (count == 1
2111 ? applicable
2112 : sort_applicable_methods (applicable, count, types));
2113 }
2114
2115 #if 0
2116 SCM_PROC (s_sys_compute_applicable_methods, "%compute-applicable-methods", 2, 0, 0, scm_sys_compute_applicable_methods);
2117 #endif
2118
2119 static const char s_sys_compute_applicable_methods[] = "%compute-applicable-methods";
2120
2121 SCM
2122 scm_sys_compute_applicable_methods (SCM gf, SCM args)
2123 #define FUNC_NAME s_sys_compute_applicable_methods
2124 {
2125 long n;
2126 SCM_VALIDATE_GENERIC (1, gf);
2127 n = scm_ilength (args);
2128 SCM_ASSERT (n >= 0, args, SCM_ARG2, FUNC_NAME);
2129 return scm_compute_applicable_methods (gf, args, n, 1);
2130 }
2131 #undef FUNC_NAME
2132
2133 SCM_SYMBOL (sym_compute_applicable_methods, "compute-applicable-methods");
2134 SCM_VARIABLE_INIT (var_compute_applicable_methods, "compute-applicable-methods",
2135 scm_c_define_gsubr (s_sys_compute_applicable_methods, 2, 0, 0,
2136 scm_sys_compute_applicable_methods));
2137
2138 /******************************************************************************
2139 *
2140 * A simple make (which will be redefined later in Scheme)
2141 * This version handles only creation of gf, methods and classes (no instances)
2142 *
2143 * Since this code will disappear when Goops will be fully booted,
2144 * no precaution is taken to be efficient.
2145 *
2146 ******************************************************************************/
2147
2148 SCM_KEYWORD (k_setter, "setter");
2149 SCM_KEYWORD (k_specializers, "specializers");
2150 SCM_KEYWORD (k_procedure, "procedure");
2151 SCM_KEYWORD (k_formals, "formals");
2152 SCM_KEYWORD (k_body, "body");
2153 SCM_KEYWORD (k_make_procedure, "make-procedure");
2154 SCM_KEYWORD (k_dsupers, "dsupers");
2155 SCM_KEYWORD (k_slots, "slots");
2156 SCM_KEYWORD (k_gf, "generic-function");
2157
2158 SCM_DEFINE (scm_make, "make", 0, 0, 1,
2159 (SCM args),
2160 "Make a new object. @var{args} must contain the class and\n"
2161 "all necessary initialization information.")
2162 #define FUNC_NAME s_scm_make
2163 {
2164 SCM class, z;
2165 long len = scm_ilength (args);
2166
2167 if (len <= 0 || (len & 1) == 0)
2168 SCM_WRONG_NUM_ARGS ();
2169
2170 class = SCM_CAR(args);
2171 args = SCM_CDR(args);
2172
2173 if (scm_is_eq (class, scm_class_generic)
2174 || scm_is_eq (class, scm_class_accessor))
2175 {
2176 z = scm_make_struct (class, SCM_INUM0,
2177 scm_list_4 (SCM_BOOL_F,
2178 SCM_EOL,
2179 SCM_INUM0,
2180 SCM_EOL));
2181 scm_set_procedure_property_x (z, scm_sym_name,
2182 scm_get_keyword (k_name,
2183 args,
2184 SCM_BOOL_F));
2185 clear_method_cache (z);
2186 if (scm_is_eq (class, scm_class_accessor))
2187 {
2188 SCM setter = scm_get_keyword (k_setter, args, SCM_BOOL_F);
2189 if (scm_is_true (setter))
2190 scm_sys_set_object_setter_x (z, setter);
2191 }
2192 }
2193 else
2194 {
2195 z = scm_sys_allocate_instance (class, args);
2196
2197 if (scm_is_eq (class, scm_class_method)
2198 || scm_is_eq (class, scm_class_accessor_method))
2199 {
2200 SCM_SET_SLOT (z, scm_si_generic_function,
2201 scm_i_get_keyword (k_gf,
2202 args,
2203 len - 1,
2204 SCM_BOOL_F,
2205 FUNC_NAME));
2206 SCM_SET_SLOT (z, scm_si_specializers,
2207 scm_i_get_keyword (k_specializers,
2208 args,
2209 len - 1,
2210 SCM_EOL,
2211 FUNC_NAME));
2212 SCM_SET_SLOT (z, scm_si_procedure,
2213 scm_i_get_keyword (k_procedure,
2214 args,
2215 len - 1,
2216 SCM_BOOL_F,
2217 FUNC_NAME));
2218 SCM_SET_SLOT (z, scm_si_formals,
2219 scm_i_get_keyword (k_formals,
2220 args,
2221 len - 1,
2222 SCM_EOL,
2223 FUNC_NAME));
2224 SCM_SET_SLOT (z, scm_si_body,
2225 scm_i_get_keyword (k_body,
2226 args,
2227 len - 1,
2228 SCM_EOL,
2229 FUNC_NAME));
2230 SCM_SET_SLOT (z, scm_si_make_procedure,
2231 scm_i_get_keyword (k_make_procedure,
2232 args,
2233 len - 1,
2234 SCM_BOOL_F,
2235 FUNC_NAME));
2236 }
2237 else
2238 {
2239 /* In all the others case, make a new class .... No instance here */
2240 SCM_SET_SLOT (z, scm_vtable_index_name,
2241 scm_i_get_keyword (k_name,
2242 args,
2243 len - 1,
2244 scm_from_latin1_symbol ("???"),
2245 FUNC_NAME));
2246 SCM_SET_SLOT (z, scm_si_direct_supers,
2247 scm_i_get_keyword (k_dsupers,
2248 args,
2249 len - 1,
2250 SCM_EOL,
2251 FUNC_NAME));
2252 SCM_SET_SLOT (z, scm_si_direct_slots,
2253 scm_i_get_keyword (k_slots,
2254 args,
2255 len - 1,
2256 SCM_EOL,
2257 FUNC_NAME));
2258 }
2259 }
2260 return z;
2261 }
2262 #undef FUNC_NAME
2263
2264 SCM_DEFINE (scm_find_method, "find-method", 0, 0, 1,
2265 (SCM l),
2266 "")
2267 #define FUNC_NAME s_scm_find_method
2268 {
2269 SCM gf;
2270 long len = scm_ilength (l);
2271
2272 if (len == 0)
2273 SCM_WRONG_NUM_ARGS ();
2274
2275 gf = SCM_CAR(l); l = SCM_CDR(l);
2276 SCM_VALIDATE_GENERIC (1, gf);
2277 if (scm_is_null (SCM_SLOT (gf, scm_si_methods)))
2278 SCM_MISC_ERROR ("no methods for generic ~S", scm_list_1 (gf));
2279
2280 return scm_compute_applicable_methods (gf, l, len - 1, 1);
2281 }
2282 #undef FUNC_NAME
2283
2284 SCM_DEFINE (scm_sys_method_more_specific_p, "%method-more-specific?", 3, 0, 0,
2285 (SCM m1, SCM m2, SCM targs),
2286 "Return true if method @var{m1} is more specific than @var{m2} "
2287 "given the argument types (classes) listed in @var{targs}.")
2288 #define FUNC_NAME s_scm_sys_method_more_specific_p
2289 {
2290 SCM l, v, result;
2291 SCM *v_elts;
2292 long i, len, m1_specs, m2_specs;
2293 scm_t_array_handle handle;
2294
2295 SCM_VALIDATE_METHOD (1, m1);
2296 SCM_VALIDATE_METHOD (2, m2);
2297
2298 len = scm_ilength (targs);
2299 m1_specs = scm_ilength (SPEC_OF (m1));
2300 m2_specs = scm_ilength (SPEC_OF (m2));
2301 SCM_ASSERT ((len >= m1_specs) || (len >= m2_specs),
2302 targs, SCM_ARG3, FUNC_NAME);
2303
2304 /* Verify that all the arguments of TARGS are classes and place them
2305 in a vector. */
2306
2307 v = scm_c_make_vector (len, SCM_EOL);
2308 v_elts = scm_vector_writable_elements (v, &handle, NULL, NULL);
2309
2310 for (i = 0, l = targs;
2311 i < len && scm_is_pair (l);
2312 i++, l = SCM_CDR (l))
2313 {
2314 SCM_ASSERT (SCM_CLASSP (SCM_CAR (l)), targs, SCM_ARG3, FUNC_NAME);
2315 v_elts[i] = SCM_CAR (l);
2316 }
2317 result = more_specificp (m1, m2, v_elts) ? SCM_BOOL_T: SCM_BOOL_F;
2318
2319 scm_array_handle_release (&handle);
2320
2321 return result;
2322 }
2323 #undef FUNC_NAME
2324
2325
2326
2327 /******************************************************************************
2328 *
2329 * Initializations
2330 *
2331 ******************************************************************************/
2332
2333 /* Munge the CPL of C in place such that BEFORE appears before AFTER,
2334 assuming that currently the reverse is true. Recalculate slots and
2335 associated getters-n-setters. */
2336 static void
2337 fix_cpl (SCM c, SCM before, SCM after)
2338 {
2339 SCM cpl = SCM_SLOT (c, scm_si_cpl);
2340 SCM ls = scm_c_memq (after, cpl);
2341 SCM tail;
2342
2343 if (scm_is_false (ls))
2344 /* if this condition occurs, fix_cpl should not be applied this way */
2345 abort ();
2346
2347 tail = scm_delq1_x (before, SCM_CDR (ls));
2348 SCM_SETCAR (ls, before);
2349 SCM_SETCDR (ls, scm_cons (after, tail));
2350 {
2351 SCM dslots = SCM_SLOT (c, scm_si_direct_slots);
2352 SCM slots = build_slots_list (maplist (dslots), cpl);
2353 SCM g_n_s = compute_getters_n_setters (slots);
2354 SCM_SET_SLOT (c, scm_si_slots, slots);
2355 SCM_SET_SLOT (c, scm_si_getters_n_setters, g_n_s);
2356 }
2357 }
2358
2359
2360 static void
2361 make_stdcls (SCM *var, char *name, SCM meta, SCM super, SCM slots)
2362 {
2363 SCM tmp = scm_from_utf8_symbol (name);
2364
2365 *var = scm_basic_make_class (meta, tmp,
2366 scm_is_pair (super) ? super : scm_list_1 (super),
2367 slots);
2368 scm_module_define (scm_module_goops, tmp, *var);
2369 }
2370
2371
2372 SCM_KEYWORD (k_slot_definition, "slot-definition");
2373
2374 static void
2375 create_standard_classes (void)
2376 {
2377 SCM slots;
2378 SCM method_slots = scm_list_n (scm_from_latin1_symbol ("generic-function"),
2379 scm_from_latin1_symbol ("specializers"),
2380 sym_procedure,
2381 scm_from_latin1_symbol ("formals"),
2382 scm_from_latin1_symbol ("body"),
2383 scm_from_latin1_symbol ("make-procedure"),
2384 SCM_UNDEFINED);
2385 SCM amethod_slots = scm_list_1 (scm_list_3 (scm_from_latin1_symbol ("slot-definition"),
2386 k_init_keyword,
2387 k_slot_definition));
2388 SCM gf_slots = scm_list_4 (scm_from_latin1_symbol ("methods"),
2389 scm_list_3 (scm_from_latin1_symbol ("n-specialized"),
2390 k_init_value,
2391 SCM_INUM0),
2392 scm_list_3 (scm_from_latin1_symbol ("extended-by"),
2393 k_init_value,
2394 SCM_EOL),
2395 scm_from_latin1_symbol ("effective-methods"));
2396 SCM setter_slots = scm_list_1 (sym_setter);
2397 SCM egf_slots = scm_list_1 (scm_list_3 (scm_from_latin1_symbol ("extends"),
2398 k_init_value,
2399 SCM_EOL));
2400 /* Foreign class slot classes */
2401 make_stdcls (&scm_class_foreign_slot, "<foreign-slot>",
2402 scm_class_class, scm_class_top, SCM_EOL);
2403 make_stdcls (&scm_class_protected, "<protected-slot>",
2404 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2405 make_stdcls (&scm_class_hidden, "<hidden-slot>",
2406 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2407 make_stdcls (&scm_class_opaque, "<opaque-slot>",
2408 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2409 make_stdcls (&scm_class_read_only, "<read-only-slot>",
2410 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2411 make_stdcls (&scm_class_self, "<self-slot>",
2412 scm_class_class, scm_class_read_only, SCM_EOL);
2413 make_stdcls (&scm_class_protected_opaque, "<protected-opaque-slot>",
2414 scm_class_class,
2415 scm_list_2 (scm_class_protected, scm_class_opaque),
2416 SCM_EOL);
2417 make_stdcls (&scm_class_protected_hidden, "<protected-hidden-slot>",
2418 scm_class_class,
2419 scm_list_2 (scm_class_protected, scm_class_hidden),
2420 SCM_EOL);
2421 make_stdcls (&scm_class_protected_read_only, "<protected-read-only-slot>",
2422 scm_class_class,
2423 scm_list_2 (scm_class_protected, scm_class_read_only),
2424 SCM_EOL);
2425 make_stdcls (&scm_class_scm, "<scm-slot>",
2426 scm_class_class, scm_class_protected, SCM_EOL);
2427 make_stdcls (&scm_class_int, "<int-slot>",
2428 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2429 make_stdcls (&scm_class_float, "<float-slot>",
2430 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2431 make_stdcls (&scm_class_double, "<double-slot>",
2432 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2433
2434 /* Continue initialization of class <class> */
2435
2436 slots = build_class_class_slots ();
2437 SCM_SET_SLOT (scm_class_class, scm_si_direct_slots, slots);
2438 SCM_SET_SLOT (scm_class_class, scm_si_slots, slots);
2439 SCM_SET_SLOT (scm_class_class, scm_si_getters_n_setters,
2440 compute_getters_n_setters (slots));
2441
2442 /* scm_class_generic functions classes */
2443 make_stdcls (&scm_class_procedure_class, "<procedure-class>",
2444 scm_class_class, scm_class_class, SCM_EOL);
2445 make_stdcls (&scm_class_applicable_struct_class, "<applicable-struct-class>",
2446 scm_class_class, scm_class_procedure_class, SCM_EOL);
2447 SCM_SET_VTABLE_FLAGS (scm_class_applicable_struct_class, SCM_VTABLE_FLAG_APPLICABLE_VTABLE);
2448 make_stdcls (&scm_class_method, "<method>",
2449 scm_class_class, scm_class_object, method_slots);
2450 make_stdcls (&scm_class_accessor_method, "<accessor-method>",
2451 scm_class_class, scm_class_method, amethod_slots);
2452 make_stdcls (&scm_class_applicable, "<applicable>",
2453 scm_class_class, scm_class_top, SCM_EOL);
2454 make_stdcls (&scm_class_applicable_struct, "<applicable-struct>",
2455 scm_class_applicable_struct_class,
2456 scm_list_2 (scm_class_object, scm_class_applicable),
2457 scm_list_1 (sym_procedure));
2458 make_stdcls (&scm_class_generic, "<generic>",
2459 scm_class_applicable_struct_class, scm_class_applicable_struct, gf_slots);
2460 SCM_SET_CLASS_FLAGS (scm_class_generic, SCM_CLASSF_PURE_GENERIC);
2461 make_stdcls (&scm_class_extended_generic, "<extended-generic>",
2462 scm_class_applicable_struct_class, scm_class_generic, egf_slots);
2463 SCM_SET_CLASS_FLAGS (scm_class_extended_generic, SCM_CLASSF_PURE_GENERIC);
2464 make_stdcls (&scm_class_generic_with_setter, "<generic-with-setter>",
2465 scm_class_applicable_struct_class, scm_class_generic, setter_slots);
2466 SCM_SET_CLASS_FLAGS (scm_class_generic_with_setter, SCM_CLASSF_PURE_GENERIC);
2467 make_stdcls (&scm_class_accessor, "<accessor>",
2468 scm_class_applicable_struct_class, scm_class_generic_with_setter, SCM_EOL);
2469 SCM_SET_CLASS_FLAGS (scm_class_accessor, SCM_CLASSF_PURE_GENERIC);
2470 make_stdcls (&scm_class_extended_generic_with_setter,
2471 "<extended-generic-with-setter>",
2472 scm_class_applicable_struct_class,
2473 scm_list_2 (scm_class_extended_generic,
2474 scm_class_generic_with_setter),
2475 SCM_EOL);
2476 SCM_SET_CLASS_FLAGS (scm_class_extended_generic_with_setter,
2477 SCM_CLASSF_PURE_GENERIC);
2478 make_stdcls (&scm_class_extended_accessor, "<extended-accessor>",
2479 scm_class_applicable_struct_class,
2480 scm_list_2 (scm_class_accessor,
2481 scm_class_extended_generic_with_setter),
2482 SCM_EOL);
2483 /* <extended-generic> is misplaced. */
2484 fix_cpl (scm_class_extended_accessor,
2485 scm_class_extended_generic, scm_class_generic_with_setter);
2486 SCM_SET_CLASS_FLAGS (scm_class_extended_accessor, SCM_CLASSF_PURE_GENERIC);
2487
2488 /* Primitive types classes */
2489 make_stdcls (&scm_class_boolean, "<boolean>",
2490 scm_class_class, scm_class_top, SCM_EOL);
2491 make_stdcls (&scm_class_char, "<char>",
2492 scm_class_class, scm_class_top, SCM_EOL);
2493 make_stdcls (&scm_class_list, "<list>",
2494 scm_class_class, scm_class_top, SCM_EOL);
2495 make_stdcls (&scm_class_pair, "<pair>",
2496 scm_class_class, scm_class_list, SCM_EOL);
2497 make_stdcls (&scm_class_null, "<null>",
2498 scm_class_class, scm_class_list, SCM_EOL);
2499 make_stdcls (&scm_class_string, "<string>",
2500 scm_class_class, scm_class_top, SCM_EOL);
2501 make_stdcls (&scm_class_symbol, "<symbol>",
2502 scm_class_class, scm_class_top, SCM_EOL);
2503 make_stdcls (&scm_class_vector, "<vector>",
2504 scm_class_class, scm_class_top, SCM_EOL);
2505 make_stdcls (&class_foreign, "<foreign>",
2506 scm_class_class, scm_class_top, SCM_EOL);
2507 make_stdcls (&class_hashtable, "<hashtable>",
2508 scm_class_class, scm_class_top, SCM_EOL);
2509 make_stdcls (&class_fluid, "<fluid>",
2510 scm_class_class, scm_class_top, SCM_EOL);
2511 make_stdcls (&class_dynamic_state, "<dynamic-state>",
2512 scm_class_class, scm_class_top, SCM_EOL);
2513 make_stdcls (&class_frame, "<frame>",
2514 scm_class_class, scm_class_top, SCM_EOL);
2515 make_stdcls (&class_vm, "<vm>",
2516 scm_class_class, scm_class_top, SCM_EOL);
2517 make_stdcls (&class_vm_cont, "<vm-continuation>",
2518 scm_class_class, scm_class_top, SCM_EOL);
2519 make_stdcls (&class_bytevector, "<bytevector>",
2520 scm_class_class, scm_class_top, SCM_EOL);
2521 make_stdcls (&class_uvec, "<uvec>",
2522 scm_class_class, class_bytevector, SCM_EOL);
2523 make_stdcls (&class_array, "<array>",
2524 scm_class_class, scm_class_top, SCM_EOL);
2525 make_stdcls (&class_bitvector, "<bitvector>",
2526 scm_class_class, scm_class_top, SCM_EOL);
2527 make_stdcls (&scm_class_number, "<number>",
2528 scm_class_class, scm_class_top, SCM_EOL);
2529 make_stdcls (&scm_class_complex, "<complex>",
2530 scm_class_class, scm_class_number, SCM_EOL);
2531 make_stdcls (&scm_class_real, "<real>",
2532 scm_class_class, scm_class_complex, SCM_EOL);
2533 make_stdcls (&scm_class_integer, "<integer>",
2534 scm_class_class, scm_class_real, SCM_EOL);
2535 make_stdcls (&scm_class_fraction, "<fraction>",
2536 scm_class_class, scm_class_real, SCM_EOL);
2537 make_stdcls (&scm_class_keyword, "<keyword>",
2538 scm_class_class, scm_class_top, SCM_EOL);
2539 make_stdcls (&scm_class_unknown, "<unknown>",
2540 scm_class_class, scm_class_top, SCM_EOL);
2541 make_stdcls (&scm_class_procedure, "<procedure>",
2542 scm_class_procedure_class, scm_class_applicable, SCM_EOL);
2543 make_stdcls (&scm_class_primitive_generic, "<primitive-generic>",
2544 scm_class_procedure_class, scm_class_procedure, SCM_EOL);
2545 make_stdcls (&scm_class_port, "<port>",
2546 scm_class_class, scm_class_top, SCM_EOL);
2547 make_stdcls (&scm_class_input_port, "<input-port>",
2548 scm_class_class, scm_class_port, SCM_EOL);
2549 make_stdcls (&scm_class_output_port, "<output-port>",
2550 scm_class_class, scm_class_port, SCM_EOL);
2551 make_stdcls (&scm_class_input_output_port, "<input-output-port>",
2552 scm_class_class,
2553 scm_list_2 (scm_class_input_port, scm_class_output_port),
2554 SCM_EOL);
2555 }
2556
2557 /**********************************************************************
2558 *
2559 * Smob classes
2560 *
2561 **********************************************************************/
2562
2563 static SCM
2564 make_class_from_template (char const *template, char const *type_name, SCM supers, int applicablep)
2565 {
2566 SCM name;
2567 if (type_name)
2568 {
2569 char buffer[100];
2570 sprintf (buffer, template, type_name);
2571 name = scm_from_utf8_symbol (buffer);
2572 }
2573 else
2574 name = SCM_GOOPS_UNBOUND;
2575
2576 return scm_basic_make_class (applicablep ? scm_class_procedure_class : scm_class_class,
2577 name, supers, SCM_EOL);
2578 }
2579
2580 static SCM
2581 make_class_from_symbol (SCM type_name_sym, SCM supers, int applicablep)
2582 {
2583 SCM name;
2584
2585 if (scm_is_true (type_name_sym))
2586 {
2587 name = scm_string_append (scm_list_3 (scm_from_locale_string ("<"),
2588 scm_symbol_to_string (type_name_sym),
2589 scm_from_locale_string (">")));
2590 name = scm_string_to_symbol (name);
2591 }
2592 else
2593 name = SCM_GOOPS_UNBOUND;
2594
2595 return scm_basic_make_class (applicablep ? scm_class_procedure_class : scm_class_class,
2596 name, supers, SCM_EOL);
2597 }
2598
2599 SCM
2600 scm_make_extended_class (char const *type_name, int applicablep)
2601 {
2602 return make_class_from_template ("<%s>",
2603 type_name,
2604 scm_list_1 (applicablep
2605 ? scm_class_applicable
2606 : scm_class_top),
2607 applicablep);
2608 }
2609
2610 static SCM
2611 scm_make_extended_class_from_symbol (SCM type_name_sym, int applicablep)
2612 {
2613 return make_class_from_symbol (type_name_sym,
2614 scm_list_1 (applicablep
2615 ? scm_class_applicable
2616 : scm_class_top),
2617 applicablep);
2618 }
2619
2620 void
2621 scm_i_inherit_applicable (SCM c)
2622 {
2623 if (!SCM_SUBCLASSP (c, scm_class_applicable))
2624 {
2625 SCM dsupers = SCM_SLOT (c, scm_si_direct_supers);
2626 SCM cpl = SCM_SLOT (c, scm_si_cpl);
2627 /* patch scm_class_applicable into direct-supers */
2628 SCM top = scm_c_memq (scm_class_top, dsupers);
2629 if (scm_is_false (top))
2630 dsupers = scm_append (scm_list_2 (dsupers,
2631 scm_list_1 (scm_class_applicable)));
2632 else
2633 {
2634 SCM_SETCAR (top, scm_class_applicable);
2635 SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
2636 }
2637 SCM_SET_SLOT (c, scm_si_direct_supers, dsupers);
2638 /* patch scm_class_applicable into cpl */
2639 top = scm_c_memq (scm_class_top, cpl);
2640 if (scm_is_false (top))
2641 abort ();
2642 else
2643 {
2644 SCM_SETCAR (top, scm_class_applicable);
2645 SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
2646 }
2647 /* add class to direct-subclasses of scm_class_applicable */
2648 SCM_SET_SLOT (scm_class_applicable,
2649 scm_si_direct_subclasses,
2650 scm_cons (c, SCM_SLOT (scm_class_applicable,
2651 scm_si_direct_subclasses)));
2652 }
2653 }
2654
2655 static void
2656 create_smob_classes (void)
2657 {
2658 long i;
2659
2660 for (i = 0; i < SCM_I_MAX_SMOB_TYPE_COUNT; ++i)
2661 scm_smob_class[i] = SCM_BOOL_F;
2662
2663 scm_smob_class[SCM_TC2SMOBNUM (scm_tc16_keyword)] = scm_class_keyword;
2664
2665 for (i = 0; i < scm_numsmob; ++i)
2666 if (scm_is_false (scm_smob_class[i]))
2667 scm_smob_class[i] = scm_make_extended_class (SCM_SMOBNAME (i),
2668 scm_smobs[i].apply != 0);
2669 }
2670
2671 void
2672 scm_make_port_classes (long ptobnum, char *type_name)
2673 {
2674 SCM c, class = make_class_from_template ("<%s-port>",
2675 type_name,
2676 scm_list_1 (scm_class_port),
2677 0);
2678 scm_port_class[SCM_IN_PCLASS_INDEX + ptobnum]
2679 = make_class_from_template ("<%s-input-port>",
2680 type_name,
2681 scm_list_2 (class, scm_class_input_port),
2682 0);
2683 scm_port_class[SCM_OUT_PCLASS_INDEX + ptobnum]
2684 = make_class_from_template ("<%s-output-port>",
2685 type_name,
2686 scm_list_2 (class, scm_class_output_port),
2687 0);
2688 scm_port_class[SCM_INOUT_PCLASS_INDEX + ptobnum]
2689 = c
2690 = make_class_from_template ("<%s-input-output-port>",
2691 type_name,
2692 scm_list_2 (class, scm_class_input_output_port),
2693 0);
2694 /* Patch cpl (since this tree is too complex for the C level compute-cpl) */
2695 SCM_SET_SLOT (c, scm_si_cpl,
2696 scm_cons2 (c, class, SCM_SLOT (scm_class_input_output_port, scm_si_cpl)));
2697 }
2698
2699 static void
2700 create_port_classes (void)
2701 {
2702 long i;
2703
2704 for (i = scm_c_num_port_types () - 1; i >= 0; i--)
2705 scm_make_port_classes (i, SCM_PTOBNAME (i));
2706 }
2707
2708 static SCM
2709 make_struct_class (void *closure SCM_UNUSED,
2710 SCM vtable, SCM data, SCM prev SCM_UNUSED)
2711 {
2712 if (scm_is_false (data))
2713 scm_i_define_class_for_vtable (vtable);
2714 return SCM_UNSPECIFIED;
2715 }
2716
2717 static void
2718 create_struct_classes (void)
2719 {
2720 /* FIXME: take the vtable_class_map while initializing goops? */
2721 scm_internal_hash_fold (make_struct_class, 0, SCM_BOOL_F,
2722 vtable_class_map);
2723 }
2724
2725 /**********************************************************************
2726 *
2727 * C interface
2728 *
2729 **********************************************************************/
2730
2731 void
2732 scm_load_goops ()
2733 {
2734 if (!goops_loaded_p)
2735 scm_c_resolve_module ("oop goops");
2736 }
2737
2738
2739 SCM_SYMBOL (sym_o, "o");
2740 SCM_SYMBOL (sym_x, "x");
2741
2742 SCM_KEYWORD (k_accessor, "accessor");
2743 SCM_KEYWORD (k_getter, "getter");
2744
2745 SCM
2746 scm_ensure_accessor (SCM name)
2747 {
2748 SCM var, gf;
2749
2750 var = scm_module_variable (scm_current_module (), name);
2751 if (SCM_VARIABLEP (var) && !SCM_UNBNDP (SCM_VARIABLE_REF (var)))
2752 gf = SCM_VARIABLE_REF (var);
2753 else
2754 gf = SCM_BOOL_F;
2755
2756 if (!SCM_IS_A_P (gf, scm_class_accessor))
2757 {
2758 gf = scm_make (scm_list_3 (scm_class_generic, k_name, name));
2759 gf = scm_make (scm_list_5 (scm_class_accessor,
2760 k_name, name, k_setter, gf));
2761 }
2762
2763 return gf;
2764 }
2765
2766 #ifdef GUILE_DEBUG
2767 /*
2768 * Debugging utilities
2769 */
2770
2771 SCM_DEFINE (scm_pure_generic_p, "pure-generic?", 1, 0, 0,
2772 (SCM obj),
2773 "Return @code{#t} if @var{obj} is a pure generic.")
2774 #define FUNC_NAME s_scm_pure_generic_p
2775 {
2776 return scm_from_bool (SCM_PUREGENERICP (obj));
2777 }
2778 #undef FUNC_NAME
2779
2780 #endif /* GUILE_DEBUG */
2781
2782 /*
2783 * Initialization
2784 */
2785
2786 SCM_DEFINE (scm_sys_goops_loaded, "%goops-loaded", 0, 0, 0,
2787 (),
2788 "Announce that GOOPS is loaded and perform initialization\n"
2789 "on the C level which depends on the loaded GOOPS modules.")
2790 #define FUNC_NAME s_scm_sys_goops_loaded
2791 {
2792 goops_loaded_p = 1;
2793 var_compute_applicable_methods =
2794 scm_module_variable (scm_module_goops, sym_compute_applicable_methods);
2795 var_slot_unbound =
2796 scm_module_variable (scm_module_goops, sym_slot_unbound);
2797 var_slot_missing =
2798 scm_module_variable (scm_module_goops, sym_slot_missing);
2799 var_compute_cpl =
2800 scm_module_variable (scm_module_goops, sym_compute_cpl);
2801 var_no_applicable_method =
2802 scm_module_variable (scm_module_goops, sym_no_applicable_method);
2803 var_change_class =
2804 scm_module_variable (scm_module_goops, sym_change_class);
2805 setup_extended_primitive_generics ();
2806 return SCM_UNSPECIFIED;
2807 }
2808 #undef FUNC_NAME
2809
2810 SCM scm_module_goops;
2811
2812 SCM
2813 scm_init_goops_builtins (void)
2814 {
2815 scm_module_goops = scm_current_module ();
2816
2817 goops_rstate = scm_c_make_rstate ("GOOPS", 5);
2818
2819 #include "libguile/goops.x"
2820
2821 hell = scm_calloc (hell_size * sizeof (*hell));
2822 hell_mutex = scm_make_mutex ();
2823
2824 create_basic_classes ();
2825 create_standard_classes ();
2826 create_smob_classes ();
2827 create_struct_classes ();
2828 create_port_classes ();
2829
2830 {
2831 SCM name = scm_from_latin1_symbol ("no-applicable-method");
2832 scm_no_applicable_method =
2833 scm_make (scm_list_3 (scm_class_generic, k_name, name));
2834 scm_module_define (scm_module_goops, name, scm_no_applicable_method);
2835 }
2836
2837 return SCM_UNSPECIFIED;
2838 }
2839
2840 void
2841 scm_init_goops ()
2842 {
2843 scm_c_define_gsubr ("%init-goops-builtins", 0, 0, 0,
2844 scm_init_goops_builtins);
2845 }
2846
2847 /*
2848 Local Variables:
2849 c-file-style: "gnu"
2850 End:
2851 */