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