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