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