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