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