%invalidate-method-cache invalidates the dispatch procedure too
[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
e29db33c
AW
1902SCM_SYMBOL (sym_delayed_compile, "delayed-compile");
1903static SCM
1904make_dispatch_procedure (SCM gf)
1905{
1906 static SCM var = SCM_BOOL_F;
1907 if (var == SCM_BOOL_F)
1908 var = scm_module_variable (scm_c_resolve_module ("oop goops dispatch"),
1909 sym_delayed_compile);
1910 return scm_call_1 (SCM_VARIABLE_REF (var), gf);
1911}
1912
80662eda
MD
1913static void
1914clear_method_cache (SCM gf)
1915{
322ec19d 1916 SCM cache = scm_make_method_cache (gf);
521ac49b 1917 SCM_SET_GENERIC_METHOD_CACHE (gf, cache);
e29db33c 1918 SCM_SET_GENERIC_DISPATCH_PROCEDURE (gf, make_dispatch_procedure (gf));
a9a90a88 1919 SCM_CLEAR_GENERIC_EFFECTIVE_METHODS (gf);
80662eda
MD
1920}
1921
398d8ee1
KN
1922SCM_DEFINE (scm_sys_invalidate_method_cache_x, "%invalidate-method-cache!", 1, 0, 0,
1923 (SCM gf),
1924 "")
1925#define FUNC_NAME s_scm_sys_invalidate_method_cache_x
80662eda 1926{
25ba37df 1927 SCM_ASSERT (SCM_PUREGENERICP (gf), gf, SCM_ARG1, FUNC_NAME);
6d33e90f 1928 clear_method_cache (gf);
c40944c9
AW
1929 /* The sign of n-specialized is a flag indicating rest args. */
1930 SCM_SET_MCACHE_N_SPECIALIZED (SCM_GENERIC_METHOD_CACHE (gf),
1931 SCM_SLOT (gf, scm_si_n_specialized));
80662eda
MD
1932 return SCM_UNSPECIFIED;
1933}
398d8ee1 1934#undef FUNC_NAME
80662eda 1935
398d8ee1
KN
1936SCM_DEFINE (scm_generic_capability_p, "generic-capability?", 1, 0, 0,
1937 (SCM proc),
1938 "")
1939#define FUNC_NAME s_scm_generic_capability_p
80662eda 1940{
7888309b 1941 SCM_ASSERT (scm_is_true (scm_procedure_p (proc)),
398d8ee1 1942 proc, SCM_ARG1, FUNC_NAME);
80662eda
MD
1943 return (scm_subr_p (proc) && SCM_SUBR_GENERIC (proc)
1944 ? SCM_BOOL_T
1945 : SCM_BOOL_F);
1946}
398d8ee1 1947#undef FUNC_NAME
80662eda 1948
398d8ee1
KN
1949SCM_DEFINE (scm_enable_primitive_generic_x, "enable-primitive-generic!", 0, 0, 1,
1950 (SCM subrs),
1951 "")
1952#define FUNC_NAME s_scm_enable_primitive_generic_x
80662eda 1953{
6b80d352 1954 SCM_VALIDATE_REST_ARGUMENT (subrs);
d2e53ed6 1955 while (!scm_is_null (subrs))
80662eda
MD
1956 {
1957 SCM subr = SCM_CAR (subrs);
1958 SCM_ASSERT (scm_subr_p (subr) && SCM_SUBR_GENERIC (subr),
398d8ee1 1959 subr, SCM_ARGn, FUNC_NAME);
80662eda 1960 *SCM_SUBR_GENERIC (subr)
1afff620
KN
1961 = scm_make (scm_list_3 (scm_class_generic,
1962 k_name,
ce471ab8 1963 SCM_SUBR_NAME (subr)));
80662eda
MD
1964 subrs = SCM_CDR (subrs);
1965 }
1966 return SCM_UNSPECIFIED;
1967}
398d8ee1 1968#undef FUNC_NAME
80662eda 1969
398d8ee1
KN
1970SCM_DEFINE (scm_primitive_generic_generic, "primitive-generic-generic", 1, 0, 0,
1971 (SCM subr),
1972 "")
1973#define FUNC_NAME s_scm_primitive_generic_generic
80662eda
MD
1974{
1975 if (scm_subr_p (subr) && SCM_SUBR_GENERIC (subr))
1976 {
a48d60b1
MD
1977 if (!*SCM_SUBR_GENERIC (subr))
1978 scm_enable_primitive_generic_x (scm_list_1 (subr));
1979 return *SCM_SUBR_GENERIC (subr);
80662eda 1980 }
db4b4ca6 1981 SCM_WRONG_TYPE_ARG (SCM_ARG1, subr);
80662eda 1982}
398d8ee1 1983#undef FUNC_NAME
80662eda 1984
a48d60b1
MD
1985typedef struct t_extension {
1986 struct t_extension *next;
1987 SCM extended;
1988 SCM extension;
1989} t_extension;
1990
d0cad249
LC
1991
1992/* Hint for `scm_gc_malloc ()' et al. when allocating `t_extension'
1993 objects. */
1994static const char extension_gc_hint[] = "GOOPS extension";
1995
a48d60b1
MD
1996static t_extension *extensions = 0;
1997
1998SCM_VARIABLE (scm_var_make_extended_generic, "make-extended-generic");
1999
2000void
2001scm_c_extend_primitive_generic (SCM extended, SCM extension)
2002{
2003 if (goops_loaded_p)
2004 {
2005 SCM gf, gext;
2006 if (!*SCM_SUBR_GENERIC (extended))
2007 scm_enable_primitive_generic_x (scm_list_1 (extended));
2008 gf = *SCM_SUBR_GENERIC (extended);
2009 gext = scm_call_2 (SCM_VARIABLE_REF (scm_var_make_extended_generic),
2010 gf,
ce471ab8 2011 SCM_SUBR_NAME (extension));
feccd2d3 2012 SCM_SET_SUBR_GENERIC (extension, gext);
a48d60b1
MD
2013 }
2014 else
2015 {
d0cad249
LC
2016 t_extension *e = scm_gc_malloc (sizeof (t_extension),
2017 extension_gc_hint);
a48d60b1
MD
2018 t_extension **loc = &extensions;
2019 /* Make sure that extensions are placed before their own
2020 * extensions in the extensions list. O(N^2) algorithm, but
2021 * extensions of primitive generics are rare.
2022 */
2023 while (*loc && extension != (*loc)->extended)
2024 loc = &(*loc)->next;
2025 e->next = *loc;
2026 e->extended = extended;
2027 e->extension = extension;
2028 *loc = e;
2029 }
2030}
2031
2032static void
2033setup_extended_primitive_generics ()
2034{
2035 while (extensions)
2036 {
2037 t_extension *e = extensions;
2038 scm_c_extend_primitive_generic (e->extended, e->extension);
2039 extensions = e->next;
a48d60b1
MD
2040 }
2041}
2042
80662eda 2043/******************************************************************************
6d77c894 2044 *
80662eda 2045 * Protocol for calling a generic fumction
6d77c894 2046 * This protocol is roughly equivalent to (parameter are a little bit different
80662eda
MD
2047 * for efficiency reasons):
2048 *
2049 * + apply-generic (gf args)
2050 * + compute-applicable-methods (gf args ...)
2051 * + sort-applicable-methods (methods args)
2052 * + apply-methods (gf methods args)
6d77c894
TTN
2053 *
2054 * apply-methods calls make-next-method to build the "continuation" of a a
80662eda
MD
2055 * method. Applying a next-method will call apply-next-method which in
2056 * turn will call apply again to call effectively the following method.
2057 *
2058 ******************************************************************************/
2059
2060static int
2061applicablep (SCM actual, SCM formal)
2062{
79a3dafe 2063 /* We already know that the cpl is well formed. */
7888309b 2064 return scm_is_true (scm_c_memq (formal, SCM_SLOT (actual, scm_si_cpl)));
80662eda
MD
2065}
2066
2067static int
34d19ef6 2068more_specificp (SCM m1, SCM m2, SCM const *targs)
80662eda
MD
2069{
2070 register SCM s1, s2;
c014a02e 2071 register long i;
6d77c894
TTN
2072 /*
2073 * Note:
2074 * m1 and m2 can have != length (i.e. one can be one element longer than the
80662eda
MD
2075 * other when we have a dotted parameter list). For instance, with the call
2076 * (M 1)
2077 * with
2078 * (define-method M (a . l) ....)
6d77c894 2079 * (define-method M (a) ....)
80662eda
MD
2080 *
2081 * we consider that the second method is more specific.
2082 *
2083 * BTW, targs is an array of types. We don't need it's size since
2084 * we already know that m1 and m2 are applicable (no risk to go past
2085 * the end of this array).
2086 *
2087 */
34d19ef6 2088 for (i=0, s1=SPEC_OF(m1), s2=SPEC_OF(m2); ; i++, s1=SCM_CDR(s1), s2=SCM_CDR(s2)) {
d2e53ed6
MV
2089 if (scm_is_null(s1)) return 1;
2090 if (scm_is_null(s2)) return 0;
80662eda
MD
2091 if (SCM_CAR(s1) != SCM_CAR(s2)) {
2092 register SCM l, cs1 = SCM_CAR(s1), cs2 = SCM_CAR(s2);
6d77c894 2093
dcb410ec 2094 for (l = SCM_SLOT (targs[i], scm_si_cpl); ; l = SCM_CDR(l)) {
80662eda
MD
2095 if (cs1 == SCM_CAR(l))
2096 return 1;
2097 if (cs2 == SCM_CAR(l))
2098 return 0;
2099 }
2100 return 0;/* should not occur! */
2101 }
2102 }
2103 return 0; /* should not occur! */
2104}
2105
2106#define BUFFSIZE 32 /* big enough for most uses */
2107
2108static SCM
c014a02e 2109scm_i_vector2list (SCM l, long len)
80662eda 2110{
c014a02e 2111 long j;
00ffa0e7 2112 SCM z = scm_c_make_vector (len, SCM_UNDEFINED);
6d77c894 2113
80662eda 2114 for (j = 0; j < len; j++, l = SCM_CDR (l)) {
4057a3e0 2115 SCM_SIMPLE_VECTOR_SET (z, j, SCM_CAR (l));
80662eda
MD
2116 }
2117 return z;
2118}
2119
2120static SCM
34d19ef6 2121sort_applicable_methods (SCM method_list, long size, SCM const *targs)
80662eda 2122{
c014a02e 2123 long i, j, incr;
80662eda
MD
2124 SCM *v, vector = SCM_EOL;
2125 SCM buffer[BUFFSIZE];
2126 SCM save = method_list;
4057a3e0 2127 scm_t_array_handle handle;
80662eda
MD
2128
2129 /* For reasonably sized method_lists we can try to avoid all the
2130 * consing and reorder the list in place...
2131 * This idea is due to David McClain <Dave_McClain@msn.com>
2132 */
2133 if (size <= BUFFSIZE)
2134 {
2135 for (i = 0; i < size; i++)
2136 {
2137 buffer[i] = SCM_CAR (method_list);
2138 method_list = SCM_CDR (method_list);
2139 }
2140 v = buffer;
6d77c894 2141 }
80662eda
MD
2142 else
2143 {
2144 /* Too many elements in method_list to keep everything locally */
2145 vector = scm_i_vector2list (save, size);
4057a3e0 2146 v = scm_vector_writable_elements (vector, &handle, NULL, NULL);
80662eda
MD
2147 }
2148
6d77c894 2149 /* Use a simple shell sort since it is generally faster than qsort on
80662eda
MD
2150 * small vectors (which is probably mostly the case when we have to
2151 * sort a list of applicable methods).
2152 */
2153 for (incr = size / 2; incr; incr /= 2)
2154 {
2155 for (i = incr; i < size; i++)
2156 {
2157 for (j = i - incr; j >= 0; j -= incr)
2158 {
2159 if (more_specificp (v[j], v[j+incr], targs))
2160 break;
2161 else
2162 {
2163 SCM tmp = v[j + incr];
2164 v[j + incr] = v[j];
2165 v[j] = tmp;
2166 }
2167 }
2168 }
2169 }
2170
2171 if (size <= BUFFSIZE)
2172 {
2173 /* We did it in locally, so restore the original list (reordered) in-place */
2174 for (i = 0, method_list = save; i < size; i++, v++)
2175 {
2176 SCM_SETCAR (method_list, *v);
2177 method_list = SCM_CDR (method_list);
2178 }
2179 return save;
2180 }
4057a3e0 2181
6d77c894 2182 /* If we are here, that's that we did it the hard way... */
c8857a4d 2183 scm_array_handle_release (&handle);
80662eda
MD
2184 return scm_vector_to_list (vector);
2185}
2186
2187SCM
c014a02e 2188scm_compute_applicable_methods (SCM gf, SCM args, long len, int find_method_p)
80662eda 2189{
c014a02e
ML
2190 register long i;
2191 long count = 0;
80662eda
MD
2192 SCM l, fl, applicable = SCM_EOL;
2193 SCM save = args;
34d19ef6
HWN
2194 SCM buffer[BUFFSIZE];
2195 SCM const *types;
2196 SCM *p;
2197 SCM tmp = SCM_EOL;
4057a3e0 2198 scm_t_array_handle handle;
6d77c894 2199
80662eda 2200 /* Build the list of arguments types */
4057a3e0
MV
2201 if (len >= BUFFSIZE)
2202 {
2203 tmp = scm_c_make_vector (len, SCM_UNDEFINED);
2204 types = p = scm_vector_writable_elements (tmp, &handle, NULL, NULL);
34d19ef6
HWN
2205
2206 /*
2207 note that we don't have to work to reset the generation
2208 count. TMP is a new vector anyway, and it is found
2209 conservatively.
2210 */
4057a3e0 2211 }
80662eda
MD
2212 else
2213 types = p = buffer;
6d77c894 2214
d2e53ed6 2215 for ( ; !scm_is_null (args); args = SCM_CDR (args))
80662eda 2216 *p++ = scm_class_of (SCM_CAR (args));
34d19ef6 2217
80662eda 2218 /* Build a list of all applicable methods */
d2e53ed6 2219 for (l = scm_generic_function_methods (gf); !scm_is_null (l); l = SCM_CDR (l))
80662eda
MD
2220 {
2221 fl = SPEC_OF (SCM_CAR (l));
2222 /* Only accept accessors which match exactly in first arg. */
2223 if (SCM_ACCESSORP (SCM_CAR (l))
d2e53ed6 2224 && (scm_is_null (fl) || types[0] != SCM_CAR (fl)))
80662eda
MD
2225 continue;
2226 for (i = 0; ; i++, fl = SCM_CDR (fl))
2227 {
c312aca7 2228 if (SCM_INSTANCEP (fl)
80662eda 2229 /* We have a dotted argument list */
d2e53ed6 2230 || (i >= len && scm_is_null (fl)))
80662eda
MD
2231 { /* both list exhausted */
2232 applicable = scm_cons (SCM_CAR (l), applicable);
2233 count += 1;
2234 break;
2235 }
2236 if (i >= len
d2e53ed6 2237 || scm_is_null (fl)
80662eda
MD
2238 || !applicablep (types[i], SCM_CAR (fl)))
2239 break;
2240 }
2241 }
2242
c8857a4d
MV
2243 if (len >= BUFFSIZE)
2244 scm_array_handle_release (&handle);
2245
80662eda
MD
2246 if (count == 0)
2247 {
2248 if (find_method_p)
2249 return SCM_BOOL_F;
bef95911 2250 scm_call_2 (SCM_VARIABLE_REF (var_no_applicable_method), gf, save);
80662eda
MD
2251 /* if we are here, it's because no-applicable-method hasn't signaled an error */
2252 return SCM_BOOL_F;
2253 }
34d19ef6 2254
80662eda
MD
2255 return (count == 1
2256 ? applicable
2257 : sort_applicable_methods (applicable, count, types));
2258}
2259
2260#if 0
2261SCM_PROC (s_sys_compute_applicable_methods, "%compute-applicable-methods", 2, 0, 0, scm_sys_compute_applicable_methods);
2262#endif
2263
2264static const char s_sys_compute_applicable_methods[] = "%compute-applicable-methods";
2265
2266SCM
2267scm_sys_compute_applicable_methods (SCM gf, SCM args)
398d8ee1 2268#define FUNC_NAME s_sys_compute_applicable_methods
80662eda 2269{
c014a02e 2270 long n;
398d8ee1 2271 SCM_VALIDATE_GENERIC (1, gf);
80662eda 2272 n = scm_ilength (args);
398d8ee1 2273 SCM_ASSERT (n >= 0, args, SCM_ARG2, FUNC_NAME);
80662eda
MD
2274 return scm_compute_applicable_methods (gf, args, n, 1);
2275}
398d8ee1 2276#undef FUNC_NAME
80662eda 2277
86d31dfe 2278SCM_SYMBOL (sym_compute_applicable_methods, "compute-applicable-methods");
9a441ddb 2279SCM_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 2280
80662eda
MD
2281static void
2282lock_cache_mutex (void *m)
2283{
6b80d352 2284 SCM mutex = SCM_PACK ((scm_t_bits) m);
80662eda
MD
2285 scm_lock_mutex (mutex);
2286}
2287
2288static void
2289unlock_cache_mutex (void *m)
2290{
6b80d352 2291 SCM mutex = SCM_PACK ((scm_t_bits) m);
80662eda
MD
2292 scm_unlock_mutex (mutex);
2293}
80662eda
MD
2294
2295static SCM
2296call_memoize_method (void *a)
2297{
6b80d352 2298 SCM args = SCM_PACK ((scm_t_bits) a);
80662eda
MD
2299 SCM gf = SCM_CAR (args);
2300 SCM x = SCM_CADR (args);
2301 /* First check if another thread has inserted a method between
2302 * the cache miss and locking the mutex.
2303 */
2304 SCM cmethod = scm_mcache_lookup_cmethod (x, SCM_CDDR (args));
7888309b 2305 if (scm_is_true (cmethod))
80662eda 2306 return cmethod;
bef95911
AW
2307
2308 if (SCM_UNLIKELY (scm_is_false (var_memoize_method_x)))
2309 var_memoize_method_x =
2310 scm_permanent_object
2311 (scm_module_variable (scm_module_goops, sym_memoize_method_x));
2312
2313 return scm_call_3 (SCM_VARIABLE_REF (var_memoize_method_x), gf, SCM_CDDR (args), x);
80662eda
MD
2314}
2315
2316SCM
2317scm_memoize_method (SCM x, SCM args)
2318{
2319 SCM gf = SCM_CAR (scm_last_pair (x));
6b80d352
DH
2320 return scm_internal_dynamic_wind (
2321 lock_cache_mutex,
2322 call_memoize_method,
2323 unlock_cache_mutex,
2324 (void *) SCM_UNPACK (scm_cons2 (gf, x, args)),
2325 (void *) SCM_UNPACK (SCM_SLOT (gf, scm_si_cache_mutex)));
80662eda
MD
2326}
2327
2328/******************************************************************************
2329 *
2330 * A simple make (which will be redefined later in Scheme)
2331 * This version handles only creation of gf, methods and classes (no instances)
2332 *
6d77c894 2333 * Since this code will disappear when Goops will be fully booted,
80662eda
MD
2334 * no precaution is taken to be efficient.
2335 *
2336 ******************************************************************************/
2337
2338SCM_KEYWORD (k_setter, "setter");
2339SCM_KEYWORD (k_specializers, "specializers");
2340SCM_KEYWORD (k_procedure, "procedure");
5487977b
AW
2341SCM_KEYWORD (k_formals, "formals");
2342SCM_KEYWORD (k_body, "body");
e177058b 2343SCM_KEYWORD (k_make_procedure, "make-procedure");
80662eda
MD
2344SCM_KEYWORD (k_dsupers, "dsupers");
2345SCM_KEYWORD (k_slots, "slots");
2346SCM_KEYWORD (k_gf, "generic-function");
2347
398d8ee1
KN
2348SCM_DEFINE (scm_make, "make", 0, 0, 1,
2349 (SCM args),
27c37006 2350 "Make a new object. @var{args} must contain the class and\n"
6bcefd15 2351 "all necessary initialization information.")
398d8ee1 2352#define FUNC_NAME s_scm_make
80662eda
MD
2353{
2354 SCM class, z;
c014a02e 2355 long len = scm_ilength (args);
80662eda
MD
2356
2357 if (len <= 0 || (len & 1) == 0)
398d8ee1 2358 SCM_WRONG_NUM_ARGS ();
80662eda
MD
2359
2360 class = SCM_CAR(args);
2361 args = SCM_CDR(args);
2362
f8af5c6d 2363 if (class == scm_class_generic || class == scm_class_accessor)
80662eda 2364 {
80662eda 2365 z = scm_make_struct (class, SCM_INUM0,
6d33e90f 2366 scm_list_4 (SCM_EOL,
1afff620 2367 SCM_INUM0,
bbf8d523
MD
2368 scm_make_mutex (),
2369 SCM_EOL));
80662eda
MD
2370 scm_set_procedure_property_x (z, scm_sym_name,
2371 scm_get_keyword (k_name,
2372 args,
2373 SCM_BOOL_F));
2374 clear_method_cache (z);
f8af5c6d 2375 if (class == scm_class_accessor)
80662eda
MD
2376 {
2377 SCM setter = scm_get_keyword (k_setter, args, SCM_BOOL_F);
7888309b 2378 if (scm_is_true (setter))
80662eda
MD
2379 scm_sys_set_object_setter_x (z, setter);
2380 }
2381 }
2382 else
2383 {
2384 z = scm_sys_allocate_instance (class, args);
2385
2386 if (class == scm_class_method
2387 || class == scm_class_simple_method
f8af5c6d 2388 || class == scm_class_accessor_method)
80662eda 2389 {
6d77c894 2390 SCM_SET_SLOT (z, scm_si_generic_function,
80662eda
MD
2391 scm_i_get_keyword (k_gf,
2392 args,
2393 len - 1,
2394 SCM_BOOL_F,
dcb410ec 2395 FUNC_NAME));
6d77c894 2396 SCM_SET_SLOT (z, scm_si_specializers,
80662eda
MD
2397 scm_i_get_keyword (k_specializers,
2398 args,
2399 len - 1,
2400 SCM_EOL,
dcb410ec 2401 FUNC_NAME));
6d77c894 2402 SCM_SET_SLOT (z, scm_si_procedure,
80662eda
MD
2403 scm_i_get_keyword (k_procedure,
2404 args,
2405 len - 1,
e177058b 2406 SCM_BOOL_F,
dcb410ec 2407 FUNC_NAME));
5487977b
AW
2408 SCM_SET_SLOT (z, scm_si_formals,
2409 scm_i_get_keyword (k_formals,
2410 args,
2411 len - 1,
2412 SCM_EOL,
2413 FUNC_NAME));
2414 SCM_SET_SLOT (z, scm_si_body,
2415 scm_i_get_keyword (k_body,
2416 args,
2417 len - 1,
2418 SCM_EOL,
2419 FUNC_NAME));
e177058b
AW
2420 SCM_SET_SLOT (z, scm_si_make_procedure,
2421 scm_i_get_keyword (k_make_procedure,
5487977b
AW
2422 args,
2423 len - 1,
2424 SCM_BOOL_F,
2425 FUNC_NAME));
80662eda
MD
2426 }
2427 else
2428 {
2429 /* In all the others case, make a new class .... No instance here */
b6cf4d02 2430 SCM_SET_SLOT (z, scm_vtable_index_name,
80662eda
MD
2431 scm_i_get_keyword (k_name,
2432 args,
2433 len - 1,
cc95e00a 2434 scm_from_locale_symbol ("???"),
dcb410ec 2435 FUNC_NAME));
6d77c894 2436 SCM_SET_SLOT (z, scm_si_direct_supers,
80662eda
MD
2437 scm_i_get_keyword (k_dsupers,
2438 args,
2439 len - 1,
2440 SCM_EOL,
dcb410ec 2441 FUNC_NAME));
6d77c894 2442 SCM_SET_SLOT (z, scm_si_direct_slots,
80662eda
MD
2443 scm_i_get_keyword (k_slots,
2444 args,
2445 len - 1,
2446 SCM_EOL,
dcb410ec 2447 FUNC_NAME));
80662eda
MD
2448 }
2449 }
2450 return z;
2451}
398d8ee1 2452#undef FUNC_NAME
80662eda 2453
398d8ee1
KN
2454SCM_DEFINE (scm_find_method, "find-method", 0, 0, 1,
2455 (SCM l),
2456 "")
2457#define FUNC_NAME s_scm_find_method
80662eda
MD
2458{
2459 SCM gf;
c014a02e 2460 long len = scm_ilength (l);
80662eda
MD
2461
2462 if (len == 0)
398d8ee1 2463 SCM_WRONG_NUM_ARGS ();
80662eda
MD
2464
2465 gf = SCM_CAR(l); l = SCM_CDR(l);
398d8ee1 2466 SCM_VALIDATE_GENERIC (1, gf);
d2e53ed6 2467 if (scm_is_null (SCM_SLOT (gf, scm_si_methods)))
1afff620 2468 SCM_MISC_ERROR ("no methods for generic ~S", scm_list_1 (gf));
80662eda
MD
2469
2470 return scm_compute_applicable_methods (gf, l, len - 1, 1);
2471}
398d8ee1 2472#undef FUNC_NAME
80662eda 2473
398d8ee1
KN
2474SCM_DEFINE (scm_sys_method_more_specific_p, "%method-more-specific?", 3, 0, 0,
2475 (SCM m1, SCM m2, SCM targs),
b1f57ea4
LC
2476 "Return true if method @var{m1} is more specific than @var{m2} "
2477 "given the argument types (classes) listed in @var{targs}.")
398d8ee1 2478#define FUNC_NAME s_scm_sys_method_more_specific_p
80662eda 2479{
4057a3e0
MV
2480 SCM l, v, result;
2481 SCM *v_elts;
b1f57ea4 2482 long i, len, m1_specs, m2_specs;
4057a3e0 2483 scm_t_array_handle handle;
80662eda 2484
398d8ee1
KN
2485 SCM_VALIDATE_METHOD (1, m1);
2486 SCM_VALIDATE_METHOD (2, m2);
80662eda 2487
b1f57ea4
LC
2488 len = scm_ilength (targs);
2489 m1_specs = scm_ilength (SPEC_OF (m1));
2490 m2_specs = scm_ilength (SPEC_OF (m2));
2491 SCM_ASSERT ((len >= m1_specs) || (len >= m2_specs),
2492 targs, SCM_ARG3, FUNC_NAME);
2493
2494 /* Verify that all the arguments of TARGS are classes and place them
2495 in a vector. */
4057a3e0 2496
00ffa0e7 2497 v = scm_c_make_vector (len, SCM_EOL);
4057a3e0 2498 v_elts = scm_vector_writable_elements (v, &handle, NULL, NULL);
80662eda 2499
b1f57ea4
LC
2500 for (i = 0, l = targs;
2501 i < len && scm_is_pair (l);
2502 i++, l = SCM_CDR (l))
4057a3e0
MV
2503 {
2504 SCM_ASSERT (SCM_CLASSP (SCM_CAR (l)), targs, SCM_ARG3, FUNC_NAME);
b1f57ea4 2505 v_elts[i] = SCM_CAR (l);
4057a3e0 2506 }
4057a3e0 2507 result = more_specificp (m1, m2, v_elts) ? SCM_BOOL_T: SCM_BOOL_F;
c8857a4d
MV
2508
2509 scm_array_handle_release (&handle);
2510
4057a3e0 2511 return result;
80662eda 2512}
398d8ee1 2513#undef FUNC_NAME
6d77c894
TTN
2514
2515
80662eda
MD
2516
2517/******************************************************************************
2518 *
6d77c894 2519 * Initializations
80662eda
MD
2520 *
2521 ******************************************************************************/
2522
74b6d6e4
MD
2523static void
2524fix_cpl (SCM c, SCM before, SCM after)
2525{
2526 SCM cpl = SCM_SLOT (c, scm_si_cpl);
2527 SCM ls = scm_c_memq (after, cpl);
2528 SCM tail = scm_delq1_x (before, SCM_CDR (ls));
7888309b 2529 if (scm_is_false (ls))
74b6d6e4
MD
2530 /* if this condition occurs, fix_cpl should not be applied this way */
2531 abort ();
2532 SCM_SETCAR (ls, before);
2533 SCM_SETCDR (ls, scm_cons (after, tail));
2534 {
2535 SCM dslots = SCM_SLOT (c, scm_si_direct_slots);
2536 SCM slots = build_slots_list (maplist (dslots), cpl);
2537 SCM g_n_s = compute_getters_n_setters (slots);
2538 SCM_SET_SLOT (c, scm_si_slots, slots);
2539 SCM_SET_SLOT (c, scm_si_getters_n_setters, g_n_s);
2540 }
2541}
2542
80662eda
MD
2543
2544static void
2545make_stdcls (SCM *var, char *name, SCM meta, SCM super, SCM slots)
2546{
cc95e00a 2547 SCM tmp = scm_from_locale_symbol (name);
6d77c894 2548
80662eda
MD
2549 *var = scm_permanent_object (scm_basic_make_class (meta,
2550 tmp,
d2e53ed6 2551 scm_is_pair (super)
80662eda 2552 ? super
1afff620 2553 : scm_list_1 (super),
80662eda
MD
2554 slots));
2555 DEFVAR(tmp, *var);
2556}
2557
2558
2559SCM_KEYWORD (k_slot_definition, "slot-definition");
2560
2561static void
2562create_standard_classes (void)
2563{
2564 SCM slots;
21497600 2565 SCM method_slots = scm_list_n (scm_from_locale_symbol ("generic-function"),
cc95e00a 2566 scm_from_locale_symbol ("specializers"),
6b80d352 2567 sym_procedure,
21497600
AW
2568 scm_from_locale_symbol ("formals"),
2569 scm_from_locale_symbol ("body"),
e177058b 2570 scm_from_locale_symbol ("make-procedure"),
21497600 2571 SCM_UNDEFINED);
cc95e00a 2572 SCM amethod_slots = scm_list_1 (scm_list_3 (scm_from_locale_symbol ("slot-definition"),
1afff620
KN
2573 k_init_keyword,
2574 k_slot_definition));
cc95e00a 2575 SCM mutex_slot = scm_list_1 (scm_from_locale_symbol ("make-mutex"));
366ecaec
DH
2576 SCM mutex_closure = scm_i_eval_x (scm_list_3 (scm_sym_lambda,
2577 SCM_EOL,
2578 mutex_slot),
2579 SCM_EOL);
b6cf4d02 2580 SCM gf_slots = scm_list_n (scm_from_locale_symbol ("methods"),
cc95e00a 2581 scm_list_3 (scm_from_locale_symbol ("n-specialized"),
1afff620
KN
2582 k_init_value,
2583 SCM_INUM0),
cc95e00a 2584 scm_list_3 (scm_from_locale_symbol ("cache-mutex"),
1afff620 2585 k_init_thunk,
366ecaec 2586 mutex_closure),
cc95e00a 2587 scm_list_3 (scm_from_locale_symbol ("extended-by"),
bbf8d523 2588 k_init_value,
b6cf4d02
AW
2589 SCM_EOL),
2590 scm_from_locale_symbol ("%cache"),
a9a90a88
AW
2591 scm_from_locale_symbol ("dispatch-procedure"),
2592 scm_from_locale_symbol ("effective-methods"),
b6cf4d02 2593 SCM_UNDEFINED);
a9a90a88 2594 SCM setter_slots = scm_list_1 (sym_setter);
cc95e00a 2595 SCM egf_slots = scm_list_1 (scm_list_3 (scm_from_locale_symbol ("extends"),
bbf8d523
MD
2596 k_init_value,
2597 SCM_EOL));
80662eda
MD
2598 /* Foreign class slot classes */
2599 make_stdcls (&scm_class_foreign_slot, "<foreign-slot>",
2600 scm_class_class, scm_class_top, SCM_EOL);
2601 make_stdcls (&scm_class_protected, "<protected-slot>",
2602 scm_class_class, scm_class_foreign_slot, SCM_EOL);
b6cf4d02
AW
2603 make_stdcls (&scm_class_hidden, "<hidden-slot>",
2604 scm_class_class, scm_class_foreign_slot, SCM_EOL);
80662eda
MD
2605 make_stdcls (&scm_class_opaque, "<opaque-slot>",
2606 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2607 make_stdcls (&scm_class_read_only, "<read-only-slot>",
2608 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2609 make_stdcls (&scm_class_self, "<self-slot>",
b6cf4d02 2610 scm_class_class, scm_class_read_only, SCM_EOL);
80662eda
MD
2611 make_stdcls (&scm_class_protected_opaque, "<protected-opaque-slot>",
2612 scm_class_class,
1afff620 2613 scm_list_2 (scm_class_protected, scm_class_opaque),
80662eda 2614 SCM_EOL);
b6cf4d02
AW
2615 make_stdcls (&scm_class_protected_hidden, "<protected-hidden-slot>",
2616 scm_class_class,
2617 scm_list_2 (scm_class_protected, scm_class_hidden),
2618 SCM_EOL);
80662eda
MD
2619 make_stdcls (&scm_class_protected_read_only, "<protected-read-only-slot>",
2620 scm_class_class,
1afff620 2621 scm_list_2 (scm_class_protected, scm_class_read_only),
80662eda
MD
2622 SCM_EOL);
2623 make_stdcls (&scm_class_scm, "<scm-slot>",
2624 scm_class_class, scm_class_protected, SCM_EOL);
2625 make_stdcls (&scm_class_int, "<int-slot>",
2626 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2627 make_stdcls (&scm_class_float, "<float-slot>",
2628 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2629 make_stdcls (&scm_class_double, "<double-slot>",
2630 scm_class_class, scm_class_foreign_slot, SCM_EOL);
2631
2632 /* Continue initialization of class <class> */
6d77c894 2633
80662eda 2634 slots = build_class_class_slots ();
dcb410ec
DH
2635 SCM_SET_SLOT (scm_class_class, scm_si_direct_slots, slots);
2636 SCM_SET_SLOT (scm_class_class, scm_si_slots, slots);
2637 SCM_SET_SLOT (scm_class_class, scm_si_getters_n_setters,
2638 compute_getters_n_setters (slots));
6d77c894 2639
80662eda
MD
2640 make_stdcls (&scm_class_foreign_class, "<foreign-class>",
2641 scm_class_class, scm_class_class,
cc95e00a 2642 scm_list_2 (scm_list_3 (scm_from_locale_symbol ("constructor"),
1afff620
KN
2643 k_class,
2644 scm_class_opaque),
cc95e00a 2645 scm_list_3 (scm_from_locale_symbol ("destructor"),
1afff620
KN
2646 k_class,
2647 scm_class_opaque)));
80662eda
MD
2648 make_stdcls (&scm_class_foreign_object, "<foreign-object>",
2649 scm_class_foreign_class, scm_class_object, SCM_EOL);
2650 SCM_SET_CLASS_FLAGS (scm_class_foreign_object, SCM_CLASSF_FOREIGN);
2651
2652 /* scm_class_generic functions classes */
2653 make_stdcls (&scm_class_procedure_class, "<procedure-class>",
2654 scm_class_class, scm_class_class, SCM_EOL);
2655 make_stdcls (&scm_class_entity_class, "<entity-class>",
2656 scm_class_class, scm_class_procedure_class, SCM_EOL);
80662eda
MD
2657 make_stdcls (&scm_class_method, "<method>",
2658 scm_class_class, scm_class_object, method_slots);
2659 make_stdcls (&scm_class_simple_method, "<simple-method>",
2660 scm_class_class, scm_class_method, SCM_EOL);
2661 SCM_SET_CLASS_FLAGS (scm_class_simple_method, SCM_CLASSF_SIMPLE_METHOD);
f8af5c6d 2662 make_stdcls (&scm_class_accessor_method, "<accessor-method>",
80662eda 2663 scm_class_class, scm_class_simple_method, amethod_slots);
f8af5c6d 2664 SCM_SET_CLASS_FLAGS (scm_class_accessor_method, SCM_CLASSF_ACCESSOR_METHOD);
74b6d6e4
MD
2665 make_stdcls (&scm_class_applicable, "<applicable>",
2666 scm_class_class, scm_class_top, SCM_EOL);
80662eda 2667 make_stdcls (&scm_class_entity, "<entity>",
74b6d6e4
MD
2668 scm_class_entity_class,
2669 scm_list_2 (scm_class_object, scm_class_applicable),
2670 SCM_EOL);
80662eda
MD
2671 make_stdcls (&scm_class_entity_with_setter, "<entity-with-setter>",
2672 scm_class_entity_class, scm_class_entity, SCM_EOL);
2673 make_stdcls (&scm_class_generic, "<generic>",
2674 scm_class_entity_class, scm_class_entity, gf_slots);
2675 SCM_SET_CLASS_FLAGS (scm_class_generic, SCM_CLASSF_PURE_GENERIC);
bbf8d523 2676 make_stdcls (&scm_class_extended_generic, "<extended-generic>",
f8af5c6d 2677 scm_class_entity_class, scm_class_generic, egf_slots);
bbf8d523 2678 SCM_SET_CLASS_FLAGS (scm_class_extended_generic, SCM_CLASSF_PURE_GENERIC);
80662eda
MD
2679 make_stdcls (&scm_class_generic_with_setter, "<generic-with-setter>",
2680 scm_class_entity_class,
1afff620 2681 scm_list_2 (scm_class_generic, scm_class_entity_with_setter),
b6cf4d02 2682 setter_slots);
80662eda 2683 SCM_SET_CLASS_FLAGS (scm_class_generic_with_setter, SCM_CLASSF_PURE_GENERIC);
f8af5c6d
MD
2684 make_stdcls (&scm_class_accessor, "<accessor>",
2685 scm_class_entity_class, scm_class_generic_with_setter, SCM_EOL);
2686 SCM_SET_CLASS_FLAGS (scm_class_accessor, SCM_CLASSF_PURE_GENERIC);
bbf8d523
MD
2687 make_stdcls (&scm_class_extended_generic_with_setter,
2688 "<extended-generic-with-setter>",
2689 scm_class_entity_class,
74b6d6e4
MD
2690 scm_list_2 (scm_class_generic_with_setter,
2691 scm_class_extended_generic),
bbf8d523
MD
2692 SCM_EOL);
2693 SCM_SET_CLASS_FLAGS (scm_class_extended_generic_with_setter,
2694 SCM_CLASSF_PURE_GENERIC);
74b6d6e4
MD
2695 make_stdcls (&scm_class_extended_accessor, "<extended-accessor>",
2696 scm_class_entity_class,
2697 scm_list_2 (scm_class_accessor,
2698 scm_class_extended_generic_with_setter),
2699 SCM_EOL);
2700 fix_cpl (scm_class_extended_accessor,
2701 scm_class_extended_generic, scm_class_generic);
2702 SCM_SET_CLASS_FLAGS (scm_class_extended_accessor, SCM_CLASSF_PURE_GENERIC);
80662eda
MD
2703
2704 /* Primitive types classes */
2705 make_stdcls (&scm_class_boolean, "<boolean>",
2706 scm_class_class, scm_class_top, SCM_EOL);
2707 make_stdcls (&scm_class_char, "<char>",
2708 scm_class_class, scm_class_top, SCM_EOL);
2709 make_stdcls (&scm_class_list, "<list>",
2710 scm_class_class, scm_class_top, SCM_EOL);
2711 make_stdcls (&scm_class_pair, "<pair>",
2712 scm_class_class, scm_class_list, SCM_EOL);
2713 make_stdcls (&scm_class_null, "<null>",
2714 scm_class_class, scm_class_list, SCM_EOL);
2715 make_stdcls (&scm_class_string, "<string>",
2716 scm_class_class, scm_class_top, SCM_EOL);
2717 make_stdcls (&scm_class_symbol, "<symbol>",
2718 scm_class_class, scm_class_top, SCM_EOL);
2719 make_stdcls (&scm_class_vector, "<vector>",
2720 scm_class_class, scm_class_top, SCM_EOL);
2721 make_stdcls (&scm_class_number, "<number>",
2722 scm_class_class, scm_class_top, SCM_EOL);
2723 make_stdcls (&scm_class_complex, "<complex>",
2724 scm_class_class, scm_class_number, SCM_EOL);
2725 make_stdcls (&scm_class_real, "<real>",
2726 scm_class_class, scm_class_complex, SCM_EOL);
2727 make_stdcls (&scm_class_integer, "<integer>",
2728 scm_class_class, scm_class_real, SCM_EOL);
f92e85f7
MV
2729 make_stdcls (&scm_class_fraction, "<fraction>",
2730 scm_class_class, scm_class_real, SCM_EOL);
80662eda
MD
2731 make_stdcls (&scm_class_keyword, "<keyword>",
2732 scm_class_class, scm_class_top, SCM_EOL);
2733 make_stdcls (&scm_class_unknown, "<unknown>",
2734 scm_class_class, scm_class_top, SCM_EOL);
2735 make_stdcls (&scm_class_procedure, "<procedure>",
74b6d6e4 2736 scm_class_procedure_class, scm_class_applicable, SCM_EOL);
80662eda
MD
2737 make_stdcls (&scm_class_procedure_with_setter, "<procedure-with-setter>",
2738 scm_class_procedure_class, scm_class_procedure, SCM_EOL);
2739 make_stdcls (&scm_class_primitive_generic, "<primitive-generic>",
2740 scm_class_procedure_class, scm_class_procedure, SCM_EOL);
2741 make_stdcls (&scm_class_port, "<port>",
2742 scm_class_class, scm_class_top, SCM_EOL);
2743 make_stdcls (&scm_class_input_port, "<input-port>",
2744 scm_class_class, scm_class_port, SCM_EOL);
2745 make_stdcls (&scm_class_output_port, "<output-port>",
2746 scm_class_class, scm_class_port, SCM_EOL);
2747 make_stdcls (&scm_class_input_output_port, "<input-output-port>",
2748 scm_class_class,
1afff620 2749 scm_list_2 (scm_class_input_port, scm_class_output_port),
80662eda
MD
2750 SCM_EOL);
2751}
2752
2753/**********************************************************************
2754 *
2755 * Smob classes
2756 *
2757 **********************************************************************/
2758
2759static SCM
da0e6c2b 2760make_class_from_template (char const *template, char const *type_name, SCM supers, int applicablep)
80662eda
MD
2761{
2762 SCM class, name;
2763 if (type_name)
2764 {
2765 char buffer[100];
2766 sprintf (buffer, template, type_name);
cc95e00a 2767 name = scm_from_locale_symbol (buffer);
80662eda
MD
2768 }
2769 else
2770 name = SCM_GOOPS_UNBOUND;
2771
74b6d6e4
MD
2772 class = scm_permanent_object (scm_basic_make_class (applicablep
2773 ? scm_class_procedure_class
2774 : scm_class_class,
80662eda
MD
2775 name,
2776 supers,
2777 SCM_EOL));
2778
2779 /* Only define name if doesn't already exist. */
2780 if (!SCM_GOOPS_UNBOUNDP (name)
bef95911 2781 && scm_is_false (scm_module_variable (scm_module_goops, name)))
0ba8a0a5 2782 DEFVAR (name, class);
80662eda
MD
2783 return class;
2784}
2785
9db8cf16
MG
2786static SCM
2787make_class_from_symbol (SCM type_name_sym, SCM supers, int applicablep)
2788{
2789 SCM class, name;
2790 if (type_name_sym != SCM_BOOL_F)
2791 {
2792 name = scm_string_append (scm_list_3 (scm_from_locale_string ("<"),
2793 scm_symbol_to_string (type_name_sym),
2794 scm_from_locale_string (">")));
2795 name = scm_string_to_symbol (name);
2796 }
2797 else
2798 name = SCM_GOOPS_UNBOUND;
2799
2800 class = scm_permanent_object (scm_basic_make_class (applicablep
2801 ? scm_class_procedure_class
2802 : scm_class_class,
2803 name,
2804 supers,
2805 SCM_EOL));
2806
2807 /* Only define name if doesn't already exist. */
2808 if (!SCM_GOOPS_UNBOUNDP (name)
2809 && scm_is_false (scm_module_variable (scm_module_goops, name)))
2810 DEFVAR (name, class);
2811 return class;
2812}
2813
80662eda 2814SCM
da0e6c2b 2815scm_make_extended_class (char const *type_name, int applicablep)
80662eda
MD
2816{
2817 return make_class_from_template ("<%s>",
2818 type_name,
74b6d6e4
MD
2819 scm_list_1 (applicablep
2820 ? scm_class_applicable
2821 : scm_class_top),
2822 applicablep);
2823}
2824
9db8cf16
MG
2825static SCM
2826scm_make_extended_class_from_symbol (SCM type_name_sym, int applicablep)
2827{
2828 return make_class_from_symbol (type_name_sym,
2829 scm_list_1 (applicablep
2830 ? scm_class_applicable
2831 : scm_class_top),
2832 applicablep);
2833}
2834
74b6d6e4
MD
2835void
2836scm_i_inherit_applicable (SCM c)
2837{
2838 if (!SCM_SUBCLASSP (c, scm_class_applicable))
2839 {
2840 SCM dsupers = SCM_SLOT (c, scm_si_direct_supers);
2841 SCM cpl = SCM_SLOT (c, scm_si_cpl);
2842 /* patch scm_class_applicable into direct-supers */
2843 SCM top = scm_c_memq (scm_class_top, dsupers);
7888309b 2844 if (scm_is_false (top))
74b6d6e4
MD
2845 dsupers = scm_append (scm_list_2 (dsupers,
2846 scm_list_1 (scm_class_applicable)));
2847 else
2848 {
2849 SCM_SETCAR (top, scm_class_applicable);
2850 SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
2851 }
2852 SCM_SET_SLOT (c, scm_si_direct_supers, dsupers);
2853 /* patch scm_class_applicable into cpl */
2854 top = scm_c_memq (scm_class_top, cpl);
7888309b 2855 if (scm_is_false (top))
74b6d6e4
MD
2856 abort ();
2857 else
2858 {
2859 SCM_SETCAR (top, scm_class_applicable);
2860 SCM_SETCDR (top, scm_cons (scm_class_top, SCM_CDR (top)));
2861 }
2862 /* add class to direct-subclasses of scm_class_applicable */
2863 SCM_SET_SLOT (scm_class_applicable,
2864 scm_si_direct_subclasses,
2865 scm_cons (c, SCM_SLOT (scm_class_applicable,
2866 scm_si_direct_subclasses)));
2867 }
80662eda
MD
2868}
2869
2870static void
2871create_smob_classes (void)
2872{
c014a02e 2873 long i;
80662eda 2874
c891a40e 2875 for (i = 0; i < SCM_I_MAX_SMOB_TYPE_COUNT; ++i)
80662eda
MD
2876 scm_smob_class[i] = 0;
2877
80662eda 2878 scm_smob_class[SCM_TC2SMOBNUM (scm_tc16_keyword)] = scm_class_keyword;
6d77c894 2879
80662eda
MD
2880 for (i = 0; i < scm_numsmob; ++i)
2881 if (!scm_smob_class[i])
74b6d6e4
MD
2882 scm_smob_class[i] = scm_make_extended_class (SCM_SMOBNAME (i),
2883 scm_smobs[i].apply != 0);
80662eda
MD
2884}
2885
2886void
c014a02e 2887scm_make_port_classes (long ptobnum, char *type_name)
80662eda
MD
2888{
2889 SCM c, class = make_class_from_template ("<%s-port>",
2890 type_name,
74b6d6e4
MD
2891 scm_list_1 (scm_class_port),
2892 0);
80662eda
MD
2893 scm_port_class[SCM_IN_PCLASS_INDEX + ptobnum]
2894 = make_class_from_template ("<%s-input-port>",
2895 type_name,
74b6d6e4
MD
2896 scm_list_2 (class, scm_class_input_port),
2897 0);
80662eda
MD
2898 scm_port_class[SCM_OUT_PCLASS_INDEX + ptobnum]
2899 = make_class_from_template ("<%s-output-port>",
2900 type_name,
74b6d6e4
MD
2901 scm_list_2 (class, scm_class_output_port),
2902 0);
80662eda
MD
2903 scm_port_class[SCM_INOUT_PCLASS_INDEX + ptobnum]
2904 = c
2905 = make_class_from_template ("<%s-input-output-port>",
2906 type_name,
74b6d6e4
MD
2907 scm_list_2 (class, scm_class_input_output_port),
2908 0);
80662eda 2909 /* Patch cpl (since this tree is too complex for the C level compute-cpl) */
dcb410ec
DH
2910 SCM_SET_SLOT (c, scm_si_cpl,
2911 scm_cons2 (c, class, SCM_SLOT (scm_class_input_output_port, scm_si_cpl)));
80662eda
MD
2912}
2913
2914static void
2915create_port_classes (void)
2916{
c014a02e 2917 long i;
80662eda 2918
80662eda
MD
2919 for (i = 0; i < scm_numptob; ++i)
2920 scm_make_port_classes (i, SCM_PTOBNAME (i));
2921}
2922
2923static SCM
74b6d6e4
MD
2924make_struct_class (void *closure SCM_UNUSED,
2925 SCM vtable, SCM data, SCM prev SCM_UNUSED)
80662eda 2926{
9db8cf16
MG
2927 SCM sym = SCM_STRUCT_TABLE_NAME (data);
2928 if (scm_is_true (sym))
2929 {
b6cf4d02 2930 int applicablep = SCM_CLASS_FLAGS (vtable) & SCM_VTABLE_FLAG_APPLICABLE;
9db8cf16
MG
2931
2932 SCM_SET_STRUCT_TABLE_CLASS (data,
2933 scm_make_extended_class_from_symbol (sym, applicablep));
2934 }
2935
2936 scm_remember_upto_here_2 (data, vtable);
80662eda
MD
2937 return SCM_UNSPECIFIED;
2938}
2939
2940static void
2941create_struct_classes (void)
2942{
2943 scm_internal_hash_fold (make_struct_class, 0, SCM_BOOL_F, scm_struct_table);
2944}
2945
2946/**********************************************************************
2947 *
2948 * C interface
2949 *
2950 **********************************************************************/
2951
2952void
2953scm_load_goops ()
2954{
2955 if (!goops_loaded_p)
abd28220 2956 scm_c_resolve_module ("oop goops");
80662eda
MD
2957}
2958
e11208ca 2959
80662eda
MD
2960SCM_SYMBOL (sym_o, "o");
2961SCM_SYMBOL (sym_x, "x");
2962
2963SCM_KEYWORD (k_accessor, "accessor");
2964SCM_KEYWORD (k_getter, "getter");
2965
80662eda
MD
2966SCM
2967scm_ensure_accessor (SCM name)
2968{
fdc28395 2969 SCM gf = scm_call_2 (SCM_TOP_LEVEL_LOOKUP_CLOSURE, name, SCM_BOOL_F);
f8af5c6d 2970 if (!SCM_IS_A_P (gf, scm_class_accessor))
80662eda 2971 {
1afff620 2972 gf = scm_make (scm_list_3 (scm_class_generic, k_name, name));
f8af5c6d 2973 gf = scm_make (scm_list_5 (scm_class_accessor,
1afff620 2974 k_name, name, k_setter, gf));
80662eda
MD
2975 }
2976 return gf;
2977}
2978
2979SCM_SYMBOL (sym_internal_add_method_x, "internal-add-method!");
2980
2981void
2982scm_add_method (SCM gf, SCM m)
2983{
1afff620 2984 scm_eval (scm_list_3 (sym_internal_add_method_x, gf, m), scm_module_goops);
80662eda
MD
2985}
2986
2987#ifdef GUILE_DEBUG
2988/*
2989 * Debugging utilities
2990 */
2991
398d8ee1
KN
2992SCM_DEFINE (scm_pure_generic_p, "pure-generic?", 1, 0, 0,
2993 (SCM obj),
6bcefd15 2994 "Return @code{#t} if @var{obj} is a pure generic.")
398d8ee1 2995#define FUNC_NAME s_scm_pure_generic_p
80662eda 2996{
7888309b 2997 return scm_from_bool (SCM_PUREGENERICP (obj));
80662eda 2998}
398d8ee1 2999#undef FUNC_NAME
80662eda
MD
3000
3001#endif /* GUILE_DEBUG */
3002
3003/*
3004 * Initialization
3005 */
3006
398d8ee1
KN
3007SCM_DEFINE (scm_sys_goops_loaded, "%goops-loaded", 0, 0, 0,
3008 (),
6bcefd15
MG
3009 "Announce that GOOPS is loaded and perform initialization\n"
3010 "on the C level which depends on the loaded GOOPS modules.")
398d8ee1 3011#define FUNC_NAME s_scm_sys_goops_loaded
80662eda
MD
3012{
3013 goops_loaded_p = 1;
86d31dfe 3014 var_compute_applicable_methods =
bef95911
AW
3015 scm_permanent_object
3016 (scm_module_variable (scm_module_goops, sym_compute_applicable_methods));
3017 var_slot_unbound =
3018 scm_permanent_object
3019 (scm_module_variable (scm_module_goops, sym_slot_unbound));
3020 var_slot_missing =
3021 scm_permanent_object
3022 (scm_module_variable (scm_module_goops, sym_slot_missing));
3023 var_compute_cpl =
3024 scm_permanent_object
3025 (scm_module_variable (scm_module_goops, sym_compute_cpl));
3026 var_no_applicable_method =
3027 scm_permanent_object
3028 (scm_module_variable (scm_module_goops, sym_no_applicable_method));
3029 var_change_class =
3030 scm_permanent_object
3031 (scm_module_variable (scm_module_goops, sym_change_class));
a48d60b1 3032 setup_extended_primitive_generics ();
80662eda
MD
3033 return SCM_UNSPECIFIED;
3034}
398d8ee1 3035#undef FUNC_NAME
80662eda
MD
3036
3037SCM scm_module_goops;
3038
abd28220
MV
3039SCM
3040scm_init_goops_builtins (void)
80662eda 3041{
abd28220 3042 scm_module_goops = scm_current_module ();
80662eda 3043
6d77c894 3044 /* Not really necessary right now, but who knows...
0ba8a0a5
MV
3045 */
3046 scm_permanent_object (scm_module_goops);
0ba8a0a5 3047
80662eda
MD
3048 goops_rstate = scm_c_make_rstate ("GOOPS", 5);
3049
3050#include "libguile/goops.x"
3051
1afff620 3052 list_of_no_method = scm_permanent_object (scm_list_1 (sym_no_method));
80662eda 3053
bb764c0e 3054 hell = scm_calloc (hell_size * sizeof (*hell));
2132f0d2 3055 hell_mutex = scm_permanent_object (scm_make_mutex ());
80662eda
MD
3056
3057 create_basic_classes ();
3058 create_standard_classes ();
3059 create_smob_classes ();
3060 create_struct_classes ();
3061 create_port_classes ();
3062
3063 {
cc95e00a 3064 SCM name = scm_from_locale_symbol ("no-applicable-method");
80662eda 3065 scm_no_applicable_method
1afff620
KN
3066 = scm_permanent_object (scm_make (scm_list_3 (scm_class_generic,
3067 k_name,
3068 name)));
80662eda
MD
3069 DEFVAR (name, scm_no_applicable_method);
3070 }
abd28220
MV
3071
3072 return SCM_UNSPECIFIED;
80662eda
MD
3073}
3074
3075void
abd28220 3076scm_init_goops ()
80662eda 3077{
9a441ddb
MV
3078 scm_c_define_gsubr ("%init-goops-builtins", 0, 0, 0,
3079 scm_init_goops_builtins);
80662eda 3080}
23437298
DH
3081
3082/*
3083 Local Variables:
3084 c-file-style: "gnu"
3085 End:
3086*/