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