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