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