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