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