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