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