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