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