1 /*
2 * class.c - class metaobject implementation
3 *
4 * Copyright (c) 2000-2020 Shiro Kawai <shiro@acm.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the authors nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #define LIBGAUCHE_BODY
35 #include "gauche.h"
36 #include "gauche/class.h"
37 #include "gauche/code.h"
38 #include "gauche/priv/classP.h"
39 #include "gauche/priv/builtin-syms.h"
40 #include "gauche/priv/macroP.h"
41 #include "gauche/priv/pairP.h"
42 #include "gauche/priv/writerP.h"
43 #include "gauche/priv/dispatchP.h"
44 #include "gauche/priv/stringP.h"
45
46 /* Some routines uses small array on stack to keep data about
47 arguments to dispatch. If the # of args used for dispach is bigger
48 than this, the routine allocates an array in heap. */
49 #define PREALLOC_SIZE 32
50
51
52 /*===================================================================
53 * Built-in classes
54 */
55
56 static void class_print(ScmObj, ScmPort *, ScmWriteContext*);
57 static void generic_print(ScmObj, ScmPort *, ScmWriteContext*);
58 static void method_print(ScmObj, ScmPort *, ScmWriteContext*);
59 static void next_method_print(ScmObj, ScmPort *, ScmWriteContext*);
60 static void slot_accessor_print(ScmObj, ScmPort *, ScmWriteContext*);
61 static void accessor_method_print(ScmObj, ScmPort *, ScmWriteContext*);
62
63 static ScmObj class_allocate(ScmClass *klass, ScmObj initargs);
64 static ScmObj generic_allocate(ScmClass *klass, ScmObj initargs);
65 static ScmObj method_allocate(ScmClass *klass, ScmObj initargs);
66 static ScmObj slot_accessor_allocate(ScmClass *klass, ScmObj initargs);
67 static void initialize_builtin_cpl(ScmClass *klass, ScmObj supers);
68
69 static ScmObj instance_class_redefinition(ScmObj obj, ScmClass *old);
70 static ScmObj slot_set_using_accessor(ScmObj obj, ScmSlotAccessor *sa,
71 ScmObj val);
72 static ScmObj instance_allocate(ScmClass *klass, ScmObj initargs);
73
74 static ScmObj fallback_compare(ScmObj *, int, ScmGeneric *);
75
76 static ScmObj builtin_initialize(ScmObj *, int, ScmGeneric *);
77
78 ScmClass *Scm_DefaultCPL[] = {
79 SCM_CLASS_STATIC_PTR(Scm_TopClass),
80 NULL
81 };
82
83 ScmClass *Scm_ObjectCPL[] = {
84 SCM_CLASS_STATIC_PTR(Scm_ObjectClass),
85 SCM_CLASS_STATIC_PTR(Scm_TopClass),
86 NULL
87 };
88
89 static ScmClass *Scm_MethodCPL[] = {
90 SCM_CLASS_STATIC_PTR(Scm_MethodClass),
91 SCM_CLASS_STATIC_PTR(Scm_ObjectClass),
92 SCM_CLASS_STATIC_PTR(Scm_TopClass),
93 NULL
94 };
95
96 /* Class <top> is the superclass of all classes. The class initialization
97 routine ensures that the class precedence list always terminates by <top>.
98 Class <bottom> is the subclass of all classes. It won't appear in the
99 class precedence list, but Scm_SubTypeP treats it specially and answers
100 yes to Scm_SubTypeP(<bottom>, <any-class>). */
101 SCM_DEFINE_ABSTRACT_CLASS(Scm_TopClass, NULL);
102 SCM_DEFINE_ABSTRACT_CLASS(Scm_BottomClass, NULL);
103
104 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_BoolClass, NULL);
105 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_CharClass, NULL);
106 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_UnknownClass, NULL);
107 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_EOFObjectClass, NULL);
108 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_UndefinedObjectClass, NULL);
109 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_ForeignPointerClass, NULL);
110
111 SCM_DEFINE_BASE_CLASS(Scm_ObjectClass, ScmInstance,
112 NULL, NULL, NULL, instance_allocate,
113 SCM_CLASS_DEFAULT_CPL);
114
115 /* Basic metaobjects */
116 SCM_DEFINE_BASE_CLASS(Scm_ClassClass, ScmClass,
117 class_print, NULL, NULL, class_allocate,
118 SCM_CLASS_OBJECT_CPL);
119 SCM_DEFINE_BASE_CLASS(Scm_GenericClass, ScmGeneric,
120 generic_print, NULL, NULL, generic_allocate,
121 SCM_CLASS_OBJECT_CPL);
122 SCM_DEFINE_BASE_CLASS(Scm_MethodClass, ScmMethod,
123 method_print, NULL, NULL, method_allocate,
124 SCM_CLASS_OBJECT_CPL);
125
126 /* Internally used classes */
127 SCM_DEFINE_BUILTIN_CLASS(Scm_SlotAccessorClass,
128 slot_accessor_print, NULL, NULL,
129 slot_accessor_allocate,
130 SCM_CLASS_DEFAULT_CPL);
131 SCM_DEFINE_BUILTIN_CLASS(Scm_AccessorMethodClass,
132 accessor_method_print, NULL, NULL,
133 method_allocate,
134 Scm_MethodCPL);
135 SCM_DEFINE_BUILTIN_CLASS_SIMPLE(Scm_NextMethodClass, next_method_print);
136
137 /* Builtin generic functions */
138 SCM_DEFINE_GENERIC(Scm_GenericMake, Scm_NoNextMethod, NULL);
139 SCM_DEFINE_GENERIC(Scm_GenericAllocate, Scm_NoNextMethod, NULL);
140 SCM_DEFINE_GENERIC(Scm_GenericInitialize, builtin_initialize, NULL);
141 SCM_DEFINE_GENERIC(Scm_GenericAddMethod, Scm_NoNextMethod, NULL);
142 SCM_DEFINE_GENERIC(Scm_GenericDeleteMethod, Scm_NoNextMethod, NULL);
143 SCM_DEFINE_GENERIC(Scm_GenericComputeCPL, Scm_NoNextMethod, NULL);
144 SCM_DEFINE_GENERIC(Scm_GenericComputeSlots, Scm_NoNextMethod, NULL);
145 SCM_DEFINE_GENERIC(Scm_GenericComputeGetNSet, Scm_NoNextMethod, NULL);
146 SCM_DEFINE_GENERIC(Scm_GenericComputeApplicableMethods, Scm_NoNextMethod, NULL);
147 SCM_DEFINE_GENERIC(Scm_GenericUpdateDirectMethod, Scm_NoNextMethod, NULL);
148 SCM_DEFINE_GENERIC(Scm_GenericApplyGeneric, Scm_NoNextMethod, NULL);
149 SCM_DEFINE_GENERIC(Scm_GenericMethodMoreSpecificP, Scm_NoNextMethod, NULL);
150 SCM_DEFINE_GENERIC(Scm_GenericSlotMissing, Scm_NoNextMethod, NULL);
151 SCM_DEFINE_GENERIC(Scm_GenericSlotUnbound, Scm_NoNextMethod, NULL);
152 SCM_DEFINE_GENERIC(Scm_GenericSlotRefUsingClass, Scm_NoNextMethod, NULL);
153 SCM_DEFINE_GENERIC(Scm_GenericSlotSetUsingClass, Scm_NoNextMethod, NULL);
154 SCM_DEFINE_GENERIC(Scm_GenericSlotBoundUsingClassP, Scm_NoNextMethod, NULL);
155 SCM_DEFINE_GENERIC(Scm_GenericObjectEqualP, fallback_compare, NULL);
156 SCM_DEFINE_GENERIC(Scm_GenericObjectCompare, fallback_compare, NULL);
157 SCM_DEFINE_GENERIC(Scm_GenericObjectHash, Scm_NoNextMethod, NULL);
158 SCM_DEFINE_GENERIC(Scm_GenericObjectApply, Scm_InvalidApply, NULL);
159 SCM_DEFINE_GENERIC(Scm_GenericObjectSetter, Scm_InvalidApply, NULL);
160 SCM_DEFINE_GENERIC(Scm_GenericChangeClass, Scm_NoNextMethod, NULL);
161
162 /* Some frequently-used pointers */
163 static ScmObj key_allocation = SCM_FALSE;
164 static ScmObj key_slot_accessor = SCM_FALSE;
165 static ScmObj key_builtin = SCM_FALSE;
166 static ScmObj key_name = SCM_FALSE;
167 static ScmObj key_lambda_list = SCM_FALSE;
168 static ScmObj key_method_locked = SCM_FALSE;
169 static ScmObj key_generic = SCM_FALSE;
170 static ScmObj key_specializers = SCM_FALSE;
171 static ScmObj key_body = SCM_FALSE;
172
173 /* TRANSIENT: Global flag to disable generic dispatcher. This is an escape
174 pod to fall back the default mechanism when we find a serious bug in
175 dispatch accelerator. Can be turned on with a environment variable. */
176 static int disable_generic_dispatcher = FALSE;
177
178 /* A global lock to serialize class redefinition. We need it since
179 class redefinition is not a local effect---it propagates through
180 its subclasses. So it is pretty difficult to guarantee consistency
181 if two threads enter the class redefinition, even if they redefine
182 different classes.
183 This lock works as a recursive lock. Scm_StartClassRedefinition
184 increments the lock count, and Scm_CommitClassRedefinition decrements it.
185 */
186 static struct {
187 ScmVM *owner; /* thread that grabs the lock, or NULL */
188 int count;
189 ScmInternalMutex mutex;
190 ScmInternalCond cv;
191 } class_redefinition_lock;
192
193 /* Imporant slots in <class> metaboject can be modified only when the
194 class is in 'malleable' state. Here's the check. */
195 #define CHECK_MALLEABLE(k, who) \
196 if (!SCM_CLASS_MALLEABLE_P(k)) { \
197 Scm_Error("%s: class is not malleable: %S", \
198 who, SCM_OBJ(k)); \
199 }
200
201 /*=====================================================================
202 * Auxiliary utilities
203 */
204
class_list_to_array(ScmObj classes,int len)205 static ScmClass **class_list_to_array(ScmObj classes, int len)
206 {
207 ScmObj cp;
208 ScmClass **v, **vp;
209 v = vp = SCM_NEW_ARRAY(ScmClass*, len+1);
210 SCM_FOR_EACH(cp, classes) {
211 if (!Scm_TypeP(SCM_CAR(cp), SCM_CLASS_CLASS))
212 Scm_Error("list of classes required, but found non-class object"
213 " %S in %S", SCM_CAR(cp), classes);
214 *vp++ = SCM_CLASS(SCM_CAR(cp));
215 }
216 *vp = NULL;
217 return v;
218 }
219
class_array_to_list(ScmClass ** array,int len)220 static ScmObj class_array_to_list(ScmClass **array, int len)
221 {
222 ScmObj h = SCM_NIL, t = SCM_NIL;
223 if (array) while (len-- > 0) SCM_APPEND1(h, t, SCM_OBJ(*array++));
224 return h;
225 }
226
class_array_to_names(ScmClass ** array,int len)227 static ScmObj class_array_to_names(ScmClass **array, int len)
228 {
229 ScmObj h = SCM_NIL, t = SCM_NIL;
230 for (int i=0; i<len; i++, array++) SCM_APPEND1(h, t, (*array)->name);
231 return h;
232 }
233
234 /* If the class name has brackets '<' and '>', as in Gauche's convention,
235 returns a string without those brackets. Otherwise returns the class
236 name in a string. This is used by some print method. Always returns
237 a string. */
Scm_ShortClassName(ScmClass * klass)238 ScmObj Scm_ShortClassName(ScmClass *klass)
239 {
240 ScmObj name = klass->name;
241
242 if (SCM_SYMBOLP(name)) {
243 const ScmStringBody *b = SCM_STRING_BODY(SCM_SYMBOL_NAME(name));
244 int size;
245 if (((size = SCM_STRING_BODY_SIZE(b)) > 2)
246 && SCM_STRING_BODY_START(b)[0] == '<'
247 && SCM_STRING_BODY_START(b)[size-1] == '>') {
248 return Scm_Substring(SCM_SYMBOL_NAME(name), 1,
249 SCM_STRING_BODY_LENGTH(b)-1, FALSE);
250 } else {
251 return SCM_OBJ(SCM_SYMBOL_NAME(name));
252 }
253 }
254 /* Fallback. At this moment we don't have unnamed classes,
255 so this is an ad hoc code. We may need better handling
256 (like write-to-string) later. */
257 return SCM_MAKE_STR("(unnamed class)");
258 }
259
260 #if GAUCHE_API_VERSION < 1000
261 /* TRANSIENT: For the backward compatibility. Remove this on 1.0. */
Scm__InternalClassName(ScmClass * klass)262 ScmObj Scm__InternalClassName(ScmClass *klass)
263 {
264 return Scm_ShortClassName(klass);
265 }
266 #endif /*GAUCHE_API_VERSION < 1000*/
267
268 /*=====================================================================
269 * Class metaobject
270 */
271
272 /* One of the design goals of Gauche object system is to make Scheme-defined
273 * class easily accessible from C code, and vice versa.
274 *
275 * Class is implemented in two layers; Scheme layer and C layer. The two
276 * layers work together to realize efficient MOP. In the following
277 * description, (FOOBAR baz) indicates Scheme call where FooBar(baz) indicates
278 * C call.
279 *
280 * Class instantiation is handled as follows.
281 *
282 * (MAKE class . initargs)
283 * If class is a descendant of <class> eventually this calls
284 * a method (MAKE <class> . initargs).
285 *
286 * (MAKE <class> . initargs)
287 * Defined in lib/gauche/object.scm. This calls
288 * (ALLOCATE-INSTANCE <class> initargs), then
289 * (INITIALIZE obj initargs).
290 *
291 * (ALLOCATE-INSTANCE <class> <list>)
292 * This is a C-defined method, and calls allocate() below.
293 *
294 * static ScmObj allocate(ScmNextMethod *, ScmObj *, int, void*)
295 * The default allocation dispatcher. This calls class->allocate().
296 * Some builtin function doesn't allow instantiation from Scheme and
297 * sets class->allocate() to NULL; an error is raised in such case.
298 *
299 * The class->allocate() function usually allocates the instance
300 * (Scm*** structure) and initializes its slots with reasonable values.
301 * For example, if class is <class>, class->allocate allocates
302 * ScmClass structure. If the class allows subclassing, class->allocate
303 * must allocate extra storage for as many slots as class->numInstanceSlots.
304 *
305 * The allocated and set up structure is returned as ScmObj, which
306 * eventually retured by (ALLOCATE-INSTANCE ...) method, and passed to
307 * (INITIALIZE obj initargs) structure.
308 *
309 * (INITIALIZE obj initargs)
310 * In most cases this method is defined in Scheme, if ever defined.
311 * The Scheme method does whatever it want, but it must call
312 * (NEXT-METHOD) in it, and it eventually calls the C-defined fallback
313 * method buildin_initialize().
314 *
315 * ScmObj builtin_initialize(ScmObj *, int, ScmGeneric*)
316 * This function traverses the slot accessors, and if the slot has
317 * not been initialized, initialize it as specified in initargs or
318 * slot options.
319 */
320
321 /* Defining builtin class in C.
322 *
323 * Defining classes in C is divided in two steps. First, you have to
324 * define the static part of the class; it is done by one of the
325 * SCM_DEFINE_***_CLASS macros provided in gauche.h, and it defines
326 * static instance of ScmClass structure. Then, in the initialization
327 * phase, you have to call Scm_InitStaticClass to initialize the dynamic
328 * part of the structure.
329 *
330 * void Scm_InitStaticClass(ScmClass *klass, const char *name,
331 * ScmModule *mod,
332 * ScmClassStaticSlotSpec *slots,
333 * int flags)
334 *
335 * This function fills the ScmClass structure that can't be
336 * defined statically, and inserts the binding from the named
337 * symbol to the class object in the specified module.
338 * The 'flags' arg is reserved for future use, and must be 0
339 * for the time being.
340 *
341 * See comments in gauche.h (around "Class categories") about
342 * the categories of C-defined classes.
343 */
344
345 /*
346 * Built-in protocols
347 *
348 * ScmObj klass->allocate(ScmClass *klass, ScmObj initargs)
349 * Called at the bottom of the chain of allocate-instance method.
350 * Besides allocating the required space, it must initialize
351 * members of the C-specific part of the instance, including SCM_HEADER.
352 * This protocol can be NULL for core base classes; if so, attempt
353 * to "make" such class reports an error.
354 *
355 * void klass->print(ScmObj obj, ScmPort *sink, ScmWriteContext *ctx)
356 * OBJ is an instance of klass (you can safely assume it). This
357 * function should print OBJ into SINK. See write.c about the
358 * details of the context.
359 * If this function pointer is not set, a default print method
360 * is used.
361 *
362 * int klass->compare(ScmObj x, ScmObj y, int equalp)
363 * X and Y are instances of klass. If equalp is FALSE,
364 * return -1, 0, or 1, when X < Y, X == Y or X > Y, respectively.
365 * In case if klass is not orderable, it can signal an error.
366 * If equalp is TRUE, just test the equality: return -1 if X != Y
367 * and 0 if X == Y.
368 *
369 * int klass->serialize(ScmObj obj, ScmPort *sink, ScmObj table)
370 * OBJ is an instance of klass. This method is only called when OBJ
371 * has not been output in the current serializing session.
372 */
373
374 /* A note on the 'data' member of ScmClass
375 *
376 * It can be used to hang an opaque data to a specific class. So far,
377 * we use it only for <simple> class mechanism. Its use is highly
378 * controversial; I mean, The Right Thing is to define a metaclass
379 * which defines an extra member, and allocate <simple> class as an
380 * instance of it. However, creating metaclass from C is messy now,
381 * so I chose to hack. In future we may have a nice C API to create
382 * a metaclass, and then we may remove this 'data' member. So DO NOT
383 * RELY ON ITS EXISTENCE.
384 */
385
386 /*
387 * Class metaobject protocol implementation
388 */
389
390 /* Allocate class structure. klass is a metaclass. */
class_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)391 static ScmObj class_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
392 {
393 ScmClass *instance = SCM_NEW_INSTANCE(ScmClass, klass);
394 instance->allocate = NULL; /* will be set when CPL is set */
395 instance->print = NULL;
396 instance->compare = Scm_ObjectCompare;
397 instance->hash = NULL;
398 instance->cpa = NULL;
399 instance->numInstanceSlots = 0; /* will be adjusted in class init */
400 instance->coreSize = 0; /* will be set when CPL is set */
401 instance->flags = SCM_CLASS_SCHEME|SCM_CLASS_MALLEABLE; /* default */
402 instance->name = SCM_FALSE;
403 instance->directSupers = SCM_NIL;
404 instance->accessors = SCM_NIL;
405 instance->cpl = SCM_NIL;
406 instance->directSlots = SCM_NIL;
407 instance->slots = SCM_NIL;
408 instance->directSubclasses = SCM_NIL;
409 instance->directMethods = SCM_NIL;
410 instance->initargs = SCM_NIL;
411 instance->modules = SCM_NIL;
412 instance->redefined = SCM_FALSE;
413 (void)SCM_INTERNAL_MUTEX_INIT(instance->mutex);
414 (void)SCM_INTERNAL_COND_INIT(instance->cv);
415 instance->data = NULL; /* see the above note on the 'data' member */
416 return SCM_OBJ(instance);
417 }
418
class_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)419 static void class_print(ScmObj obj, ScmPort *port,
420 ScmWriteContext *ctx SCM_UNUSED)
421 {
422 Scm_Printf(port, "#<class %A%s>",
423 SCM_CLASS(obj)->name,
424 (SCM_FALSEP(SCM_CLASS(obj)->redefined)? "" : " (redefined)"));
425 }
426
427 /*
428 * (make <class> ...) - default method to make a class instance.
429 */
430
431 /* defined in Scheme */
432
433 /*
434 * (allocate-instance <class> initargs)
435 */
Scm_Allocate(ScmClass * c,ScmObj initargs)436 ScmObj Scm_Allocate(ScmClass *c, ScmObj initargs)
437 {
438 if (c->allocate == NULL) {
439 Scm_Error("built-in class can't be allocated via allocate-instance: %S",
440 SCM_OBJ(c));
441 }
442 return c->allocate(c, initargs);
443 }
444
allocate(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * d SCM_UNUSED)445 static ScmObj allocate(ScmNextMethod *nm SCM_UNUSED,
446 ScmObj *argv,
447 int argc SCM_UNUSED,
448 void *d SCM_UNUSED)
449 {
450 return Scm_Allocate(SCM_CLASS(argv[0]), argv[1]);
451 }
452
453 static ScmClass *class_allocate_SPEC[] = {
454 SCM_CLASS_STATIC_PTR(Scm_ClassClass), SCM_CLASS_STATIC_PTR(Scm_ListClass)
455 };
456 static SCM_DEFINE_METHOD(class_allocate_rec, &Scm_GenericAllocate,
457 2, 0, class_allocate_SPEC, allocate, NULL);
458
459 /*
460 * (compute-cpl <class>)
461 */
class_compute_cpl(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * d SCM_UNUSED)462 static ScmObj class_compute_cpl(ScmNextMethod *nm SCM_UNUSED,
463 ScmObj *argv,
464 int argc SCM_UNUSED,
465 void *d SCM_UNUSED)
466 {
467 ScmClass *c = SCM_CLASS(argv[0]);
468 return Scm_ComputeCPL(c);
469 }
470
471 static ScmClass *class_compute_cpl_SPEC[] = {
472 SCM_CLASS_STATIC_PTR(Scm_ClassClass)
473 };
474 static SCM_DEFINE_METHOD(class_compute_cpl_rec, &Scm_GenericComputeCPL,
475 1, 0, class_compute_cpl_SPEC,
476 class_compute_cpl, NULL);
477
478 /*
479 * (class-of obj)
480 */
481
Scm_ClassOf(ScmObj obj)482 ScmClass *Scm_ClassOf(ScmObj obj)
483 {
484 if (!SCM_PTRP(obj)) {
485 if (SCM_TRUEP(obj) || SCM_FALSEP(obj)) return SCM_CLASS_BOOL;
486 if (SCM_NULLP(obj)) return SCM_CLASS_NULL;
487 if (SCM_CHARP(obj)) return SCM_CLASS_CHAR;
488 if (SCM_INTP(obj)) return SCM_CLASS_INTEGER;
489 if (SCM_EOFP(obj)) return SCM_CLASS_EOF_OBJECT;
490 if (SCM_UNDEFINEDP(obj)) return SCM_CLASS_UNDEFINED_OBJECT;
491 if (SCM_STRING_CURSOR_SMALL_P(obj)) return SCM_CLASS_STRING_CURSOR;
492 else return SCM_CLASS_UNKNOWN;
493 }
494 if (SCM_FLONUMP(obj)) return SCM_CLASS_REAL;
495 /* check lazy pair first, so that we won't trigger forcing. */
496 if (SCM_LAZY_PAIR_P(obj)) return SCM_CLASS_PAIR;
497 if (SCM_PAIRP(obj)) {
498 ScmExtendedPairDescriptor *d = Scm__GetExtendedPairDescriptor(obj);
499 if (d) {
500 return d->klass;
501 } else {
502 return SCM_CLASS_PAIR;
503 }
504 }
505
506 return SCM_CLASS_OF(obj);
507 }
508
509 /* Returns the pointer of the first base class found in the given
510 class's CPA. If the class is pure abstract or builtin, NULL is
511 returned. */
Scm_BaseClassOf(ScmClass * klass)512 ScmClass *Scm_BaseClassOf(ScmClass *klass)
513 {
514 ScmClass **cp = klass->cpa;
515 ScmClass *k;
516 while ((k = *cp++) != NULL) {
517 if (SCM_CLASS_CATEGORY(k) == SCM_CLASS_BASE) return k;
518 }
519 return NULL;
520 }
521
522 /*
523 * (class-of obj class)
524 * - if obj's class is redefined, first updates obj.
525 */
class_of_cc(ScmObj result,void ** data SCM_UNUSED)526 ScmObj class_of_cc(ScmObj result, void **data SCM_UNUSED)
527 {
528 return Scm_VMClassOf(result);
529 }
530
Scm_VMClassOf(ScmObj obj)531 ScmObj Scm_VMClassOf(ScmObj obj)
532 {
533 ScmClass *k = Scm_ClassOf(obj);
534 if (!SCM_FALSEP(k->redefined)) {
535 Scm_VMPushCC(class_of_cc, NULL, 0);
536 return instance_class_redefinition(obj, k);
537 }
538 return SCM_OBJ(k);
539 }
540
541 /*
542 * (is-a? obj class)
543 * - if obj's class is redefined, first updates obj.
544 */
is_a_cc(ScmObj result SCM_UNUSED,void ** data)545 ScmObj is_a_cc(ScmObj result SCM_UNUSED, void **data)
546 {
547 return Scm_VMIsA(SCM_OBJ(data[0]), SCM_CLASS(data[1]));
548 }
549
Scm_VMIsA(ScmObj obj,ScmClass * klass)550 ScmObj Scm_VMIsA(ScmObj obj, ScmClass *klass)
551 {
552 ScmClass *k = Scm_ClassOf(obj);
553 if (!SCM_FALSEP(k->redefined)) {
554 void *data[2];
555 data[0] = obj;
556 data[1] = klass;
557 Scm_VMPushCC(is_a_cc, data, 2);
558 return instance_class_redefinition(obj, k);
559 }
560 return SCM_MAKE_BOOL(Scm_TypeP(obj, klass));
561 }
562
563 /*
564 * Setting/resetting SCM_CLASS_MALLEABLE flag
565 */
Scm_ClassMalleableSet(ScmClass * klass,int flag)566 void Scm_ClassMalleableSet(ScmClass *klass, int flag)
567 {
568 if (SCM_CLASS_CATEGORY(klass) != SCM_CLASS_SCHEME) {
569 Scm_Error("You cannot modify malleable flag of a class not defined in Scheme: %S", SCM_OBJ(klass));
570 }
571 if (flag) {
572 klass->flags |= SCM_CLASS_MALLEABLE;
573 } else {
574 klass->flags &= ~SCM_CLASS_MALLEABLE;
575 }
576 }
577
578 /*--------------------------------------------------------------
579 * Metainformation accessors
580 */
581
582 /* TODO: disable modification of system-builtin classes */
583
class_name(ScmClass * klass)584 static ScmObj class_name(ScmClass *klass)
585 {
586 return klass->name;
587 }
588
class_name_set(ScmClass * klass,ScmObj val)589 static void class_name_set(ScmClass *klass, ScmObj val)
590 {
591 CHECK_MALLEABLE(klass, "(setter name)");
592 klass->name = val;
593 }
594
class_cpl(ScmClass * klass)595 static ScmObj class_cpl(ScmClass *klass)
596 {
597 return klass->cpl;
598 }
599
600 /* Subroutine for class_cpl_set. Scans KLASS's CPL and find out the
601 suitable allocator function, C-struct core size, and some flags.
602 If KLASS inherits more than one C-defined classes (BASEs), they must
603 form a single inheritance chain. */
find_core_allocator(ScmClass * klass)604 static void find_core_allocator(ScmClass *klass)
605 {
606 ScmClass *b = NULL; /* the base class klass gets the allocate func */
607 int object_inherited = FALSE;
608
609 klass->allocate = NULL;
610 for (ScmClass **p = klass->cpa; *p; p++) {
611 if (SCM_CLASS_CATEGORY(*p) == SCM_CLASS_BUILTIN) {
612 Scm_Error("class '%S' attempted to inherit from a builtin class "
613 "%S; you cannot subclass a builtin class.",
614 klass->name, *p);
615 }
616
617 if ((*p)->allocate == instance_allocate) {
618 /* Check if we certainly inherited <object> */
619 object_inherited = TRUE;
620 continue;
621 }
622
623 if ((*p)->flags & SCM_CLASS_APPLICABLE) {
624 klass->flags |= SCM_CLASS_APPLICABLE;
625 }
626
627 if (b
628 && SCM_CLASS_CATEGORY(*p) == SCM_CLASS_BASE
629 && b->allocate != (*p)->allocate) {
630 /* found different C-defined class. check to see if (*p) is
631 superclass of b. If not, the single-inheritance rule is
632 violated. */
633 ScmClass **bp = b->cpa;
634 for (; *bp; bp++) {
635 if (*bp == *p) break;
636 }
637 if (!*bp) {
638 Scm_Error("class '%S' attempted to inherit multiple C-defined "
639 "base class (%S and %S) which are not in a "
640 "superclass-subclass relathionship.",
641 klass->name, b, *p);
642 }
643 continue;
644 }
645 if (!b) {
646 /* Here we found the closest C-base class. Get the allocator
647 from it. */
648 b = *p;
649 klass->allocate = b->allocate;
650 klass->coreSize = b->coreSize;
651 }
652 }
653
654 if (!object_inherited) {
655 Scm_Error("class %S's precedence list doesn't have a base class: %S",
656 klass->name, klass->cpl);
657 }
658 if (!klass->allocate) {
659 klass->allocate = instance_allocate;
660 klass->coreSize = sizeof(ScmInstance);
661 }
662 }
663
class_cpl_set(ScmClass * klass,ScmObj val)664 static void class_cpl_set(ScmClass *klass, ScmObj val)
665 {
666 CHECK_MALLEABLE(klass, "(setter cpl)");
667
668 /* We make sure things are consistent. */
669 if (!SCM_PAIRP(val)) goto err;
670 /* check if the CPL begins with the class itself. */
671 if (SCM_CAR(val) != SCM_OBJ(klass)) goto err;
672
673 /* set up the cpa */
674 ScmObj cp = SCM_CDR(val);
675 int len = Scm_Length(cp);
676 if (len < 0) goto err;
677 klass->cpa = class_list_to_array(cp, len);
678 for (int i=0; i<len; i++) {
679 /* sanity check */
680 if (klass->cpa[i] == SCM_CLASS_BOTTOM) goto err;
681 }
682 if (klass->cpa[len-1] != SCM_CLASS_TOP) goto err;
683 klass->cpl = Scm_CopyList(val);
684 /* find correct allocation method */
685 find_core_allocator(klass);
686 return;
687 err:
688 Scm_Error("class precedence list must be a proper list of class "
689 "metaobject, beginning from the class itself owing the list, "
690 "and ending by the class <top>, and must not include <bottom>: "
691 "%S", val);
692 }
693
class_direct_supers(ScmClass * klass)694 static ScmObj class_direct_supers(ScmClass *klass)
695 {
696 return klass->directSupers;
697 }
698
class_direct_supers_set(ScmClass * klass,ScmObj val)699 static void class_direct_supers_set(ScmClass *klass, ScmObj val)
700 {
701 CHECK_MALLEABLE(klass, "(setter direct-supers)")
702 ScmObj vp;
703 SCM_FOR_EACH(vp, val) {
704 if (!Scm_TypeP(SCM_CAR(vp), SCM_CLASS_CLASS))
705 Scm_Error("non-class object found in direct superclass list: %S",
706 SCM_CAR(vp));
707 }
708 klass->directSupers = val;
709 }
710
class_direct_slots(ScmClass * klass)711 static ScmObj class_direct_slots(ScmClass *klass)
712 {
713 return klass->directSlots;
714 }
715
class_direct_slots_set(ScmClass * klass,ScmObj val)716 static void class_direct_slots_set(ScmClass *klass, ScmObj val)
717 {
718 CHECK_MALLEABLE(klass, "(setter direct-slots)");
719 ScmObj vp;
720 SCM_FOR_EACH(vp, val) {
721 if (!SCM_PAIRP(SCM_CAR(vp)))
722 Scm_Error("bad slot spec found in direct slot list: %S",
723 SCM_CAR(vp));
724 }
725 klass->directSlots = val;
726 }
727
class_slots_ref(ScmClass * klass)728 static ScmObj class_slots_ref(ScmClass *klass)
729 {
730 return klass->slots;
731 }
732
class_slots_set(ScmClass * klass,ScmObj val)733 static void class_slots_set(ScmClass *klass, ScmObj val)
734 {
735 CHECK_MALLEABLE(klass, "(setter slots)");
736 ScmObj vp;
737 SCM_FOR_EACH(vp, val) {
738 if (!SCM_PAIRP(SCM_CAR(vp)))
739 Scm_Error("bad slot spec found in slot list: %S",
740 SCM_CAR(vp));
741 }
742 klass->slots = val;
743 }
744
class_accessors(ScmClass * klass)745 static ScmObj class_accessors(ScmClass *klass)
746 {
747 return klass->accessors;
748 }
749
class_accessors_set(ScmClass * klass,ScmObj val)750 static void class_accessors_set(ScmClass *klass, ScmObj val)
751 {
752 CHECK_MALLEABLE(klass, "(setter accessors)");
753 ScmObj vp;
754 SCM_FOR_EACH(vp, val) {
755 if (!SCM_PAIRP(SCM_CAR(vp))
756 || !SCM_SLOT_ACCESSOR_P(SCM_CDAR(vp)))
757 Scm_Error("slot accessor list must be an assoc-list of slot name and slot accessor object, but found: %S",
758 SCM_CAR(vp));
759 }
760 klass->accessors = val;
761 }
762
class_numislots(ScmClass * klass)763 static ScmObj class_numislots(ScmClass *klass)
764 {
765 return Scm_MakeInteger(klass->numInstanceSlots);
766 }
767
class_numislots_set(ScmClass * klass,ScmObj snf)768 static void class_numislots_set(ScmClass *klass, ScmObj snf)
769 {
770 CHECK_MALLEABLE(klass, "(setter num-instance-slots)");
771 int nf = 0;
772 if (!SCM_INTP(snf) || (nf = SCM_INT_VALUE(snf)) < 0) {
773 Scm_Error("invalid argument: %S", snf);
774 /*NOTREACHED*/
775 }
776 klass->numInstanceSlots = nf;
777 }
778
class_category(ScmClass * klass)779 static ScmObj class_category(ScmClass *klass)
780 {
781 switch (SCM_CLASS_CATEGORY(klass)) {
782 case SCM_CLASS_BUILTIN: return SCM_SYM_BUILTIN;
783 case SCM_CLASS_ABSTRACT: return SCM_SYM_ABSTRACT;
784 case SCM_CLASS_BASE: return SCM_SYM_BASE;
785 default: return SCM_SYM_SCHEME;
786 }
787 }
788
class_initargs(ScmClass * klass)789 static ScmObj class_initargs(ScmClass *klass)
790 {
791 return klass->initargs;
792 }
793
class_initargs_set(ScmClass * klass,ScmObj val)794 static void class_initargs_set(ScmClass *klass, ScmObj val)
795 {
796 CHECK_MALLEABLE(klass, "(setter initargs)");
797 int len = Scm_Length(val);
798 if (len < 0 || len%2 != 0) {
799 Scm_Error("class-initargs must be a list of even number of elements, but got %S", val);
800 }
801 klass->initargs = val;
802 }
803
class_defined_modules(ScmClass * klass)804 static ScmObj class_defined_modules(ScmClass *klass)
805 {
806 return klass->modules;
807 }
808
class_defined_modules_set(ScmClass * klass,ScmObj val)809 static void class_defined_modules_set(ScmClass *klass, ScmObj val)
810 {
811 CHECK_MALLEABLE(klass, "(setter defined-modules)");
812 ScmObj cp;
813 SCM_FOR_EACH(cp, val) {
814 if (!SCM_MODULEP(SCM_CAR(cp))) goto err;
815 }
816 if (!SCM_NULLP(cp)) goto err;
817 klass->modules = val;
818 return;
819 err:
820 Scm_Error("list of modules required, bot got %S", val);
821 }
822
823 /*
824 * The following slots should only be modified by a special MT-safe procedures.
825 */
class_direct_subclasses(ScmClass * klass)826 static ScmObj class_direct_subclasses(ScmClass *klass)
827 {
828 return klass->directSubclasses;
829 }
830
class_direct_methods(ScmClass * klass)831 static ScmObj class_direct_methods(ScmClass *klass)
832 {
833 return klass->directMethods;
834 }
835
class_redefined(ScmClass * klass)836 static ScmObj class_redefined(ScmClass *klass)
837 {
838 int abandoned = FALSE;
839
840 /* If this class is being redefined by other thread, you should wait */
841 (void)SCM_INTERNAL_MUTEX_LOCK(klass->mutex);
842 while (SCM_VMP(klass->redefined)) {
843 if (SCM_VM(klass->redefined)->state == SCM_VM_TERMINATED) {
844 /* TODO: this means redefinition of klass has been abandoned,
845 so the state of klass may be inconsistent. Should we do
846 something to it? */
847 abandoned = TRUE;
848 klass->redefined = SCM_FALSE;
849 } else {
850 (void)SCM_INTERNAL_COND_WAIT(klass->cv, klass->mutex);
851 }
852 }
853 ScmObj r = klass->redefined;
854 (void)SCM_INTERNAL_MUTEX_UNLOCK(klass->mutex);
855 if (abandoned) {
856 Scm_Warn("redefinition of class %S has been abandoned", klass);
857 }
858 return r;
859 }
860
861 /*--------------------------------------------------------------
862 * Implicit metaclass
863 */
864 /* This function does the equivalent to
865 * (make <class> :name NAME :supers (list <class>))
866 */
867
make_implicit_meta(const char * name,ScmClass ** cpa,ScmModule * mod)868 static ScmClass *make_implicit_meta(const char *name,
869 ScmClass **cpa,
870 ScmModule *mod)
871 {
872 ScmClass *meta = (ScmClass*)class_allocate(SCM_CLASS_CLASS, SCM_NIL);
873 ScmObj s = SCM_INTERN(name);
874 static ScmClass *metacpa[] = { SCM_CLASS_CLASS, SCM_CLASS_OBJECT, SCM_CLASS_TOP, NULL };
875 ScmClass **metas = metacpa;
876
877 /* check to see if parent class has also metaclass, and if so,
878 adds it to the CPA. We know all the builtin classes use
879 single inheritance, so the CPA calculation should be straightforward.
880 Note that this assumes the parent classes are already initialized.
881 */
882 {
883 ScmClass **parent;
884 int numExtraMetas = 0, i;
885 for (parent = cpa; *parent; parent++) {
886 if (SCM_CLASS_OF(*parent) != SCM_CLASS_CLASS) {
887 numExtraMetas++;
888 }
889 }
890 if (numExtraMetas) {
891 metas = SCM_NEW_ARRAY(ScmClass*, numExtraMetas+4);
892 for (i = 0, parent = cpa; *parent; parent++) {
893 if (SCM_CLASS_OF(*parent) != SCM_CLASS_CLASS) {
894 metas[i++] = SCM_CLASS_OF(*parent);
895 }
896 }
897 metas[i++] = SCM_CLASS_CLASS;
898 metas[i++] = SCM_CLASS_OBJECT;
899 metas[i++] = SCM_CLASS_TOP;
900 metas[i] = NULL;
901 }
902 }
903
904 meta->name = s;
905 meta->allocate = class_allocate;
906 meta->print = class_print;
907 meta->cpa = metas;
908 meta->flags = SCM_CLASS_ABSTRACT;
909 initialize_builtin_cpl(meta, SCM_FALSE);
910 Scm_Define(mod, SCM_SYMBOL(s), SCM_OBJ(meta));
911 meta->slots = Scm_ClassClass.slots;
912 meta->accessors = Scm_ClassClass.accessors;
913 return meta;
914 }
915
916 /*--------------------------------------------------------------
917 * External interface
918 */
919
Scm_SubtypeP(ScmClass * sub,ScmClass * type)920 int Scm_SubtypeP(ScmClass *sub, ScmClass *type)
921 {
922 if (sub == type) return TRUE;
923 if (sub == SCM_CLASS_BOTTOM) return TRUE;
924
925 ScmClass **p = sub->cpa;
926 while (*p) {
927 if (*p++ == type) return TRUE;
928 }
929 return FALSE;
930 }
931
Scm_TypeP(ScmObj obj,ScmClass * type)932 int Scm_TypeP(ScmObj obj, ScmClass *type)
933 {
934 return Scm_SubtypeP(Scm_ClassOf(obj), type);
935 }
936
937 /*
938 * compute-cpl
939 */
Scm_ComputeCPL(ScmClass * klass)940 ScmObj Scm_ComputeCPL(ScmClass *klass)
941 {
942 ScmObj seqh = SCM_NIL, seqt = SCM_NIL;
943
944 /* a trick to ensure we have <object> <top> at the end of CPL. */
945 ScmObj ds = Scm_Delete(SCM_OBJ(SCM_CLASS_OBJECT), klass->directSupers,
946 SCM_CMP_EQ);
947 ds = Scm_Delete(SCM_OBJ(SCM_CLASS_TOP), ds, SCM_CMP_EQ);
948 ds = Scm_Append2(ds, SCM_LIST1(SCM_OBJ(SCM_CLASS_OBJECT)));
949
950 ScmObj dp;
951 SCM_FOR_EACH(dp, klass->directSupers) {
952 if (!Scm_TypeP(SCM_CAR(dp), SCM_CLASS_CLASS))
953 Scm_Error("non-class found in direct superclass list: %S",
954 klass->directSupers);
955 if (SCM_CAR(dp) == SCM_OBJ(SCM_CLASS_OBJECT)
956 || SCM_CAR(dp) == SCM_OBJ(SCM_CLASS_TOP))
957 continue;
958 SCM_APPEND1(seqh, seqt, SCM_CLASS(SCM_CAR(dp))->cpl);
959 }
960 SCM_APPEND1(seqh, seqt, Scm_ObjectClass.cpl);
961
962 SCM_APPEND1(seqh, seqt, ds);
963
964 ScmObj result = Scm_MonotonicMerge1(seqh);
965 if (SCM_FALSEP(result))
966 Scm_Error("discrepancy found in class precedence lists of the superclasses: %S",
967 klass->directSupers);
968 return Scm_Cons(SCM_OBJ(klass), result);
969 }
970
971 /*
972 * Internal procedures for class redefinition
973 */
974
975 /* global lock manipulation */
lock_class_redefinition(ScmVM * vm)976 static void lock_class_redefinition(ScmVM *vm)
977 {
978 ScmVM *stolefrom = NULL;
979 if (class_redefinition_lock.owner == vm) {
980 class_redefinition_lock.count++;
981 } else {
982 (void)SCM_INTERNAL_MUTEX_LOCK(class_redefinition_lock.mutex);
983 while (class_redefinition_lock.owner != vm) {
984 if (class_redefinition_lock.owner == NULL) {
985 class_redefinition_lock.owner = vm;
986 } else if (class_redefinition_lock.owner->state
987 == SCM_VM_TERMINATED) {
988 stolefrom = class_redefinition_lock.owner;
989 class_redefinition_lock.owner = vm;
990 } else {
991 (void)SCM_INTERNAL_COND_WAIT(class_redefinition_lock.cv,
992 class_redefinition_lock.mutex);
993 }
994 }
995 (void)SCM_INTERNAL_MUTEX_UNLOCK(class_redefinition_lock.mutex);
996 if (stolefrom) {
997 Scm_Warn("a thread holding class redefinition lock has been terminated: %S", stolefrom);
998 }
999 class_redefinition_lock.count = 1;
1000 }
1001 }
1002
unlock_class_redefinition(ScmVM * vm)1003 static void unlock_class_redefinition(ScmVM *vm)
1004 {
1005 if (class_redefinition_lock.owner != vm) return;
1006 if (--class_redefinition_lock.count <= 0) {
1007 (void)SCM_INTERNAL_MUTEX_LOCK(class_redefinition_lock.mutex);
1008 (void)SCM_INTERNAL_COND_BROADCAST(class_redefinition_lock.cv);
1009 class_redefinition_lock.owner = NULL;
1010 (void)SCM_INTERNAL_MUTEX_UNLOCK(class_redefinition_lock.mutex);
1011 }
1012 }
1013
1014 /* %start-class-redefinition klass */
Scm_StartClassRedefinition(ScmClass * klass)1015 void Scm_StartClassRedefinition(ScmClass *klass)
1016 {
1017 if (SCM_CLASS_CATEGORY(klass) != SCM_CLASS_SCHEME) {
1018 Scm_Error("cannot redefine class %S, which is not a Scheme-defined class", klass);
1019 }
1020 ScmVM *vm = Scm_VM();
1021
1022 /* First, acquire the global lock. */
1023 lock_class_redefinition(vm);
1024
1025 /* Mark this class to be redefined. */
1026 int success = FALSE;
1027 (void)SCM_INTERNAL_MUTEX_LOCK(klass->mutex);
1028 if (SCM_FALSEP(klass->redefined)) {
1029 klass->redefined = SCM_OBJ(vm);
1030 success = TRUE;
1031 }
1032 (void)SCM_INTERNAL_MUTEX_UNLOCK(klass->mutex);
1033
1034 if (!success) {
1035 unlock_class_redefinition(vm);
1036 Scm_Error("class %S seems abandoned during class redefinition", klass);
1037 }
1038
1039 /* Allow modification of important slots */
1040 Scm_ClassMalleableSet(klass, TRUE);
1041 }
1042
1043 /* %commit-class-redefinition klass newklass */
Scm_CommitClassRedefinition(ScmClass * klass,ScmObj newklass)1044 void Scm_CommitClassRedefinition(ScmClass *klass, ScmObj newklass)
1045 {
1046 if (SCM_CLASS_CATEGORY(klass) != SCM_CLASS_SCHEME) return;
1047 if (!SCM_FALSEP(newklass)&&!SCM_CLASSP(newklass)) {
1048 Scm_Error("class or #f required, but got %S", newklass);
1049 }
1050
1051 ScmVM *vm = Scm_VM();
1052
1053 /* Release the lock of the class.
1054 We execute this regardless of class_redefinition_lock.owner.
1055 Theoretically, this procedure shouldn't be called unless the thread
1056 owns global class_redefinition_lock. However, we don't require it,
1057 so that this procedure can be used for a program to exit from
1058 obscure state. */
1059 (void)SCM_INTERNAL_MUTEX_LOCK(klass->mutex);
1060 if (SCM_EQ(klass->redefined, SCM_OBJ(vm))) {
1061 Scm_ClassMalleableSet(klass, FALSE); /* disable modification */
1062 klass->redefined = newklass;
1063 (void)SCM_INTERNAL_COND_BROADCAST(klass->cv);
1064 }
1065 (void)SCM_INTERNAL_MUTEX_UNLOCK(klass->mutex);
1066
1067 /* Decrement the recursive global lock. */
1068 unlock_class_redefinition(vm);
1069 }
1070
1071 /* %check-class-binding name module
1072 See the bindings of name in module, and iff it is bound to a class,
1073 returns the class; otherwise returns #f. */
Scm_CheckClassBinding(ScmObj name,ScmModule * module)1074 ScmObj Scm_CheckClassBinding(ScmObj name, ScmModule *module)
1075 {
1076 if (!SCM_SYMBOLP(name)) return SCM_FALSE;
1077 ScmObj v = Scm_GlobalVariableRef(module, SCM_SYMBOL(name), 0);
1078 return SCM_CLASSP(v) ? v : SCM_FALSE;
1079 }
1080
1081 /* %replace-class-binding! klass newklass
1082 Called when a descendant of klass is redefined. If klass has a global
1083 binding, replace it to newklass. */
Scm_ReplaceClassBinding(ScmClass * klass,ScmClass * newklass)1084 void Scm_ReplaceClassBinding(ScmClass *klass, ScmClass *newklass)
1085 {
1086 if (!SCM_SYMBOLP(klass->name)) return;
1087 ScmObj cp;
1088 SCM_FOR_EACH(cp, klass->modules) {
1089 if (!SCM_MODULEP(SCM_CAR(cp))) continue;
1090 Scm_Define(SCM_MODULE(SCM_CAR(cp)),
1091 SCM_SYMBOL(klass->name),
1092 SCM_OBJ(newklass));
1093 }
1094 }
1095
1096 /* %add-direct-subclass! super sub */
Scm_AddDirectSubclass(ScmClass * super,ScmClass * sub)1097 void Scm_AddDirectSubclass(ScmClass *super, ScmClass *sub)
1098 {
1099 if (SCM_CLASS_CATEGORY(super) == SCM_CLASS_SCHEME) {
1100 ScmObj p = Scm_Cons(SCM_OBJ(sub), SCM_NIL);
1101 (void)SCM_INTERNAL_MUTEX_LOCK(super->mutex);
1102 /* avoid duplication */
1103 if (SCM_FALSEP(Scm_Memq(super->directSubclasses, SCM_OBJ(sub)))) {
1104 SCM_SET_CDR_UNCHECKED(p, super->directSubclasses);
1105 super->directSubclasses = p;
1106 }
1107 (void)SCM_INTERNAL_MUTEX_UNLOCK(super->mutex);
1108 }
1109 }
1110
1111 /* %delete-direct-subclass! super sub */
Scm_DeleteDirectSubclass(ScmClass * super,ScmClass * sub)1112 void Scm_DeleteDirectSubclass(ScmClass *super, ScmClass *sub)
1113 {
1114 if (SCM_CLASS_CATEGORY(super) == SCM_CLASS_SCHEME) {
1115 (void)SCM_INTERNAL_MUTEX_LOCK(super->mutex);
1116 super->directSubclasses =
1117 Scm_DeleteX(SCM_OBJ(sub), super->directSubclasses, SCM_CMP_EQ);
1118 (void)SCM_INTERNAL_MUTEX_UNLOCK(super->mutex);
1119 }
1120 }
1121
1122 /* %add-direct-method! super method
1123 method can be added or deleted freely, so we don't check malleablility. */
Scm_AddDirectMethod(ScmClass * super,ScmMethod * m)1124 void Scm_AddDirectMethod(ScmClass *super, ScmMethod *m)
1125 {
1126 if (SCM_CLASS_CATEGORY(super) == SCM_CLASS_SCHEME) {
1127 ScmObj p = Scm_Cons(SCM_OBJ(m), SCM_NIL);
1128 (void)SCM_INTERNAL_MUTEX_LOCK(super->mutex);
1129 /* avoid duplication */
1130 if (SCM_FALSEP(Scm_Memq(super->directMethods, SCM_OBJ(m)))) {
1131 SCM_SET_CDR_UNCHECKED(p, super->directMethods);
1132 super->directMethods = p;
1133 }
1134 (void)SCM_INTERNAL_MUTEX_UNLOCK(super->mutex);
1135 }
1136 }
1137
1138 /* %delete-direct-method! super method
1139 method can be added or deleted freely, so we don't check malleablility. */
Scm_DeleteDirectMethod(ScmClass * super,ScmMethod * m)1140 void Scm_DeleteDirectMethod(ScmClass *super, ScmMethod *m)
1141 {
1142 if (SCM_CLASS_CATEGORY(super) == SCM_CLASS_SCHEME) {
1143 (void)SCM_INTERNAL_MUTEX_LOCK(super->mutex);
1144 super->directMethods =
1145 Scm_DeleteX(SCM_OBJ(m), super->directMethods, SCM_CMP_EQ);
1146 (void)SCM_INTERNAL_MUTEX_UNLOCK(super->mutex);
1147 }
1148 }
1149
1150 /* %transplant-instance! src dst */
1151 /* Copies the contents of the core structure pointed by src over
1152 the contents of dst. The contents of dst is destroyed. This
1153 astonishingly dangerous operation has to be done at the last stage
1154 of change-class, in order to keep the identity of the instance
1155 being updated.
1156
1157 Note that this procedure doesn't overwrite the Scheme slot
1158 vectors. */
Scm_TransplantInstance(ScmObj src,ScmObj dst)1159 void Scm_TransplantInstance(ScmObj src, ScmObj dst)
1160 {
1161 ScmClass *srcklass = Scm_ClassOf(src);
1162 ScmClass *dstklass = Scm_ClassOf(dst);
1163 ScmClass *base;
1164
1165 /* Extra check. We can't transplant the contents to different
1166 an instance that has different base class. */
1167 if ((base = Scm_BaseClassOf(srcklass)) == NULL
1168 || !SCM_EQ(base, Scm_BaseClassOf(dstklass))) {
1169 Scm_Error("%%transplant-instance: classes are incompatible between %S and %S",
1170 src, dst);
1171 }
1172 if (base->coreSize < (int)sizeof(ScmInstance)) {
1173 Scm_Error("%%transplant-instance: baseclass is too small (implementation error?)");
1174 }
1175 memcpy(dst, src, base->coreSize);
1176 }
1177
1178 /* touch-instance! obj
1179 * If obj's class is redefined, update obj. Otherwise it does nothing.
1180 * Handy to ensure obj is in the newest state. Returns obj.
1181 */
Scm_VMTouchInstance(ScmObj obj)1182 ScmObj Scm_VMTouchInstance(ScmObj obj)
1183 {
1184 ScmClass *klass = Scm_ClassOf(obj);
1185 if (!SCM_FALSEP(klass->redefined)) {
1186 return instance_class_redefinition(obj, klass);
1187 }
1188 return obj;
1189 }
1190
1191 /*=====================================================================
1192 * Scheme slot access
1193 */
1194
1195 /* Scheme slots are stored in ScmObj array pointed by slots field
1196 * of ScmInstance. This one-level indirection allows an instance
1197 * to be redefined.
1198 */
1199
1200 /* Unbound slot: if the slot value yields either SCM_UNBOUND or
1201 * SCM_UNDEFINED, a generic function slot-unbound is called.
1202 * We count SCM_UNDEFINED as unbound so that a Scheme program can
1203 * make slot unbound, especially needed for procedural slots.
1204 */
1205
1206 /* A common routine to be used to allocate object.
1207 Coresize should be a size of base C structure in bytes.
1208 Klass may be a subclass. If klass is inheritable by Scheme
1209 (i.e. it's category is either SCM_CLASS_BASE or SCM_CLASS_SCHEME),
1210 This routine also allocates a slot vector, and initializes the
1211 slot vector with SCM_UNBOUND.
1212 We don't care class redefinition at this point. If the class is
1213 redefined simultaneously, it will be handled by the subsequent initialize
1214 method.
1215 */
Scm_NewInstance(ScmClass * klass,int coresize)1216 ScmObj Scm_NewInstance(ScmClass *klass, int coresize)
1217 {
1218 ScmObj obj = SCM_NEW2(ScmObj, coresize);
1219
1220 if (SCM_CLASS_CATEGORY(klass) == SCM_CLASS_BASE
1221 || SCM_CLASS_CATEGORY(klass) == SCM_CLASS_SCHEME) {
1222 ScmObj *slots = SCM_NEW_ARRAY(ScmObj, klass->numInstanceSlots);
1223
1224 /* NB: actually, for Scheme instances, 'coresize' argument is
1225 redundant since klass->coreSize has it. There's a historical
1226 confusion in the class protocol. We should clear it out someday.
1227 */
1228 if (coresize != klass->coreSize) {
1229 Scm_Printf(SCM_CURERR, "WARNING: allocating instance of class %S: coresize argument %d doesn't match the class definition's (%d)\n", klass, coresize, klass->coreSize);
1230 }
1231
1232 for (int i=0; i<klass->numInstanceSlots; i++) {
1233 slots[i] = SCM_UNBOUND;
1234 }
1235 SCM_INSTANCE(obj)->slots = slots;
1236 }
1237 SCM_SET_CLASS(obj, klass);
1238 return obj;
1239 }
1240
1241 #if GAUCHE_API_VERSION < 1000
1242 /* TRANSIENT: For the binary compatibility. Will go on 1.0. */
Scm_AllocateInstance(ScmClass * klass,int coresize)1243 ScmObj Scm_AllocateInstance(ScmClass *klass, int coresize)
1244 {
1245 return Scm_NewInstance(klass, coresize);
1246 }
1247 #endif /*GAUCHE_API_VERSION < 1000*/
1248
1249
1250 /* A special procedure that shortcuts allocate-instance and initialize
1251 * slots directly.
1252 * This is mainly used for fast construction of records. This bypasses
1253 * normal MOP initialization steps, so this shouldn't be used casually.
1254 */
Scm__AllocateAndInitializeInstance(ScmClass * klass,ScmObj * inits,int numInits,u_long flags SCM_UNUSED)1255 ScmObj Scm__AllocateAndInitializeInstance(ScmClass *klass,
1256 ScmObj *inits, int numInits,
1257 u_long flags SCM_UNUSED /*reserved*/)
1258 {
1259 if (SCM_CLASS_CATEGORY(klass) != SCM_CLASS_BASE
1260 && SCM_CLASS_CATEGORY(klass) != SCM_CLASS_SCHEME) {
1261 Scm_Error("Scm_AllocateAndInitializeInstance can't be called on "
1262 "this class: %S", SCM_OBJ(klass));
1263 }
1264
1265 /* We allocate an instance and a slot vector at once for speed.
1266 It is reasonable optimization, since record classes won't be redefined,
1267 and the instances' slot vector will never be replaced.
1268 We may provide an another mode to allocate the slot vector separately,
1269 using FLAGS argument. */
1270 int corewords = (klass->coreSize + sizeof(ScmObj)-1)/sizeof(ScmObj);
1271 ScmObj obj = SCM_NEW2(ScmObj, (corewords+klass->numInstanceSlots)*sizeof(ScmObj));
1272 SCM_SET_CLASS(obj, klass);
1273 ScmObj *slots = ((ScmObj*)obj) + corewords;
1274 for (int i=0; i<klass->numInstanceSlots; i++) {
1275 if (i < numInits) slots[i] = inits[i];
1276 else slots[i] = SCM_UNBOUND;
1277 }
1278 SCM_INSTANCE(obj)->slots = slots;
1279 return obj;
1280 }
1281
1282 /* Invoke class redefinition method */
instance_class_redefinition(ScmObj obj,ScmClass * old)1283 static ScmObj instance_class_redefinition(ScmObj obj, ScmClass *old)
1284 {
1285 (void)SCM_INTERNAL_MUTEX_LOCK(old->mutex);
1286 while (!SCM_ISA(old->redefined, SCM_CLASS_CLASS)) {
1287 (void)SCM_INTERNAL_COND_WAIT(old->cv, old->mutex);
1288 }
1289 ScmObj newc = old->redefined;
1290 (void)SCM_INTERNAL_MUTEX_UNLOCK(old->mutex);
1291 if (SCM_CLASSP(newc)) {
1292 return Scm_VMApply2(SCM_OBJ(&Scm_GenericChangeClass), obj, newc);
1293 } else {
1294 return SCM_OBJ(old);
1295 }
1296 }
1297
1298 /* most primitive internal accessor */
scheme_slot_ref(ScmObj obj,ScmSmallInt number)1299 static inline ScmObj scheme_slot_ref(ScmObj obj, ScmSmallInt number)
1300 {
1301 ScmClass *k = Scm_ClassOf(obj);
1302 if (number < 0 || number >= k->numInstanceSlots)
1303 Scm_Error("instance slot index %ld out of bounds for %S", number, obj);
1304 return SCM_INSTANCE_SLOTS(obj)[number];
1305 }
1306
scheme_slot_set(ScmObj obj,ScmSmallInt number,ScmObj val)1307 static inline void scheme_slot_set(ScmObj obj, ScmSmallInt number, ScmObj val)
1308 {
1309 ScmClass *k = Scm_ClassOf(obj);
1310 if (number < 0 || number >= k->numInstanceSlots)
1311 Scm_Error("instance slot index %ld out of bounds for %S", number, obj);
1312 SCM_INSTANCE_SLOTS(obj)[number] = val;
1313 }
1314
1315 /* These three are exposed to Scheme to do some nasty things.
1316 We shouldn't do class redefinition check here, since the slot number
1317 is calculated based on the old class, if the class is ever redefined.
1318 */
1319 #if GAUCHE_API_VERSION < 1000
1320 /* OBSOLETED, for the backward compatibility */
Scm_InstanceSlotRef(ScmObj obj,ScmSmallInt number)1321 ScmObj Scm_InstanceSlotRef(ScmObj obj, ScmSmallInt number)
1322 {
1323 return scheme_slot_ref(obj, number);
1324 }
1325
1326 /* TRANSIENT: we'll rename this to Scm_InstanceSlotRef() in 1.0. */
Scm_InstanceSlotRef3(ScmObj obj,ScmSmallInt number,ScmObj fallback)1327 ScmObj Scm_InstanceSlotRef3(ScmObj obj, ScmSmallInt number, ScmObj fallback)
1328 #else /*GAUCHE_API_VERSION >= 1000*/
1329 ScmObj Scm_InstanceSlotRef(ScmObj obj, ScmSmallInt number, ScmObj fallback)
1330 #endif /*GAUCHE_API_VERSION*/
1331 {
1332 ScmObj v = scheme_slot_ref(obj, number);
1333 if (SCM_UNBOUNDP(v)) {
1334 if (SCM_UNBOUNDP(fallback)) {
1335 Scm_Error("Slot #%d of object of class %S is unbound.",
1336 number, SCM_OBJ(Scm_ClassOf(obj)));
1337 }
1338 return fallback;
1339 }
1340 return v;
1341 }
1342
Scm_InstanceSlotSet(ScmObj obj,ScmSmallInt number,ScmObj val)1343 void Scm_InstanceSlotSet(ScmObj obj, ScmSmallInt number, ScmObj val)
1344 {
1345 scheme_slot_set(obj, number, val);
1346 }
1347
1348 /* Initialize a slot according to its accessor spec
1349 TODO: class redefintion check
1350 */
slot_initialize_cc(ScmObj result,void ** data)1351 static ScmObj slot_initialize_cc(ScmObj result, void **data)
1352 {
1353 ScmObj obj = data[0];
1354 ScmSlotAccessor *sa = SCM_SLOT_ACCESSOR(data[1]);
1355 return slot_set_using_accessor(obj, sa, result);
1356 }
1357
Scm_VMSlotInitializeUsingAccessor(ScmObj obj,ScmSlotAccessor * sa,ScmObj initargs)1358 ScmObj Scm_VMSlotInitializeUsingAccessor(ScmObj obj,
1359 ScmSlotAccessor *sa,
1360 ScmObj initargs)
1361 {
1362 /* (1) see if we have init-keyword */
1363 if (SCM_KEYWORDP(sa->initKeyword)) {
1364 ScmObj v = Scm_GetKeyword(sa->initKeyword, initargs, SCM_UNDEFINED);
1365 if (!SCM_UNDEFINEDP(v)) {
1366 return slot_set_using_accessor(obj, sa, v);
1367 }
1368 }
1369 /* (2) use init-value or init-thunk, if this slot is initializable. */
1370 if (sa->initializable) {
1371 if (!SCM_UNBOUNDP(sa->initValue)) {
1372 return slot_set_using_accessor(obj, sa, sa->initValue);
1373 }
1374 if (SCM_PROCEDUREP(sa->initThunk)) {
1375 void *data[2];
1376 data[0] = (void*)obj;
1377 data[1] = (void*)sa;
1378 Scm_VMPushCC(slot_initialize_cc, data, 2);
1379 return Scm_VMApply(sa->initThunk, SCM_NIL);
1380 }
1381 }
1382 return SCM_UNDEFINED;
1383 }
1384
1385 /*-------------------------------------------------------------------
1386 * slot-ref, slot-set! and families
1387 */
1388
1389 /* helper macros */
1390 #define SLOT_UNBOUND(klass, obj, slot) \
1391 Scm_VMApply(SCM_OBJ(&Scm_GenericSlotUnbound), \
1392 SCM_LIST3(SCM_OBJ(klass), obj, slot))
1393
1394 #define SLOT_MISSING3(klass, obj, slot) \
1395 Scm_VMApply(SCM_OBJ(&Scm_GenericSlotMissing), \
1396 SCM_LIST3(SCM_OBJ(klass), obj, slot))
1397
1398 #define SLOT_MISSING4(klass, obj, slot, val) \
1399 Scm_VMApply(SCM_OBJ(&Scm_GenericSlotMissing), \
1400 SCM_LIST4(SCM_OBJ(klass), obj, slot, val))
1401
1402 /* GET-SLOT-ACCESSOR
1403 *
1404 * (define (get-slot-accessor class slot)
1405 * (cond ((assq slot (ref class 'accessors)) => cdr)
1406 * (else (error !!!))))
1407 */
Scm_GetSlotAccessor(ScmClass * klass,ScmObj slot)1408 ScmSlotAccessor *Scm_GetSlotAccessor(ScmClass *klass, ScmObj slot)
1409 {
1410 ScmObj p = Scm_Assq(slot, klass->accessors);
1411 if (!SCM_PAIRP(p)) return NULL;
1412 if (!SCM_XTYPEP(SCM_CDR(p), SCM_CLASS_SLOT_ACCESSOR))
1413 Scm_Error("slot accessor information of class %S, slot %S is screwed up.",
1414 SCM_OBJ(klass), slot);
1415 return SCM_SLOT_ACCESSOR(SCM_CDR(p));
1416 }
1417
1418 /* (internal) slot-ref-using-accessor
1419 *
1420 * - assumes accessor belongs to the proper class.
1421 * - no class redefinition check is done
1422 */
slot_ref_using_accessor_cc(ScmObj result,void ** data)1423 static ScmObj slot_ref_using_accessor_cc(ScmObj result, void **data)
1424 {
1425 ScmObj obj = data[0];
1426 ScmObj slot = data[1];
1427 int boundp = (data[2] != NULL);
1428
1429 if (SCM_UNBOUNDP(result) || SCM_UNDEFINEDP(result)) {
1430 if (boundp) {
1431 return SCM_FALSE;
1432 } else {
1433 return SLOT_UNBOUND(Scm_ClassOf(obj), obj, slot);
1434 }
1435 } else {
1436 if (boundp) return SCM_TRUE;
1437 else return result;
1438 }
1439 }
1440
slot_boundp_using_accessor_cc(ScmObj result,void ** data SCM_UNUSED)1441 static ScmObj slot_boundp_using_accessor_cc(ScmObj result,
1442 void **data SCM_UNUSED)
1443 {
1444 return SCM_FALSEP(result)? SCM_FALSE:SCM_TRUE;
1445 }
1446
slot_ref_using_accessor(ScmObj obj,ScmSlotAccessor * sa,int boundp)1447 static ScmObj slot_ref_using_accessor(ScmObj obj,
1448 ScmSlotAccessor *sa,
1449 int boundp)
1450 {
1451 ScmObj val = SCM_UNBOUND;
1452 if (sa->getter) {
1453 val = sa->getter(obj);
1454 } else if (sa->slotNumber >= 0) {
1455 val = scheme_slot_ref(obj, sa->slotNumber);
1456 } else if (boundp && SCM_PROCEDUREP(sa->schemeBoundp)) {
1457 void *data[3];
1458 data[0] = obj;
1459 data[1] = sa->name;
1460 data[2] = (void*)(intptr_t)boundp;
1461 Scm_VMPushCC(slot_boundp_using_accessor_cc, data, 3);
1462 return Scm_VMApply(sa->schemeBoundp, SCM_LIST1(obj));
1463 } else if (SCM_PROCEDUREP(sa->schemeGetter)) {
1464 void *data[3];
1465 data[0] = obj;
1466 data[1] = sa->name;
1467 data[2] = (void*)(intptr_t)boundp;
1468 Scm_VMPushCC(slot_ref_using_accessor_cc, data, 3);
1469 return Scm_VMApply(sa->schemeGetter, SCM_LIST1(obj));
1470 } else {
1471 Scm_Error("don't know how to retrieve value of slot %S of object %S (MOP error?)",
1472 sa->name, obj);
1473 }
1474 if (boundp) {
1475 return SCM_MAKE_BOOL(!(SCM_UNBOUNDP(val) || SCM_UNDEFINEDP(val)));
1476 } else {
1477 if (SCM_UNBOUNDP(val) || SCM_UNDEFINEDP(val)) {
1478 return SLOT_UNBOUND(Scm_ClassOf(obj), obj, sa->name);
1479 } else {
1480 return val;
1481 }
1482 }
1483 }
1484
1485 /* SLOT-REF
1486 *
1487 *(define (slot-ref obj slot bound-check?)
1488 * (%check-class-redefined (class-of obj))
1489 * (let ((sa (get-slot-accessor (class-of obj) slot)))
1490 * (if sa
1491 * (%internal-slot-ref-using-accessor obj sa bound-check?)
1492 * (slot-missing (class-of obj) obj slot))))
1493 */
slot_ref_cc(ScmObj result SCM_UNUSED,void ** data)1494 static ScmObj slot_ref_cc(ScmObj result SCM_UNUSED, void **data)
1495 {
1496 return Scm_VMSlotRef(SCM_OBJ(data[0]), SCM_OBJ(data[1]), (int)(intptr_t)data[2]);
1497 }
1498
Scm_VMSlotRef(ScmObj obj,ScmObj slot,int boundp)1499 ScmObj Scm_VMSlotRef(ScmObj obj, ScmObj slot, int boundp)
1500 {
1501 ScmClass *klass = Scm_ClassOf(obj);
1502
1503 if (!SCM_FALSEP(klass->redefined)) {
1504 void *data[3];
1505 data[0] = obj;
1506 data[1] = slot;
1507 data[2] = (void*)(intptr_t)boundp;
1508 Scm_VMPushCC(slot_ref_cc, data, 3);
1509 return instance_class_redefinition(obj, klass);
1510 }
1511 ScmSlotAccessor *sa = Scm_GetSlotAccessor(klass, slot);
1512 if (sa == NULL) return SLOT_MISSING3(klass, obj, slot);
1513 else return slot_ref_using_accessor(obj, sa, boundp);
1514 }
1515
1516 /* SLOT-REF-USING-ACCESSOR
1517 *
1518 * (define (slot-ref-using-accessor obj sa bound-check?)
1519 * (%check-if-sa-is-valid-for-object obj sa)
1520 * (%internal-slot-ref-using-accessor obj sa bound-check?))
1521 *
1522 * - no class redefinition check is performed. if obj isn't updated
1523 * for the new class, sa must come from the old class.
1524 */
Scm_VMSlotRefUsingAccessor(ScmObj obj,ScmSlotAccessor * sa,int boundp)1525 ScmObj Scm_VMSlotRefUsingAccessor(ScmObj obj, ScmSlotAccessor *sa, int boundp)
1526 {
1527 ScmClass *klass = Scm_ClassOf(obj);
1528 if (klass != sa->klass) {
1529 Scm_Error("attempt to use a slot accessor %S on the object of different class: %S",
1530 SCM_OBJ(sa), obj);
1531 }
1532 return slot_ref_using_accessor(obj, sa, boundp);
1533 }
1534
1535 /* SLOT-REF-USING-CLASS
1536 *
1537 * (define-method slot-ref-using-class
1538 * ((class <class>) (obj <object>) slot)
1539 * (unless (eq? (class-of obj) class) (error !!!))
1540 * (let ((sa (get-slot-accessor class slot)))
1541 * (if sa
1542 * (%internal-slot-ref-using-accessor obj sa #f)
1543 * (slot-missing class obj slot))))
1544 *
1545 * - no class redefinition check is performed. if obj isn't updated,
1546 * and class is an old class, then it can access to the old instance's
1547 * slot value.
1548 */
slot_ref_using_class(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * d SCM_UNUSED)1549 static ScmObj slot_ref_using_class(ScmNextMethod *nm SCM_UNUSED,
1550 ScmObj *argv,
1551 int argc SCM_UNUSED,
1552 void *d SCM_UNUSED)
1553 {
1554 ScmClass *klass = SCM_CLASS(argv[0]);
1555 ScmObj obj = argv[1];
1556 ScmObj slot = argv[2];
1557
1558 if (!SCM_EQ(SCM_OBJ(klass), SCM_OBJ(Scm_ClassOf(obj)))) {
1559 Scm_Error("slot-ref-using-class: class %S is not the class of object %S", klass, obj);
1560 }
1561 ScmSlotAccessor *sa = Scm_GetSlotAccessor(klass, slot);
1562 if (sa == NULL) return SLOT_MISSING3(klass, obj, slot);
1563 else return slot_ref_using_accessor(obj, sa, FALSE);
1564 }
1565
1566 static ScmClass *slot_ref_using_class_SPEC[] = {
1567 SCM_CLASS_STATIC_PTR(Scm_ClassClass),
1568 SCM_CLASS_STATIC_PTR(Scm_ObjectClass),
1569 SCM_CLASS_STATIC_PTR(Scm_TopClass)
1570 };
1571 static SCM_DEFINE_METHOD(slot_ref_using_class_rec,
1572 &Scm_GenericSlotRefUsingClass,
1573 3, 0, slot_ref_using_class_SPEC,
1574 slot_ref_using_class, NULL);
1575
1576 /* (internal) SLOT-SET-USING-ACCESSOR
1577 *
1578 * - assumes accessor belongs to the proper class.
1579 * - no class redefinition check is done
1580 */
slot_set_using_accessor(ScmObj obj,ScmSlotAccessor * sa,ScmObj val)1581 ScmObj slot_set_using_accessor(ScmObj obj,
1582 ScmSlotAccessor *sa,
1583 ScmObj val)
1584 {
1585 if (sa->setter) {
1586 sa->setter(obj, val);
1587 } else if (sa->slotNumber >= 0) {
1588 scheme_slot_set(obj, sa->slotNumber, val);
1589 } else if (SCM_PROCEDUREP(sa->schemeSetter)) {
1590 return Scm_VMApply(sa->schemeSetter, SCM_LIST2(obj, val));
1591 } else {
1592 Scm_Error("slot %S of class %S is read-only", sa->name,
1593 SCM_OBJ(Scm_ClassOf(obj)));
1594 }
1595 return SCM_UNDEFINED;
1596 }
1597
1598 /* (internal) SLOT-ACCESSOR-SETTABLE
1599 * must be in sync with slot_set_using_accessor.
1600 * this won't detect the case when slot mutation is rejected by
1601 * the setter procedure.
1602 */
slot_accessor_settable_p(ScmSlotAccessor * sa)1603 static int slot_accessor_settable_p(ScmSlotAccessor *sa)
1604 {
1605 if (sa->setter
1606 || sa->slotNumber >= 0
1607 || SCM_PROCEDUREP(sa->schemeSetter))
1608 return TRUE;
1609 else
1610 return FALSE;
1611 }
1612
1613 /* SLOT-SET!
1614 *
1615 * (define (slot-set! obj slot val)
1616 * (%check-class-redefined (class-of obj))
1617 * (let ((sa (get-slot-accessor (class-of obj) slot)))
1618 * (if sa
1619 * (%internal-slot-set-using-accessor obj sa val)
1620 * (slot-missing (class-of obj) obj slot val))))
1621 */
slot_set_cc(ScmObj result SCM_UNUSED,void ** data)1622 static ScmObj slot_set_cc(ScmObj result SCM_UNUSED, void **data)
1623 {
1624 return Scm_VMSlotSet(SCM_OBJ(data[0]), SCM_OBJ(data[1]), SCM_OBJ(data[2]));
1625 }
1626
Scm_VMSlotSet(ScmObj obj,ScmObj slot,ScmObj val)1627 ScmObj Scm_VMSlotSet(ScmObj obj, ScmObj slot, ScmObj val)
1628 {
1629 ScmClass *klass = Scm_ClassOf(obj);
1630 if (!SCM_FALSEP(klass->redefined)) {
1631 void *data[3];
1632 data[0] = obj;
1633 data[1] = slot;
1634 data[2] = val;
1635 Scm_VMPushCC(slot_set_cc, data, 3);
1636 return instance_class_redefinition(obj, klass);
1637 }
1638 ScmSlotAccessor *sa = Scm_GetSlotAccessor(klass, slot);
1639 if (sa == NULL) return SLOT_MISSING4(klass, obj, slot, val);
1640 else return slot_set_using_accessor(obj, sa, val);
1641 }
1642
1643 /* SLOT-SET-USING-ACCESSOR
1644 *
1645 * (define (slot-set-using-accessor obj sa val)
1646 * (%check-if-sa-is-valid-for-object obj sa)
1647 * (%internal-slot-set-using-accessor obj sa val))
1648 *
1649 * - no class redefinition check is performed. if obj isn't updated
1650 * for the new class, sa must come from the old class.
1651 */
Scm_VMSlotSetUsingAccessor(ScmObj obj,ScmSlotAccessor * sa,ScmObj val)1652 ScmObj Scm_VMSlotSetUsingAccessor(ScmObj obj, ScmSlotAccessor *sa, ScmObj val)
1653 {
1654 ScmClass *klass = Scm_ClassOf(obj);
1655 if (klass != sa->klass) {
1656 Scm_Error("attempt to use a slot accessor %S on the object of different class: %S",
1657 SCM_OBJ(sa), obj);
1658 }
1659 return slot_set_using_accessor(obj, sa, val);
1660 }
1661
1662 /* SLOT-SET-USING-CLASS
1663 *
1664 * (define-method slot-set-using-class
1665 * ((class <class>) (obj <object>) slot val)
1666 * (unless (eq? (class-of obj) class) (error !!!))
1667 * (let ((sa (get-slot-accessor class slot)))
1668 * (if sa
1669 * (%internal-slot-set-using-accessor obj sa val)
1670 * (slot-missing class obj slot val))))
1671 *
1672 * - no class redefinition check is performed. if obj isn't updated,
1673 * and class is an old class, then it can access to the old instance's
1674 * slot value.
1675 */
slot_set_using_class(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * d SCM_UNUSED)1676 static ScmObj slot_set_using_class(ScmNextMethod *nm SCM_UNUSED,
1677 ScmObj *argv,
1678 int argc SCM_UNUSED,
1679 void *d SCM_UNUSED)
1680 {
1681 ScmClass *klass = SCM_CLASS(argv[0]);
1682 ScmObj obj = argv[1];
1683 ScmObj slot = argv[2];
1684 ScmObj val = argv[3];
1685
1686 if (!SCM_EQ(SCM_OBJ(klass), SCM_OBJ(Scm_ClassOf(obj)))) {
1687 Scm_Error("slot-ref-using-class: class %S is not the class of object %S", klass, obj);
1688 }
1689 ScmSlotAccessor *sa = Scm_GetSlotAccessor(klass, slot);
1690 if (sa == NULL) return SLOT_MISSING4(klass, obj, slot, val);
1691 else return slot_set_using_accessor(obj, sa, val);
1692 }
1693
1694 static ScmClass *slot_set_using_class_SPEC[] = {
1695 SCM_CLASS_STATIC_PTR(Scm_ClassClass),
1696 SCM_CLASS_STATIC_PTR(Scm_ObjectClass),
1697 SCM_CLASS_STATIC_PTR(Scm_TopClass),
1698 SCM_CLASS_STATIC_PTR(Scm_TopClass)
1699 };
1700 static SCM_DEFINE_METHOD(slot_set_using_class_rec,
1701 &Scm_GenericSlotSetUsingClass,
1702 4, 0, slot_set_using_class_SPEC,
1703 slot_set_using_class, NULL);
1704
1705 /* SLOT-BOUND?
1706 *
1707 * (define (slot-bound? obj slot)
1708 * (%check-class-redefined (class-of obj))
1709 * (slot-bound-using-class (class-of obj) obj slot))
1710 */
slot_boundp_cc(ScmObj result SCM_UNUSED,void ** data)1711 static ScmObj slot_boundp_cc(ScmObj result SCM_UNUSED, void **data)
1712 {
1713 ScmObj obj = SCM_OBJ(data[0]);
1714 ScmObj slot = SCM_OBJ(data[1]);
1715 return Scm_VMSlotBoundP(obj, slot);
1716 }
1717
Scm_VMSlotBoundP(ScmObj obj,ScmObj slot)1718 ScmObj Scm_VMSlotBoundP(ScmObj obj, ScmObj slot)
1719 {
1720 ScmClass *klass = Scm_ClassOf(obj);
1721
1722 if (!SCM_FALSEP(klass->redefined)) {
1723 void *data[2];
1724 data[0] = obj;
1725 data[1] = slot;
1726 Scm_VMPushCC(slot_boundp_cc, data, 2);
1727 return instance_class_redefinition(obj, Scm_ClassOf(obj));
1728 }
1729 return Scm_VMApply(SCM_OBJ(&Scm_GenericSlotBoundUsingClassP),
1730 SCM_LIST3(SCM_OBJ(klass), obj, slot));
1731 }
1732
1733 /* SLOT-BOUND-USING-CLASS?
1734 *
1735 * (define-method slot-bound-using-class? ((class <class>)
1736 * (obj <obj>)
1737 * slot)
1738 * (unless (eq? class (class-of obj)) (error !!!))
1739 * (let ((sa (get-slot-accessor class slot)))
1740 * (if sa
1741 * (%internal-slot-ref-using-accessor obj sa #t)
1742 * (slot-missing class obj slot)))
1743 *
1744 * - no redefinition check!
1745 */
slot_bound_using_class_p(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)1746 static ScmObj slot_bound_using_class_p(ScmNextMethod *nm SCM_UNUSED,
1747 ScmObj *argv,
1748 int argc SCM_UNUSED,
1749 void *data SCM_UNUSED)
1750 {
1751 ScmClass *klass = SCM_CLASS(argv[0]);
1752 ScmObj obj = argv[1];
1753 ScmObj slot = argv[2];
1754
1755 if (!SCM_EQ(SCM_OBJ(klass), SCM_OBJ(Scm_ClassOf(obj)))) {
1756 Scm_Error("slot-bound-using-class?: class %S is not the class of object %S", klass, obj);
1757 }
1758 ScmSlotAccessor *sa =Scm_GetSlotAccessor(klass, slot);
1759 if (sa == NULL) return SLOT_MISSING3(klass, obj, slot);
1760 else return slot_ref_using_accessor(obj, sa, TRUE);
1761 }
1762
1763 static ScmClass *slot_bound_using_class_p_SPEC[] = {
1764 SCM_CLASS_STATIC_PTR(Scm_ClassClass),
1765 SCM_CLASS_STATIC_PTR(Scm_TopClass),
1766 SCM_CLASS_STATIC_PTR(Scm_TopClass)
1767 };
1768 static SCM_DEFINE_METHOD(slot_bound_using_class_p_rec,
1769 &Scm_GenericSlotBoundUsingClassP,
1770 3, 0,
1771 slot_bound_using_class_p_SPEC,
1772 slot_bound_using_class_p, NULL);
1773
1774 /*
1775 * Builtin object initializer
1776 * This is the fallback method of generic initialize. Since all the
1777 * Scheme-defined objects will be initialized by object_initialize,
1778 * this method is called only for built-in classes.
1779 */
builtin_initialize(ScmObj * argv,int argc,ScmGeneric * gf SCM_UNUSED)1780 static ScmObj builtin_initialize(ScmObj *argv, int argc,
1781 ScmGeneric *gf SCM_UNUSED)
1782 {
1783 SCM_ASSERT(argc == 2);
1784 ScmObj instance = argv[0];
1785 ScmObj initargs = argv[1];
1786 if (Scm_Length(initargs) % 2) {
1787 Scm_Error("initializer list is not even: %S", initargs);
1788 }
1789 ScmClass *klass = Scm_ClassOf(instance);
1790 ScmObj ap;
1791 SCM_FOR_EACH(ap, klass->accessors) {
1792 ScmSlotAccessor *acc = SCM_SLOT_ACCESSOR(SCM_CDAR(ap));
1793 if (acc->setter && SCM_KEYWORDP(acc->initKeyword)) {
1794 ScmObj val = Scm_GetKeyword(acc->initKeyword, initargs, SCM_UNDEFINED);
1795 if (!SCM_UNDEFINEDP(val)) {
1796 acc->setter(instance, val);
1797 }
1798 }
1799 }
1800 return instance;
1801 }
1802
1803 /*--------------------------------------------------------------
1804 * Slot accessor object
1805 */
1806
1807 /* we initialize fields appropriately here. */
slot_accessor_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)1808 static ScmObj slot_accessor_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
1809 {
1810 ScmSlotAccessor *sa = SCM_NEW(ScmSlotAccessor);
1811
1812 SCM_SET_CLASS(sa, klass);
1813 sa->name = SCM_FALSE;
1814 sa->getter = NULL;
1815 sa->setter = NULL;
1816 sa->initValue = SCM_UNBOUND;
1817 sa->initKeyword = SCM_FALSE;
1818 sa->initThunk = SCM_FALSE;
1819 sa->initializable = FALSE;
1820 sa->slotNumber = -1;
1821 sa->schemeGetter = SCM_FALSE;
1822 sa->schemeSetter = SCM_FALSE;
1823 sa->schemeBoundp = SCM_FALSE;
1824 return SCM_OBJ(sa);
1825 }
1826
slot_accessor_print(ScmObj obj,ScmPort * out,ScmWriteContext * ctx SCM_UNUSED)1827 static void slot_accessor_print(ScmObj obj, ScmPort *out,
1828 ScmWriteContext *ctx SCM_UNUSED)
1829 {
1830 ScmSlotAccessor *sa = SCM_SLOT_ACCESSOR(obj);
1831
1832 Scm_Printf(out, "#<slot-accessor %S.%S ",
1833 (sa->klass? sa->klass->name : SCM_FALSE),
1834 sa->name);
1835 if (sa->getter) Scm_Printf(out, "native");
1836 else if (!SCM_FALSEP(sa->schemeGetter)) Scm_Printf(out, "proc");
1837 else if (sa->slotNumber >= 0) Scm_Printf(out, "%d", sa->slotNumber);
1838 else Scm_Printf(out, "unknown");
1839 if (!SCM_FALSEP(sa->initKeyword))
1840 Scm_Printf(out, " %S", sa->initKeyword);
1841 Scm_Printf(out, ">");
1842 }
1843
1844 /* some information is visible from Scheme world */
slot_accessor_class(ScmSlotAccessor * sa)1845 static ScmObj slot_accessor_class(ScmSlotAccessor *sa)
1846 {
1847 return SCM_OBJ(sa->klass);
1848 }
1849
slot_accessor_class_set(ScmSlotAccessor * sa,ScmObj v)1850 static void slot_accessor_class_set(ScmSlotAccessor *sa, ScmObj v)
1851 {
1852 if (!Scm_TypeP(v, SCM_CLASS_CLASS)) {
1853 Scm_Error(":class argument must be a class metaobject, but got %S", v);
1854 }
1855 sa->klass = SCM_CLASS(v);
1856 }
1857
slot_accessor_name(ScmSlotAccessor * sa)1858 static ScmObj slot_accessor_name(ScmSlotAccessor *sa)
1859 {
1860 return sa->name;
1861 }
1862
slot_accessor_name_set(ScmSlotAccessor * sa,ScmObj v)1863 static void slot_accessor_name_set(ScmSlotAccessor *sa, ScmObj v)
1864 {
1865 sa->name = v;
1866 }
1867
slot_accessor_init_value(ScmSlotAccessor * sa)1868 static ScmObj slot_accessor_init_value(ScmSlotAccessor *sa)
1869 {
1870 return sa->initValue;
1871 }
1872
slot_accessor_init_value_set(ScmSlotAccessor * sa,ScmObj v)1873 static void slot_accessor_init_value_set(ScmSlotAccessor *sa, ScmObj v)
1874 {
1875 sa->initValue = v;
1876 }
1877
slot_accessor_init_keyword(ScmSlotAccessor * sa)1878 static ScmObj slot_accessor_init_keyword(ScmSlotAccessor *sa)
1879 {
1880 return sa->initKeyword;
1881 }
1882
slot_accessor_init_keyword_set(ScmSlotAccessor * sa,ScmObj v)1883 static void slot_accessor_init_keyword_set(ScmSlotAccessor *sa, ScmObj v)
1884 {
1885 sa->initKeyword = v;
1886 }
1887
slot_accessor_init_thunk(ScmSlotAccessor * sa)1888 static ScmObj slot_accessor_init_thunk(ScmSlotAccessor *sa)
1889 {
1890 return sa->initThunk;
1891 }
1892
slot_accessor_init_thunk_set(ScmSlotAccessor * sa,ScmObj v)1893 static void slot_accessor_init_thunk_set(ScmSlotAccessor *sa, ScmObj v)
1894 {
1895 sa->initThunk = v;
1896 }
1897
slot_accessor_slot_number(ScmSlotAccessor * sa)1898 static ScmObj slot_accessor_slot_number(ScmSlotAccessor *sa)
1899 {
1900 return SCM_MAKE_INT(sa->slotNumber);
1901 }
1902
slot_accessor_slot_number_set(ScmSlotAccessor * sa,ScmObj val)1903 static void slot_accessor_slot_number_set(ScmSlotAccessor *sa, ScmObj val)
1904 {
1905 int n = 0;
1906 if (!SCM_INTP(val) || ((n = SCM_INT_VALUE(val)) < 0))
1907 Scm_Error("small positive integer required, but got %S", val);
1908 sa->slotNumber = n;
1909 }
1910
slot_accessor_initializable(ScmSlotAccessor * sa)1911 static ScmObj slot_accessor_initializable(ScmSlotAccessor *sa)
1912 {
1913 return SCM_MAKE_BOOL(sa->initializable);
1914 }
1915
slot_accessor_initializable_set(ScmSlotAccessor * sa,ScmObj v)1916 static void slot_accessor_initializable_set(ScmSlotAccessor *sa, ScmObj v)
1917 {
1918 sa->initializable = SCM_FALSEP(v)? FALSE : TRUE;
1919 }
1920
slot_accessor_settable(ScmSlotAccessor * sa)1921 static ScmObj slot_accessor_settable(ScmSlotAccessor *sa)
1922 {
1923 return SCM_MAKE_BOOL(slot_accessor_settable_p(sa));
1924 }
1925
slot_accessor_scheme_getter(ScmSlotAccessor * sa)1926 static ScmObj slot_accessor_scheme_getter(ScmSlotAccessor *sa)
1927 {
1928 return sa->schemeGetter;
1929 }
1930
slot_accessor_scheme_getter_set(ScmSlotAccessor * sa,ScmObj p)1931 static void slot_accessor_scheme_getter_set(ScmSlotAccessor *sa, ScmObj p)
1932 {
1933 /* TODO: check */
1934 sa->schemeGetter = p;
1935 }
1936
slot_accessor_scheme_setter(ScmSlotAccessor * sa)1937 static ScmObj slot_accessor_scheme_setter(ScmSlotAccessor *sa)
1938 {
1939 return sa->schemeSetter;
1940 }
1941
slot_accessor_scheme_setter_set(ScmSlotAccessor * sa,ScmObj p)1942 static void slot_accessor_scheme_setter_set(ScmSlotAccessor *sa, ScmObj p)
1943 {
1944 /* TODO: check */
1945 sa->schemeSetter = p;
1946 }
1947
slot_accessor_scheme_boundp(ScmSlotAccessor * sa)1948 static ScmObj slot_accessor_scheme_boundp(ScmSlotAccessor *sa)
1949 {
1950 return sa->schemeBoundp;
1951 }
1952
slot_accessor_scheme_boundp_set(ScmSlotAccessor * sa,ScmObj p)1953 static void slot_accessor_scheme_boundp_set(ScmSlotAccessor *sa, ScmObj p)
1954 {
1955 /* TODO: check */
1956 sa->schemeBoundp = p;
1957 }
1958
1959 /*=====================================================================
1960 * <object> class initialization
1961 */
1962
instance_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)1963 static ScmObj instance_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
1964 {
1965 return SCM_OBJ(SCM_NEW_INSTANCE(ScmInstance, klass));
1966 }
1967
1968 #if GAUCHE_API_VERSION < 1000
1969 /* TRANSIENT: For the binary compatibility during 0.9 series. Remove
1970 this on 1.0 */
Scm_ObjectAllocate(ScmClass * klass,ScmObj initargs)1971 ScmObj Scm_ObjectAllocate(ScmClass *klass, ScmObj initargs)
1972 {
1973 return instance_allocate(klass, initargs);
1974 }
1975 #endif /*GAUCHE_API_VERSION < 1000*/
1976
1977 /* (initialize <object> initargs) */
1978 static ScmObj object_initialize_cc(ScmObj result, void **data);
1979
object_initialize1(ScmObj obj,ScmObj accs,ScmObj initargs)1980 static ScmObj object_initialize1(ScmObj obj, ScmObj accs, ScmObj initargs)
1981 {
1982 if (SCM_NULLP(accs)) return obj;
1983 SCM_ASSERT(SCM_PAIRP(SCM_CAR(accs))
1984 && SCM_SLOT_ACCESSOR_P(SCM_CDAR(accs)));
1985 void *next[3];
1986 next[0] = obj;
1987 next[1] = SCM_CDR(accs);
1988 next[2] = initargs;
1989 Scm_VMPushCC(object_initialize_cc, next, 3);
1990 return Scm_VMSlotInitializeUsingAccessor(obj,
1991 SCM_SLOT_ACCESSOR(SCM_CDAR(accs)),
1992 initargs);
1993 }
1994
object_initialize_cc(ScmObj result SCM_UNUSED,void ** data)1995 static ScmObj object_initialize_cc(ScmObj result SCM_UNUSED, void **data)
1996 {
1997 ScmObj obj = SCM_OBJ(data[0]);
1998 ScmObj accs = SCM_OBJ(data[1]);
1999 ScmObj initargs = SCM_OBJ(data[2]);
2000 return object_initialize1(obj, accs, initargs);
2001 }
2002
object_initialize(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2003 static ScmObj object_initialize(ScmNextMethod *nm SCM_UNUSED,
2004 ScmObj *argv,
2005 int argc SCM_UNUSED,
2006 void *data SCM_UNUSED)
2007 {
2008 ScmObj obj = argv[0];
2009 ScmObj initargs = argv[1];
2010 ScmObj accs = Scm_ClassOf(obj)->accessors;
2011 if (SCM_NULLP(accs)) return obj;
2012 return object_initialize1(obj, accs, initargs);
2013 }
2014
2015 static ScmClass *object_initialize_SPEC[] = {
2016 SCM_CLASS_STATIC_PTR(Scm_ObjectClass), SCM_CLASS_STATIC_PTR(Scm_ListClass)
2017 };
2018 static SCM_DEFINE_METHOD(object_initialize_rec,
2019 &Scm_GenericInitialize,
2020 2, 0,
2021 object_initialize_SPEC,
2022 object_initialize, NULL);
2023
2024 /* Default equal? delegates compare action to generic function object-equal?.
2025 We can't use VMApply here */
Scm_ObjectCompare(ScmObj x,ScmObj y,int equalp)2026 int Scm_ObjectCompare(ScmObj x, ScmObj y, int equalp)
2027 {
2028 ScmObj r;
2029 if (equalp) {
2030 r = Scm_ApplyRec2(SCM_OBJ(&Scm_GenericObjectEqualP), x, y);
2031 return (SCM_FALSEP(r)? -1 : 0);
2032 } else {
2033 r = Scm_ApplyRec2(SCM_OBJ(&Scm_GenericObjectCompare), x, y);
2034 if (SCM_INTP(r)) {
2035 int ri = SCM_INT_VALUE(r);
2036 if (ri < 0) return -1;
2037 if (ri > 0) return 1;
2038 else return 0;
2039 }
2040 Scm_Error("object %S and %S can't be ordered", x, y);
2041 return 0; /* dummy */
2042 }
2043 }
2044
2045 /* Fallback of object-equal? and object-compare.
2046 We return #f for fallback of object-compare, which means two objects
2047 can't be ordered.
2048 */
fallback_compare(ScmObj * argv,int argc,ScmGeneric * gf)2049 static ScmObj fallback_compare(ScmObj *argv, int argc, ScmGeneric *gf)
2050 {
2051 if (argc == 2) return SCM_FALSE;
2052 else return Scm_NoNextMethod(argv, argc, gf);
2053 }
2054
2055
2056 /*=====================================================================
2057 * Generic function
2058 */
2059
generic_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)2060 static ScmObj generic_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
2061 {
2062 ScmGeneric *gf = SCM_NEW_INSTANCE(ScmGeneric, klass);
2063 SCM_PROCEDURE_INIT(gf, 0, 0, SCM_PROC_GENERIC, SCM_FALSE);
2064 gf->methods = SCM_NIL;
2065 gf->dispatcher = NULL;
2066 gf->fallback = Scm_NoNextMethod;
2067 gf->data = NULL;
2068 gf->maxReqargs = 0;
2069 (void)SCM_INTERNAL_MUTEX_INIT(gf->lock);
2070 return SCM_OBJ(gf);
2071 }
2072
generic_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)2073 static void generic_print(ScmObj obj, ScmPort *port,
2074 ScmWriteContext *ctx SCM_UNUSED)
2075 {
2076 #if 0 /* enable this to show maxReqargs */
2077 Scm_Printf(port, "#<generic %S (%d:%d)>",
2078 SCM_GENERIC(obj)->common.info,
2079 Scm_Length(SCM_GENERIC(obj)->methods),
2080 SCM_GENERIC(obj)->maxReqargs);
2081 #else
2082 Scm_Printf(port, "#<generic %S (%d)>",
2083 SCM_GENERIC(obj)->common.info,
2084 Scm_Length(SCM_GENERIC(obj)->methods));
2085 #endif
2086 }
2087
2088 /*
2089 * Accessors
2090 */
generic_name(ScmGeneric * gf)2091 static ScmObj generic_name(ScmGeneric *gf)
2092 {
2093 return gf->common.info;
2094 }
2095
generic_name_set(ScmGeneric * gf,ScmObj val)2096 static void generic_name_set(ScmGeneric *gf, ScmObj val)
2097 {
2098 gf->common.info = val;
2099 }
2100
generic_sealed(ScmGeneric * gf)2101 static ScmObj generic_sealed(ScmGeneric *gf)
2102 {
2103 return SCM_GENERIC_SEALED_P(gf)? SCM_TRUE:SCM_FALSE;
2104 }
2105
generic_methods(ScmGeneric * gf)2106 static ScmObj generic_methods(ScmGeneric *gf)
2107 {
2108 return gf->methods;
2109 }
2110
generic_methods_set(ScmGeneric * gf,ScmObj val)2111 static void generic_methods_set(ScmGeneric *gf, ScmObj val)
2112 {
2113 int reqs = 0;
2114 ScmObj cp;
2115 SCM_FOR_EACH(cp, val) {
2116 if (!SCM_METHODP(SCM_CAR(cp))) {
2117 Scm_Error("The methods slot of <generic> must be a list of method, but given: %S", val);
2118 }
2119 if (SCM_PROCEDURE_REQUIRED(SCM_CAR(cp)) > reqs) {
2120 reqs = SCM_PROCEDURE_REQUIRED(SCM_CAR(cp));
2121 }
2122 }
2123 if (!SCM_NULLP(cp)) {
2124 Scm_Error("The methods slot of <generic> cannot contain an improper list: %S", val);
2125 }
2126 (void)SCM_INTERNAL_MUTEX_LOCK(gf->lock);
2127 gf->methods = val;
2128 gf->maxReqargs = reqs;
2129 (void)SCM_INTERNAL_MUTEX_UNLOCK(gf->lock);
2130 }
2131
2132 /* Make base generic function from C */
Scm_MakeBaseGeneric(ScmObj name,ScmObj (* fallback)(ScmObj *,int,ScmGeneric *),void * data)2133 ScmObj Scm_MakeBaseGeneric(ScmObj name,
2134 ScmObj (*fallback)(ScmObj *, int, ScmGeneric*),
2135 void *data)
2136 {
2137 ScmGeneric *gf = SCM_GENERIC(generic_allocate(SCM_CLASS_GENERIC, SCM_NIL));
2138 gf->common.info = name;
2139 if (fallback) {
2140 gf->fallback = fallback;
2141 gf->data = data;
2142 }
2143 return SCM_OBJ(gf);
2144 }
2145
2146 /* default "default method" */
Scm_NoNextMethod(ScmObj * argv,int argc,ScmGeneric * gf)2147 ScmObj Scm_NoNextMethod(ScmObj *argv, int argc, ScmGeneric *gf)
2148 {
2149 Scm_Error("no applicable method for %S with arguments %S",
2150 SCM_OBJ(gf), Scm_ArrayToList(argv, argc));
2151 return SCM_UNDEFINED; /* dummy */
2152 }
2153
2154 /* another handy "default method", which does nothing. */
Scm_NoOperation(ScmObj * argv SCM_UNUSED,int argc SCM_UNUSED,ScmGeneric * gf SCM_UNUSED)2155 ScmObj Scm_NoOperation(ScmObj *argv SCM_UNUSED,
2156 int argc SCM_UNUSED,
2157 ScmGeneric *gf SCM_UNUSED)
2158 {
2159 return SCM_UNDEFINED;
2160 }
2161
2162 /* fallback of object-apply */
Scm_InvalidApply(ScmObj * argv,int argc,ScmGeneric * gf SCM_UNUSED)2163 ScmObj Scm_InvalidApply(ScmObj *argv, int argc, ScmGeneric *gf SCM_UNUSED)
2164 {
2165 Scm_Error("invalid application: %S", Scm_ArrayToList(argv, argc));
2166 return SCM_UNDEFINED;
2167 }
2168
2169 /* method-appliable-for-classes?
2170 NB: This may need to be redesigned once we support eqv specializer.
2171 */
Scm_MethodApplicableForClasses(ScmMethod * m,ScmClass * types[],int nargs)2172 int Scm_MethodApplicableForClasses(ScmMethod *m, ScmClass *types[], int nargs)
2173 {
2174 if (nargs < m->common.required
2175 || (!m->common.optional && nargs != m->common.required)) {
2176 return FALSE;
2177 } else {
2178 ScmClass **sp = m->specializers;
2179 int n = 0;
2180 for (; n < m->common.required; n++) {
2181 if (SCM_EQ(sp[n], SCM_CLASS_TOP)) continue;
2182 if (!Scm_SubtypeP(types[n], sp[n])) return FALSE;
2183 }
2184 }
2185 return TRUE;
2186 }
2187
2188 /* compute-applicable-methods */
Scm_ComputeApplicableMethods(ScmGeneric * gf,ScmObj * argv,int argc,int applyargs)2189 ScmObj Scm_ComputeApplicableMethods(ScmGeneric *gf, ScmObj *argv, int argc,
2190 int applyargs)
2191 {
2192 ScmObj methods = gf->methods, mp, ap;
2193 ScmObj h = SCM_NIL, t = SCM_NIL;
2194 ScmClass *typev_s[PREALLOC_SIZE], **typev = typev_s;
2195 int i, nsel;
2196
2197 if (SCM_NULLP(methods)) return SCM_NIL;
2198
2199 if (gf->maxReqargs > PREALLOC_SIZE) {
2200 typev = SCM_NEW_ATOMIC_ARRAY(ScmClass*, gf->maxReqargs);
2201 }
2202 nsel = gf->maxReqargs;
2203 if (applyargs) argc--;
2204 for (i = 0; i < argc && nsel >= 0; i++, nsel--) {
2205 typev[i] = Scm_ClassOf(argv[i]);
2206 }
2207 if (applyargs && nsel) {
2208 SCM_FOR_EACH(ap, argv[argc]) {
2209 if (--nsel >= 0) typev[i++] = Scm_ClassOf(SCM_CAR(ap));
2210 argc++;
2211 }
2212 }
2213
2214 if (gf->dispatcher
2215 && argc <= SCM_DISPATCHER_MAX_NARGS
2216 && argc >= 1) {
2217 ScmMethodDispatcher *dis = (ScmMethodDispatcher*)gf->dispatcher;
2218 ScmObj p = Scm__MethodDispatcherLookup(dis, typev, argc);
2219 if (SCM_PAIRP(p)) methods = p;
2220 }
2221
2222 SCM_ASSERT(SCM_PAIRP(methods));
2223 if (SCM_NULLP(SCM_CDR(methods))) {
2224 /* We have only one method, so just check its applicability
2225 and retrun the list without allocation if possible. */
2226 if (Scm_MethodApplicableForClasses(SCM_METHOD(SCM_CAR(methods)),
2227 typev, argc)) {
2228 return methods;
2229 } else {
2230 return SCM_NIL;
2231 }
2232 } else {
2233 SCM_FOR_EACH(mp, methods) {
2234 ScmObj m = SCM_CAR(mp);
2235 SCM_ASSERT(SCM_METHODP(m));
2236 if (Scm_MethodApplicableForClasses(SCM_METHOD(m), typev, argc)) {
2237 SCM_APPEND1(h, t, SCM_OBJ(m));
2238 }
2239 }
2240 return h;
2241 }
2242 }
2243
compute_applicable_methods(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2244 static ScmObj compute_applicable_methods(ScmNextMethod *nm SCM_UNUSED,
2245 ScmObj *argv,
2246 int argc SCM_UNUSED,
2247 void *data SCM_UNUSED)
2248 {
2249 ScmGeneric *gf = SCM_GENERIC(argv[0]);
2250 ScmObj arglist = argv[1];
2251 int n = Scm_Length(arglist);
2252 if (n < 0) Scm_Error("bad argument list: %S", arglist);
2253
2254 return Scm_ComputeApplicableMethods(gf, &arglist, 1, TRUE);
2255 }
2256
2257 static ScmClass *compute_applicable_methods_SPEC[] = {
2258 SCM_CLASS_STATIC_PTR(Scm_GenericClass), SCM_CLASS_STATIC_PTR(Scm_ListClass)
2259 };
2260 static SCM_DEFINE_METHOD(compute_applicable_methods_rec,
2261 &Scm_GenericComputeApplicableMethods,
2262 2, 0,
2263 compute_applicable_methods_SPEC,
2264 compute_applicable_methods, NULL);
2265
2266 /* method-more-specific? */
method_more_specific(ScmMethod * x,ScmMethod * y,ScmClass ** targv,int argc SCM_UNUSED)2267 static inline int method_more_specific(ScmMethod *x, ScmMethod *y,
2268 ScmClass **targv, int argc SCM_UNUSED)
2269 {
2270 ScmClass **xs = x->specializers;
2271 ScmClass **ys = y->specializers;
2272 int xreq = SCM_PROCEDURE_REQUIRED(x), yreq = SCM_PROCEDURE_REQUIRED(y);
2273
2274 for (int i=0; i<xreq && i<yreq; i++) {
2275 if (xs[i] != ys[i]) {
2276 ScmClass *ac = targv[i];
2277 if (xs[i] == ac) return TRUE;
2278 if (ys[i] == ac) return FALSE;
2279 for (ScmClass **acpl = ac->cpa; *acpl; acpl++) {
2280 if (xs[i] == *acpl) return TRUE;
2281 if (ys[i] == *acpl) return FALSE;
2282 }
2283 /* If we're here, two methods are not orderable. */
2284 Scm_Error("Couldn't determine which method is more specific:"
2285 " %S and %S: Check if compute-applicable-methods is "
2286 "working properly.", SCM_OBJ(x), SCM_OBJ(y));
2287 }
2288 }
2289 if (xreq > yreq) return TRUE;
2290 if (xreq < yreq) return FALSE;
2291
2292 /* all specializers match. the one without optional arg is more special.*/
2293 if (SCM_PROCEDURE_OPTIONAL(y)) return TRUE;
2294 else return FALSE;
2295 }
2296
method_more_specific_p(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2297 static ScmObj method_more_specific_p(ScmNextMethod *nm SCM_UNUSED,
2298 ScmObj *argv,
2299 int argc SCM_UNUSED,
2300 void *data SCM_UNUSED)
2301 {
2302 ScmMethod *x = SCM_METHOD(argv[0]);
2303 ScmMethod *y = SCM_METHOD(argv[1]);
2304 ScmObj targlist = argv[2];
2305 ScmClass *targv_s[PREALLOC_SIZE], **targv = targv_s;
2306 int targc = Scm_Length(targlist);
2307 if (targc < 0) Scm_Error("bad targ list: %S", targlist);
2308 if (targc > PREALLOC_SIZE) {
2309 targv = SCM_NEW_ARRAY(ScmClass*, targc);
2310 }
2311 int i = 0;
2312 ScmObj tp;
2313 SCM_FOR_EACH(tp, targlist) {
2314 if (!Scm_TypeP(SCM_CAR(tp), SCM_CLASS_CLASS))
2315 Scm_Error("bad class object in type list: %S", SCM_CAR(tp));
2316 targv[i++] = SCM_CLASS(SCM_CAR(tp));
2317 }
2318 return SCM_MAKE_BOOL(method_more_specific(x, y, targv, targc));
2319 }
2320 static ScmClass *method_more_specific_p_SPEC[] = {
2321 SCM_CLASS_STATIC_PTR(Scm_MethodClass),
2322 SCM_CLASS_STATIC_PTR(Scm_MethodClass),
2323 SCM_CLASS_STATIC_PTR(Scm_ListClass)
2324 };
2325 static SCM_DEFINE_METHOD(method_more_specific_p_rec,
2326 &Scm_GenericMethodMoreSpecificP,
2327 3, 0,
2328 method_more_specific_p_SPEC,
2329 method_more_specific_p, NULL);
2330
2331 /* sort-methods
2332 * This is a naive implementation just to make things work.
2333 *
2334 * Argv/argc is used to create an array of classes used to order methods.
2335 * We never need the arguments more than the maximum number of required
2336 * arguments among the given methods; when VM calls Scm_SortMethods, it
2337 * only puts as many args as gf->maxReqargs.
2338 *
2339 * TODO: can't we carry around the method list in array
2340 * instead of list, at least internally?
2341 */
Scm_SortMethods(ScmObj methods,ScmObj * argv,int argc)2342 ScmObj Scm_SortMethods(ScmObj methods, ScmObj *argv, int argc)
2343 {
2344 ScmObj array_s[PREALLOC_SIZE], *array = array_s;
2345 ScmClass *targv_s[PREALLOC_SIZE], **targv = targv_s;
2346 int cnt = 0, len = Scm_Length(methods);
2347
2348 if (len >= PREALLOC_SIZE) array = SCM_NEW_ARRAY(ScmObj, len);
2349 if (argc >= PREALLOC_SIZE) targv = SCM_NEW_ARRAY(ScmClass*, argc);
2350
2351 ScmObj mp;
2352 SCM_FOR_EACH(mp, methods) {
2353 if (!Scm_TypeP(SCM_CAR(mp), SCM_CLASS_METHOD))
2354 Scm_Error("bad method in applicable method list: %S", SCM_CAR(mp));
2355 array[cnt] = SCM_CAR(mp);
2356 cnt++;
2357 }
2358 for (int i=0; i<argc; i++) targv[i] = Scm_ClassOf(argv[i]);
2359
2360 for (int step = len/2; step > 0; step /= 2) {
2361 for (int i=step; i<len; i++) {
2362 for (int j=i-step; j >= 0; j -= step) {
2363 if (method_more_specific(SCM_METHOD(array[j]),
2364 SCM_METHOD(array[j+step]),
2365 targv, argc)) {
2366 break;
2367 } else {
2368 ScmObj tmp = array[j+step];
2369 array[j+step] = array[j];
2370 array[j] = tmp;
2371 }
2372 }
2373 }
2374 }
2375 return Scm_ArrayToList(array, len);
2376 }
2377
2378
2379 /* Developer API. Accessible from Scheme via generic-build-dispatcher!
2380 If axis is out of range, we do nothing and returns #f.
2381 */
Scm__GenericBuildDispatcher(ScmGeneric * gf,int axis)2382 ScmObj Scm__GenericBuildDispatcher(ScmGeneric *gf, int axis)
2383 {
2384 if (!disable_generic_dispatcher
2385 && axis >= 0 && axis < SCM_DISPATCHER_MAX_NARGS) {
2386 (void)SCM_INTERNAL_MUTEX_LOCK(gf->lock);
2387 gf->dispatcher = Scm__BuildMethodDispatcher(gf->methods, axis);
2388 (void)SCM_INTERNAL_MUTEX_UNLOCK(gf->lock);
2389 return SCM_TRUE;
2390 } else {
2391 return SCM_FALSE;
2392 }
2393 }
2394
2395 /* Developer API */
Scm__GenericInvalidateDispatcher(ScmGeneric * gf)2396 void Scm__GenericInvalidateDispatcher(ScmGeneric *gf)
2397 {
2398 (void)SCM_INTERNAL_MUTEX_LOCK(gf->lock);
2399 gf->dispatcher = NULL;
2400 (void)SCM_INTERNAL_MUTEX_UNLOCK(gf->lock);
2401 }
2402
2403 /* Developer API */
Scm__GenericDispatcherInfo(ScmGeneric * gf)2404 ScmObj Scm__GenericDispatcherInfo(ScmGeneric *gf)
2405 {
2406 if (gf->dispatcher) {
2407 return Scm__MethodDispatcherInfo(gf->dispatcher);
2408 } else {
2409 return SCM_FALSE;
2410 }
2411 }
2412
2413 /* Developer API */
Scm__GenericDispatcherDump(ScmGeneric * gf,ScmPort * port)2414 void Scm__GenericDispatcherDump(ScmGeneric *gf, ScmPort *port)
2415 {
2416 if (gf->dispatcher) {
2417 Scm_Printf(port, "%S's dispatcher:\n", gf);
2418 Scm__MethodDispatcherDump((ScmMethodDispatcher*)gf->dispatcher, port);
2419 } else {
2420 Scm_Printf(port, "%S doesn't have a dispatcher.\n", gf);
2421 }
2422 }
2423
2424 /*=====================================================================
2425 * Method
2426 */
2427
method_allocate(ScmClass * klass,ScmObj initargs SCM_UNUSED)2428 static ScmObj method_allocate(ScmClass *klass, ScmObj initargs SCM_UNUSED)
2429 {
2430 ScmMethod *instance = SCM_NEW_INSTANCE(ScmMethod, klass);
2431 SCM_PROCEDURE_INIT(instance, 0, 0, SCM_PROC_METHOD, SCM_FALSE);
2432 instance->generic = NULL;
2433 instance->specializers = NULL;
2434 instance->func = NULL;
2435 return SCM_OBJ(instance);
2436 }
2437
method_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)2438 static void method_print(ScmObj obj, ScmPort *port,
2439 ScmWriteContext *ctx SCM_UNUSED)
2440 {
2441 Scm_Printf(port, "#<method %S>", SCM_METHOD(obj)->common.info);
2442 }
2443
2444 /* See if this method doesn't use 'next-method' in its body. */
method_leaf_p(ScmClosure * body)2445 static int method_leaf_p(ScmClosure *body)
2446 {
2447 ScmCompiledCode *code = SCM_COMPILED_CODE(SCM_CLOSURE_CODE(body));
2448 if (!SCM_PAIRP(code->signatureInfo)
2449 || !SCM_PAIRP(SCM_CAR(code->signatureInfo))) return FALSE;
2450 ScmObj attr = Scm_PairAttrGet(SCM_PAIR(SCM_CAR(code->signatureInfo)),
2451 SCM_SYM_UNUSED_ARGS,
2452 SCM_NIL);
2453 return !SCM_FALSEP(Scm_Memq(SCM_SYM_NEXT_METHOD, attr));
2454 }
2455
2456 /*
2457 * (initialize <method> (&key lamdba-list generic specializers body method-locked))
2458 * Method initialization. This needs to be hardcoded, since
2459 * we can't call Scheme version of initialize to initialize the
2460 * "initialize" method (chicken-and-egg circularity).
2461 */
method_initialize(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2462 static ScmObj method_initialize(ScmNextMethod *nm SCM_UNUSED,
2463 ScmObj *argv,
2464 int argc SCM_UNUSED,
2465 void *data SCM_UNUSED)
2466 {
2467 ScmMethod *m = SCM_METHOD(argv[0]);
2468 ScmObj initargs = argv[1];
2469 ScmObj llist = Scm_GetKeyword(key_lambda_list, initargs, SCM_FALSE);
2470 ScmObj generic = Scm_GetKeyword(key_generic, initargs, SCM_FALSE);
2471 ScmObj specs = Scm_GetKeyword(key_specializers, initargs, SCM_FALSE);
2472 ScmObj body = Scm_GetKeyword(key_body, initargs, SCM_FALSE);
2473 ScmObj locked = Scm_GetKeyword(key_method_locked, initargs, SCM_FALSE);
2474 ScmObj lp, h, t;
2475 int speclen = 0, req = 0, opt = 0;
2476
2477 if (!Scm_TypeP(generic, SCM_CLASS_GENERIC))
2478 Scm_Error("generic function required for :generic argument: %S",
2479 generic);
2480 ScmGeneric *g = SCM_GENERIC(generic);
2481 if (!SCM_CLOSUREP(body))
2482 Scm_Error("closure required for :body argument: %S", body);
2483 if ((speclen = Scm_Length(specs)) < 0)
2484 Scm_Error("invalid specializers list: %S", specs);
2485 ScmClass **specarray = class_list_to_array(specs, speclen);
2486
2487 /* find out # of args from lambda list */
2488 SCM_FOR_EACH(lp, llist) req++;
2489 if (!SCM_NULLP(lp)) opt++;
2490
2491 if (SCM_PROCEDURE_REQUIRED(body) != req + opt + 1)
2492 Scm_Error("method body %S doesn't match with lambda list %S",
2493 body, llist);
2494 if (speclen != req)
2495 Scm_Error("specializer list doesn't match with lambda list: %S",specs);
2496
2497 m->common.required = req;
2498 m->common.optional = opt;
2499 m->common.info = Scm_Cons(g->common.info,
2500 class_array_to_names(specarray, speclen));
2501 m->common.leaf = method_leaf_p(SCM_CLOSURE(body));
2502 m->generic = g;
2503 m->specializers = specarray;
2504 m->func = NULL;
2505 m->data = SCM_CLOSURE_CODE(body);
2506 m->env = SCM_CLOSURE_ENV(body);
2507
2508 SCM_METHOD_LOCKED(m) = SCM_BOOL_VALUE(locked);
2509
2510 /* NB: for comprehensive debugging & profiling information, we modify
2511 the 'name' field of the compiled code to contain
2512 (generic-name specializer-class-names ...). It may be a hazard if
2513 some existing named closure is given as BODY; as far as the standard
2514 macro is used, though, altering it should be OK. */
2515 h = t = SCM_NIL;
2516 for (int i=0; i<speclen; i++) {
2517 SCM_APPEND1(h, t, specarray[i]->name);
2518 }
2519 SCM_COMPILED_CODE(m->data)->name = Scm_Cons(SCM_PROCEDURE_INFO(g), h);
2520
2521 /* Register this method to all classes in the specializers.
2522 This has to come after the part that may throw an error. */
2523 for (int i=0; i<speclen; i++) {
2524 Scm_AddDirectMethod(specarray[i], m);
2525 }
2526 return SCM_OBJ(m);
2527 }
2528
2529 static ScmClass *method_initialize_SPEC[] = {
2530 SCM_CLASS_STATIC_PTR(Scm_MethodClass),
2531 SCM_CLASS_STATIC_PTR(Scm_ListClass)
2532 };
2533 static SCM_DEFINE_METHOD(method_initialize_rec,
2534 &Scm_GenericInitialize,
2535 2, 0,
2536 method_initialize_SPEC,
2537 method_initialize, NULL);
2538
2539 /*
2540 * Accessors
2541 */
method_required(ScmMethod * m)2542 static ScmObj method_required(ScmMethod *m)
2543 {
2544 return SCM_MAKE_INT(m->common.required);
2545 }
2546
method_optional(ScmMethod * m)2547 static ScmObj method_optional(ScmMethod *m)
2548 {
2549 return SCM_MAKE_BOOL(m->common.optional);
2550 }
2551
method_locked(ScmMethod * m)2552 static ScmObj method_locked(ScmMethod *m)
2553 {
2554 return SCM_MAKE_BOOL(SCM_METHOD_LOCKED(m));
2555 }
2556
method_leaf(ScmMethod * m)2557 static ScmObj method_leaf(ScmMethod *m)
2558 {
2559 return SCM_MAKE_BOOL(SCM_METHOD_LEAF_P(m));
2560 }
2561
method_generic(ScmMethod * m)2562 static ScmObj method_generic(ScmMethod *m)
2563 {
2564 return m->generic ? SCM_OBJ(m->generic) : SCM_FALSE;
2565 }
2566
method_generic_set(ScmMethod * m,ScmObj val)2567 static void method_generic_set(ScmMethod *m, ScmObj val)
2568 {
2569 if (SCM_GENERICP(val))
2570 m->generic = SCM_GENERIC(val);
2571 else
2572 Scm_Error("generic function required, but got %S", val);
2573 }
2574
method_specializers(ScmMethod * m)2575 static ScmObj method_specializers(ScmMethod *m)
2576 {
2577 if (m->specializers) {
2578 return class_array_to_list(m->specializers, m->common.required);
2579 } else {
2580 return SCM_NIL;
2581 }
2582 }
2583
method_specializers_set(ScmMethod * m,ScmObj val)2584 static void method_specializers_set(ScmMethod *m, ScmObj val)
2585 {
2586 int len = Scm_Length(val);
2587 if (len != m->common.required)
2588 Scm_Error("specializer list doesn't match body's lambda list: %S", val);
2589 if (len == 0)
2590 m->specializers = NULL;
2591 else
2592 m->specializers = class_list_to_array(val, len);
2593 }
2594
2595 /* update-direct-method! method old-class new-class
2596 * To be called during class redefinition, and swaps reference of
2597 * old-class for new-class.
2598 *
2599 * This procedure swaps the pointer "in-place", so as far as the pointer
2600 * arithmetic is atomic, we won't have a race condition. Class
2601 * redefinition is serialized inside class-redefinition, so we won't
2602 * have the case that more than one thread call this procedure with
2603 * the same OLD pointer. It is possible that more than one thread call
2604 * this procedure on the same method simultaneously, but the OLD pointer
2605 * should differ, and it won't do any harm for them to run concurrently.
2606 *
2607 * Note that if we implement this in Scheme, we need a mutex to lock the
2608 * specializer array.
2609 */
Scm_UpdateDirectMethod(ScmMethod * m,ScmClass * old,ScmClass * newc)2610 ScmObj Scm_UpdateDirectMethod(ScmMethod *m, ScmClass *old, ScmClass *newc)
2611 {
2612 int rec = SCM_PROCEDURE_REQUIRED(m);
2613 ScmClass **sp = m->specializers;
2614 for (int i=0; i<rec; i++) {
2615 if (sp[i] == old) sp[i] = newc;
2616 }
2617 if (SCM_FALSEP(Scm_Memq(SCM_OBJ(m), newc->directMethods))) {
2618 newc->directMethods = Scm_Cons(SCM_OBJ(m), newc->directMethods);
2619 }
2620 /* NB: For now, we just invalidate dispatcher. Redefining class may
2621 trigger massive update-direct-method! and it's inefficient to rebuild
2622 dispatcher table for every invocation of it.
2623 */
2624 Scm__GenericInvalidateDispatcher(m->generic);
2625 return SCM_OBJ(m);
2626 }
2627
generic_updatedirectmethod(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2628 static ScmObj generic_updatedirectmethod(ScmNextMethod *nm SCM_UNUSED,
2629 ScmObj *argv,
2630 int argc SCM_UNUSED,
2631 void *data SCM_UNUSED)
2632 {
2633 return Scm_UpdateDirectMethod(SCM_METHOD(argv[0]),
2634 SCM_CLASS(argv[1]),
2635 SCM_CLASS(argv[2]));
2636 }
2637
2638 static ScmClass *generic_updatedirectmethod_SPEC[] = {
2639 SCM_CLASS_STATIC_PTR(Scm_MethodClass),
2640 SCM_CLASS_STATIC_PTR(Scm_ClassClass),
2641 SCM_CLASS_STATIC_PTR(Scm_ClassClass)
2642 };
2643 static SCM_DEFINE_METHOD(generic_updatedirectmethod_rec,
2644 &Scm_GenericUpdateDirectMethod, 3, 0,
2645 generic_updatedirectmethod_SPEC,
2646 generic_updatedirectmethod, NULL);
2647
2648 /*
2649 * ADD-METHOD, and it's default method version.
2650 */
Scm_AddMethod(ScmGeneric * gf,ScmMethod * method)2651 ScmObj Scm_AddMethod(ScmGeneric *gf, ScmMethod *method)
2652 {
2653 if (method->generic && method->generic != gf)
2654 Scm_Error("method %S already added to a generic function %S",
2655 method, method->generic);
2656 if (!SCM_FALSEP(Scm_Memq(SCM_OBJ(method), gf->methods)))
2657 Scm_Error("method %S already appears in a method list of generic %S"
2658 " something wrong in MOP implementation?",
2659 method, gf);
2660 if (SCM_GENERIC_SEALED_P(gf)) {
2661 Scm_Warn("Attempt to add a method to a sealed generic %S. "
2662 "You may need to recompile code that calls it.", gf);
2663 }
2664
2665 int reqs = gf->maxReqargs; /* # of maximum required args */
2666 method->generic = gf;
2667 /* pre-allocate cons pair to avoid triggering GC in the critical region */
2668 ScmObj pair = Scm_Cons(SCM_OBJ(method), gf->methods);
2669 if (SCM_PROCEDURE_REQUIRED(method) > reqs) {
2670 reqs = SCM_PROCEDURE_REQUIRED(method);
2671 }
2672
2673 /* Check if a method with the same signature exists.
2674 If so, we replace the method instead of adding it. */
2675 ScmMethod *replaced = NULL;
2676 ScmMethod *method_locked = NULL;
2677 (void)SCM_INTERNAL_MUTEX_LOCK(gf->lock);
2678 ScmObj mp;
2679 SCM_FOR_EACH(mp, gf->methods) {
2680 ScmMethod *mm = SCM_METHOD(SCM_CAR(mp));
2681 if (SCM_PROCEDURE_REQUIRED(method) == SCM_PROCEDURE_REQUIRED(mm)
2682 && SCM_PROCEDURE_OPTIONAL(method) == SCM_PROCEDURE_OPTIONAL(mm)) {
2683 ScmClass **sp1 = method->specializers;
2684 ScmClass **sp2 = mm->specializers;
2685 int i;
2686 for (i=0; i<SCM_PROCEDURE_REQUIRED(method); i++) {
2687 if (sp1[i] != sp2[i]) break;
2688 }
2689 if (i == SCM_PROCEDURE_REQUIRED(method)) {
2690 if (SCM_METHOD_LOCKED(mm)) {
2691 /* We'll throw an error */
2692 method_locked = mm;
2693 } else {
2694 replaced = mm;
2695 Scm_SetCar(mp, SCM_OBJ(method));
2696 }
2697 break;
2698 }
2699 }
2700 }
2701 if (!replaced && (method_locked == NULL)) {
2702 gf->methods = pair;
2703 gf->maxReqargs = reqs;
2704 }
2705 if (gf->dispatcher && (method_locked == NULL)) {
2706 ScmMethodDispatcher *dis = (ScmMethodDispatcher*)gf->dispatcher;
2707 if (replaced) Scm__MethodDispatcherDelete(dis, replaced);
2708 Scm__MethodDispatcherAdd(dis, method);
2709 }
2710 (void)SCM_INTERNAL_MUTEX_UNLOCK(gf->lock);
2711
2712 if (method_locked != NULL) {
2713 Scm_Error("Attempt to replace a locked method %S",
2714 SCM_OBJ(method_locked));
2715 }
2716 return SCM_UNDEFINED;
2717 }
2718
generic_addmethod(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2719 static ScmObj generic_addmethod(ScmNextMethod *nm SCM_UNUSED,
2720 ScmObj *argv,
2721 int argc SCM_UNUSED,
2722 void *data SCM_UNUSED)
2723 {
2724 return Scm_AddMethod(SCM_GENERIC(argv[0]), SCM_METHOD(argv[1]));
2725 }
2726
2727 static ScmClass *generic_addmethod_SPEC[] = {
2728 SCM_CLASS_STATIC_PTR(Scm_GenericClass),
2729 SCM_CLASS_STATIC_PTR(Scm_MethodClass)
2730 };
2731 static SCM_DEFINE_METHOD(generic_addmethod_rec,
2732 &Scm_GenericAddMethod, 2, 0,
2733 generic_addmethod_SPEC,
2734 generic_addmethod, NULL);
2735
2736 /*
2737 * DELETE-METHOD, and it's default method version.
2738 */
Scm_DeleteMethod(ScmGeneric * gf,ScmMethod * method)2739 ScmObj Scm_DeleteMethod(ScmGeneric *gf, ScmMethod *method)
2740 {
2741 if (!method->generic || method->generic != gf) return SCM_UNDEFINED;
2742
2743 (void)SCM_INTERNAL_MUTEX_LOCK(gf->lock);
2744 ScmObj mp = gf->methods;
2745 if (SCM_PAIRP(mp)) {
2746 if (SCM_EQ(SCM_CAR(mp), SCM_OBJ(method))) {
2747 gf->methods = SCM_CDR(mp);
2748 method->generic = NULL;
2749 } else {
2750 while (SCM_PAIRP(SCM_CDR(mp))) {
2751 if (SCM_EQ(SCM_CADR(mp), SCM_OBJ(method))) {
2752 SCM_CDR(mp) = SCM_CDDR(mp);
2753 method->generic = NULL;
2754 break;
2755 }
2756 mp = SCM_CDR(mp);
2757 }
2758 }
2759 }
2760 if (gf->dispatcher) {
2761 Scm__MethodDispatcherDelete((ScmMethodDispatcher*)gf->dispatcher,
2762 method);
2763 }
2764 SCM_FOR_EACH(mp, gf->methods) {
2765 /* sync # of required selector */
2766 if (SCM_PROCEDURE_REQUIRED(SCM_CAR(mp)) > gf->maxReqargs) {
2767 gf->maxReqargs = SCM_PROCEDURE_REQUIRED(SCM_CAR(mp));
2768 }
2769 }
2770 (void)SCM_INTERNAL_MUTEX_UNLOCK(gf->lock);
2771 return SCM_UNDEFINED;
2772 }
2773
generic_deletemethod(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2774 static ScmObj generic_deletemethod(ScmNextMethod *nm SCM_UNUSED,
2775 ScmObj *argv,
2776 int argc SCM_UNUSED,
2777 void *data SCM_UNUSED)
2778 {
2779 return Scm_DeleteMethod(SCM_GENERIC(argv[0]), SCM_METHOD(argv[1]));
2780 }
2781
2782 static ScmClass *generic_deletemethod_SPEC[] = {
2783 SCM_CLASS_STATIC_PTR(Scm_GenericClass),
2784 SCM_CLASS_STATIC_PTR(Scm_MethodClass)
2785 };
2786 static SCM_DEFINE_METHOD(generic_deletemethod_rec,
2787 &Scm_GenericDeleteMethod, 2, 0,
2788 generic_deletemethod_SPEC,
2789 generic_deletemethod, NULL);
2790
2791 /*=====================================================================
2792 * Next Method
2793 */
2794
Scm_MakeNextMethod(ScmGeneric * gf,ScmObj methods,ScmObj * argv,int argc,int copyargs,int applyargs)2795 ScmObj Scm_MakeNextMethod(ScmGeneric *gf, ScmObj methods,
2796 ScmObj *argv, int argc, int copyargs, int applyargs)
2797 {
2798 ScmNextMethod *nm = SCM_NEW(ScmNextMethod);
2799 SCM_SET_CLASS(nm, SCM_CLASS_NEXT_METHOD);
2800 SCM_PROCEDURE_INIT(nm, 0, 0, SCM_PROC_NEXT_METHOD, SCM_FALSE);
2801 nm->generic = gf;
2802 nm->methods = methods;
2803 if (copyargs) {
2804 nm->argv = SCM_NEW_ARRAY(ScmObj, argc);
2805 memcpy(nm->argv, argv, sizeof(ScmObj)*argc);
2806 } else {
2807 nm->argv = argv;
2808 }
2809 nm->argc = argc;
2810 nm->applyargs = applyargs;
2811 return SCM_OBJ(nm);
2812 }
2813
next_method_print(ScmObj obj,ScmPort * out,ScmWriteContext * ctx SCM_UNUSED)2814 static void next_method_print(ScmObj obj, ScmPort *out,
2815 ScmWriteContext *ctx SCM_UNUSED)
2816 {
2817 ScmNextMethod *nm = SCM_NEXT_METHOD(obj);
2818 ScmObj args = Scm_ArrayToList(nm->argv, nm->argc);
2819 Scm_Printf(out, "#<next-method %S%d %S>", nm->methods, nm->applyargs, args);
2820 }
2821
2822 /*=====================================================================
2823 * Accessor Method
2824 */
2825
accessor_method_print(ScmObj obj,ScmPort * port,ScmWriteContext * ctx SCM_UNUSED)2826 static void accessor_method_print(ScmObj obj, ScmPort *port,
2827 ScmWriteContext *ctx SCM_UNUSED)
2828 {
2829 Scm_Printf(port, "#<accessor-method %S>", SCM_METHOD(obj)->common.info);
2830 }
2831
accessor_get_proc(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2832 static ScmObj accessor_get_proc(ScmNextMethod *nm SCM_UNUSED,
2833 ScmObj *argv,
2834 int argc SCM_UNUSED,
2835 void *data SCM_UNUSED)
2836 {
2837 ScmObj obj = argv[0];
2838 ScmSlotAccessor *ca = (ScmSlotAccessor*)data;
2839 /* NB: we need this extra check, in case if the getter method of parent
2840 class and the one of subclass don't share the generic function, and
2841 the getter method of parent class is called on the subclass's instance.
2842 See test/object.scm "module and accessor" section for a concrete
2843 example. */
2844 if (!SCM_EQ(Scm_ClassOf(obj), ca->klass)) {
2845 /* fallback to a normal protocol */
2846 return Scm_VMSlotRef(obj, ca->name, FALSE);
2847 }
2848 /* Standard path. We can skip searching the slot, so it is faster. */
2849 return slot_ref_using_accessor(obj, ca, FALSE);
2850 }
2851
accessor_set_proc(ScmNextMethod * nm SCM_UNUSED,ScmObj * argv,int argc SCM_UNUSED,void * data SCM_UNUSED)2852 static ScmObj accessor_set_proc(ScmNextMethod *nm SCM_UNUSED,
2853 ScmObj *argv,
2854 int argc SCM_UNUSED,
2855 void *data SCM_UNUSED)
2856 {
2857 ScmObj obj = argv[0];
2858 ScmObj val = argv[1];
2859 ScmSlotAccessor *ca = (ScmSlotAccessor*)data;
2860 /* See the comment in accessor_get_proc above about this check. */
2861 if (!SCM_EQ(Scm_ClassOf(obj), ca->klass)) {
2862 return Scm_VMSlotSet(obj, ca->name, val);
2863 }
2864 return slot_set_using_accessor(obj, ca, val);
2865 }
2866
2867 /* Accessor method can be just created by usual allocate/initialize
2868 sequence. But it requires :slot-accessor initarg. The method body
2869 is overridden by C function, and the closure given to :body doesn't
2870 have an effect. */
accessor_method_initialize(ScmNextMethod * nm,ScmObj * argv,int argc,void * data)2871 static ScmObj accessor_method_initialize(ScmNextMethod *nm, ScmObj *argv,
2872 int argc, void *data)
2873 {
2874 ScmMethod *m = SCM_METHOD(method_initialize(nm, argv, argc, data));
2875 ScmObj initargs = argv[1];
2876 ScmObj sa = Scm_GetKeyword(key_slot_accessor, initargs, SCM_FALSE);
2877
2878 if (!SCM_SLOT_ACCESSOR_P(sa)) {
2879 Scm_Error("slot accessor required for :slot-accessor argument: %S",
2880 sa);
2881 }
2882
2883 m->data = sa;
2884 switch (SCM_PROCEDURE_REQUIRED(m)) {
2885 case 1: /* accessor <obj> - this is a getter */
2886 m->func = accessor_get_proc;
2887 break;
2888 case 2: /* accessor <obj> <val> - this is a setter */
2889 m->func = accessor_set_proc;
2890 break;
2891 default:
2892 Scm_Error("bad initialization parameter for accessor method %S", m);
2893 }
2894 return SCM_OBJ(m);
2895 }
2896
2897 static ScmClass *accessor_method_initialize_SPEC[] = {
2898 SCM_CLASS_STATIC_PTR(Scm_AccessorMethodClass),
2899 SCM_CLASS_STATIC_PTR(Scm_ListClass)
2900 };
2901 static SCM_DEFINE_METHOD(accessor_method_initialize_rec,
2902 &Scm_GenericInitialize,
2903 2, 0,
2904 accessor_method_initialize_SPEC,
2905 accessor_method_initialize, NULL);
2906
accessor_method_slot_accessor(ScmAccessorMethod * m)2907 static ScmObj accessor_method_slot_accessor(ScmAccessorMethod *m)
2908 {
2909 SCM_ASSERT(SCM_SLOT_ACCESSOR_P(m->data));
2910 return SCM_OBJ(m->data);
2911 }
2912
accessor_method_slot_accessor_set(ScmAccessorMethod * m,ScmObj v)2913 static void accessor_method_slot_accessor_set(ScmAccessorMethod *m, ScmObj v)
2914 {
2915 if (!SCM_SLOT_ACCESSOR_P(v)) {
2916 Scm_Error("slot accessor required, but got %S", v);
2917 }
2918 m->data = v;
2919 }
2920
2921 /*=====================================================================
2922 * Foreign pointer mechanism
2923 */
2924
2925 /* foreign pointer instance flags */
2926 enum {
2927 SCM_FOREIGN_POINTER_INVALID = (1L<<0) /* The pointer is no longer valid. */
2928 };
2929
2930 struct foreign_data_rec {
2931 int flags;
2932 ScmForeignCleanupProc cleanup;
2933 ScmInternalMutex attr_mutex; /* lock for updating foreign pointer's
2934 "attribute" slot. we use one-per-class
2935 mutex, assuming the mutation of attrs
2936 is rare and saving space per foreign
2937 pointer is more important. */
2938 ScmHashCore *identity_map; /* for KEEP_IDENTITY */
2939 ScmInternalMutex identity_mutex; /* lock for identity_map */
2940 };
2941
Scm_MakeForeignPointerClass(ScmModule * mod,const char * name,ScmClassPrintProc print_proc,ScmForeignCleanupProc cleanup_proc,int flags)2942 ScmClass *Scm_MakeForeignPointerClass(ScmModule *mod,
2943 const char *name,
2944 ScmClassPrintProc print_proc,
2945 ScmForeignCleanupProc cleanup_proc,
2946 int flags)
2947 {
2948 ScmClass *fp = (ScmClass*)class_allocate(SCM_CLASS_CLASS, SCM_NIL);
2949 ScmObj s = SCM_INTERN(name);
2950 struct foreign_data_rec *data = SCM_NEW(struct foreign_data_rec);
2951 /* NB: here we don't need to use SCM_CLASS_STATIC_PTR, since we only
2952 refer intra-dll classes, and we don't go through init_class.
2953 If we ever find the need to go through init_class, do not forget
2954 to change fpcpa initializers as well, to make it work on windows. */
2955 static ScmClass *fpcpa[] = { SCM_CLASS_FOREIGN_POINTER,
2956 SCM_CLASS_TOP,
2957 NULL };
2958 fp->name = s;
2959 fp->allocate = NULL;
2960 fp->print = print_proc;
2961 fp->cpa = fpcpa;
2962 fp->flags = SCM_CLASS_BUILTIN;
2963 initialize_builtin_cpl(fp, SCM_FALSE);
2964 Scm_Define(mod, SCM_SYMBOL(s), SCM_OBJ(fp));
2965 fp->slots = SCM_NIL;
2966 fp->accessors = SCM_NIL;
2967 data->flags = flags;
2968 data->cleanup = cleanup_proc;
2969 (void)SCM_INTERNAL_MUTEX_INIT(data->attr_mutex);
2970 if (flags & SCM_FOREIGN_POINTER_KEEP_IDENTITY) {
2971 (void)SCM_INTERNAL_MUTEX_INIT(data->identity_mutex);
2972 data->identity_map = SCM_NEW(ScmHashCore);
2973 Scm_HashCoreInitSimple(data->identity_map, SCM_HASH_WORD, 256, NULL);
2974 } else {
2975 data->identity_map = NULL;
2976 }
2977 fp->data = (void*)data; /* see the note above class_allocate() */
2978 return fp;
2979 }
2980
fp_finalize(ScmObj obj,void * data)2981 static void fp_finalize(ScmObj obj, void *data)
2982 {
2983 void (*cleanup)(ScmObj) = (void (*)(ScmObj))data;
2984 cleanup(obj);
2985 }
2986
2987 /* This shouldn't raise an error. */
make_foreign_int(ScmClass * klass,void * ptr,ScmObj attr,struct foreign_data_rec * data)2988 static ScmForeignPointer *make_foreign_int(ScmClass *klass, void *ptr,
2989 ScmObj attr,
2990 struct foreign_data_rec *data)
2991 {
2992 ScmForeignPointer *obj = SCM_NEW(ScmForeignPointer);
2993 SCM_SET_CLASS(obj, klass);
2994 obj->ptr = ptr;
2995 obj->attributes = attr;
2996 obj->flags = 0;
2997 if (data->cleanup) {
2998 Scm_RegisterFinalizer(SCM_OBJ(obj), fp_finalize, data->cleanup);
2999 }
3000 return obj;
3001 }
3002
3003 /* Note for future API: Scm_MakeForeignPointer should take attr argument.
3004 We add *WithAttr only to keep ABI compatibility. */
Scm_MakeForeignPointer(ScmClass * klass,void * ptr)3005 ScmObj Scm_MakeForeignPointer(ScmClass *klass, void *ptr)
3006 {
3007 return Scm_MakeForeignPointerWithAttr(klass, ptr, SCM_NIL);
3008 }
3009
Scm_MakeForeignPointerWithAttr(ScmClass * klass,void * ptr,ScmObj attr)3010 ScmObj Scm_MakeForeignPointerWithAttr(ScmClass *klass, void *ptr, ScmObj attr)
3011 {
3012 ScmForeignPointer *obj;
3013 struct foreign_data_rec *data = (struct foreign_data_rec *)klass->data;
3014
3015 if (!klass) { /* for extra safety */
3016 Scm_Error("NULL pointer passed to Scm_MakeForeignPointer");
3017 }
3018 if (!Scm_SubtypeP(klass, SCM_CLASS_FOREIGN_POINTER)) {
3019 Scm_Error("attempt to instantiate non-foreign-pointer class %S via Scm_MakeForeignPointer", klass);
3020 }
3021
3022 if (ptr == NULL && (data->flags & SCM_FOREIGN_POINTER_MAP_NULL)) {
3023 return SCM_FALSE;
3024 }
3025
3026 if (data->identity_map) {
3027 (void)SCM_INTERNAL_MUTEX_LOCK(data->identity_mutex);
3028 ScmDictEntry *e = Scm_HashCoreSearch(data->identity_map,
3029 (intptr_t)ptr, SCM_DICT_CREATE);
3030 if (e->value) {
3031 if (Scm_WeakBoxEmptyP((ScmWeakBox*)e->value)) {
3032 obj = make_foreign_int(klass, ptr, attr, data);
3033 Scm_WeakBoxSet((ScmWeakBox*)e->value, obj);
3034 } else {
3035 obj = (ScmForeignPointer*)Scm_WeakBoxRef((ScmWeakBox*)e->value);
3036 }
3037 } else {
3038 obj = make_foreign_int(klass, ptr, attr, data);
3039 e->value = (intptr_t)Scm_MakeWeakBox(obj);
3040 }
3041 (void)SCM_INTERNAL_MUTEX_UNLOCK(data->identity_mutex);
3042 } else {
3043 obj = make_foreign_int(klass, ptr, attr, data);
3044 }
3045 return SCM_OBJ(obj);
3046 }
3047
Scm_ForeignPointerRef(ScmForeignPointer * fp)3048 void *Scm_ForeignPointerRef(ScmForeignPointer *fp)
3049 {
3050 if (Scm_ForeignPointerInvalidP(fp)) {
3051 Scm_Error("attempt to dereference a foreign pointer "
3052 "that is no longer valid: %S", SCM_OBJ(fp));
3053
3054 }
3055 return fp->ptr;
3056 }
3057
Scm_ForeignPointerInvalidP(ScmForeignPointer * fp)3058 int Scm_ForeignPointerInvalidP(ScmForeignPointer *fp)
3059 {
3060 return (fp->flags & SCM_FOREIGN_POINTER_INVALID);
3061 }
3062
Scm_ForeignPointerInvalidate(ScmForeignPointer * fp)3063 void Scm_ForeignPointerInvalidate(ScmForeignPointer *fp)
3064 {
3065 fp->flags |= SCM_FOREIGN_POINTER_INVALID;
3066 }
3067
Scm_ForeignPointerAttr(ScmForeignPointer * fp)3068 ScmObj Scm_ForeignPointerAttr(ScmForeignPointer *fp)
3069 {
3070 return fp->attributes;
3071 }
3072
Scm_ForeignPointerAttrGet(ScmForeignPointer * fp,ScmObj key,ScmObj fallback)3073 ScmObj Scm_ForeignPointerAttrGet(ScmForeignPointer *fp,
3074 ScmObj key, ScmObj fallback)
3075 {
3076 /* no need to lock, for AttrSet won't make fp->attributes inconsisnent
3077 at any moment. */
3078 ScmObj p = Scm_Assq(key, fp->attributes);
3079 if (SCM_PAIRP(p)) return SCM_CDR(p);
3080 if (SCM_UNBOUNDP(fallback)) {
3081 Scm_Error("No value associated with key %S in a foreign pointer %S",
3082 key, SCM_OBJ(fp));
3083 }
3084 return fallback;
3085 }
3086
Scm_ForeignPointerAttrSet(ScmForeignPointer * fp,ScmObj key,ScmObj value)3087 ScmObj Scm_ForeignPointerAttrSet(ScmForeignPointer *fp,
3088 ScmObj key, ScmObj value)
3089 {
3090 struct foreign_data_rec *data
3091 = (struct foreign_data_rec*)(SCM_CLASS_OF(fp)->data);
3092
3093 /* NB: We presume mutating foreign pointer attributes is rare operation,
3094 so we don't try hard to make it efficient. Particularly, we use
3095 one mutex shared among all instances of the same class, in order to
3096 keep the size of each foreign pointer instance small. We'll reconsider
3097 the design if the performance ever becomes a problem. */
3098 (void)SCM_INTERNAL_MUTEX_LOCK(data->attr_mutex);
3099 ScmObj r = SCM_UNDEFINED;
3100 ScmObj p = Scm_Assq(key, fp->attributes);
3101 if (SCM_PAIRP(p)) {
3102 SCM_SET_CDR_UNCHECKED(p, value);
3103 r = value;
3104 } else {
3105 fp->attributes = Scm_Acons(key, value, fp->attributes);
3106 }
3107 (void)SCM_INTERNAL_MUTEX_UNLOCK(data->attr_mutex);
3108 return r;
3109 }
3110
3111 /*=====================================================================
3112 * Class initialization
3113 */
3114
3115 /* TODO: need a cleaner way! */
3116 /* static declaration of some structures */
3117
3118 static ScmClassStaticSlotSpec class_slots[] = {
3119 SCM_CLASS_SLOT_SPEC("name", class_name, class_name_set),
3120 SCM_CLASS_SLOT_SPEC("cpl", class_cpl, class_cpl_set),
3121 SCM_CLASS_SLOT_SPEC("direct-supers", class_direct_supers, class_direct_supers_set),
3122 SCM_CLASS_SLOT_SPEC("accessors", class_accessors, class_accessors_set),
3123 SCM_CLASS_SLOT_SPEC("slots", class_slots_ref, class_slots_set),
3124 SCM_CLASS_SLOT_SPEC("direct-slots", class_direct_slots, class_direct_slots_set),
3125 SCM_CLASS_SLOT_SPEC("num-instance-slots", class_numislots, class_numislots_set),
3126 SCM_CLASS_SLOT_SPEC("direct-subclasses", class_direct_subclasses, NULL),
3127 SCM_CLASS_SLOT_SPEC("direct-methods", class_direct_methods, NULL),
3128 SCM_CLASS_SLOT_SPEC("initargs", class_initargs, class_initargs_set),
3129 SCM_CLASS_SLOT_SPEC("defined-modules", class_defined_modules, class_defined_modules_set),
3130 SCM_CLASS_SLOT_SPEC("redefined", class_redefined, NULL),
3131 SCM_CLASS_SLOT_SPEC("category", class_category, NULL),
3132 SCM_CLASS_SLOT_SPEC_END()
3133 };
3134
3135 static ScmClassStaticSlotSpec generic_slots[] = {
3136 SCM_CLASS_SLOT_SPEC("name", generic_name, generic_name_set),
3137 SCM_CLASS_SLOT_SPEC("sealed", generic_sealed, NULL),
3138 SCM_CLASS_SLOT_SPEC("methods", generic_methods, generic_methods_set),
3139 SCM_CLASS_SLOT_SPEC_END()
3140 };
3141
3142 static ScmClassStaticSlotSpec method_slots[] = {
3143 SCM_CLASS_SLOT_SPEC("required", method_required, NULL),
3144 SCM_CLASS_SLOT_SPEC("optional", method_optional, NULL),
3145 SCM_CLASS_SLOT_SPEC("method-locked", method_locked, NULL),
3146 SCM_CLASS_SLOT_SPEC("leaf?", method_leaf, NULL),
3147 SCM_CLASS_SLOT_SPEC("generic", method_generic, method_generic_set),
3148 SCM_CLASS_SLOT_SPEC("specializers", method_specializers, method_specializers_set),
3149 SCM_CLASS_SLOT_SPEC_END()
3150 };
3151
3152 static ScmClassStaticSlotSpec accessor_method_slots[] = {
3153 SCM_CLASS_SLOT_SPEC("required", method_required, NULL),
3154 SCM_CLASS_SLOT_SPEC("optional", method_optional, NULL),
3155 SCM_CLASS_SLOT_SPEC("method-locked", method_locked, NULL),
3156 SCM_CLASS_SLOT_SPEC("leaf?", method_leaf, NULL),
3157 SCM_CLASS_SLOT_SPEC("generic", method_generic, method_generic_set),
3158 SCM_CLASS_SLOT_SPEC("specializers", method_specializers, method_specializers_set),
3159 SCM_CLASS_SLOT_SPEC("slot-accessor", accessor_method_slot_accessor, accessor_method_slot_accessor_set),
3160 SCM_CLASS_SLOT_SPEC_END()
3161 };
3162
3163 static ScmClassStaticSlotSpec slot_accessor_slots[] = {
3164 SCM_CLASS_SLOT_SPEC("class", slot_accessor_class,
3165 slot_accessor_class_set),
3166 SCM_CLASS_SLOT_SPEC("name", slot_accessor_name,
3167 slot_accessor_name_set),
3168 SCM_CLASS_SLOT_SPEC("init-value", slot_accessor_init_value,
3169 slot_accessor_init_value_set),
3170 SCM_CLASS_SLOT_SPEC("init-keyword", slot_accessor_init_keyword,
3171 slot_accessor_init_keyword_set),
3172 SCM_CLASS_SLOT_SPEC("init-thunk", slot_accessor_init_thunk,
3173 slot_accessor_init_thunk_set),
3174 SCM_CLASS_SLOT_SPEC("initializable", slot_accessor_initializable,
3175 slot_accessor_initializable_set),
3176 SCM_CLASS_SLOT_SPEC("settable", slot_accessor_settable,
3177 NULL),
3178 SCM_CLASS_SLOT_SPEC("slot-number", slot_accessor_slot_number,
3179 slot_accessor_slot_number_set),
3180 SCM_CLASS_SLOT_SPEC("getter", slot_accessor_scheme_getter,
3181 slot_accessor_scheme_getter_set),
3182 SCM_CLASS_SLOT_SPEC("setter", slot_accessor_scheme_setter,
3183 slot_accessor_scheme_setter_set),
3184 SCM_CLASS_SLOT_SPEC("bound?", slot_accessor_scheme_boundp,
3185 slot_accessor_scheme_boundp_set),
3186 SCM_CLASS_SLOT_SPEC_END()
3187 };
3188
3189 /*
3190 * Sets up CPL from CPA
3191 */
initialize_builtin_cpl(ScmClass * klass,ScmObj supers)3192 static void initialize_builtin_cpl(ScmClass *klass, ScmObj supers)
3193 {
3194 ScmObj h = SCM_NIL, t = SCM_NIL;
3195
3196 SCM_APPEND1(h, t, SCM_OBJ(klass));
3197 for (ScmClass **p = klass->cpa; *p; p++) SCM_APPEND1(h, t, SCM_OBJ(*p));
3198 klass->cpl = h;
3199 if (SCM_PAIRP(supers)) {
3200 /* Check validity of the given supers. */
3201 ScmObj cp, sp = supers;
3202 SCM_FOR_EACH(cp, klass->cpl) {
3203 if (SCM_EQ(SCM_CAR(cp), SCM_CAR(sp))) {
3204 sp = SCM_CDR(sp);
3205 if (SCM_NULLP(sp)) break;
3206 }
3207 }
3208 if (!SCM_NULLP(sp)) {
3209 /* NB: At this point we may not have initialized error handing
3210 mechanism, so we have no option but quit. */
3211 const char *cname = "(unnamed class)";
3212 if (SCM_STRINGP(klass->name)) {
3213 cname = Scm_GetStringConst(SCM_STRING(klass->name));
3214 }
3215 Scm_Panic("Class %s is being initialized with inconsistent super class list. Must be an implementation error. Report to the author.", cname);
3216 }
3217 klass->directSupers = supers;
3218 } else if (SCM_PAIRP(SCM_CDR(h))) {
3219 /* Default: take the next class of CPL as the only direct super */
3220 klass->directSupers = SCM_LIST1(SCM_CADR(h));
3221 } else {
3222 /* Should this happen? */
3223 klass->directSupers = SCM_NIL;
3224 }
3225 }
3226
3227 /*
3228 * A common part for builtin class initialization
3229 */
init_class(ScmClass * klass,const char * name,ScmModule * mod,ScmObj supers,ScmClassStaticSlotSpec * specs,int flags SCM_UNUSED)3230 static void init_class(ScmClass *klass,
3231 const char *name,
3232 ScmModule *mod,
3233 ScmObj supers, /* SCM_FALSE if using default */
3234 ScmClassStaticSlotSpec *specs,
3235 int flags SCM_UNUSED) /* reserved */
3236 {
3237 ScmObj slots = SCM_NIL, t = SCM_NIL, acc = SCM_NIL;
3238
3239 /* initialize CPL and directSupers */
3240 if (klass->cpa == NULL) {
3241 klass->cpa = SCM_CLASS_DEFAULT_CPL;
3242 }
3243
3244 klass->name = SCM_INTERN(name);
3245 initialize_builtin_cpl(klass, supers);
3246
3247 /* On Windows, mutex and cv must be initialized at runtime. */
3248 SCM_INTERNAL_MUTEX_INIT(klass->mutex);
3249 SCM_INTERNAL_COND_INIT(klass->cv);
3250
3251 /* insert binding */
3252 Scm_Define(mod, SCM_SYMBOL(klass->name), SCM_OBJ(klass));
3253
3254 /* initialize direct slots */
3255 if (specs) {
3256 for (;specs->name; specs++) {
3257 ScmObj snam = SCM_INTERN(specs->name);
3258 specs->accessor.klass = klass;
3259 specs->accessor.name = snam;
3260 acc = Scm_Acons(snam, SCM_OBJ(&specs->accessor), acc);
3261 specs->accessor.initKeyword = SCM_MAKE_KEYWORD(specs->name);
3262 SCM_APPEND1(slots, t,
3263 Scm_List(snam,
3264 key_allocation, key_builtin,
3265 key_slot_accessor, SCM_OBJ(&specs->accessor),
3266 NULL));
3267 }
3268 }
3269 klass->directSlots = slots;
3270
3271 /* compute other slots inherited from supers */
3272 for (ScmClass **super = klass->cpa; *super; super++) {
3273 ScmObj sp;
3274 SCM_FOR_EACH(sp, (*super)->directSlots) {
3275 ScmObj slot = SCM_CAR(sp), snam, p, a;
3276 SCM_ASSERT(SCM_PAIRP(slot));
3277 snam = SCM_CAR(slot);
3278 p = Scm_Assq(snam, slots);
3279 if (SCM_FALSEP(p)) {
3280 slots = Scm_Cons(Scm_CopyList(slot), slots);
3281 a = Scm_GetKeyword(key_slot_accessor, SCM_CDR(slot), SCM_FALSE);
3282 SCM_ASSERT(SCM_HOBJP(a));
3283 SCM_ASSERT(SCM_SLOT_ACCESSOR_P(a));
3284 acc = Scm_Acons(snam, a, acc);
3285 }
3286 }
3287 }
3288 klass->slots = slots;
3289 klass->accessors = acc;
3290 }
3291
3292 /*
3293 * Inter-module API
3294 */
3295
3296 /* The most standard way to initialize a class. */
Scm_InitStaticClass(ScmClass * klass,const char * name,ScmModule * mod,ScmClassStaticSlotSpec * specs,int flags)3297 void Scm_InitStaticClass(ScmClass *klass,
3298 const char *name,
3299 ScmModule *mod,
3300 ScmClassStaticSlotSpec *specs,
3301 int flags) /* reserved */
3302 {
3303 init_class(klass, name, mod, SCM_FALSE, specs, flags);
3304 }
3305
3306 /* If the builtin class needs multiple inheritance... */
Scm_InitStaticClassWithSupers(ScmClass * klass,const char * name,ScmModule * mod,ScmObj supers,ScmClassStaticSlotSpec * specs,int flags)3307 void Scm_InitStaticClassWithSupers(ScmClass *klass,
3308 const char *name,
3309 ScmModule *mod,
3310 ScmObj supers,
3311 ScmClassStaticSlotSpec *specs,
3312 int flags) /* reserved */
3313 {
3314 init_class(klass, name, mod, supers, specs, flags);
3315 }
3316
3317 /* A special initialization for some of builtin classes.
3318 Sets klass's metaclass to META. If META is NULL, a new metaclass
3319 (whose name has "-meta" after the original class name except brackets)
3320 is created automatically. This procedure should be used only if
3321 metaclass is absolutely required (e.g. all condition classes should
3322 be an instance of <condition-meta>). The older version of Gauche
3323 has metaclasses for many builtin classes, which is a compensation of
3324 lack of eqv-method specializer; such use of metaclass is deprecated
3325 and will be removed in future. */
Scm_InitStaticClassWithMeta(ScmClass * klass,const char * name,ScmModule * mod,ScmClass * meta,ScmObj supers,ScmClassStaticSlotSpec * specs,int flags)3326 void Scm_InitStaticClassWithMeta(ScmClass *klass,
3327 const char *name,
3328 ScmModule *mod,
3329 ScmClass *meta,
3330 ScmObj supers,
3331 ScmClassStaticSlotSpec *specs,
3332 int flags)
3333 {
3334 init_class(klass, name, mod, supers, specs, flags);
3335
3336 if (meta) {
3337 SCM_SET_CLASS(klass, meta);
3338 } else {
3339 int nlen = (int)strlen(name);
3340 char *metaname = SCM_NEW_ATOMIC2(char *, nlen + 6);
3341
3342 if (name[nlen - 1] == '>') {
3343 strncpy(metaname, name, nlen-1);
3344 strcpy(metaname+nlen-1, "-meta>");
3345 } else {
3346 strcpy(metaname, name);
3347 strcat(metaname, "-meta");
3348 }
3349 SCM_SET_CLASS(klass, make_implicit_meta(metaname, klass->cpa, mod));
3350 }
3351 }
3352
3353 /* The old API - deprecated. We keep this around for a while
3354 for backward compatibility. */
Scm_InitBuiltinClass(ScmClass * klass,const char * name,ScmClassStaticSlotSpec * specs,int withMeta,ScmModule * mod)3355 void Scm_InitBuiltinClass(ScmClass *klass, const char *name,
3356 ScmClassStaticSlotSpec *specs,
3357 int withMeta, ScmModule *mod)
3358 {
3359 if (withMeta) {
3360 Scm_InitStaticClassWithMeta(klass, name, mod, NULL, SCM_FALSE, specs, 0);
3361 } else {
3362 Scm_InitStaticClass(klass, name, mod, specs, 0);
3363 }
3364 }
3365
Scm_InitBuiltinGeneric(ScmGeneric * gf,const char * name,ScmModule * mod)3366 void Scm_InitBuiltinGeneric(ScmGeneric *gf, const char *name, ScmModule *mod)
3367 {
3368 ScmObj s = SCM_INTERN(name);
3369 gf->common.info = s;
3370 if (gf->fallback == NULL) {
3371 gf->fallback = Scm_NoNextMethod;
3372 }
3373 (void)SCM_INTERNAL_MUTEX_INIT(gf->lock);
3374 Scm_Define(mod, SCM_SYMBOL(s), SCM_OBJ(gf));
3375 }
3376
Scm_InitBuiltinMethod(ScmMethod * m)3377 void Scm_InitBuiltinMethod(ScmMethod *m)
3378 {
3379 m->common.info = Scm_Cons(m->generic->common.info,
3380 class_array_to_names(m->specializers,
3381 m->common.required));
3382 Scm_AddMethod(m->generic, m);
3383 }
3384
Scm__InitClass(void)3385 void Scm__InitClass(void)
3386 {
3387 ScmModule *mod = Scm_GaucheModule();
3388 static ScmClass *nullcpa[1] = {NULL}; /* for <top> */
3389
3390 key_allocation = SCM_MAKE_KEYWORD("allocation");
3391 key_builtin = SCM_MAKE_KEYWORD("builtin");
3392 key_slot_accessor = SCM_MAKE_KEYWORD("slot-accessor");
3393 key_name = SCM_MAKE_KEYWORD("name");
3394 key_lambda_list = SCM_MAKE_KEYWORD("lambda-list");
3395 key_generic = SCM_MAKE_KEYWORD("generic");
3396 key_method_locked = SCM_MAKE_KEYWORD("method-locked");
3397 key_specializers = SCM_MAKE_KEYWORD("specializers");
3398 key_body = SCM_MAKE_KEYWORD("body");
3399
3400 (void)SCM_INTERNAL_MUTEX_INIT(class_redefinition_lock.mutex);
3401 (void)SCM_INTERNAL_COND_INIT(class_redefinition_lock.cv);
3402
3403 if (Scm_GetEnv("GAUCHE_DISABLE_GENERIC_DISPATCHER") != NULL) {
3404 disable_generic_dispatcher = TRUE;
3405 }
3406
3407 /* booting class metaobject */
3408 Scm_TopClass.cpa = nullcpa;
3409
3410 #define BINIT(cl, nam, slots) \
3411 Scm_InitStaticClass(cl, nam, mod, slots, 0)
3412
3413 #define CINIT(cl, nam) \
3414 Scm_InitStaticClassWithMeta(cl, nam, mod, NULL, SCM_FALSE, NULL, 0)
3415
3416 /* Need to initialize these first */
3417 BINIT(SCM_CLASS_CLASS, "<class>", class_slots);
3418 BINIT(SCM_CLASS_TOP, "<top>", NULL);
3419 BINIT(SCM_CLASS_BOTTOM, "<bottom>", NULL);
3420
3421 /* box.c */
3422 CINIT(SCM_CLASS_BOX, "<box>");
3423 CINIT(SCM_CLASS_MVBOX, "<mv-box>");
3424
3425 /* class.c */
3426 CINIT(SCM_CLASS_BOOL, "<boolean>");
3427 CINIT(SCM_CLASS_CHAR, "<char>");
3428 BINIT(SCM_CLASS_EOF_OBJECT,"<eof-object>", NULL);
3429 BINIT(SCM_CLASS_UNDEFINED_OBJECT,"<undefined-object>", NULL);
3430 BINIT(SCM_CLASS_UNKNOWN,"<unknown>", NULL);
3431 BINIT(SCM_CLASS_OBJECT, "<object>", NULL);
3432 BINIT(SCM_CLASS_GENERIC,"<generic>", generic_slots);
3433 Scm_GenericClass.flags |= SCM_CLASS_APPLICABLE;
3434 BINIT(SCM_CLASS_METHOD, "<method>", method_slots);
3435 Scm_MethodClass.flags |= SCM_CLASS_APPLICABLE;
3436 BINIT(SCM_CLASS_NEXT_METHOD, "<next-method>", NULL);
3437 Scm_NextMethodClass.flags |= SCM_CLASS_APPLICABLE;
3438 BINIT(SCM_CLASS_ACCESSOR_METHOD, "<accessor-method>", accessor_method_slots);
3439 Scm_AccessorMethodClass.flags |= SCM_CLASS_APPLICABLE;
3440 BINIT(SCM_CLASS_SLOT_ACCESSOR,"<slot-accessor>", slot_accessor_slots);
3441 BINIT(SCM_CLASS_FOREIGN_POINTER, "<foreign-pointer>", NULL);
3442
3443 /* char.c */
3444 CINIT(SCM_CLASS_CHAR_SET, "<char-set>");
3445
3446 /* connection.c */
3447 BINIT(SCM_CLASS_CONNECTION, "<connection>", NULL);
3448
3449 /* comparator.c */
3450 /* initialized in Scm__InitComparator */
3451
3452 /* compile.c */
3453 /* initialized in Scm__InitCompiler */
3454
3455 /* error.c */
3456 /* initialized in Scm__InitExceptions */
3457
3458 /* hash.c */
3459 CINIT(SCM_CLASS_HASH_TABLE, "<hash-table>");
3460
3461 /* list.c */
3462 CINIT(SCM_CLASS_LIST, "<list>");
3463 CINIT(SCM_CLASS_PAIR, "<pair>");
3464 CINIT(SCM_CLASS_NULL, "<null>");
3465
3466 /* load.c */
3467 CINIT(SCM_CLASS_AUTOLOAD, "<autoload>");
3468
3469 /* macro.c */
3470 CINIT(SCM_CLASS_SYNTAX, "<syntax>");
3471 CINIT(SCM_CLASS_MACRO, "<macro>");
3472 CINIT(SCM_CLASS_SYNTAX_RULES, "<syntax-rules>");
3473
3474 /* module.c */
3475 /* class initialized in libmod.scm */
3476
3477 /* number.c */
3478 CINIT(SCM_CLASS_NUMBER, "<number>");
3479 CINIT(SCM_CLASS_COMPLEX, "<complex>");
3480 CINIT(SCM_CLASS_REAL, "<real>");
3481 CINIT(SCM_CLASS_RATIONAL, "<rational>");
3482 CINIT(SCM_CLASS_INTEGER, "<integer>");
3483
3484 /* parameter.c */
3485 BINIT(SCM_CLASS_PRIMITIVE_PARAMETER, "<primitive-parameter>", NULL);
3486
3487 /* port.c */
3488 /* initialized in Scm__InitPort */
3489
3490 /* proc.c */
3491 /* initialized in Scm__InitProc */
3492
3493 /* promise.c */
3494 CINIT(SCM_CLASS_PROMISE, "<promise>");
3495 CINIT(SCM_CLASS_LAZY_PAIR, "<lazy-pair>");
3496
3497 /* read.c */
3498 BINIT(SCM_CLASS_READ_CONTEXT, "<read-context>", NULL);
3499 BINIT(SCM_CLASS_READ_REFERENCE, "<read-reference>", NULL);
3500
3501 /* regexp.c */
3502 CINIT(SCM_CLASS_REGEXP, "<regexp>");
3503 CINIT(SCM_CLASS_REGMATCH, "<regmatch>");
3504
3505 /* string.c */
3506 CINIT(SCM_CLASS_STRING, "<string>");
3507 BINIT(SCM_CLASS_STRING_CURSOR, "<string-cursor>", NULL);
3508 BINIT(SCM_CLASS_STRING_CURSOR_LARGE, "<string-cursor-large>", NULL);
3509 #if GAUCHE_STRING_POINTER
3510 CINIT(SCM_CLASS_STRING_POINTER, "<string-pointer>");
3511 #endif
3512
3513 /* symbol.c */
3514 CINIT(SCM_CLASS_SYMBOL, "<symbol>");
3515 CINIT(SCM_CLASS_GLOC, "<gloc>");
3516 CINIT(SCM_CLASS_KEYWORD, "<keyword>");
3517
3518 /* system.c */
3519 /* initialized in Scm__InitSystem */
3520
3521 /* treemap.c */
3522 CINIT(SCM_CLASS_TREE_MAP, "<tree-map>");
3523
3524 /* vector.c */
3525 CINIT(SCM_CLASS_VECTOR, "<vector>");
3526 CINIT(SCM_CLASS_UVECTOR, "<uvector>");
3527 CINIT(SCM_CLASS_S8VECTOR, "<s8vector>");
3528 CINIT(SCM_CLASS_U8VECTOR, "<u8vector>");
3529 CINIT(SCM_CLASS_S16VECTOR, "<s16vector>");
3530 CINIT(SCM_CLASS_U16VECTOR, "<u16vector>");
3531 CINIT(SCM_CLASS_S32VECTOR, "<s32vector>");
3532 CINIT(SCM_CLASS_U32VECTOR, "<u32vector>");
3533 CINIT(SCM_CLASS_S64VECTOR, "<s64vector>");
3534 CINIT(SCM_CLASS_U64VECTOR, "<u64vector>");
3535 CINIT(SCM_CLASS_F16VECTOR, "<f16vector>");
3536 CINIT(SCM_CLASS_F32VECTOR, "<f32vector>");
3537 CINIT(SCM_CLASS_F64VECTOR, "<f64vector>");
3538 CINIT(SCM_CLASS_C32VECTOR, "<c32vector>");
3539 CINIT(SCM_CLASS_C64VECTOR, "<c64vector>");
3540 CINIT(SCM_CLASS_C128VECTOR, "<c128vector>");
3541 CINIT(SCM_CLASS_BITVECTOR, "<bitvector>");
3542
3543 /* weak.c */
3544 CINIT(SCM_CLASS_WEAK_VECTOR, "<weak-vector>");
3545 CINIT(SCM_CLASS_WEAK_HASH_TABLE, "<weak-hash-table>");
3546
3547 /* write.c */
3548 BINIT(SCM_CLASS_WRITE_STATE, "<write-state>", NULL);
3549
3550 #define GINIT(gf, nam) \
3551 Scm_InitBuiltinGeneric(gf, nam, mod);
3552
3553 GINIT(&Scm_GenericMake, "make");
3554 GINIT(&Scm_GenericAllocate, "allocate-instance");
3555 GINIT(&Scm_GenericInitialize, "initialize");
3556 GINIT(&Scm_GenericAddMethod, "add-method!");
3557 GINIT(&Scm_GenericDeleteMethod, "delete-method!");
3558 GINIT(&Scm_GenericComputeCPL, "compute-cpl");
3559 GINIT(&Scm_GenericComputeSlots, "compute-slots");
3560 GINIT(&Scm_GenericComputeGetNSet, "compute-get-n-set");
3561 GINIT(&Scm_GenericComputeApplicableMethods, "compute-applicable-methods");
3562 GINIT(&Scm_GenericUpdateDirectMethod, "update-direct-method!");
3563 GINIT(&Scm_GenericMethodMoreSpecificP, "method-more-specific?");
3564 GINIT(&Scm_GenericApplyGeneric, "apply-generic");
3565 GINIT(&Scm_GenericSlotMissing, "slot-missing");
3566 GINIT(&Scm_GenericSlotUnbound, "slot-unbound");
3567 GINIT(&Scm_GenericSlotRefUsingClass, "slot-ref-using-class");
3568 GINIT(&Scm_GenericSlotSetUsingClass, "slot-set-using-class!");
3569 GINIT(&Scm_GenericSlotBoundUsingClassP, "slot-bound-using-class?");
3570 GINIT(&Scm_GenericObjectEqualP, "object-equal?");
3571 GINIT(&Scm_GenericObjectCompare, "object-compare");
3572 GINIT(&Scm_GenericObjectHash, "object-hash");
3573 GINIT(&Scm_GenericObjectApply, "object-apply");
3574 GINIT(&Scm_GenericObjectSetter, "setter of object-apply");
3575 GINIT(&Scm_GenericChangeClass, "change-class");
3576
3577 Scm_SetterSet(SCM_PROCEDURE(&Scm_GenericObjectApply),
3578 SCM_PROCEDURE(&Scm_GenericObjectSetter),
3579 TRUE);
3580
3581 Scm_InitBuiltinMethod(&class_allocate_rec);
3582 Scm_InitBuiltinMethod(&class_compute_cpl_rec);
3583 Scm_InitBuiltinMethod(&slot_ref_using_class_rec);
3584 Scm_InitBuiltinMethod(&slot_set_using_class_rec);
3585 Scm_InitBuiltinMethod(&slot_bound_using_class_p_rec);
3586 Scm_InitBuiltinMethod(&object_initialize_rec);
3587 Scm_InitBuiltinMethod(&generic_addmethod_rec);
3588 Scm_InitBuiltinMethod(&generic_deletemethod_rec);
3589 Scm_InitBuiltinMethod(&method_initialize_rec);
3590 Scm_InitBuiltinMethod(&accessor_method_initialize_rec);
3591 Scm_InitBuiltinMethod(&compute_applicable_methods_rec);
3592 Scm_InitBuiltinMethod(&generic_updatedirectmethod_rec);
3593 Scm_InitBuiltinMethod(&method_more_specific_p_rec);
3594 }
3595