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