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