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