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