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