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