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