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