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