1 /* clos.c -*- coding: utf-8; -*-
2 *
3 * Copyright (c) 2010-2021 Takashi Kato <ktakashi@ymail.com>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
22 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $Id: $
29 */
30 #include <string.h>
31 #define LIBSAGITTARIUS_BODY
32 #include "sagittarius/private/clos.h"
33 #include "sagittarius/private/compare.h"
34 #include "sagittarius/private/bytevector.h"
35 #include "sagittarius/private/charset.h"
36 #include "sagittarius/private/closure.h"
37 #include "sagittarius/private/code.h"
38 #include "sagittarius/private/codec.h"
39 #include "sagittarius/private/collection.h"
40 #include "sagittarius/private/core.h"
41 #include "sagittarius/private/error.h"
42 #include "sagittarius/private/exceptions.h"
43 #include "sagittarius/private/generic.h"
44 #include "sagittarius/private/gloc.h"
45 #include "sagittarius/private/hashtable.h"
46 #include "sagittarius/private/instruction.h"
47 #include "sagittarius/private/keyword.h"
48 #include "sagittarius/private/library.h"
49 #include "sagittarius/private/number.h"
50 #include "sagittarius/private/pair.h"
51 #include "sagittarius/private/record.h"
52 #include "sagittarius/private/string.h"
53 #include "sagittarius/private/subr.h"
54 #include "sagittarius/private/symbol.h"
55 #include "sagittarius/private/system.h"
56 #include "sagittarius/private/transcoder.h"
57 #include "sagittarius/private/treemap.h"
58 #include "sagittarius/private/unicode.h"
59 #include "sagittarius/private/values.h"
60 #include "sagittarius/private/vector.h"
61 #include "sagittarius/private/vm.h"
62 #include "sagittarius/private/weak.h"
63 #include "sagittarius/private/writer.h"
64 #include "sagittarius/private/builtin-keywords.h"
65
slot_acc_print(SgObject obj,SgPort * port,SgWriteContext * ctx)66 static void slot_acc_print(SgObject obj, SgPort *port, SgWriteContext *ctx)
67 {
68 SgSlotAccessor *acc = SG_SLOT_ACCESSOR(obj);
69 Sg_Printf(port, UC("#<slot-accessor %A:%A,%d>"),
70 acc->klass?acc->klass->name:SG_UNDEF, acc->name, acc->index);
71 }
72 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_SlotAccessorClass, slot_acc_print);
73
74 SgClass *Sg_DefaultCPL[] = {
75 SG_CLASS_TOP,
76 NULL,
77 };
78 SgClass *Sg_ObjectCPL[] = {
79 SG_CLASS_OBJECT,
80 SG_CLASS_TOP,
81 NULL,
82 };
83
84 static SgClass *Sg_MethodCPL[] = {
85 SG_CLASS_METHOD,
86 SG_CLASS_OBJECT,
87 SG_CLASS_TOP,
88 NULL
89 };
90
91 SG_DEFINE_ABSTRACT_CLASS(Sg_TopClass, NULL);
92
93 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_BoolClass, NULL);
94 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_CharClass, NULL);
95 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_UnknownClass, NULL);
96 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_UndefinedClass, NULL);
97 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_EOFObjectClass, NULL);
98
99 static void class_print(SgObject, SgPort *, SgWriteContext *);
100 static void generic_print(SgObject, SgPort *, SgWriteContext *);
101 static void method_print(SgObject, SgPort *, SgWriteContext *);
102 static void next_method_print(SgObject, SgPort *, SgWriteContext *);
103 /* allocate */
104 static SgObject class_allocate(SgClass *klass, SgObject initargs);
105 static SgObject generic_allocate(SgClass *klass, SgObject initargs);
106 static SgObject method_allocate(SgClass *klass, SgObject initargs);
107
108 /* compare */
109 static int object_compare(SgObject x, SgObject y, int equalp);
110
111 static SgSlotAccessor* lookup_slot_info(SgClass *klass, SgObject name);
112
113 static void init_class(SgClass *klass, const SgChar *name,
114 SgLibrary *lib, SgObject supers, SgSlotAccessor *specs,
115 int flags);
116
117 static SgObject redefine_instance_class(SgObject obj, SgClass *old);
118
119 /* helper */
class_array_to_names(SgClass ** array,int len)120 static SgObject class_array_to_names(SgClass **array, int len)
121 {
122 SgObject h = SG_NIL, t = SG_NIL;
123 int i;
124 for (i = 0; i < len; i++, array++) {
125 SG_APPEND1(h, t, (*array)->name);
126 }
127 return h;
128 }
129
class_list_to_array(SgObject lst,long len)130 static SgObject class_list_to_array(SgObject lst, long len)
131 {
132 SgObject cp;
133 SgClass **v, **vp;
134 v = vp = SG_NEW_ARRAY(SgClass*, len+1);
135 SG_FOR_EACH(cp, lst) {
136 if (!Sg_TypeP(SG_CAR(cp), SG_CLASS_CLASS)) {
137 Sg_Error(UC("list of classes required, but found non-class object"
138 " %S in %S"), SG_CAR(cp), lst);
139 }
140 *vp++ = SG_CLASS(SG_CAR(cp));
141 }
142 *vp = NULL;
143 return v;
144 }
145
class_list_to_names(SgClass ** lst,int len)146 static SgObject class_list_to_names(SgClass **lst, int len)
147 {
148 SgObject h = SG_NIL, t = SG_NIL;
149 int i;
150 for (i=0; i<len; i++, lst++) {
151 if (Sg_TypeP(*lst, SG_CLASS_EQL_SPECIALIZER)) {
152 SgObject name = SG_LIST2(SG_INTERN("eql"),
153 SG_EQL_SPECIALIZER(*lst)->object);
154 SG_APPEND1(h, t, name);
155 } else {
156 SG_APPEND1(h, t, (*lst)->name);
157 }
158 }
159 return h;
160 }
161
162 SG_DEFINE_BASE_CLASS(Sg_ObjectClass, SgInstance,
163 NULL, NULL, NULL, Sg_ObjectAllocate,
164 SG_CLASS_DEFAULT_CPL);
165 SG_DEFINE_BASE_CLASS(Sg_ClassClass, SgClass,
166 class_print, NULL, NULL, class_allocate,
167 SG_CLASS_OBJECT_CPL);
168 SG_DEFINE_BASE_CLASS(Sg_GenericClass, SgGeneric,
169 generic_print, NULL, NULL, generic_allocate,
170 SG_CLASS_OBJECT_CPL);
171 SG_DEFINE_BASE_CLASS(Sg_MethodClass, SgMethod,
172 method_print, NULL, NULL, method_allocate,
173 Sg_MethodCPL);
174
175 SG_DEFINE_BUILTIN_CLASS_SIMPLE(Sg_NextMethodClass, next_method_print);
176
Sg_AllocateInstance(SgClass * klass)177 SgObject Sg_AllocateInstance(SgClass *klass)
178 {
179 SgObject obj = SG_NEW2(SgObject, klass->coreSize);
180 SgObject *slots;
181 int i;
182
183 switch (SG_CLASS_CATEGORY(klass)) {
184 case SG_CLASS_BASE:
185 case SG_CLASS_SCHEME:
186 slots = SG_NEW_ARRAY(SgObject, klass->nfields);
187 for (i = 0; i < klass->nfields; i++) {
188 slots[i] = SG_UNBOUND;
189 }
190 SG_INSTANCE(obj)->slots = slots;
191 }
192 return obj;
193 }
194
195
make_slot_accessor(SgClass * klass,SgObject name,int index)196 static SgSlotAccessor *make_slot_accessor(SgClass *klass, SgObject name,
197 int index)
198 {
199 SgSlotAccessor *ac = SG_NEW(SgSlotAccessor);
200 SG_SET_CLASS(ac, SG_CLASS_SLOT_ACCESSOR);
201 ac->name = SG_CAR(name);
202 ac->klass = klass;
203 ac->index = index;
204 ac->getter = NULL;
205 ac->setter = NULL;
206 ac->getterS = SG_FALSE;
207 ac->setterS = SG_FALSE;
208 ac->boundP = SG_FALSE;
209 ac->definition = name; /* book keeping for redefinition */
210 return ac;
211 }
212
213 /*
214 we need to calculate required arguments count, basically we just need to
215 -1 for call-next-method.
216
217 NOTE: because of variable flatten in compiler, if a procedure has optional
218 argument, the original required arguments count will be +1.
219 ex) (lambda (a b . c) ...) ;; -> required argc = 3.
220 so if the procedure has optional argument, we need to reduce 2, instead
221 of 1.
222 */
223 #define set_method_properties(m, proc) \
224 do { \
225 int opt = SG_PROCEDURE_OPTIONAL(proc), offset=1; \
226 SG_PROCEDURE_OPTIONAL(m) = opt; \
227 /* for call-next-method */ \
228 if (opt) offset++; \
229 SG_PROCEDURE_REQUIRED(m) = SG_PROCEDURE_REQUIRED(proc)-offset; \
230 } while (0)
231
set_method_debug_name(SgMethod * m,SgGeneric * g)232 static void set_method_debug_name(SgMethod *m, SgGeneric *g)
233 {
234 SgObject body = SG_METHOD_PROCEDURE(m);
235 SgClass **tmp, **specarray = SG_METHOD_SPECIALIZERS(m);
236 int speclen = 0;
237 for (tmp = specarray; *tmp; tmp++) speclen++;
238
239 SG_PROCEDURE_NAME(m) = Sg_Cons(SG_PROCEDURE_NAME(g),
240 class_list_to_names(specarray, speclen));
241 /* mostly true */
242 if (SG_CLOSUREP(body)) {
243 SG_CODE_BUILDER(SG_CLOSURE(body)->code)->name = SG_PROCEDURE_NAME(m);
244 }
245 }
246
247 /*
248 Some of CLOS operations, such as add-method, remove-method and
249 redefining class needs to be aware of current environment so
250 that it won't propagate the changes to other environments.
251 Basically, if the current environment (library) is a child
252 environment then we need to do some trick (or simply raises an
253 error).
254 */
in_global_context_p()255 static int in_global_context_p()
256 {
257 /* if (Sg_MainThreadP()) return TRUE; */
258 /* return Sg_VM()->state == IMPORTING; */
259 return !SG_CHILD_LIBRARYP(Sg_VMCurrentLibrary());
260 }
261
262 /* some helpers */
get_thead_local_methods(SgGeneric * gf)263 static SgObject get_thead_local_methods(SgGeneric *gf)
264 {
265 SgObject gslot = Sg_Assq(gf, SG_LIBRARY_GENERICS(Sg_VMCurrentLibrary()));
266 if (SG_FALSEP(gslot)) return SG_NIL;
267 return SG_CDDR(gslot);
268 }
269
get_all_methods(SgGeneric * gf)270 static SgObject get_all_methods(SgGeneric *gf)
271 {
272 SgObject ms = get_thead_local_methods(gf);
273 if (SG_NULLP(ms)) return SG_GENERIC_METHODS(gf);
274 /* thread local first */
275 return Sg_Append2(ms, SG_GENERIC_METHODS(gf));
276 }
277
generic_max_reqargs(SgGeneric * gf)278 static int generic_max_reqargs(SgGeneric *gf)
279 {
280 SgObject gslot = Sg_Assq(gf, SG_LIBRARY_GENERICS(Sg_VMCurrentLibrary()));
281 if (SG_FALSEP(gslot)) return SG_GENERIC_MAX_REQARGS(gf);
282 return (int)(intptr_t)SG_CADR(gslot);
283 }
284
check_method(SgObject methods,SgMethod * method,int replaceP,int * errorP)285 static int check_method(SgObject methods, SgMethod *method,
286 int replaceP, int *errorP)
287 {
288 SgObject mp;
289 SG_FOR_EACH(mp, methods) {
290 SgMethod *mm = SG_METHOD(SG_CAR(mp));
291 if (SG_PROCEDURE_REQUIRED(method) == SG_PROCEDURE_REQUIRED(mm) &&
292 SG_PROCEDURE_OPTIONAL(method) == SG_PROCEDURE_OPTIONAL(mm) &&
293 SG_EQ(SG_METHOD_QUALIFIER(method), SG_METHOD_QUALIFIER(mm))) {
294 SgClass **sp1 = SG_METHOD_SPECIALIZERS(method);
295 SgClass **sp2 = SG_METHOD_SPECIALIZERS(mm);
296 int required = SG_PROCEDURE_REQUIRED(method), i;
297 for (i = 0; i < required; i++) {
298 if (sp1[i] != sp2[i]) break;
299 }
300 if (i == required) {
301 if (replaceP) {
302 SG_SET_CAR(mp, SG_OBJ(method));
303 } else if (errorP) {
304 *errorP = TRUE;
305 }
306 return TRUE;
307 }
308 }
309 }
310 return FALSE;
311 }
312 /* TODO the code is now messy referctor me */
Sg_AddMethod(SgGeneric * generic,SgMethod * method)313 SgObject Sg_AddMethod(SgGeneric *generic, SgMethod *method)
314 {
315 SgObject pair, whereToAdd, gslot = SG_NIL;
316 int reqs = generic_max_reqargs(generic), replaced = FALSE, mainP;
317 int errp = FALSE;
318 if (method->generic && method->generic != generic) {
319 Sg_Error(UC("method %S already added to a generic function %S"),
320 method, method->generic);
321 }
322 if (!SG_FALSEP(Sg_Memq(SG_OBJ(method), SG_GENERIC_METHODS(generic)))) {
323 Sg_Error(UC("method %S already appears in a method list of generic %S "
324 "something wrong in MOP implementation?"),
325 method, method->generic);
326 }
327 /* ok set it here :) */
328 if (!method->generic) set_method_debug_name(method, generic);
329
330 method->generic = generic;
331 /* pre-allcate cons pair to avoid triggering GC */
332 mainP = in_global_context_p();
333 if (mainP) {
334 whereToAdd = SG_GENERIC_METHODS(generic);
335 } else {
336 SgObject lib = Sg_VMCurrentLibrary();
337 gslot = Sg_Assq(generic, SG_LIBRARY_GENERICS(lib));
338 if (SG_FALSEP(gslot)) {
339 gslot = SG_LIST2(generic, SG_OBJ(0));
340 whereToAdd = SG_NIL;
341 SG_LIBRARY_GENERICS(lib) = Sg_Cons(gslot, SG_LIBRARY_GENERICS(lib));
342 } else {
343 whereToAdd = SG_CDDR(gslot);
344 }
345 }
346 pair = Sg_Cons(SG_OBJ(method), whereToAdd);
347 if (SG_PROCEDURE_REQUIRED(method) > (unsigned int)reqs) {
348 reqs = SG_PROCEDURE_REQUIRED(method);
349 }
350 Sg_LockMutex(&generic->mutex);
351 /* Check if a method with the same signature exists */
352 replaced = check_method(SG_GENERIC_METHODS(generic),method, mainP, &errp);
353 if (errp) {
354 Sg_UnlockMutex(&generic->mutex);
355 /* we don't allow to replace the one defined in root vm */
356 Sg_Error(UC("method %S of generic %S is defined in main thread, "
357 "child thread can not replace it"),
358 method, method->generic);
359 }
360 if (!replaced) {
361 if (mainP) {
362 SG_GENERIC_METHODS(generic) = pair;
363 SG_GENERIC_MAX_REQARGS(generic) = reqs;
364 } else {
365 replaced = check_method(SG_CDDR(gslot), method, TRUE, NULL);
366 if (!replaced) {
367 SG_SET_CDR(SG_CDR(gslot), pair);
368 SG_SET_CAR(SG_CDR(gslot), SG_OBJ((intptr_t)reqs));
369 }
370 }
371 }
372 Sg_UnlockMutex(&generic->mutex);
373 return SG_UNDEF;
374 }
375
376 /*
377 remove-method is sort of otherway around.
378 even the method exists on parent thread however it won't be
379 removed from parent thread. child thread can't modify parent
380 thread.
381 */
382 /* TODO the code is now messy referctor me */
Sg_RemoveMethod(SgGeneric * gf,SgMethod * m)383 SgObject Sg_RemoveMethod(SgGeneric *gf, SgMethod *m)
384 {
385 SgObject mp, gslot = SG_NIL;
386 int mainP, maxReq = 0;
387 if (!SG_METHOD_GENERIC(m) || SG_METHOD_GENERIC(m) != gf) return SG_UNDEF;
388
389 Sg_LockMutex(&gf->mutex);
390 mainP = in_global_context_p();
391 if (mainP) {
392 mp = SG_GENERIC_METHODS(gf);
393 } else {
394 gslot = Sg_Assq(gf, SG_LIBRARY_GENERICS(Sg_VMCurrentLibrary()));
395 if (SG_FALSEP(gslot)) {
396 mp = SG_NIL;
397 } else {
398 mp = SG_CDDR(gslot);
399 }
400 }
401 if (SG_PAIRP(mp)) {
402 if (SG_EQ(SG_CAR(mp), SG_OBJ(m))) {
403 if (mainP) {
404 SG_GENERIC_METHODS(gf) = SG_CDR(mp);
405 } else {
406 /* never be #f */
407 SG_SET_CDR(SG_CDR(gslot), SG_CDR(mp));
408 }
409 } else {
410 while (SG_PAIRP(SG_CDR(mp))) {
411 if (SG_EQ(SG_CADR(mp), SG_OBJ(m))) {
412 SG_CDR(mp) = SG_CDDR(mp);
413 SG_METHOD_GENERIC(m) = NULL;
414 break;
415 }
416 mp = SG_CDR(mp);
417 }
418 }
419 }
420 if (mainP) {
421 mp = SG_GENERIC_METHODS(gf);
422 maxReq = SG_GENERIC_MAX_REQARGS(gf);
423 } else {
424 if (SG_FALSEP(gslot)) {
425 mp = SG_NIL;
426 } else {
427 mp = SG_CDDR(gslot);
428 maxReq = (int)(intptr_t)SG_CADR(gslot);
429 }
430 }
431 SG_FOR_EACH(mp, mp) {
432 /* sync # of required selector */
433 if (SG_PROCEDURE_REQUIRED(SG_CAR(mp)) > (unsigned int)maxReq) {
434 if (mainP) {
435 SG_GENERIC_MAX_REQARGS(gf) = SG_PROCEDURE_REQUIRED(SG_CAR(mp));
436 } else {
437 intptr_t mr = SG_PROCEDURE_REQUIRED(SG_CAR(mp));
438 SG_SET_CAR(SG_CDR(gslot), SG_OBJ(mr));
439 }
440 }
441 }
442 Sg_UnlockMutex(&gf->mutex);
443 return SG_UNDEF;
444 }
445
446 /* void Sg_AddDirectMethod(SgClass *klass, SgMethod *m) */
447 /* { */
448 /* if (SG_CLASS_CATEGORY(klass) == SG_CLASS_SCHEME) { */
449 /* SgObject p = Sg_Cons(SG_OBJ(m), SG_NIL); */
450 /* Sg_LockMutex(&klass->mutex); */
451 /* if (SG_FALSEP(Sg_Memq(klass->directMethods, SG_OBJ(m)))) { */
452 /* SG_SET_CDR(p, klass->directMethods); */
453 /* klass->directMethods = p; */
454 /* } */
455 /* Sg_UnlockMutex(&klass->mutex); */
456 /* } */
457 /* } */
458
459 #define filter_in(r_, test_, l_) \
460 do { \
461 SgObject h__ = SG_NIL, t__ = SG_NIL, l__ = l_; \
462 while (1) { \
463 if (SG_NULLP(l__)) { \
464 r_ = h__; \
465 break; \
466 } \
467 if (test_(SG_CAR(l__))) { \
468 SG_APPEND1(h__, t__, SG_CAR(l__)); \
469 } \
470 l__ = SG_CDR(l__); \
471 } \
472 } while (0)
473
474 /*
475 from A Monotonic Superclass Linearization for Dylan, Appendix B
476 http://192.220.96.201/dylan/linearization-oopsla96.html
477
478 C3 linearization
479 sort of topological sort I guess. given list must be graphs like
480 '((menu choice-widget object)
481 (menu popup-mixin)
482 (popup-mixin object))
483 This indicates like this graph;
484
485 <object>
486 / \
487 <choice-widget> ---\--------------+
488 | <popup-mixin> |
489 <menu> | |
490 \ | |
491 <new-popup-menu> ---------+
492
493 And the result will be like this list;
494 (menu choice-widget popup-mixin object)
495
496 This is the Scheme implementation without recursive
497 (define (merge-lists sequence)
498 (let loop ((rpr '()) ;; seed
499 (ri sequence))
500 (if (for-all null? ri)
501 (reverse! rpr)
502 (letrec ((candidate (lambda (c)
503 (define (tail? l) (memq c (tail l)))
504 (and (not (exists tail? ri))
505 c)))
506 (candidate-at-head
507 (lambda (l)
508 (and (not (null? l))
509 (candidate (head l))))))
510 (let ((next (exists candidate-at-head ri)))
511 (if next
512 (letrec ((remove-next (lambda (l)
513 (if (eq? (head l) next) (tail l) l))))
514 (loop (cons next rpr)
515 (map remove-next ri)))
516 (error 'merge-lists "inconsistent precedence graph")))))))
517
518
519 TODO It might be goot to export to scheme world, but I don't see any use
520 case to use this one, instead of topological sort.
521 */
merge_lists(SgObject sequence)522 static SgObject merge_lists(SgObject sequence)
523 {
524 SgObject rpr = SG_NIL, next;
525 long len = Sg_Length(sequence);
526 SgObject *ri, *sp, *tp;
527 /* never happen unless we export this function to the Scheme world */
528 if (len < 0) Sg_Error(UC("bad list of sequence: %S"), sequence);
529 ri = SG_NEW_ARRAY(SgObject, len);
530 for (sp = ri; sp < ri+len; sp++, sequence=SG_CDR(sequence)) {
531 *sp = SG_CAR(sequence);
532 }
533
534 for (;;) {
535 /* (for-all null? ri) */
536 for (sp = ri; sp < ri+len; sp++) {
537 if (!SG_NULLP(*sp)) break;
538 }
539 if (sp == ri+len) return Sg_ReverseX(rpr);
540 next = SG_FALSE;
541 /* candidate-at-head */
542 for (sp = ri; sp < ri+len; sp++) {
543 SgObject c;
544 if (!SG_PAIRP(*sp)) continue;
545 c = SG_CAR(*sp);
546 /* candidate */
547 for (tp = ri; tp<ri+len; tp++) {
548 if (!SG_PAIRP(*tp)) continue;
549 if (!SG_FALSEP(Sg_Memq(c, SG_CDR(*tp)))) break;
550 }
551 if (tp != ri+len) continue;
552 next = c;
553 break;
554 }
555 if (SG_FALSEP(next)) return SG_FALSE;
556
557 rpr = Sg_Cons(next, rpr);
558 /* remove-next */
559 for (sp = ri; sp<ri+len; sp++) {
560 if (SG_PAIRP(*sp) && SG_EQ(next, SG_CAR(*sp))) {
561 *sp = SG_CDR(*sp);
562 }
563 }
564 }
565 /* not reached */
566 }
567
deletel(SgObject target,SgObject lst)568 static SgObject deletel(SgObject target, SgObject lst)
569 {
570 SgObject h = SG_NIL, t = SG_NIL, cp;
571 SG_FOR_EACH(cp, lst) {
572 if (SG_EQ(SG_CAR(cp), target)) continue;
573 SG_APPEND1(h, t, SG_CAR(cp));
574 }
575 return h;
576 }
577
Sg_ComputeCPL(SgClass * klass)578 SgObject Sg_ComputeCPL(SgClass *klass)
579 {
580 SgObject seqh = SG_NIL, seqt = SG_NIL, ds, dp, result;
581 /* a trick to ensure we have <object> <top> at the end of CPL */
582 ds = deletel(SG_OBJ(SG_CLASS_OBJECT), klass->directSupers);
583 ds = deletel(SG_OBJ(SG_CLASS_TOP), ds);
584 ds = Sg_Append2(ds, SG_LIST1(SG_OBJ(SG_CLASS_OBJECT)));
585
586 /* map(cpl-list, c-direct-superclasses */
587 SG_FOR_EACH(dp, klass->directSupers) {
588 if (!Sg_TypeP(SG_CAR(dp), SG_CLASS_CLASS)) {
589 Sg_Error(UC("non-class found in direct superclass list: %S"),
590 klass->directSupers);
591 }
592 if (SG_CAR(dp) == SG_CLASS_OBJECT || SG_CAR(dp) == SG_CLASS_TOP) continue;
593 SG_APPEND1(seqh, seqt, SG_CLASS(SG_CAR(dp))->cpl);
594 }
595 SG_APPEND1(seqh, seqt, SG_CLASS_OBJECT->cpl);
596 SG_APPEND1(seqh, seqt, ds);
597
598 result = merge_lists(seqh);
599 if (SG_FALSEP(result)) {
600 Sg_Error(UC("discrepancy found in class precedence lists of "
601 "the superclasses: %S(%S)"), klass->directSupers, seqh);
602 }
603 /* add klass itsself */
604 return Sg_Cons(SG_OBJ(klass), result);
605 }
606
607 /*
608 compute-slots
609
610 The computed slots' order is reversed order than before.
611 e.g)
612 (define-class <point> ()
613 (x y))
614 (define-class <point2> (<point>)
615 (x1 y1))
616 The <point2> of class-slots returns ((x) (y) (x1) (y1))
617 so that the accessor always indicates the same position
618 of instance slots. This makes slot accessing using class
619 consistent.
620 */
Sg_ComputeSlots(SgClass * klass)621 SgObject Sg_ComputeSlots(SgClass *klass)
622 {
623 SgObject slots = SG_NIL;
624 SgObject cp, sp;
625 SG_FOR_EACH(cp, klass->cpl) {
626 SgObject acc = SG_NIL;
627 ASSERT(Sg_TypeP(SG_CAR(cp), SG_CLASS_CLASS));
628 SG_FOR_EACH(sp, SG_CLASS(SG_CAR(cp))->directSlots) {
629 SgObject slot = SG_CAR(sp);
630 ASSERT(SG_PAIRP(slot));
631 /* copy all slots */
632 acc = Sg_Cons(Sg_CopyList(slot), acc);
633 }
634 if (!SG_NULLP(acc)) {
635 slots = Sg_Append2X(Sg_ReverseX(acc), slots);
636 }
637 }
638 return slots;
639 }
640
Sg_MakeSlotAccessor(SgClass * klass,SgObject slot,int index,SgObject getter,SgObject setter,SgObject boundP)641 SgObject Sg_MakeSlotAccessor(SgClass *klass, SgObject slot, int index,
642 SgObject getter, SgObject setter, SgObject boundP)
643 {
644 SgSlotAccessor *sac = make_slot_accessor(klass, slot, index);
645
646 if (!SG_FALSEP(getter)) sac->getterS = getter;
647 if (!SG_FALSEP(setter)) sac->setterS = setter;
648 if (!SG_FALSEP(boundP)) sac->boundP = boundP;
649 return SG_OBJ(sac);
650 }
651
Sg_ApplicableP(SgObject c,SgObject arg)652 int Sg_ApplicableP(SgObject c, SgObject arg)
653 {
654 return !SG_FALSEP(Sg_Memq(c, SG_CLASS(Sg_ClassOf(arg))->cpl));
655 }
656
657 #define PREALLOC_SIZE 32
658
specializer_match(SgObject sp,SgObject obj)659 static int specializer_match(SgObject sp, SgObject obj)
660 {
661 return (SG_EQL_SPECIALIZERP(sp)
662 && Sg_EqvP(obj, SG_EQL_SPECIALIZER(sp)->object))
663 || Sg_TypeP(obj, sp);
664 }
665
compute_applicable_methods(SgGeneric * gf,SgObject * argv,int argc,int applyargs)666 static SgObject compute_applicable_methods(SgGeneric *gf, SgObject *argv,
667 int argc, int applyargs)
668 {
669 SgObject methods = get_all_methods(gf), mp;
670 SgObject h = SG_NIL, t = SG_NIL;
671 SgObject *args = argv;
672 int nsel;
673
674 if (SG_NULLP(methods)) return SG_NIL;
675
676 nsel = generic_max_reqargs(gf);
677 if (applyargs) argc--;
678 if (applyargs && nsel) {
679 int size = (int)Sg_Length(argv[argc]) + argc, i;
680 SgObject ap;
681 args = SG_NEW_ARRAY(SgObject, size);
682 for (i = 0; i < argc; i++) {
683 args[i] = argv[i];
684 }
685 SG_FOR_EACH(ap, argv[argc]) {
686 if (--nsel >= 0) args[i++] = SG_CAR(ap);
687 }
688 argc = size;
689 }
690
691 SG_FOR_EACH(mp, methods) {
692 SgMethod *m = SG_METHOD(SG_CAR(mp));
693 SgClass **sp;
694 SgObject *ap;
695 unsigned int n;
696 /* argument count check */
697 if ((unsigned int)argc < SG_PROCEDURE_REQUIRED(m)) continue;
698 if (!SG_PROCEDURE_OPTIONAL(m) &&
699 (unsigned int)argc > SG_PROCEDURE_REQUIRED(m)) continue;
700 /* type check */
701 for (ap = args, sp = SG_METHOD_SPECIALIZERS(m), n = 0;
702 n < SG_PROCEDURE_REQUIRED(m); ap++, sp++, n++) {
703 if (!specializer_match(*sp, *ap)) break;
704 }
705 if (n == SG_PROCEDURE_REQUIRED(m)) SG_APPEND1(h, t, SG_OBJ(m));
706 }
707 return h;
708 }
709
710 /*
711 These functions must be generic, however for now we just put here
712 and ignore the others.
713 */
more_specific_p(SgClass * c1,SgClass * c2,SgClass * arg)714 static int more_specific_p(SgClass *c1, SgClass *c2, SgClass *arg)
715 {
716 SgClass **cpl;
717 /* if we have eql specializer, then it's always more specific! */
718 if (Sg_TypeP(c2, SG_CLASS_EQL_SPECIALIZER)) return FALSE;
719 if (Sg_TypeP(c1, SG_CLASS_EQL_SPECIALIZER)) return TRUE;
720
721 /* ok, non eql case. */
722 if (c1 == arg) return TRUE;
723 if (c2 == arg) return FALSE;
724 for (cpl = arg->cpa; *cpl; cpl++) {
725 if (c1 == *cpl) return TRUE;
726 if (c2 == *cpl) return FALSE;
727 }
728 Sg_Panic("internal error: couldn't determine more specific method.");
729 return FALSE; /* dummy */
730 }
731
method_more_specific(SgMethod * m1,SgMethod * m2,SgClass ** targv,int argc)732 static int method_more_specific(SgMethod *m1, SgMethod *m2,
733 SgClass **targv, int argc)
734 {
735 SgClass **spec1 = SG_METHOD_SPECIALIZERS(m1);
736 SgClass **spec2 = SG_METHOD_SPECIALIZERS(m2);
737 int i, xreq = SG_PROCEDURE_REQUIRED(m1), yreq = SG_PROCEDURE_REQUIRED(m2);
738 for (i = 0; i < argc; i++) {
739 if (!SG_EQ(spec1[i], spec2[i]) && spec1[i] && spec2[i]) {
740 return more_specific_p(spec1[i], spec2[i], targv[i]);
741 }
742 }
743 if (xreq > yreq) return TRUE;
744 if (xreq < yreq) return FALSE;
745 if (SG_PROCEDURE_OPTIONAL(m2)) return TRUE;
746 else return FALSE;
747 }
748
749 /* :around :before :after and :primary */
750 enum {
751 PRIMARY_INDEX = 0,
752 BEFORE_INDEX,
753 AFTER_INDEX,
754 AROUND_INDEX,
755 QUALIFIER_COUNT
756 };
757
sort_method_by_qualifier(SgObject methods,SgObject * result,int checkType)758 static SgObject* sort_method_by_qualifier(SgObject methods, SgObject *result,
759 int checkType)
760 {
761 SgObject cp, art = SG_NIL, bt = SG_NIL, pt = SG_NIL, aft = SG_NIL;
762 int i;
763 for (i=0; i<QUALIFIER_COUNT; i++) result[i] = SG_NIL;
764 SG_FOR_EACH(cp, methods) {
765 SgMethod *m = SG_METHOD(SG_CAR(cp));
766 if (checkType && !SG_METHODP(m)) {
767 Sg_Error(UC("method required but got %S"), m);
768 }
769 if (SG_EQ(SG_METHOD_QUALIFIER(m), SG_KEYWORD_AROUND)) {
770 SG_APPEND1(result[AROUND_INDEX], art, SG_OBJ(m));
771 } else if (SG_EQ(SG_METHOD_QUALIFIER(m), SG_KEYWORD_BEFORE)) {
772 SG_APPEND1(result[BEFORE_INDEX], bt, SG_OBJ(m));
773 } else if (SG_EQ(SG_METHOD_QUALIFIER(m), SG_KEYWORD_PRIMARY)) {
774 SG_APPEND1(result[PRIMARY_INDEX], pt, SG_OBJ(m));
775 } else if (SG_EQ(SG_METHOD_QUALIFIER(m), SG_KEYWORD_AFTER)) {
776 SG_APPEND1(result[AFTER_INDEX], aft, SG_OBJ(m));
777 } else {
778 /* invalid */
779 Sg_Error(UC("wrong method-qualifier %S in method %S"),
780 SG_METHOD_QUALIFIER(m), m);
781 }
782 }
783 return result;
784 }
785
sort_primary_methods(SgObject methods,SgObject * argv,int argc,int applyargs)786 static SgObject sort_primary_methods(SgObject methods, SgObject *argv, int argc,
787 int applyargs)
788 {
789 SgObject array_s[PREALLOC_SIZE], *array = array_s;
790 SgClass *targv_s[PREALLOC_SIZE], **targv = targv_s;
791 int count = 0, len, step, i, j, tsize = argc;
792 SgObject mp;
793 /* for safety */
794 if (SG_NULLP(methods)) return methods;
795
796 len = (int)Sg_Length(methods);
797 /* TODO maybe we should use alloca */
798 if (len >= PREALLOC_SIZE) array = SG_NEW_ARRAY(SgObject, len);
799 /* if this is apply call we need to expand the arguments */
800 if (applyargs) {
801 int n = (int)Sg_Length(argv[argc-1]);
802 if (n < 0) Sg_Error(UC("bad argument list: %S"), argv[argc-1]);
803 tsize += n-1;
804 argc--;
805 }
806 if (tsize >= PREALLOC_SIZE) targv = SG_NEW_ARRAY(SgClass*, tsize);
807
808 SG_FOR_EACH(mp, methods) {
809 if (!Sg_TypeP(SG_CAR(mp), SG_CLASS_METHOD)) {
810 Sg_Error(UC("bad method in applicable method list: %S"), SG_CAR(mp));
811 }
812 array[count++] = SG_CAR(mp);
813 }
814 for (i=0; i <argc; i++) targv[i] = Sg_ClassOf(argv[i]);
815 if (applyargs) {
816 SgObject ap;
817 SG_FOR_EACH(ap, argv[argc]) {
818 targv[i++] = Sg_ClassOf(SG_CAR(ap));
819 }
820 }
821 for (step = len/2; step > 0; step /=2) {
822 for (i = step; i<len; i++) {
823 for (j = i-step; j>=0; j -= step) {
824 /* TODO, use generic method */
825 if (method_more_specific(SG_METHOD(array[j]),
826 SG_METHOD(array[j+step]),
827 targv, tsize)) {
828 break;
829 } else {
830 SgObject tmp = array[j+step];
831 array[j+step] = array[j];
832 array[j] = tmp;
833 }
834 }
835 }
836 }
837
838 return Sg_ArrayToList(array, len);
839 }
840
841 /*
842 creates a procedure and rest of next-methods.
843 basically, only around must have next-methods, other must be called
844 */
845 static SgObject procedure_invoker(SgObject *args, int argc, void *data);
invoke_cc(SgObject result,void ** data)846 static SgObject invoke_cc(SgObject result, void **data)
847 {
848 void **dvec = (void**)data[0];
849 SgObject proc = SG_OBJ(dvec[0]);
850 SgObject *args = (SgObject*)data[1];
851 int argc = (int)(intptr_t)data[2];
852 /* store the result of :primary methods */
853 if (dvec[2]) dvec[3] = result;
854 if (SG_NULLP(proc)) return dvec[3]; /* no more methods */
855 return procedure_invoker(args, argc, dvec);
856 }
857
858 /* unpack argument for :before and :after qualifier.
859 It's attempting to reuse the oargs' last position when the optional
860 argument has only one length however DO NOT DO IT! It's the VM's stack
861 so if you modify it, it causes invalid argument (not an error but
862 unexpected value will be passed).
863 e.g)
864 ;; args of *1 will be '() but that's not what we want!
865 (define-method hoge :before ((a <base>) b . args) args) ;; *1
866 (define-method hoge :before ((a <sub>) b . args) args)
867 (define-method hoge ((a <sub>) b . args) args)
868 (hoge (make <sub>) 'b 'c)
869 And we don't have to copy the args during the method creation since
870 we know it's a valid pointer during method chain (VM stack) and
871 we allocate when we unpack the argument :)
872 */
unpack_argument(SgObject proc,SgObject ** oargs,int * oargc,SgObject rest)873 static SgObject unpack_argument(SgObject proc, SgObject **oargs, int *oargc,
874 SgObject rest)
875 {
876 int argc = *oargc;
877 SgObject *args = *oargs;
878 SgObject opts = args[--argc];
879 if (SG_NULLP(opts)) {
880 /* easy */
881 *oargc = argc;
882 return Sg_MakeNextMethod(SG_METHOD_GENERIC(proc), rest, args, argc, FALSE);
883 } else {
884 int len = (int)Sg_Length(opts), i;
885 int size = argc + len;
886 SgObject *newargs = SG_NEW_ARRAY(SgObject, size), cp;
887 for (i = 0; i < argc; i++) {
888 newargs[i] = args[i];
889 }
890 SG_FOR_EACH(cp, opts) {
891 newargs[argc++] = SG_CAR(cp);
892 }
893 *oargs = newargs;
894 *oargc = argc;
895 return Sg_MakeNextMethod(SG_METHOD_GENERIC(proc), rest, newargs,
896 argc, FALSE);
897 }
898
899 }
900
procedure_invoker(SgObject * args,int argc,void * data)901 static SgObject procedure_invoker(SgObject *args, int argc, void *data)
902 {
903 void **dvec = (void**)data;
904 SgObject proc;
905 SgObject h = SG_NIL, t = SG_NIL;
906 void *next[3];
907 int i;
908 /* retrive data */
909 proc = SG_CAR(SG_OBJ(dvec[0]));
910 dvec[0] = SG_CDR(SG_OBJ(dvec[0]));
911
912 ASSERT(SG_METHODP(proc));
913 /* prepare call frame */
914 next[0] = dvec;
915 next[1] = SG_OBJ(args);
916 next[2] = SG_OBJ((intptr_t)argc);
917 if (SG_EQ(SG_METHOD_QUALIFIER(proc), SG_KEYWORD_PRIMARY)) {
918 /* compute next-method */
919 /* issue 119 check subr otherwise wrong number error will be raised */
920 if (!SG_SUBRP(SG_METHOD_PROCEDURE(proc))) {
921 SgObject rest = SG_OBJ(dvec[1]);
922 /* unpack optional argument if the procedure accepts it
923 to avoid packing twice. */
924 if (SG_PROCEDURE_OPTIONAL(SG_METHOD_PROCEDURE(proc))) {
925 SgObject m = unpack_argument(proc, &args, &argc, rest);
926 SG_APPEND1(h, t, m);
927 } else {
928 SG_APPEND1(h, t, Sg_MakeNextMethod(SG_METHOD_GENERIC(proc), rest,
929 args, argc, FALSE));
930 }
931 }
932 dvec[2] = (void*)TRUE;
933 } else {
934 /* dummy, :before and :after can not have next-method. */
935 if (SG_PROCEDURE_OPTIONAL(SG_METHOD_PROCEDURE(proc))) {
936 SgObject m = unpack_argument(proc, &args, &argc, SG_NIL);
937 SG_APPEND1(h, t, m);
938 } else {
939 SG_APPEND1(h, t, Sg_MakeNextMethod(SG_METHOD_GENERIC(proc), SG_NIL,
940 args, argc, FALSE));
941 }
942 dvec[2] = (void*)FALSE;
943 }
944 Sg_VMPushCC(invoke_cc, next, 3);
945 for (i = 0; i < argc; i++) {
946 SG_APPEND1(h, t, args[i]);
947 }
948 return Sg_VMApply(SG_METHOD_PROCEDURE(proc), h);
949 }
950
compute_around_methods_rec(SgObject around,SgObject before,SgObject primary,SgObject after)951 static SgObject compute_around_methods_rec(SgObject around, SgObject before,
952 SgObject primary, SgObject after)
953 {
954 SgObject m, rest;
955 SgObject proc, name = SG_UNDEF;
956 SgObject result = SG_NIL, t = SG_NIL, mp;
957 SgClass **specs = NULL;
958 void **dvec;
959 int req = -1, opt = -1;
960
961 /* on tiny clos for R6RS, after is called in reverse order */
962 after = Sg_ReverseX(after);
963 /* calculate before primary and after first */
964 SG_FOR_EACH(mp, before) {
965 SG_APPEND1(result, t, SG_CAR(mp));
966 }
967 mp = primary;
968 req = SG_PROCEDURE_REQUIRED(SG_CAR(mp));
969 opt = SG_PROCEDURE_OPTIONAL(SG_CAR(mp));
970 name = SG_PROCEDURE_NAME(SG_CAR(mp));
971 specs = SG_METHOD_SPECIALIZERS(SG_CAR(mp));
972 SG_APPEND1(result, t, SG_CAR(mp));
973 rest = SG_CDR(mp);
974 /* primary next-method will be created in procedure_invoker */
975
976 SG_FOR_EACH(mp, after) {
977 SG_APPEND1(result, t, SG_CAR(mp));
978 }
979 /*
980 data store vector.
981 0: :before + first of :primary + :after
982 1: the rest of :primary
983 2: flag if invoke_cc needs to store the result or not
984 3: the result of invoke_cc. this will be returned as a result of this
985 generic method calling.
986 */
987 dvec = SG_NEW_ARRAY(void*, 4);
988 dvec[0] = result;
989 dvec[1] = rest;
990 dvec[2] = (void*)FALSE;
991 dvec[3] = SG_UNDEF;
992 proc = Sg_MakeSubr(procedure_invoker, dvec, req, opt, name);
993 m = method_allocate(SG_CLASS_METHOD, proc);
994 SG_METHOD_PROCEDURE(m) = proc;
995 SG_METHOD_SPECIALIZERS(m) = specs;
996 SG_METHOD_QUALIFIER(m) = SG_FALSE;
997 SG_PROCEDURE_REQUIRED(m) = req;
998 SG_PROCEDURE_OPTIONAL(m) = opt;
999 SG_PROCEDURE_NAME(m) = name;
1000
1001 if (SG_NULLP(around)) {
1002 return SG_LIST1(m);
1003 } else {
1004 /* calculate around.
1005 around method must have call-next-method and if it is not called,
1006 the method does not proceed to next. so we need to create a list
1007 which contains around method and the rest of result, like this;
1008 (:around m) ;; m is calculated methods.
1009 however, :around itself can be multiple, so it might be multiple
1010 lists, not only length 2 list.
1011 */
1012 SgObject h = SG_NIL, ap;
1013 t = SG_NIL; /* reuse */
1014 SG_FOR_EACH(ap, around) {
1015 SG_APPEND1(h, t, SG_CAR(ap));
1016 }
1017 SG_APPEND1(h, t, m);
1018 return h;
1019 }
1020 }
1021
compute_around_methods(SgObject around,SgObject before,SgObject primary,SgObject after,SgObject * argv,int argc,int applyargs)1022 static SgObject compute_around_methods(SgObject around, SgObject before,
1023 SgObject primary, SgObject after,
1024 SgObject *argv, int argc, int applyargs)
1025 {
1026 /* lazyness */
1027 primary = sort_primary_methods(primary, argv, argc, applyargs);
1028 /* if there is no primary method, then it must be an error */
1029 if (SG_NULLP(primary)) {
1030 return SG_NIL;
1031 }
1032
1033 around = sort_primary_methods(around, argv, argc, applyargs);
1034 before = sort_primary_methods(before, argv, argc, applyargs);
1035 after = sort_primary_methods(after, argv, argc, applyargs);
1036
1037 return compute_around_methods_rec(around, before, primary, after);
1038 }
1039
sort_method(SgObject methods,SgObject * argv,int argc,int applyargs)1040 static SgObject sort_method(SgObject methods, SgObject *argv, int argc,
1041 int applyargs)
1042 {
1043 SgObject qualified_methods[QUALIFIER_COUNT];
1044 SgObject primary, before, after, around;
1045 sort_method_by_qualifier(methods, qualified_methods, FALSE);
1046 primary = qualified_methods[PRIMARY_INDEX];
1047 before = qualified_methods[BEFORE_INDEX];
1048 after = qualified_methods[AFTER_INDEX];
1049 around = qualified_methods[AROUND_INDEX];
1050
1051 if (SG_NULLP(around) && SG_NULLP(before) && SG_NULLP(after)) {
1052 return sort_primary_methods(primary, argv, argc, applyargs);
1053 } else {
1054 /* dummy */
1055 return compute_around_methods(around, before, primary, after, argv, argc,
1056 applyargs);
1057 }
1058 }
1059
Sg_ComputeMethods(SgGeneric * gf,SgObject * argv,int argc,int applyargs)1060 SgObject Sg_ComputeMethods(SgGeneric *gf, SgObject *argv, int argc,
1061 int applyargs)
1062 {
1063 SgObject applicable = compute_applicable_methods(gf, argv, argc, applyargs);
1064 if (SG_NULLP(applicable)) return applicable;
1065 if (SG_NULLP(SG_CDR(applicable))) return applicable;
1066 return sort_method(applicable, argv, argc, applyargs);
1067 }
1068
1069 #define VMSLOT_UNBOUND(klass, obj, slot) \
1070 Sg_VMApply3(SG_OBJ(&Sg_GenericSlotUnbound), \
1071 SG_OBJ(klass), obj, slot)
1072
1073 #define VMSLOT_MISSING3(klass, obj, slot) \
1074 Sg_VMApply3(SG_OBJ(&Sg_GenericSlotMissing), \
1075 SG_OBJ(klass), obj, slot)
1076
1077 #define VMSLOT_MISSING4(klass, obj, slot, val) \
1078 Sg_VMApply4(SG_OBJ(&Sg_GenericSlotMissing), \
1079 SG_OBJ(klass), obj, slot, val)
1080
1081 #define SLOT_UNBOUND(klass, obj, slot) \
1082 Sg_Apply3(SG_OBJ(&Sg_GenericSlotUnbound), \
1083 SG_OBJ(klass), obj, slot)
1084
1085 #define SLOT_MISSING3(klass, obj, slot) \
1086 Sg_Apply3(SG_OBJ(&Sg_GenericSlotMissing), \
1087 SG_OBJ(klass), obj, slot)
1088
1089 #define SLOT_MISSING4(klass, obj, slot, val) \
1090 Sg_Apply4(SG_OBJ(&Sg_GenericSlotMissing), \
1091 SG_OBJ(klass), obj, slot, val)
1092
1093
lookup_slot_info(SgClass * klass,SgObject name)1094 static SgSlotAccessor* lookup_slot_info(SgClass *klass, SgObject name)
1095 {
1096 SgSlotAccessor **gNs = klass->gettersNSetters;
1097 SgObject cpl = klass->cpl;
1098 /* CPL never be '() */
1099 SgClass *tklass = SG_CAR(cpl);
1100 cpl = SG_CDR(cpl);
1101 entry:
1102 for (;*gNs;gNs++) {
1103 if (SG_EQ(name, (*gNs)->name)) {
1104 return *gNs;
1105 }
1106 }
1107 /* try tag */
1108 if (tklass != SG_CLASS_CLASS && !SG_NULLP(cpl)) {
1109 tklass = SG_CAR(cpl);
1110 cpl = SG_CDR(cpl);
1111 gNs = tklass->gettersNSetters;
1112 goto entry;
1113 }
1114 return NULL; /* dummy */
1115 }
1116
1117 /* FIXME this is really inefficient */
c_getter_wrapper(SgObject * argv,int argc,void * data)1118 static SgObject c_getter_wrapper(SgObject *argv, int argc, void *data)
1119 {
1120 if (argc != 1) {
1121 Sg_WrongNumberOfArgumentsViolation(SG_INTERN("slot getter"), 1, argc,
1122 (argc > 0) ? argv[0] : SG_NIL);
1123 }
1124 return ((SgSlotGetterProc)data)(argv[0]);
1125 }
1126
c_setter_wrapper(SgObject * argv,int argc,void * data)1127 static SgObject c_setter_wrapper(SgObject *argv, int argc, void *data)
1128 {
1129 if (argc != 2) {
1130 Sg_WrongNumberOfArgumentsViolation(SG_INTERN("slot setter"), 2, argc,
1131 (argc > 0) ? argv[0] : SG_NIL);
1132 }
1133 ((SgSlotSetterProc)data)(argv[0], argv[1]);
1134 return SG_UNDEF;
1135 }
1136
1137
Sg_ComputeGetterAndSetter(SgClass * klass,SgObject slot)1138 SgObject Sg_ComputeGetterAndSetter(SgClass *klass, SgObject slot)
1139 {
1140 /* remove klass itself from cpl */
1141 SgObject rcpl = SG_CDR(klass->cpl), cp;
1142 SgObject ds = klass->directSlots, s = SG_CAR(slot);
1143 SgObject getter = SG_FALSE, setter = SG_FALSE;
1144
1145 SG_FOR_EACH(cp, rcpl) {
1146 SgObject check = Sg_Assq(s, ds);
1147 if (SG_FALSEP(check)) {
1148 SgSlotAccessor *sac = lookup_slot_info(SG_CLASS(SG_CAR(cp)), s);
1149
1150 if (!sac) continue;
1151 if (sac->getter && SG_FALSEP(getter)) {
1152 /* TODO, can we assume C getter is transparent? */
1153 getter = Sg_MakeSubr(c_getter_wrapper, sac->getter, 1, 0, s);
1154 }
1155 if (sac->setter && SG_FALSEP(setter)) {
1156 setter = Sg_MakeSubr(c_setter_wrapper, sac->setter, 2, 0, s);
1157 }
1158 if (!SG_FALSEP(getter) && !SG_FALSEP(setter)) break;
1159 }
1160 }
1161 /* by default bound? is not defined */
1162 return SG_LIST3(getter, setter, SG_FALSE);
1163 }
1164
slot_boundp_cc(SgObject result,void ** data)1165 static SgObject slot_boundp_cc(SgObject result, void **data)
1166 {
1167 return SG_FALSEP(result) ? SG_FALSE: SG_TRUE;
1168 }
1169
slot_ref_cc(SgObject result,void ** data)1170 static SgObject slot_ref_cc(SgObject result, void **data)
1171 {
1172 SgObject obj = data[0];
1173 SgObject slot = data[1];
1174 int boundp = (int)(intptr_t)data[2];
1175 if (SG_UNBOUNDP(result) || SG_UNDEFP(result)) {
1176 if (boundp) return SG_FALSE;
1177 else return VMSLOT_UNBOUND(Sg_ClassOf(obj), obj, slot);
1178 } else {
1179 if (boundp) return SG_TRUE;
1180 else return result;
1181 }
1182 }
1183
slot_ref_rec(SgObject obj,SgObject name,int boundp)1184 static SgObject slot_ref_rec(SgObject obj, SgObject name, int boundp)
1185 {
1186 SgSlotAccessor *accessor = lookup_slot_info(Sg_ClassOf(obj), name);
1187 if (accessor) {
1188 if (accessor->getter) {
1189 void *data[3];
1190 data[0] = obj;
1191 data[1] = name;
1192 data[2] = (void*)(intptr_t)boundp;
1193 return slot_ref_cc(accessor->getter(obj), data);
1194 } else {
1195 /* scheme accessor, assume obj is instance */
1196 if (boundp && SG_PROCEDUREP(accessor->boundP)) {
1197 void *data[3];
1198 data[0] = obj;
1199 data[1] = name;
1200 data[2] = (void*)(intptr_t)boundp;
1201 Sg_VMPushCC(slot_boundp_cc, data, 3);
1202 return Sg_VMApply1(accessor->boundP, obj);
1203 } else if (!SG_PROCEDUREP(accessor->getterS)) {
1204 SgObject val = SG_INSTANCE(obj)->slots[accessor->index];
1205 void *data[3];
1206 data[0] = obj;
1207 data[1] = name;
1208 data[2] = (void*)(intptr_t)boundp;
1209 return slot_ref_cc(val, data);
1210 } else {
1211 /* Hope this will be removed by compiler... */
1212 void *data[3];
1213 data[0] = obj;
1214 data[1] = name;
1215 data[2] = (void*)(intptr_t)boundp;
1216 Sg_VMPushCC(slot_ref_cc, data, 3);
1217 return Sg_VMApply1(accessor->getterS, obj);
1218 }
1219 }
1220 } else {
1221 return VMSLOT_MISSING3(Sg_ClassOf(obj), obj, name);
1222 }
1223 }
1224
vmslot_ref_cc(SgObject result,void ** data)1225 static SgObject vmslot_ref_cc(SgObject result, void **data)
1226 {
1227 return Sg_VMSlotRef(SG_OBJ(data[0]), SG_OBJ(data[1]));
1228 }
1229
Sg_VMSlotRef(SgObject obj,SgObject name)1230 SgObject Sg_VMSlotRef(SgObject obj, SgObject name)
1231 {
1232 SgClass *klass = Sg_ClassOf(obj);
1233 if (!SG_FALSEP(klass->redefined)) {
1234 void *data[2];
1235 data[0] = obj;
1236 data[1] = name;
1237 Sg_VMPushCC(vmslot_ref_cc, data, 2);
1238 return redefine_instance_class(obj, klass);
1239 }
1240 return slot_ref_rec(obj, name, FALSE);
1241 }
1242
slot_set_rec(SgObject obj,SgObject name,SgObject value)1243 static SgObject slot_set_rec(SgObject obj, SgObject name, SgObject value)
1244 {
1245 SgSlotAccessor *accessor = lookup_slot_info(Sg_ClassOf(obj), name);
1246 if (accessor) {
1247 if (accessor->setter) {
1248 accessor->setter(obj, value);
1249 return SG_UNDEF;
1250 } else {
1251 /* scheme accessor */
1252 if (!SG_PROCEDUREP(accessor->setterS)) {
1253 SG_INSTANCE(obj)->slots[accessor->index] = value;
1254 return SG_UNDEF;
1255 } else {
1256 return Sg_VMApply2(accessor->setterS, obj, value);
1257 }
1258 }
1259 } else {
1260 return VMSLOT_MISSING4(Sg_ClassOf(obj), obj, name, value);
1261 }
1262 }
1263
vmslot_set_cc(SgObject result,void ** data)1264 static SgObject vmslot_set_cc(SgObject result, void **data)
1265 {
1266 return Sg_VMSlotSet(SG_OBJ(data[0]), SG_OBJ(data[1]), SG_OBJ(data[2]));
1267 }
1268
Sg_VMSlotSet(SgObject obj,SgObject name,SgObject value)1269 SgObject Sg_VMSlotSet(SgObject obj, SgObject name, SgObject value)
1270 {
1271 SgClass *klass = Sg_ClassOf(obj);
1272 if (!SG_FALSEP(klass->redefined)) {
1273 void *data[3];
1274 data[0] = obj;
1275 data[1] = name;
1276 data[2] = value;
1277 Sg_VMPushCC(vmslot_set_cc, data, 3);
1278 return redefine_instance_class(obj, klass);
1279 }
1280 return slot_set_rec(obj, name, value);
1281 }
1282
1283 /* For now, these 2 are really simple */
Sg_SlotRefUsingAccessor(SgObject obj,SgSlotAccessor * ac)1284 SgObject Sg_SlotRefUsingAccessor(SgObject obj, SgSlotAccessor *ac)
1285 {
1286 if (ac->getter) {
1287 return ac->getter(obj);
1288 } else {
1289 return SG_INSTANCE(obj)->slots[ac->index];
1290 }
1291 }
1292
Sg_SlotBoundUsingAccessor(SgObject obj,SgSlotAccessor * ac)1293 int Sg_SlotBoundUsingAccessor(SgObject obj, SgSlotAccessor *ac)
1294 {
1295 SgObject v = Sg_SlotRefUsingAccessor(obj, ac);
1296 return !(SG_UNBOUNDP(v) || SG_UNDEFP(v));
1297 }
1298
Sg_SlotSetUsingAccessor(SgObject obj,SgSlotAccessor * ac,SgObject value)1299 void Sg_SlotSetUsingAccessor(SgObject obj, SgSlotAccessor *ac, SgObject value)
1300 {
1301 if (ac->setter) {
1302 ac->setter(obj, value);
1303 } else {
1304 SG_INSTANCE(obj)->slots[ac->index] = value;
1305 }
1306 }
1307
Sg_SlotRefUsingClass(SgClass * klass,SgObject obj,SgObject name)1308 SgObject Sg_SlotRefUsingClass(SgClass *klass, SgObject obj, SgObject name)
1309 {
1310 SgSlotAccessor *ac;
1311 if (!SG_ISA(obj, klass)) {
1312 Sg_Error(UC("object %S is not an instance of class %S"), obj, klass);
1313 }
1314 ac = lookup_slot_info(klass, name);
1315 if (!ac) Sg_Error(UC("class %S doesn't have slot named %S."), klass, name);
1316 return Sg_SlotRefUsingAccessor(obj, ac);
1317 }
1318
Sg_SlotSetUsingClass(SgClass * klass,SgObject obj,SgObject name,SgObject value)1319 void Sg_SlotSetUsingClass(SgClass *klass, SgObject obj, SgObject name,
1320 SgObject value)
1321 {
1322 SgSlotAccessor *ac;
1323 if (!SG_ISA(obj, klass)) {
1324 Sg_Error(UC("object %S is not an instance of class %S"), obj, klass);
1325 }
1326 ac = lookup_slot_info(klass, name);
1327 if (!ac) Sg_Error(UC("class %S doesn't have slot named %S."), klass, name);
1328 Sg_SlotSetUsingAccessor(obj, ac, value);
1329 }
1330
Sg_SlotBoundUsingClass(SgClass * klass,SgObject obj,SgObject name)1331 int Sg_SlotBoundUsingClass(SgClass *klass, SgObject obj, SgObject name)
1332 {
1333 SgSlotAccessor *ac = lookup_slot_info(klass, name);
1334 if (!ac) Sg_Error(UC("class %S doesn't have slot named %S."), klass, name);
1335 return !SG_UNBOUNDP(Sg_SlotRefUsingAccessor(obj, ac));
1336 }
1337
vmslot_boundp_cc(SgObject result,void ** data)1338 static SgObject vmslot_boundp_cc(SgObject result, void **data)
1339 {
1340 return Sg_VMSlotBoundP(SG_OBJ(data[0]), SG_OBJ(data[1]));
1341 }
1342
Sg_VMSlotBoundP(SgObject obj,SgObject slot)1343 SgObject Sg_VMSlotBoundP(SgObject obj, SgObject slot)
1344 {
1345 SgClass *klass = Sg_ClassOf(obj);
1346 if (!SG_FALSEP(klass->redefined)) {
1347 void *data[2];
1348 data[0] = obj;
1349 data[1] = slot;
1350 Sg_VMPushCC(vmslot_boundp_cc, data, 2);
1351 return redefine_instance_class(obj, klass);
1352 }
1353 return slot_ref_rec(obj, slot, TRUE);
1354 }
1355
Sg_ClassOf(SgObject obj)1356 SgClass* Sg_ClassOf(SgObject obj)
1357 {
1358 if (!SG_PTRP(obj)) {
1359 if (SG_TRUEP(obj) || SG_FALSEP(obj)) return SG_CLASS_BOOL;
1360 if (SG_NULLP(obj)) return SG_CLASS_NULL;
1361 if (SG_CHARP(obj)) return SG_CLASS_CHAR;
1362 if (SG_INTP(obj)) return SG_CLASS_INTEGER;
1363 if (SG_EOFP(obj)) return SG_CLASS_EOF_OBJECT;
1364 if (SG_UNDEFP(obj)) return SG_CLASS_UNDEFINED_OBJECT;
1365 #ifdef USE_IMMEDIATE_FLONUM
1366 if (SG_IFLONUMP(obj)) return SG_CLASS_REAL;
1367 #endif
1368 else return SG_CLASS_UNKNOWN;
1369 }
1370 if (SG_FLONUMP(obj)) return SG_CLASS_REAL;
1371 if (SG_PAIRP(obj)) return SG_CLASS_PAIR;
1372 return SG_CLASS_OF(obj);
1373 }
1374
vmclassof_cc(SgObject result,void ** data)1375 static SgObject vmclassof_cc(SgObject result, void **data)
1376 {
1377 return Sg_VMClassOf(result);
1378 }
1379
Sg_VMClassOf(SgObject obj)1380 SgObject Sg_VMClassOf(SgObject obj)
1381 {
1382 /* for now */
1383 SgClass *klass = Sg_ClassOf(obj);
1384 if (!SG_FALSEP(klass->redefined)) {
1385 Sg_VMPushCC(vmclassof_cc, NULL, 0);
1386 return redefine_instance_class(obj, klass);
1387 }
1388 return SG_OBJ(Sg_ClassOf(obj));
1389 }
1390
vmisa_cc(SgObject result,void ** data)1391 static SgObject vmisa_cc(SgObject result, void **data)
1392 {
1393 return Sg_VMIsA(SG_OBJ(data[0]), SG_CLASS(data[1]));
1394 }
1395
Sg_VMIsA(SgObject obj,SgClass * klass)1396 SgObject Sg_VMIsA(SgObject obj, SgClass *klass)
1397 {
1398 /* for now */
1399 SgClass *k = Sg_ClassOf(obj);
1400 if (!SG_FALSEP(k->redefined)) {
1401 void *data[2];
1402 data[0] = obj;
1403 data[1] = klass;
1404 Sg_VMPushCC(vmisa_cc, data, 2);
1405 return redefine_instance_class(obj, k);
1406 }
1407 return SG_MAKE_BOOL(Sg_TypeP(obj, klass));
1408 }
1409
Sg_TypeP(SgObject obj,SgClass * type)1410 int Sg_TypeP(SgObject obj, SgClass *type)
1411 {
1412 return Sg_SubtypeP(Sg_ClassOf(obj), type);
1413 }
1414
Sg_SubtypeP(SgClass * sub,SgClass * type)1415 int Sg_SubtypeP(SgClass *sub, SgClass *type)
1416 {
1417 SgClass **p;
1418 if (sub == type) return TRUE;
1419 p = sub->cpa;
1420 while (*p) {
1421 if (*p++ == type) return TRUE;
1422 }
1423 return FALSE;
1424 }
1425
1426 /* <class> */
class_print(SgObject obj,SgPort * port,SgWriteContext * ctx)1427 static void class_print(SgObject obj, SgPort *port, SgWriteContext *ctx)
1428 {
1429 Sg_Printf(port, UC("#<class %A%s>"),
1430 SG_CLASS(obj)->name,
1431 /* for now */
1432 UC(""));
1433 }
1434
class_finalize(SgObject obj,void * data)1435 static void class_finalize(SgObject obj, void *data)
1436 {
1437 Sg_DestroyMutex(&SG_CLASS(obj)->mutex);
1438 Sg_DestroyCond(&SG_CLASS(obj)->cv);
1439 }
1440
class_allocate(SgClass * klass,SgObject initargs)1441 static SgObject class_allocate(SgClass *klass, SgObject initargs)
1442 {
1443 SgClass *instance = SG_ALLOCATE(SgClass, klass);
1444 SG_SET_CLASS(instance, klass);
1445 instance->allocate = NULL;
1446 instance->printer = NULL;
1447 instance->compare = object_compare;
1448 instance->serialize = NULL;
1449 instance->cpa = NULL;
1450 instance->nfields = 0;
1451 instance->coreSize = 0;
1452 instance->flags = SG_CLASS_SCHEME;
1453 instance->name = SG_FALSE;
1454 instance->directSupers = SG_NIL;
1455 instance->directSlots = SG_NIL;
1456 instance->gettersNSetters = SG_NIL;
1457 instance->cpl = SG_NIL;
1458 instance->directSubclasses = SG_NIL;
1459 instance->creader = SG_FALSE;
1460 instance->cscanner = SG_FALSE;
1461 instance->cwriter = SG_FALSE;
1462 instance->redefined = SG_FALSE;
1463 instance->library = SG_FALSE;
1464
1465 Sg_InitMutex(&instance->mutex, FALSE);
1466 Sg_InitCond(&instance->cv);
1467 /* we may have redefinition and class may be GCed
1468 so add finalizer to destroy mutex */
1469 Sg_RegisterFinalizer(SG_OBJ(instance), class_finalize, NULL);
1470 return SG_OBJ(instance);
1471 }
1472
1473 /* not in the header for now */
Sg_ClassAllocate(SgClass * klass,SgObject initargs)1474 SgObject Sg_ClassAllocate(SgClass *klass, SgObject initargs)
1475 {
1476 return class_allocate(klass, initargs);
1477 }
1478
1479 /*
1480 <class> slot accessors
1481
1482 I think it's safer to copy the all list slots in case of
1483 destructive operation such as set-car!. but for now I trust
1484 the users.
1485 */
class_name(SgClass * klass)1486 static SgObject class_name(SgClass *klass)
1487 {
1488 return klass->name;
1489 }
1490
class_name_set(SgClass * klass,SgObject name)1491 static void class_name_set(SgClass *klass, SgObject name)
1492 {
1493 klass->name = name;
1494 }
1495
class_direct_supers(SgClass * klass)1496 static SgObject class_direct_supers(SgClass *klass)
1497 {
1498 return klass->directSupers;
1499 }
1500
class_direct_supers_set(SgClass * klass,SgObject supers)1501 static void class_direct_supers_set(SgClass *klass, SgObject supers)
1502 {
1503 /* TODO assertion */
1504 klass->directSupers = supers;
1505 }
1506
class_direct_slots(SgClass * klass)1507 static SgObject class_direct_slots(SgClass *klass)
1508 {
1509 return klass->directSlots;
1510 }
1511
class_direct_slots_set(SgClass * klass,SgObject slots)1512 static void class_direct_slots_set(SgClass *klass, SgObject slots)
1513 {
1514 /* TODO assertion */
1515 klass->directSlots = slots;
1516 }
1517
class_cpl(SgClass * klass)1518 static SgObject class_cpl(SgClass *klass)
1519 {
1520 return klass->cpl;
1521 }
1522
1523 /* subroutine for class_cpl_set. Scans klass' CPL and find out the
1524 suitable allocator function, C-struct core size and some flags*/
find_core_allocator(SgClass * klass)1525 static void find_core_allocator(SgClass *klass)
1526 {
1527 SgClass **p;
1528 SgClass *b = NULL; /* the base calss klass gets the allocator func */
1529 int object_inherited = FALSE;
1530
1531 klass->allocate = NULL;
1532 for (p = klass->cpa; *p; p++) {
1533 if (SG_CLASS_CATEGORY(*p) == SG_CLASS_BUILTIN) {
1534 Sg_Error(UC("class '%S' attempted to inherit from a builtin class "
1535 "%S; you cannnot subclass a builtin class"), klass->name, *p);
1536 }
1537 if ((*p)->allocate == Sg_ObjectAllocate) {
1538 object_inherited = TRUE;
1539 continue;
1540 }
1541 if ((*p)->flags & SG_CLASS_APPLICABLE) {
1542 klass->flags |= SG_CLASS_APPLICABLE;
1543 }
1544
1545 if (b &&
1546 SG_CLASS_CATEGORY(*p) == SG_CLASS_BASE &&
1547 b->allocate != (*p)->allocate) {
1548 /* found different C-defined class. */
1549 SgClass **bp = b->cpa;
1550 for (; *bp; bp++) {
1551 if (*bp == *p) break;
1552 }
1553 if (!*bp) {
1554 Sg_Error(UC("class '%S' attempted to inherit multiple C-defined "
1555 "base class (%S and %S) which are not in a "
1556 "superclass-superclass relathionship"),
1557 klass->name, b, *p);
1558 }
1559 continue;
1560 }
1561 if (!b) {
1562 b = *p;
1563 klass->allocate = b->allocate;
1564 klass->coreSize = b->coreSize;
1565 }
1566 }
1567 if (!object_inherited) {
1568 Sg_Error(UC("class %S's precedence list doesn't have a base class: %S"),
1569 klass->name, klass->cpl);
1570 }
1571 if (!klass->allocate) {
1572 klass->allocate = Sg_ObjectAllocate;
1573 klass->coreSize = sizeof(SgInstance);
1574 }
1575 }
1576
class_cpl_set(SgClass * klass,SgObject cpl)1577 static void class_cpl_set(SgClass *klass, SgObject cpl)
1578 {
1579 long len;
1580 SgObject cp;
1581
1582 if (!SG_PAIRP(cpl)) goto err;
1583 if (SG_CAR(cpl) != SG_OBJ(klass)) goto err;
1584
1585 cp = SG_CDR(cpl);
1586 if ((len = Sg_Length(cp)) < 0) goto err;
1587 klass->cpa = class_list_to_array(cp, len);
1588 if (klass->cpa[len-1] != SG_CLASS_TOP) goto err;
1589 klass->cpl = Sg_CopyList(cpl);
1590 find_core_allocator(klass);
1591 return;
1592 err:
1593 Sg_Error(UC("class precedence list must be a proper list of class "
1594 "metaobject, beginning from the class itself owing the list, "
1595 "and ending by the class <top>: %S"), cpl);
1596 }
1597
class_slots_ref(SgClass * klass)1598 static SgObject class_slots_ref(SgClass *klass)
1599 {
1600 return klass->slots;
1601 }
1602
class_slots_set(SgClass * klass,SgObject slots)1603 static void class_slots_set(SgClass *klass, SgObject slots)
1604 {
1605 klass->slots = slots;
1606 }
1607
class_nfields(SgClass * klass)1608 static SgObject class_nfields(SgClass *klass)
1609 {
1610 return SG_MAKE_INT(klass->nfields);
1611 }
1612
class_nfields_set(SgClass * klass,SgObject nfields)1613 static void class_nfields_set(SgClass *klass, SgObject nfields)
1614 {
1615 /* TODO should we make nfields long? but who would list so many fields? */
1616 klass->nfields = (int)SG_INT_VALUE(nfields);
1617 }
1618
class_direct_subclasses(SgClass * klass)1619 static SgObject class_direct_subclasses(SgClass *klass)
1620 {
1621 return klass->directSubclasses;
1622 }
1623
1624 /*
1625 Now it's stored in reverse order but to show it in Scheme
1626 world we make it in proper order.
1627 */
class_getters_n_setters(SgClass * klass)1628 static SgObject class_getters_n_setters(SgClass *klass)
1629 {
1630 SgObject r = Sg_ArrayToList((SgObject*)klass->gettersNSetters,
1631 klass->nfields);
1632 return Sg_ReverseX(r);
1633 }
1634
1635 /*
1636 This is a bit confusing part.
1637 Since the computed slots are ascendant, the slot accessor must be
1638 set to reverse order so that the very bottom class's slot will be
1639 refer first.
1640 */
class_getters_n_setters_set(SgClass * klass,SgObject getters)1641 static void class_getters_n_setters_set(SgClass *klass, SgObject getters)
1642 {
1643 SgObject cp;
1644 if (!SG_LISTP(getters))
1645 Sg_Error(UC("proper list required, but got %S"), getters);
1646
1647 SG_FOR_EACH(cp, getters) {
1648 if (!Sg_TypeP(SG_CAR(cp), SG_CLASS_SLOT_ACCESSOR)) {
1649 Sg_Error(UC("list of slot-accessor required, but got %S"), getters);
1650 }
1651 }
1652 getters = Sg_Reverse(getters);
1653 klass->gettersNSetters = (SgSlotAccessor**)Sg_ListToArray(getters, TRUE);
1654 }
1655
class_cache_reader(SgClass * klass)1656 static SgObject class_cache_reader(SgClass *klass)
1657 {
1658 return klass->creader;
1659 }
1660
class_cache_reader_set(SgClass * klass,SgObject proc)1661 static void class_cache_reader_set(SgClass *klass, SgObject proc)
1662 {
1663 if (!SG_PROCEDUREP(proc)) {
1664 Sg_Error(UC("procedure required, but got %S"), proc);
1665 }
1666 klass->creader = proc;
1667 }
1668
class_cache_writer(SgClass * klass)1669 static SgObject class_cache_writer(SgClass *klass)
1670 {
1671 return klass->cwriter;
1672 }
1673
class_cache_writer_set(SgClass * klass,SgObject proc)1674 static void class_cache_writer_set(SgClass *klass, SgObject proc)
1675 {
1676 if (!SG_PROCEDUREP(proc)) {
1677 Sg_Error(UC("procedure required, but got %S"), proc);
1678 }
1679 klass->cwriter = proc;
1680 }
1681
class_cache_scanner(SgClass * klass)1682 static SgObject class_cache_scanner(SgClass *klass)
1683 {
1684 return klass->cscanner;
1685 }
1686
class_cache_scanner_set(SgClass * klass,SgObject proc)1687 static void class_cache_scanner_set(SgClass *klass, SgObject proc)
1688 {
1689 if (!SG_PROCEDUREP(proc)) {
1690 Sg_Error(UC("procedure required, but got %S"), proc);
1691 }
1692 klass->cscanner = proc;
1693 }
1694
class_redefined(SgClass * klass)1695 static SgObject class_redefined(SgClass *klass)
1696 {
1697 return klass->redefined;
1698 }
1699
class_library(SgClass * klass)1700 static SgObject class_library(SgClass *klass)
1701 {
1702 return klass->library;
1703 }
1704
class_library_set(SgClass * klass,SgObject lib)1705 static void class_library_set(SgClass *klass, SgObject lib)
1706 {
1707 if (!SG_FALSEP(lib) && !SG_LIBRARYP(lib)) {
1708 Sg_Error(UC("library or #f required, but got %S"), lib);
1709 }
1710 klass->library = lib;
1711 }
1712
class_initargs(SgClass * klass)1713 static SgObject class_initargs(SgClass *klass)
1714 {
1715 return klass->initargs;
1716 }
1717
class_initargs_set(SgClass * klass,SgObject initargs)1718 static void class_initargs_set(SgClass *klass, SgObject initargs)
1719 {
1720 if (!SG_LISTP(initargs)) {
1721 Sg_Error(UC("list required, but got %S"), initargs);
1722 }
1723 klass->initargs = initargs;
1724 }
1725
1726
Sg_AddDirectSubclass(SgClass * super,SgClass * sub)1727 void Sg_AddDirectSubclass(SgClass *super, SgClass *sub)
1728 {
1729 /* built in classes can't have subclass.
1730 if we consider the base class, then <top> must have
1731 all the sub classes and that's basically the same as
1732 accepting builtin class. I think... so we only consider
1733 Scheme defined class. */
1734 if (SG_CLASS_CATEGORY(super) == SG_CLASS_SCHEME) {
1735 /* lock the class */
1736 Sg_LockMutex(&super->mutex);
1737 if (SG_FALSEP(Sg_Memq(sub, super->directSubclasses))) {
1738 super->directSubclasses = Sg_Cons(sub, super->directSubclasses);
1739 }
1740 Sg_UnlockMutex(&super->mutex);
1741 }
1742 }
1743
Sg_RemoveDirectSubclass(SgClass * super,SgClass * sub)1744 void Sg_RemoveDirectSubclass(SgClass *super, SgClass *sub)
1745 {
1746 if (SG_CLASS_CATEGORY(super) == SG_CLASS_SCHEME) {
1747 /* lock the class */
1748 Sg_LockMutex(&super->mutex);
1749 /* should we make Sg_Remq and Sg_RemqX? */
1750 super->directSubclasses = deletel(sub, super->directSubclasses);
1751 Sg_UnlockMutex(&super->mutex);
1752 }
1753 }
1754
redefine_instance_class(SgObject obj,SgClass * old)1755 static SgObject redefine_instance_class(SgObject obj, SgClass *old)
1756 {
1757 /* MT safe */
1758 SgObject newc;
1759 Sg_LockMutex(&old->mutex);
1760 while (!SG_ISA(old->redefined, SG_CLASS_CLASS)) {
1761 Sg_Wait(&old->cv, &old->mutex);
1762 }
1763 newc = old->redefined;
1764 Sg_UnlockMutex(&old->mutex);
1765 if (SG_CLASSP(newc)) {
1766 return Sg_VMApply2(&Sg_GenericChangeClass, obj, newc);
1767 } else {
1768 return SG_OBJ(old);
1769 }
1770 }
1771
1772 /*
1773 to redefine a class, we need world lock.
1774 not sure how much trouble are there if i implement this lock very
1775 naive way like this. but for now.
1776 */
1777 static struct {
1778 int dummy;
1779 SgInternalMutex mutex;
1780 SgInternalCond cv;
1781 } class_world_lock = {-1, };
1782
lock_world()1783 static void lock_world()
1784 {
1785 Sg_LockMutex(&class_world_lock.mutex);
1786 }
1787
unlock_world()1788 static void unlock_world()
1789 {
1790 Sg_UnlockMutex(&class_world_lock.mutex);
1791 }
1792
Sg_StartClassRedefinition(SgClass * klass)1793 void Sg_StartClassRedefinition(SgClass *klass)
1794 {
1795 SgVM *vm;
1796 if (SG_CLASS_CATEGORY(klass) != SG_CLASS_SCHEME) {
1797 Sg_Error(UC("builtin class can not redefined %S"), klass);
1798 }
1799 if (!in_global_context_p()) {
1800 /* now we need to check if the class is defined in the same environment.
1801 to detect the defined library we use simply the name of class the same
1802 way of define-class does (see lib/clos/user.scm).
1803 NOTE: the prediction is a bit naive. for example subclasses.
1804 */
1805 SgObject lib = Sg_VMCurrentLibrary();
1806 SgObject g = Sg_FindBinding(lib, klass->name, SG_FALSE);
1807 /* gloc won't be #f but in case. and if it is #f then assume it's defined
1808 somewhere else. */
1809 if (SG_FALSEP(g) || SG_GLOC(g)->library != lib) {
1810 Sg_Error(UC("Given class %S is defined in non child environment. "
1811 "Child environment does not allow to change global class."),
1812 klass);
1813 }
1814 }
1815
1816 vm = Sg_VM();
1817 lock_world();
1818 Sg_LockMutex(&klass->mutex);
1819 if (SG_FALSEP(klass->redefined)) {
1820 klass->redefined = vm;
1821 }
1822 Sg_UnlockMutex(&klass->mutex);
1823
1824 /* done for now */
1825 }
1826
Sg_EndClassRedefinition(SgClass * klass,SgObject newklass)1827 void Sg_EndClassRedefinition(SgClass *klass, SgObject newklass)
1828 {
1829 SgVM *vm;
1830 if (SG_CLASS_CATEGORY(klass) != SG_CLASS_SCHEME) return;
1831 if (!SG_FALSEP(newklass) && !SG_CLASSP(newklass)) {
1832 Sg_WrongTypeOfArgumentViolation(SG_INTERN("%end-class-redefinition!"),
1833 SG_MAKE_STRING("class or #f"),
1834 newklass, SG_LIST2(klass, newklass));
1835 }
1836 vm = Sg_VM();
1837 Sg_LockMutex(&klass->mutex);
1838 if (SG_EQ(klass->redefined, vm)) {
1839 klass->redefined = newklass;
1840 Sg_NotifyAll(&klass->cv);
1841 }
1842 Sg_UnlockMutex(&klass->mutex);
1843
1844 unlock_world();
1845 }
1846
Sg_ReplaceClassBinding(SgClass * oldklass,SgClass * newklass)1847 void Sg_ReplaceClassBinding(SgClass *oldklass, SgClass *newklass)
1848 {
1849 if (!SG_LIBRARYP(oldklass->library)) return;
1850 if (!SG_SYMBOLP(oldklass->name)) return;
1851 Sg_InsertBinding(SG_LIBRARY(oldklass->library), oldklass->name,
1852 SG_OBJ(newklass));
1853 }
1854
1855 /* <object> */
Sg_ObjectAllocate(SgClass * klass,SgObject initargs)1856 SgObject Sg_ObjectAllocate(SgClass *klass, SgObject initargs)
1857 {
1858 SgObject obj = Sg_AllocateInstance(klass);
1859 SG_SET_CLASS(obj, klass);
1860 return obj;
1861 }
1862
1863 /* <generic> */
generic_print(SgObject obj,SgPort * port,SgWriteContext * ctx)1864 static void generic_print(SgObject obj, SgPort *port, SgWriteContext *ctx)
1865 {
1866 Sg_Printf(port, UC("#<generic %S (%d)>"),
1867 SG_PROCEDURE_NAME(SG_GENERIC(obj)),
1868 Sg_Length(SG_GENERIC_METHODS(obj)) +
1869 Sg_Length(get_thead_local_methods(SG_GENERIC(obj))));
1870 }
1871
generic_allocate(SgClass * klass,SgObject initargs)1872 static SgObject generic_allocate(SgClass *klass, SgObject initargs)
1873 {
1874 SgGeneric *gf = SG_ALLOCATE(SgGeneric, klass);
1875 SG_SET_CLASS(gf, klass);
1876 SG_PROCEDURE_INIT(gf, 0, 0, SG_PROC_GENERIC, SG_FALSE);
1877 SG_GENERIC_METHODS(gf) = SG_NIL;
1878 SG_GENERIC_FALLBACK(gf) = Sg_NoNextMethod;
1879 SG_GENERIC_DATA(gf) = NULL;
1880 SG_GENERIC_MAX_REQARGS(gf) = 0;
1881 Sg_InitMutex(SG_GENERIC_MUTEX(gf), FALSE);
1882 return SG_OBJ(gf);
1883 }
1884
generic_name(SgGeneric * gf)1885 static SgObject generic_name(SgGeneric *gf)
1886 {
1887 return SG_PROCEDURE_NAME(gf);
1888 }
1889
generic_name_set(SgGeneric * gf,SgObject name)1890 static void generic_name_set(SgGeneric *gf, SgObject name)
1891 {
1892 SG_PROCEDURE_NAME(gf) = name;
1893 }
1894
generic_methods(SgGeneric * gf)1895 static SgObject generic_methods(SgGeneric *gf)
1896 {
1897 /* for MOP we need to consider all methods. */
1898 return get_all_methods(gf);
1899 }
1900
1901
Sg_MakeBaseGeneric(SgObject name,SgObject (* fallback)(SgObject *,int,SgGeneric *),void * data)1902 SgObject Sg_MakeBaseGeneric(SgObject name,
1903 SgObject (*fallback)(SgObject *, int, SgGeneric *),
1904 void *data)
1905 {
1906 SgGeneric *gf = SG_GENERIC(generic_allocate(SG_CLASS_GENERIC, SG_NIL));
1907 SG_PROCEDURE_NAME(gf) = name;
1908 if (fallback) {
1909 SG_GENERIC_FALLBACK(gf) = fallback;
1910 SG_GENERIC_DATA(gf) = data;
1911 }
1912 return SG_OBJ(gf);
1913 }
1914
Sg_InitBuiltinGeneric(SgGeneric * gf,const SgChar * name,SgLibrary * lib)1915 void Sg_InitBuiltinGeneric(SgGeneric *gf, const SgChar *name, SgLibrary *lib)
1916 {
1917 SgObject s = Sg_Intern(Sg_String(name));
1918 SG_PROCEDURE_NAME(gf) = s;
1919 if (gf->fallback == NULL) {
1920 gf->fallback = Sg_NoNextMethod;
1921 }
1922 Sg_InitMutex(&gf->mutex, FALSE);
1923 Sg_InsertBinding(lib, s, SG_OBJ(gf));
1924 }
1925
Sg_InitBuiltinMethod(SgMethod * m)1926 void Sg_InitBuiltinMethod(SgMethod *m)
1927 {
1928 SG_PROCEDURE_NAME(m)
1929 = Sg_Cons(SG_PROCEDURE_NAME(SG_METHOD_GENERIC(m)),
1930 class_array_to_names(SG_METHOD_SPECIALIZERS(m),
1931 SG_PROCEDURE_REQUIRED(m)));
1932 SG_METHOD_QUALIFIER(m) = SG_KEYWORD(SG_KEYWORD_PRIMARY);
1933 Sg_AddMethod(SG_METHOD_GENERIC(m), m);
1934 }
1935
Sg_InvalidApply(SgObject * argv,int argc,SgGeneric * gf)1936 SgObject Sg_InvalidApply(SgObject *argv, int argc, SgGeneric *gf)
1937 {
1938 Sg_AssertionViolation(SG_INTERN("apply"),
1939 SG_MAKE_STRING("invalid application"),
1940 Sg_ArrayToList(argv, argc));
1941 return SG_UNDEF;
1942 }
1943
Sg_NoNextMethod(SgObject * argv,int argc,SgGeneric * gf)1944 SgObject Sg_NoNextMethod(SgObject *argv, int argc, SgGeneric *gf)
1945 {
1946 SgObject h = SG_NIL, t = SG_NIL, cp, args = Sg_ArrayToList(argv, argc);
1947 SG_FOR_EACH(cp, args) {
1948 SG_APPEND1(h, t, Sg_ClassOf(SG_CAR(cp)));
1949 }
1950 Sg_AssertionViolation(SG_INTERN("call-next-method"),
1951 Sg_Sprintf(UC("no applicable method for %S with "
1952 "class(es) %S of arguments"),
1953 SG_OBJ(gf), h),
1954 args);
1955 return SG_UNDEF; /* dummy */
1956 }
1957
1958
1959 /* <method> */
method_allocate(SgClass * klass,SgObject initargs)1960 static SgObject method_allocate(SgClass *klass, SgObject initargs)
1961 {
1962 SgMethod *instance = SG_ALLOCATE(SgMethod, klass);
1963 SG_SET_CLASS(instance, klass);
1964 SG_PROCEDURE_INIT(instance, 0, 0, SG_PROC_METHOD, SG_FALSE);
1965 SG_METHOD_PROCEDURE(instance) = SG_FALSE;
1966 SG_METHOD_SPECIALIZERS(instance) = NULL;
1967 SG_METHOD_GENERIC(instance) = NULL;
1968 return SG_OBJ(instance);
1969 }
1970
method_print(SgObject obj,SgPort * port,SgWriteContext * ctx)1971 static void method_print(SgObject obj, SgPort *port, SgWriteContext *ctx)
1972 {
1973 Sg_Printf(port, UC("#<method %S%S>"),
1974 SG_PROCEDURE_NAME(SG_METHOD(obj)),
1975 SG_METHOD_QUALIFIER(obj));
1976 }
1977
method_specializers(SgMethod * method)1978 static SgObject method_specializers(SgMethod *method)
1979 {
1980 SgClass **specs = SG_METHOD_SPECIALIZERS(method);
1981 SgObject h = SG_NIL, t = SG_NIL;
1982 for (;*specs; specs++) {
1983 SG_APPEND1(h, t, SG_OBJ(*specs));
1984 }
1985 return h;
1986 }
1987
method_specializers_set(SgMethod * method,SgObject specs)1988 static void method_specializers_set(SgMethod *method, SgObject specs)
1989 {
1990 SgClass **s;
1991 SgObject cp;
1992 if (!SG_LISTP(specs)) {
1993 Sg_Error(UC("proper list required, but got %S"), specs);
1994 }
1995 SG_FOR_EACH(cp, specs) {
1996 if (!Sg_TypeP(SG_CAR(cp), SG_CLASS_CLASS)) {
1997 Sg_Error(UC("list of class required, but got %S"), specs);
1998 }
1999 }
2000 s = (SgClass**)Sg_ListToArray(specs, TRUE);
2001 SG_METHOD_SPECIALIZERS(method) = s;
2002 }
2003
method_name(SgMethod * method)2004 static SgObject method_name(SgMethod *method)
2005 {
2006 return SG_PROCEDURE_NAME(method);
2007 }
2008
2009
method_name_set(SgMethod * method,SgObject name)2010 static void method_name_set(SgMethod *method, SgObject name)
2011 {
2012 SG_PROCEDURE_NAME(method) = name;
2013 }
2014
method_procedure(SgMethod * method)2015 static SgObject method_procedure(SgMethod *method)
2016 {
2017 return SG_METHOD_PROCEDURE(method);
2018 }
2019
method_procedure_set(SgMethod * method,SgObject proc)2020 static void method_procedure_set(SgMethod *method, SgObject proc)
2021 {
2022 if (!SG_CLOSUREP(proc) && !SG_SUBRP(proc)) {
2023 Sg_Error(UC("method procedure requires procedure but got %S"), proc);
2024 }
2025 SG_METHOD_PROCEDURE(method) = proc;
2026 set_method_properties(method, proc);
2027 }
2028
method_required(SgMethod * method)2029 static SgObject method_required(SgMethod *method)
2030 {
2031 return SG_MAKE_INT(method->common.required);
2032 }
2033
method_optional(SgMethod * method)2034 static SgObject method_optional(SgMethod *method)
2035 {
2036 return SG_MAKE_BOOL(method->common.optional);
2037 }
2038
method_qualifier(SgMethod * method)2039 static SgObject method_qualifier(SgMethod *method)
2040 {
2041 return SG_METHOD_QUALIFIER(method);
2042 }
2043
method_leaf(SgMethod * method)2044 static SgObject method_leaf(SgMethod *method)
2045 {
2046 return SG_MAKE_BOOL(SG_METHOD_LEAF_P(method));
2047 }
2048
2049 /* next method */
next_method_print(SgObject obj,SgPort * port,SgWriteContext * ctx)2050 static void next_method_print(SgObject obj, SgPort *port, SgWriteContext *ctx)
2051 {
2052 SgNextMethod *nm = SG_NEXT_METHOD(obj);
2053 SgObject args = Sg_ArrayToList(nm->argv, nm->argc);
2054 Sg_Printf(port, UC("#<next-method %S %S>"), nm->methods, args);
2055 }
2056
next_method_has_nextP(SgNextMethod * nm)2057 static SgObject next_method_has_nextP(SgNextMethod *nm)
2058 {
2059 return SG_MAKE_BOOL(!SG_NULLP(nm->methods));
2060 }
2061
Sg_MakeNextMethod(SgGeneric * gf,SgObject methods,SgObject * argv,int argc,int copyargs)2062 SgObject Sg_MakeNextMethod(SgGeneric *gf, SgObject methods,
2063 SgObject *argv, int argc, int copyargs)
2064 {
2065 SgNextMethod *nm = SG_NEW(SgNextMethod);
2066 SG_SET_CLASS(nm, SG_CLASS_NEXT_METHOD);
2067 SG_PROCEDURE_INIT(nm, 0, 0, SG_PROC_NEXT_METHOD, SG_FALSE);
2068 nm->generic = gf;
2069 nm->methods = methods;
2070 if (copyargs) {
2071 nm->argv = SG_NEW_ARRAY(SgObject, argc);
2072 memcpy(nm->argv, argv, sizeof(SgObject) * argc);
2073 } else {
2074 nm->argv = argv;
2075 }
2076 nm->argc = argc;
2077 return SG_OBJ(nm);
2078 }
2079
2080 /* slot accessor */
sa_getter(SgSlotAccessor * sa)2081 static SgObject sa_getter(SgSlotAccessor *sa)
2082 {
2083 return sa->getterS;
2084 }
sa_getter_set(SgSlotAccessor * sa,SgObject proc)2085 static void sa_getter_set(SgSlotAccessor *sa, SgObject proc)
2086 {
2087 sa->getterS = proc;
2088 }
sa_setter(SgSlotAccessor * sa)2089 static SgObject sa_setter(SgSlotAccessor *sa)
2090 {
2091 return sa->setterS;
2092 }
sa_setter_set(SgSlotAccessor * sa,SgObject proc)2093 static void sa_setter_set(SgSlotAccessor *sa, SgObject proc)
2094 {
2095 sa->setterS = proc;
2096 }
sa_name(SgSlotAccessor * sa)2097 static SgObject sa_name(SgSlotAccessor *sa)
2098 {
2099 return sa->name;
2100 }
sa_class(SgSlotAccessor * sa)2101 static SgObject sa_class(SgSlotAccessor *sa)
2102 {
2103 return sa->klass;
2104 }
sa_definition(SgSlotAccessor * sa)2105 static SgObject sa_definition(SgSlotAccessor *sa)
2106 {
2107 return sa->definition;
2108 }
2109
2110 /* static initializer */
2111
2112 /* slot initialization */
2113 static SgSlotAccessor class_slots[] = {
2114 SG_CLASS_SLOT_SPEC("name", 0, class_name,
2115 class_name_set),
2116 SG_CLASS_SLOT_SPEC("direct-supers", 1, class_direct_supers,
2117 class_direct_supers_set),
2118 SG_CLASS_SLOT_SPEC("direct-slots", 2, class_direct_slots,
2119 class_direct_slots_set),
2120 SG_CLASS_SLOT_SPEC("cpl", 3, class_cpl,
2121 class_cpl_set),
2122 SG_CLASS_SLOT_SPEC("slots", 4, class_slots_ref,
2123 class_slots_set),
2124 SG_CLASS_SLOT_SPEC("nfields", 5, class_nfields,
2125 class_nfields_set),
2126 SG_CLASS_SLOT_SPEC("direct-subclasses", 6, class_direct_subclasses, NULL),
2127 SG_CLASS_SLOT_SPEC("getters-n-setters", 7, class_getters_n_setters,
2128 class_getters_n_setters_set),
2129 SG_CLASS_SLOT_SPEC("cache-reader", 8, class_cache_reader,
2130 class_cache_reader_set),
2131 SG_CLASS_SLOT_SPEC("cache-scanner", 9, class_cache_scanner,
2132 class_cache_scanner_set),
2133 SG_CLASS_SLOT_SPEC("cache-writer", 10, class_cache_writer,
2134 class_cache_writer_set),
2135 SG_CLASS_SLOT_SPEC("redefined", 11, class_redefined, NULL),
2136 SG_CLASS_SLOT_SPEC("defined-library", 12, class_library,
2137 class_library_set),
2138 SG_CLASS_SLOT_SPEC("initargs", 13, class_initargs,
2139 class_initargs_set),
2140 { { NULL } }
2141 };
2142
2143 static SgSlotAccessor generic_slots[] = {
2144 SG_CLASS_SLOT_SPEC("name", 0, generic_name, generic_name_set),
2145 SG_CLASS_SLOT_SPEC("methods", 1, generic_methods, NULL),
2146 { { NULL } }
2147 };
2148
2149 static SgSlotAccessor method_slots[] = {
2150 SG_CLASS_SLOT_SPEC("specializers", 0, method_specializers, method_specializers_set),
2151 SG_CLASS_SLOT_SPEC("procedure", 1, method_procedure, method_procedure_set),
2152 SG_CLASS_SLOT_SPEC("name", 2, method_name, method_name_set),
2153 SG_CLASS_SLOT_SPEC("required", 3, method_required, NULL),
2154 SG_CLASS_SLOT_SPEC("optional", 4, method_optional, NULL),
2155 SG_CLASS_SLOT_SPEC("qualifier", 5, method_qualifier, NULL),
2156 /* name is taken from Gauche */
2157 SG_CLASS_SLOT_SPEC("method-leaf", 6, method_leaf, NULL),
2158 { { NULL } }
2159 };
2160
2161 static SgSlotAccessor slot_accessor_slots[] = {
2162 SG_CLASS_SLOT_SPEC("getter", 0, sa_getter, sa_getter_set),
2163 SG_CLASS_SLOT_SPEC("setter", 1, sa_setter, sa_setter_set),
2164 SG_CLASS_SLOT_SPEC("name", 2, sa_name, NULL),
2165 SG_CLASS_SLOT_SPEC("class", 3, sa_class, NULL),
2166 SG_CLASS_SLOT_SPEC("definition", 4, sa_definition, NULL),
2167 { { NULL } }
2168 };
2169
2170 static SgSlotAccessor next_method_slots[] = {
2171 SG_CLASS_SLOT_SPEC("next-method?", 0, next_method_has_nextP, NULL),
2172 { { NULL } }
2173 };
2174
initialize_builtin_cpl(SgClass * klass,SgObject supers)2175 static void initialize_builtin_cpl(SgClass *klass, SgObject supers)
2176 {
2177 SgClass **p;
2178 SgObject h = SG_NIL, t = SG_NIL;
2179 SG_APPEND1(h, t, SG_OBJ(klass));
2180 for (p = klass->cpa; *p; p++) SG_APPEND1(h, t, SG_OBJ(*p));
2181 klass->cpl = h;
2182 if (SG_PAIRP(supers)) {
2183 SgObject cp, sp = supers;
2184 SG_FOR_EACH(cp, klass->cpl) {
2185 if (SG_EQ(SG_CAR(cp), SG_CAR(sp))) {
2186 sp = SG_CDR(sp);
2187 if (SG_NULLP(sp)) break;
2188 }
2189 }
2190 if (!SG_NULLP(sp)) {
2191 /* this happens in initialization of Sagittarius itself, so we can not
2192 handle any exception yet, but exit*/
2193 const char *cname = "(unnamed class)";
2194 if (SG_SYMBOLP(klass->name)) {
2195 cname = (const char*)Sg_Utf32sToUtf8s(SG_SYMBOL(klass->name)->name);
2196 }
2197 Sg_Panic("Class %s is being initialized with inconsistent super class "
2198 "list. Must be an implementation error. Report to the author.",
2199 cname);
2200 }
2201 klass->directSupers = supers;
2202 } else if (SG_PAIRP(SG_CDR(h))) {
2203 /* Default: take the next class of CPL as the only direct super */
2204 klass->directSupers = SG_LIST1(SG_CADR(h));
2205 } else {
2206 /* what is this? */
2207 klass->directSupers = SG_NIL;
2208 }
2209 }
2210
2211 /* Fixup the index, the operation is done destructively for the list
2212 but not for the accessor. */
fixup_slot_accessor(SgObject accs)2213 static void fixup_slot_accessor(SgObject accs)
2214 {
2215 int index = (int)Sg_Length(accs) - 1;
2216 SgObject cp;
2217 SG_FOR_EACH(cp, accs) {
2218 SgSlotAccessor *acc = SG_SLOT_ACCESSOR(SG_CAR(cp));
2219 if (acc->index != index) {
2220 /* copy it. */
2221 SgSlotAccessor *n = SG_NEW(SgSlotAccessor);
2222 memcpy(n, acc, sizeof(SgSlotAccessor));
2223 n->index = index; /* update index */
2224 SG_SET_CAR(cp, n);
2225 }
2226 index--;
2227 }
2228 }
2229
init_class(SgClass * klass,const SgChar * name,SgLibrary * lib,SgObject supers,SgSlotAccessor * specs,int flags)2230 static void init_class(SgClass *klass, const SgChar *name,
2231 SgLibrary *lib, SgObject supers,
2232 SgSlotAccessor *specs, int flags)
2233 {
2234 SgObject slots = SG_NIL, t = SG_NIL;
2235 SgObject acc = SG_NIL, sp;
2236 SgClass **super;
2237
2238 if (klass->cpa == NULL) klass->cpa = SG_CLASS_DEFAULT_CPL;
2239
2240 initialize_builtin_cpl(klass, supers);
2241
2242 if (name && lib) {
2243 klass->name = Sg_Intern(Sg_String(name));
2244 klass->library = lib;
2245 Sg_InsertBinding(lib, SG_SYMBOL(klass->name), SG_OBJ(klass));
2246 }
2247
2248 /* initialize direct slots */
2249 if (specs) {
2250 for (;specs->name; specs++) {
2251 SgObject snam = Sg_Intern(Sg_MakeStringC(specs->cname));
2252 SgObject slot = SG_LIST3(snam,
2253 SG_KEYWORD_INIT_KEYWORD,
2254 Sg_MakeKeyword(SG_SYMBOL(snam)->name));
2255 specs->klass = klass;
2256 specs->name = snam;
2257 specs->definition = slot;
2258 acc = Sg_Cons(SG_OBJ(&*specs), acc);
2259 SG_APPEND1(slots, t, slot);
2260 }
2261 }
2262 klass->directSlots = slots;
2263
2264 /* compute other slots inherited from supers */
2265 for (super = klass->cpa; *super; super++) {
2266 SgSlotAccessor **dacc = (*super)->gettersNSetters;
2267 /* I think slot should have accessor info but for now */
2268 SgObject tmp = SG_NIL;
2269 for (;dacc && *dacc; dacc++) {
2270 tmp = Sg_Cons(SG_OBJ(*dacc), tmp);
2271 }
2272 /* A (a b) <- B (c d)
2273
2274 now acc is reverse order (d c) and super is (b a)
2275 append super to acc */
2276 if (!SG_NULLP(tmp)) {
2277 acc = Sg_Append2X(acc, tmp);
2278 }
2279 SG_FOR_EACH(sp, (*super)->directSlots) {
2280 SgObject slot = SG_CAR(sp);
2281 ASSERT(SG_PAIRP(slot));
2282 slots = Sg_Cons(Sg_CopyList(slot), slots);
2283 }
2284 }
2285 /* fixup slot index */
2286 fixup_slot_accessor(acc);
2287 klass->gettersNSetters = (SgSlotAccessor**)Sg_ListToArray(acc, TRUE);
2288 klass->slots = slots;
2289 klass->nfields = (int)Sg_Length(slots);
2290 /* do we need this? */
2291 Sg_InitMutex(&klass->mutex, FALSE);
2292 Sg_InitCond(&klass->cv);
2293 }
2294
Sg_InitStaticClass(SgClass * klass,const SgChar * name,SgLibrary * lib,SgSlotAccessor * specs,int flags)2295 void Sg_InitStaticClass(SgClass *klass, const SgChar *name,
2296 SgLibrary *lib, SgSlotAccessor *specs, int flags)
2297 {
2298 init_class(klass, name, lib, SG_FALSE, specs, flags);
2299 }
2300
2301 /*
2302 (make <class> (list <class>))
2303 */
make_implicit_meta(const SgChar * name,SgClass ** cpa,SgLibrary * lib)2304 static SgClass* make_implicit_meta(const SgChar *name, SgClass **cpa,
2305 SgLibrary *lib)
2306 {
2307 SgClass *meta = (SgClass*)class_allocate(SG_CLASS_CLASS, SG_NIL);
2308 SgObject s = Sg_Intern(Sg_String(name));
2309 static SgClass *metacpa[] = {
2310 SG_CLASS_CLASS,
2311 SG_CLASS_OBJECT,
2312 SG_CLASS_TOP,
2313 NULL
2314 };
2315 SgClass **metas = metacpa;
2316 SgClass **parent;
2317 int numExtraMetas = 0, i;
2318
2319 for (parent = cpa; *parent; parent++) {
2320 if (SG_CLASS_OF(*parent) != SG_CLASS_CLASS) {
2321 numExtraMetas++;
2322 }
2323 }
2324 if (numExtraMetas) {
2325 metas = SG_NEW_ARRAY(SgClass*, numExtraMetas+4);
2326 for (i = 0, parent = cpa; *parent; parent++) {
2327 if (SG_CLASS_OF(*parent) != SG_CLASS_CLASS) {
2328 metas[i++] = SG_CLASS_OF(*parent);
2329 }
2330 }
2331 metas[i++] = SG_CLASS_CLASS;
2332 metas[i++] = SG_CLASS_OBJECT;
2333 metas[i++] = SG_CLASS_TOP;
2334 metas[i] = NULL;
2335 }
2336 meta->name = s;
2337 meta->allocate = class_allocate;
2338 meta->printer = class_print;
2339 meta->cpa = metas;
2340 initialize_builtin_cpl(meta, SG_FALSE);
2341 Sg_InsertBinding(lib, SG_SYMBOL(s), SG_OBJ(meta));
2342 meta->slots = SG_CLASS_CLASS->slots;
2343 meta->gettersNSetters = SG_CLASS_CLASS->gettersNSetters;
2344 return meta;
2345
2346 }
2347
2348
Sg_InitStaticClassWithMeta(SgClass * klass,const SgChar * name,SgLibrary * lib,SgClass * meta,SgObject supers,SgSlotAccessor * specs,int flags)2349 void Sg_InitStaticClassWithMeta(SgClass *klass, const SgChar *name,
2350 SgLibrary *lib, SgClass *meta,
2351 SgObject supers, SgSlotAccessor *specs,
2352 int flags)
2353 {
2354 init_class(klass, name, lib, supers, specs, flags);
2355 if (meta) {
2356 SG_SET_CLASS(klass, meta);
2357 } else {
2358 int nlen;
2359 SgChar *metaname;
2360 nlen = (int)ustrlen(name);
2361 metaname = SG_NEW_ATOMIC2(SgChar *, sizeof(SgChar) * (nlen+6));
2362 if (name[nlen-1] == '>') {
2363 memcpy(metaname, name, (nlen-1)*sizeof(SgChar));
2364 memcpy(metaname+nlen-1, UC("-meta>"), 6*sizeof(SgChar));
2365 } else {
2366 memcpy(metaname, name, (nlen)*sizeof(SgChar));
2367 memcpy(metaname+nlen, UC("-meta"), 5*sizeof(SgChar));
2368 }
2369 SG_SET_CLASS(klass, make_implicit_meta(metaname, klass->cpa, lib));
2370 }
2371 }
2372
Sg_BaseClassOf(SgClass * klass)2373 SgClass* Sg_BaseClassOf(SgClass *klass)
2374 {
2375 SgClass **cpa = klass->cpa, *k;
2376 while ((k = *cpa++) != NULL) {
2377 if (SG_CLASS_CATEGORY(k) == SG_CLASS_BASE) return k;
2378 }
2379 return NULL;
2380 }
2381
2382 /* %swap-class-and-slots
2383 Swap the class and slots.
2384 The instances must be either instance of scheme defined class or
2385 inherit the same base class.
2386 */
Sg_SwapClassAndSlots(SgObject newInstance,SgObject oldInstance)2387 void Sg_SwapClassAndSlots(SgObject newInstance, SgObject oldInstance)
2388 {
2389 SgClass *newKlass = Sg_ClassOf(newInstance);
2390 SgClass *oldKlass = Sg_ClassOf(oldInstance);
2391 SgClass *base, *tmp;
2392 SgObject *slots;
2393
2394 if ((base = Sg_BaseClassOf(newKlass)) == NULL ||
2395 !SG_EQ(base, Sg_BaseClassOf(oldKlass))) {
2396 Sg_Error(UC("incompatible class swap: %S <-> %S"),
2397 newInstance, oldInstance);
2398 }
2399 /*
2400 Now the instance memory structure is like this
2401
2402 | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 |
2403 +----+----+----+----+----+----+----+----+----+
2404 | Tag |
2405 +----+----+----+----+----+----+----+----+----+
2406 | Slots |
2407 +----+----+----+----+----+----+----+----+----+
2408 | C defined slots ... |
2409 :
2410 | |
2411 +----+----+----+----+----+----+----+----+----+
2412
2413 The coreSize has at least sizeof(SgInstance).
2414 If the old class has some other C defined slot
2415 then it also has the size. As long as the base
2416 class is the same then coreSize is the same.
2417 So swap 'Class, 'Slots' and the rest of memory.
2418 */
2419 /* swap class */
2420 /* get the raw class, at this point it's safe (I believe) */
2421 tmp = SG_CLASS_OF(oldInstance);
2422 SG_SET_CLASS(oldInstance, SG_CLASS_OF(newInstance));
2423 SG_SET_CLASS(newInstance, tmp);
2424 /* swap slots */
2425 slots = SG_INSTANCE(oldInstance)->slots;
2426 SG_INSTANCE(oldInstance)->slots = SG_INSTANCE(newInstance)->slots;
2427 SG_INSTANCE(newInstance)->slots = slots;
2428 /* swap extra slots */
2429 if (base->coreSize > (int)sizeof(SgInstance)) {
2430 const intptr_t offset = sizeof(SgInstance);
2431 uint8_t *src = (uint8_t *)((intptr_t)oldInstance + offset);
2432 uint8_t *dst = (uint8_t *)((intptr_t)newInstance + offset);
2433 int count = base->coreSize - (int)offset;
2434 while (count--) {
2435 uint8_t tmp = *src;
2436 *dst++ = *src;
2437 *src++ = tmp;
2438 }
2439 }
2440 }
2441
2442 /*
2443 builtin object initializer
2444 for now it the same as (lambda (call-next-method object . initargs) object)
2445 */
builtin_initialize(SgObject * argv,int argc,SgGeneric * gf)2446 static SgObject builtin_initialize(SgObject *argv, int argc, SgGeneric *gf)
2447 {
2448 ASSERT(argc >= 2);
2449 return argv[1];
2450 }
2451
2452 /* builtin generics */
2453 SG_DEFINE_GENERIC(Sg_GenericMake, Sg_NoNextMethod, NULL);
2454 SG_DEFINE_GENERIC(Sg_GenericAllocateInstance, Sg_NoNextMethod, NULL);
2455 SG_DEFINE_GENERIC(Sg_GenericInitialize, builtin_initialize, NULL);
2456 SG_DEFINE_GENERIC(Sg_GenericComputeCPL, Sg_NoNextMethod, NULL);
2457 SG_DEFINE_GENERIC(Sg_GenericComputeSlots, Sg_NoNextMethod, NULL);
2458 SG_DEFINE_GENERIC(Sg_GenericAddMethod, Sg_NoNextMethod, NULL);
2459 SG_DEFINE_GENERIC(Sg_GenericRemoveMethod, Sg_NoNextMethod, NULL);
2460 SG_DEFINE_GENERIC(Sg_GenericObjectEqualP, Sg_NoNextMethod, NULL);
2461 SG_DEFINE_GENERIC(Sg_GenericObjectCompare, Sg_NoNextMethod, NULL);
2462 SG_DEFINE_GENERIC(Sg_GenericObjectHash, Sg_NoNextMethod, NULL);
2463 SG_DEFINE_GENERIC(Sg_GenericObjectApply, Sg_InvalidApply, NULL);
2464 SG_DEFINE_GENERIC(Sg_GenericObjectSetter, Sg_InvalidApply, NULL);
2465 SG_DEFINE_GENERIC(Sg_GenericComputeGetterAndSetter, Sg_NoNextMethod, NULL);
2466 /* generic invocation */
2467 SG_DEFINE_GENERIC(Sg_GenericComputeApplyGeneric, Sg_NoNextMethod, NULL);
2468 SG_DEFINE_GENERIC(Sg_GenericComputeMethodMoreSpecificP, Sg_NoNextMethod, NULL);
2469 SG_DEFINE_GENERIC(Sg_GenericComputeApplyMethods, Sg_NoNextMethod, NULL);
2470 /* slot */
2471 SG_DEFINE_GENERIC(Sg_GenericSlotUnbound, Sg_NoNextMethod, NULL);
2472 SG_DEFINE_GENERIC(Sg_GenericSlotMissing, Sg_NoNextMethod, NULL);
2473 /* unbound-variable */
2474 SG_DEFINE_GENERIC(Sg_GenericUnboundVariable, Sg_NoNextMethod, NULL);
2475 /* change-class */
2476 SG_DEFINE_GENERIC(Sg_GenericChangeClass, Sg_NoNextMethod, NULL);
2477
allocate_impl(SgObject * args,int argc,void * data)2478 static SgObject allocate_impl(SgObject *args, int argc, void *data)
2479 {
2480 SgClass *c = SG_CLASS(args[0]);
2481 if (c->allocate == NULL) {
2482 Sg_Error(UC("built-in class can't be allocated via allocate-instance: %S"),
2483 SG_OBJ(c));
2484 }
2485 return c->allocate(c, args[1]);
2486 }
2487
2488 SG_DEFINE_SUBR(allocate, 2, 0, allocate_impl, SG_FALSE, NULL);
2489
2490 static SgClass *class_allocate_SPEC[] = {
2491 SG_CLASS_CLASS, SG_CLASS_LIST
2492 };
2493
2494 static SG_DEFINE_METHOD(class_allocate_rec, &Sg_GenericAllocateInstance,
2495 2, 0, class_allocate_SPEC, &allocate);
2496
2497
2498
Sg_VMSlotRefUsingSlotDefinition(SgObject obj,SgObject slot)2499 SgObject Sg_VMSlotRefUsingSlotDefinition(SgObject obj, SgObject slot)
2500 {
2501 SgSlotAccessor *ac = lookup_slot_info(Sg_ClassOf(obj), SG_CAR(slot));
2502 if (!ac) Sg_Error(UC("Unknown slot %S"), SG_CAR(slot));
2503 return Sg_SlotRefUsingAccessor(obj, ac);
2504 }
Sg_VMSlotSetUsingSlotDefinition(SgObject obj,SgObject slot,SgObject value)2505 SgObject Sg_VMSlotSetUsingSlotDefinition(SgObject obj, SgObject slot,
2506 SgObject value)
2507 {
2508 SgSlotAccessor *ac = lookup_slot_info(Sg_ClassOf(obj), SG_CAR(slot));
2509 if (!ac) Sg_Error(UC("Unknown slot %S"), SG_CAR(slot));
2510 Sg_SlotSetUsingAccessor(obj, ac, value);
2511 return SG_UNDEF;
2512 }
Sg_VMSlotBoundUsingSlotDefinition(SgObject obj,SgObject slot)2513 SgObject Sg_VMSlotBoundUsingSlotDefinition(SgObject obj, SgObject slot)
2514 {
2515 SgSlotAccessor *ac;
2516 if (!SG_PAIRP(slot)) {
2517 Sg_Error(UC("slot definition must be a list but got %S"), slot);
2518 }
2519 ac = lookup_slot_info(Sg_ClassOf(obj), SG_CAR(slot));
2520 if (!ac) Sg_Error(UC("Unknown slot %S"), SG_CAR(slot));
2521 return SG_MAKE_BOOL(Sg_SlotBoundUsingAccessor(obj, ac));
2522 }
2523
slot_initialize_cc(SgObject result,void ** data)2524 static SgObject slot_initialize_cc(SgObject result, void **data)
2525 {
2526 SgObject obj = data[0];
2527 SgSlotAccessor *ac = SG_SLOT_ACCESSOR(data[1]);
2528 Sg_SlotSetUsingAccessor(obj, ac, result);
2529 return SG_UNDEF;
2530 }
2531
Sg_VMSlotInitializeUsingAccessor(SgObject obj,SgObject acc,SgObject initargs)2532 SgObject Sg_VMSlotInitializeUsingAccessor(SgObject obj, SgObject acc,
2533 SgObject initargs)
2534 {
2535 SgSlotAccessor *ac = SG_SLOT_ACCESSOR(acc);
2536 SgObject slot = ac->definition;
2537 SgObject key = Sg_Memq(SG_KEYWORD_INIT_KEYWORD, slot);
2538
2539 /* (1) use init-keyword */
2540 if (!SG_FALSEP(key) && SG_PAIRP(SG_CDR(key)) &&
2541 SG_KEYWORDP(SG_CADR(key))) {
2542 SgObject v = Sg_GetKeyword(SG_CADR(key), initargs, SG_UNDEF);
2543 if (!SG_UNDEFP(v)) {
2544 Sg_SlotSetUsingAccessor(obj, ac, v);
2545 return SG_UNDEF;
2546 }
2547 /* go through */
2548 }
2549 /* (2) use init-value */
2550 key = Sg_Memq(SG_KEYWORD_INIT_VALUE, slot);
2551 if (!SG_FALSEP(key)) {
2552 SgObject v = Sg_GetKeyword(SG_KEYWORD_INIT_VALUE, SG_CDR(slot),
2553 SG_UNDEF);
2554 if (!SG_UNDEFP(v)) {
2555 Sg_SlotSetUsingAccessor(obj, ac, v);
2556 return SG_UNDEF;
2557 }
2558 }
2559 /* (2) use init-thunk */
2560 key = Sg_Memq(SG_KEYWORD_INIT_THUNK, slot);
2561 if (!SG_FALSEP(key)) {
2562 SgObject v = Sg_GetKeyword(SG_KEYWORD_INIT_THUNK, SG_CDR(slot),
2563 SG_UNDEF);
2564 if (!SG_UNDEFP(v)) {
2565 void *data[2];
2566 data[0] = obj;
2567 data[1] = ac;
2568 Sg_VMPushCC(slot_initialize_cc, data, 2);
2569 return Sg_VMApply0(v);
2570 }
2571 }
2572 return SG_UNDEF;
2573 }
2574
2575 /* object-initialize */
2576 static SgObject object_initialize_cc(SgObject result, void **data);
2577
object_initialize1(SgObject obj,SgObject slots,SgObject initargs)2578 static SgObject object_initialize1(SgObject obj, SgObject slots,
2579 SgObject initargs)
2580 {
2581 void *next[3];
2582 if (SG_NULLP(slots)) return obj;
2583 next[0] = obj;
2584 next[1] = SG_CDR(slots);
2585 next[2] = initargs;
2586 Sg_VMPushCC(object_initialize_cc, next, 3);
2587 return Sg_VMSlotInitializeUsingAccessor(obj, SG_CAR(slots), initargs);
2588 }
2589
object_initialize_cc(SgObject result,void ** data)2590 static SgObject object_initialize_cc(SgObject result, void **data)
2591 {
2592 SgObject obj = data[0];
2593 SgObject slots = data[1];
2594 SgObject initargs = data[2];
2595 return object_initialize1(obj, slots, initargs);
2596 }
2597
object_initialize_impl(SgObject * argv,int argc,void * data)2598 static SgObject object_initialize_impl(SgObject *argv, int argc, void *data)
2599 {
2600 SgObject obj = argv[0];
2601 SgObject initargs = argv[1];
2602 SgClass *klass = SG_CLASS(Sg_ClassOf(obj));
2603 SgObject slots = Sg_ReverseX(Sg_ArrayToList((SgObject*)klass->gettersNSetters,
2604 klass->nfields));
2605 if (SG_NULLP(slots)) return obj;
2606 return object_initialize1(obj, slots, initargs);
2607 }
2608
2609 SG_DEFINE_SUBR(object_initialize, 2, 0, object_initialize_impl, SG_FALSE, NULL);
2610 static SgClass *object_initialize_SPEC[] = {
2611 SG_CLASS_OBJECT, SG_CLASS_LIST
2612 };
2613
2614 static SG_DEFINE_METHOD(object_initialize_rec, &Sg_GenericInitialize,
2615 2, 0,
2616 object_initialize_SPEC,
2617 &object_initialize);
2618
object_compare(SgObject x,SgObject y,int equalp)2619 static int object_compare(SgObject x, SgObject y, int equalp)
2620 {
2621 SgObject r;
2622 if (equalp) {
2623 r = Sg_Apply2(SG_OBJ(&Sg_GenericObjectEqualP), x, y);
2624 return (SG_FALSEP(r) ? -1: 0);
2625 } else {
2626 /* not supported yet */
2627 r = Sg_Apply2(SG_OBJ(&Sg_GenericObjectCompare), x, y);
2628 if (SG_INTP(r)) {
2629 long v = SG_INT_VALUE(r);
2630 if (v < 0) return -1;
2631 if (v > 0) return 1;
2632 return 0;
2633 }
2634 Sg_Error(UC("object %S and %S can't be ordered"), x, y);
2635 return 0; /* dummy */
2636 }
2637 }
2638
2639 /* fallback */
object_equalp_impl(SgObject * argv,int argc,void * data)2640 static SgObject object_equalp_impl(SgObject *argv, int argc, void *data)
2641 {
2642 return SG_FALSE;
2643 }
2644
2645 SG_DEFINE_SUBR(object_equalp_default, 2, 0, object_equalp_impl, SG_FALSE, NULL);
2646 static SgClass *object_equalp_SPEC[] = {
2647 SG_CLASS_TOP, SG_CLASS_TOP
2648 };
2649 static SG_DEFINE_METHOD(object_equalp_rec, &Sg_GenericObjectEqualP,
2650 2, 0,
2651 object_equalp_SPEC,
2652 &object_equalp_default);
2653 static SG_DEFINE_METHOD(object_compare_rec, &Sg_GenericObjectCompare,
2654 2, 0,
2655 object_equalp_SPEC,
2656 &object_equalp_default);
2657
Sg_ObjectCompare(SgObject x,SgObject y)2658 int Sg_ObjectCompare(SgObject x, SgObject y)
2659 {
2660 return object_compare(x, y, FALSE);
2661 }
2662
object_hash_impl(SgObject * argv,int argc,void * data)2663 static SgObject object_hash_impl(SgObject *argv, int argc, void *data)
2664 {
2665 /* this will do address hash trick */
2666 return SG_FALSE;
2667 }
2668
2669 SG_DEFINE_SUBR(object_hash_default, 2, 0, object_hash_impl, SG_FALSE, NULL);
2670 static SgClass *object_hash_SPEC[] = {
2671 SG_CLASS_TOP, SG_CLASS_TOP
2672 };
2673 static SG_DEFINE_METHOD(object_hash_rec, &Sg_GenericObjectHash,
2674 2, 0,
2675 object_hash_SPEC,
2676 &object_hash_default);
2677
check_lref0(SgObject procedure)2678 static int check_lref0(SgObject procedure)
2679 {
2680 SgCodeBuilder *cb;
2681 int size, i;
2682 SgWord *code;
2683
2684 if (!SG_CLOSUREP(procedure)) return FALSE;
2685
2686 cb = SG_CODE_BUILDER(SG_CLOSURE(procedure)->code);
2687 size = cb->size;
2688 /* here we do rather naive way. thus, if it's referred it's called. */
2689 code = cb->code;
2690
2691 for (i = 0; i < size; i++) {
2692 InsnInfo *info = Sg_LookupInsnName(INSN(code[i]));
2693 switch (info->number) {
2694 case LREF: case LREF_PUSH:
2695 /* we don't check LREF_CAR and LREF_CAR_PUSH since it'd be
2696 an error for. */
2697 if (INSN_VALUE1(code[i])) {
2698 continue;
2699 }
2700 return FALSE;
2701 }
2702 i += info->argc;
2703 }
2704 return TRUE;
2705 }
2706
method_initialize_impl(SgObject * argv,int argc,void * data)2707 static SgObject method_initialize_impl(SgObject *argv, int argc, void *data)
2708 {
2709 SgMethod *m = SG_METHOD(argv[0]);
2710 SgGeneric *g = NULL;
2711 SgObject initargs = argv[1];
2712 SgObject llist, quoli, generic, specs, body;
2713 SgClass **specarray;
2714 SgObject lp;
2715 int speclen = 0, req = 0, opt = 0;
2716 /* for sanity */
2717 ASSERT(SG_METHODP(m));
2718 /* get keyword arguments */
2719 llist = Sg_GetKeyword(SG_KEYWORD_LAMBDA_LIST, initargs, SG_FALSE);
2720 quoli = Sg_GetKeyword(SG_KEYWORD_QUALIFIER, initargs, SG_KEYWORD_PRIMARY);
2721 generic = Sg_GetKeyword(SG_KEYWORD_GENERIC, initargs, SG_FALSE);
2722 specs = Sg_GetKeyword(SG_KEYWORD_SPECIALIZERS, initargs, SG_FALSE);
2723 body = Sg_GetKeyword(SG_KEYWORD_PROCEDURE, initargs, SG_FALSE);
2724
2725 if (!SG_FALSEP(generic)) {
2726 g = SG_GENERIC(generic);
2727 }
2728 if (!SG_CLOSUREP(body) && !SG_SUBRP(body)) {
2729 Sg_Error(UC("closure required for :body argument: %S"), body);
2730 }
2731 if ((speclen = (int)Sg_Length(specs)) < 0) {
2732 Sg_Error(UC("invalid specializers list: %S"), specs);
2733 }
2734 SG_METHOD_LEAF_P(m) = check_lref0(body);
2735
2736 specarray = class_list_to_array(specs, speclen);
2737
2738 SG_FOR_EACH(lp, llist) req++;
2739 if (!SG_NULLP(lp)) opt++;
2740
2741 if (SG_PROCEDURE_REQUIRED(body)+SG_PROCEDURE_OPTIONAL(body) != req+opt+1) {
2742 Sg_Error(UC("body doesn't match with lambda list: %S"), body);
2743 }
2744 if (speclen != req) {
2745 Sg_Error(UC("specializer list doesn't match with lambda list: %S"), specs);
2746 }
2747 SG_PROCEDURE_REQUIRED(m) = req;
2748 SG_PROCEDURE_OPTIONAL(m) = opt;
2749
2750 SG_METHOD_GENERIC(m) = g;
2751 SG_METHOD_SPECIALIZERS(m) = specarray;
2752 SG_METHOD_PROCEDURE(m) = body;
2753 SG_METHOD_QUALIFIER(m) = quoli;
2754 if (g) {
2755 set_method_debug_name(m, g);
2756 }
2757 /* add direct methods? */
2758 return SG_OBJ(m);
2759 }
2760
2761 SG_DEFINE_SUBR(method_initialize, 2, 0, method_initialize_impl, SG_FALSE, NULL);
2762 static SgClass *method_initialize_SPEC[] = {
2763 SG_CLASS_METHOD, SG_CLASS_LIST
2764 };
2765
2766 static SG_DEFINE_METHOD(method_initialize_rec, &Sg_GenericInitialize,
2767 2, 0,
2768 method_initialize_SPEC,
2769 &method_initialize);
2770
2771 /* compute-cpl */
compute_cpl_impl(SgObject * args,int argc,void * data)2772 static SgObject compute_cpl_impl(SgObject *args, int argc, void *data)
2773 {
2774 return Sg_ComputeCPL(SG_CLASS(args[0]));
2775 }
2776
2777 SG_DEFINE_SUBR(compute_cpl, 1, 0, compute_cpl_impl, SG_FALSE, NULL);
2778
2779 static SgClass *compute_cpl_SPEC[] = {
2780 SG_CLASS_CLASS
2781 };
2782
2783 static SG_DEFINE_METHOD(compute_cpl_rec, &Sg_GenericComputeCPL,
2784 1, 0,
2785 compute_cpl_SPEC, &compute_cpl);
2786
2787 /* compute-slots */
compute_slots_impl(SgObject * args,int argc,void * data)2788 static SgObject compute_slots_impl(SgObject *args, int argc, void *data)
2789 {
2790 return Sg_ComputeSlots(SG_CLASS(args[0]));
2791 }
2792
2793 SG_DEFINE_SUBR(compute_slots, 1, 0, compute_slots_impl, SG_FALSE, NULL);
2794
2795 static SgClass *compute_slots_SPEC[] = {
2796 SG_CLASS_CLASS
2797 };
2798
2799 static SG_DEFINE_METHOD(compute_slots_rec, &Sg_GenericComputeSlots,
2800 1, 0,
2801 compute_slots_SPEC, &compute_slots);
2802
2803 /* compute-getter-and-setter */
compute_gas_impl(SgObject * args,int argc,void * data)2804 static SgObject compute_gas_impl(SgObject *args, int argc, void *data)
2805 {
2806 return Sg_ComputeGetterAndSetter(SG_CLASS(args[0]), args[1]);
2807 }
2808
2809 SG_DEFINE_SUBR(compute_gas, 2, 0, compute_gas_impl, SG_FALSE, NULL);
2810
2811 static SgClass *compute_gas_SPEC[] = {
2812 SG_CLASS_CLASS, SG_CLASS_LIST
2813 };
2814
2815 static SG_DEFINE_METHOD(compute_gas_rec, &Sg_GenericComputeGetterAndSetter,
2816 2, 0,
2817 compute_gas_SPEC, &compute_gas);
2818
2819
2820
2821 /* add-method */
add_method_impl(SgObject * args,int argc,void * data)2822 static SgObject add_method_impl(SgObject *args, int argc, void *data)
2823 {
2824 return Sg_AddMethod(SG_GENERIC(args[0]), SG_METHOD(args[1]));
2825 }
2826
2827 SG_DEFINE_SUBR(add_method, 2, 0, add_method_impl, SG_FALSE, NULL);
2828
2829 static SgClass *add_method_SPEC[] = {
2830 SG_CLASS_GENERIC, SG_CLASS_METHOD
2831 };
2832
2833 static SG_DEFINE_METHOD(add_method_rec, &Sg_GenericAddMethod,
2834 2, 0,
2835 add_method_SPEC, &add_method);
2836 /* remove-method */
remove_method_impl(SgObject * args,int argc,void * data)2837 static SgObject remove_method_impl(SgObject *args, int argc, void *data)
2838 {
2839 return Sg_RemoveMethod(SG_GENERIC(args[0]), SG_METHOD(args[1]));
2840 }
2841
2842 SG_DEFINE_SUBR(remove_method, 2, 0, remove_method_impl, SG_FALSE, NULL);
2843
2844 static SgClass *remove_method_SPEC[] = {
2845 SG_CLASS_GENERIC, SG_CLASS_METHOD
2846 };
2847
2848 static SG_DEFINE_METHOD(remove_method_rec, &Sg_GenericRemoveMethod,
2849 2, 0,
2850 remove_method_SPEC, &remove_method);
2851
2852 /* compute-method-more-specific? */
more_specific_p_subr(SgObject * args,int argc,void * data)2853 static SgObject more_specific_p_subr(SgObject *args, int argc, void *data)
2854 {
2855 int i, r;
2856 SgClass **klass = (SgClass **)data;
2857 if (!SG_METHODP(args[0])) {
2858 Sg_WrongTypeOfArgumentViolation(SG_INTERN("method-more-specific?"),
2859 SG_INTERN("method"),
2860 args[0], SG_LIST2(args[0], args[1]));
2861 }
2862 if (!SG_METHODP(args[1])) {
2863 Sg_WrongTypeOfArgumentViolation(SG_INTERN("method-more-specific?"),
2864 SG_INTERN("method"),
2865 args[1], SG_LIST2(args[0], args[1]));
2866 }
2867 for (i = 0; klass[i]; i++);
2868 r = method_more_specific(SG_METHOD(args[0]), SG_METHOD(args[1]),
2869 klass, i);
2870 return SG_MAKE_BOOL(r);
2871 }
2872
compute_method_more_specific_p(SgObject * args,int argc,void * data)2873 static SgObject compute_method_more_specific_p(SgObject *args, int argc,
2874 void *data)
2875 {
2876 SgObject argv = args[1], cp;
2877 int len = (int)Sg_Length(argv), i;
2878 SgClass **klass = SG_NEW2(SgClass **, len);
2879 i = 0;
2880 SG_FOR_EACH(cp, argv) {
2881 klass[i++] = Sg_ClassOf(SG_CAR(cp));
2882 }
2883 return Sg_MakeSubr(more_specific_p_subr, klass, 2, 0,
2884 SG_MAKE_STRING("more-specific?"));
2885 }
2886
2887 SG_DEFINE_SUBR(compute_method_more_specific_p_subr, 2, 0,
2888 compute_method_more_specific_p, SG_FALSE, NULL);
2889
2890 static SgClass *compute_method_more_specific_SPEC[] = {
2891 SG_CLASS_GENERIC, SG_CLASS_LIST
2892 };
2893
2894 static SG_DEFINE_METHOD(compute_method_more_specific_p_rec,
2895 &Sg_GenericComputeMethodMoreSpecificP,
2896 2, 0,
2897 compute_method_more_specific_SPEC,
2898 &compute_method_more_specific_p_subr);
2899
Sg_ComputeApplicableMethods(SgObject gf,SgObject args)2900 SgObject Sg_ComputeApplicableMethods(SgObject gf, SgObject args)
2901 {
2902 SgObject argv[1];
2903 argv[0] = args;
2904 if (Sg_TypeP(gf, SG_CLASS_GENERIC)) {
2905 return compute_applicable_methods(SG_GENERIC(gf), argv, 1, TRUE);
2906 } else {
2907 Sg_WrongTypeOfArgumentViolation(SG_INTERN("%compute-applicable-methods"),
2908 SG_MAKE_STRING("sub type of generic"),
2909 gf, SG_LIST1(gf));
2910 return SG_UNDEF; /* dummy */
2911 }
2912 }
2913
Sg_VMSortMethodByQualifier(SgObject methods)2914 SgObject Sg_VMSortMethodByQualifier(SgObject methods)
2915 {
2916 SgObject qualified_methods[QUALIFIER_COUNT];
2917 sort_method_by_qualifier(methods, qualified_methods, TRUE);
2918 return Sg_Values4(qualified_methods[PRIMARY_INDEX],
2919 qualified_methods[BEFORE_INDEX],
2920 qualified_methods[AFTER_INDEX],
2921 qualified_methods[AROUND_INDEX]);
2922 }
2923
2924
Sg_VMComputeAroundMethods(SgObject around,SgObject before,SgObject primary,SgObject after)2925 SgObject Sg_VMComputeAroundMethods(SgObject around, SgObject before,
2926 SgObject primary, SgObject after)
2927 {
2928 return compute_around_methods_rec(around, before, primary, after);
2929 }
2930
eql_printer(SgObject o,SgPort * p,SgWriteContext * ctx)2931 static void eql_printer(SgObject o, SgPort *p, SgWriteContext *ctx)
2932 {
2933 Sg_Printf(p, UC("#<eql-specializer (eql %S)>"),
2934 SG_EQL_SPECIALIZER(o)->object);
2935 }
2936
2937 static SgClass *Sg_ClassCPL[] = {
2938 SG_CLASS_CLASS,
2939 SG_CLASS_OBJECT,
2940 SG_CLASS_TOP,
2941 NULL
2942 };
2943
2944 SG_DEFINE_BUILTIN_CLASS(Sg_EqlSpecializerClass, eql_printer, NULL, NULL, NULL,
2945 Sg_ClassCPL);
2946
2947 /* eql specializer stuff */
Sg_MakeEqlSpecializer(SgObject obj)2948 SgObject Sg_MakeEqlSpecializer(SgObject obj)
2949 {
2950 SgEqlSpecializer *z = SG_NEW(SgEqlSpecializer);
2951 SG_SET_CLASS(z, SG_CLASS_EQL_SPECIALIZER);
2952 z->object = obj;
2953 return SG_OBJ(z);
2954 }
2955
2956 /* default slot-unbound and slot-missing methods */
slot_unbound_subr(SgObject * argv,int argc,void * data)2957 static SgObject slot_unbound_subr(SgObject *argv, int argc, void *data)
2958 {
2959 Sg_Error(UC("slot %S of object of class %S is unbound"),
2960 argv[2], argv[0]);
2961 return SG_UNDEF; /* dummy */
2962 }
2963
2964 SG_DEFINE_SUBR(slot_unbound_subr_rec, 3, 0, slot_unbound_subr, SG_FALSE, NULL);
2965 static SgClass *slot_unbound_SPEC[] = {
2966 SG_CLASS_CLASS,
2967 SG_CLASS_TOP,
2968 SG_CLASS_TOP
2969 };
2970 static SG_DEFINE_METHOD(slot_unbound_rec, &Sg_GenericSlotUnbound,
2971 3, 0, slot_unbound_SPEC, &slot_unbound_subr_rec);
2972
2973 /* slot-missing */
slot_missing_subr(SgObject * argv,int argc,void * data)2974 static SgObject slot_missing_subr(SgObject *argv, int argc, void *data)
2975 {
2976 Sg_Error(UC("object of class %S doesn't have such slot: %S"),
2977 argv[0], argv[2]);
2978 return SG_UNDEF; /* dummy */
2979 }
2980
2981 SG_DEFINE_SUBR(slot_missing_subr_rec, 3, 1, slot_missing_subr, SG_FALSE, NULL);
2982 static SgClass *slot_missing_SPEC[] = {
2983 SG_CLASS_CLASS,
2984 SG_CLASS_TOP,
2985 SG_CLASS_TOP
2986 };
2987 static SG_DEFINE_METHOD(slot_missing_rec, &Sg_GenericSlotMissing,
2988 3, 1, slot_missing_SPEC, &slot_missing_subr_rec);
2989
unbound_variable_subr(SgObject * argv,int argc,void * data)2990 static SgObject unbound_variable_subr(SgObject *argv, int argc, void *data)
2991 {
2992 SgObject h = SG_NIL, t = SG_NIL;
2993 SgObject lib = argv[1], variable = argv[0];
2994 SgObject message;
2995 SG_APPEND1(h, t, Sg_MakeUndefinedViolation());
2996 if (variable) {
2997 SG_APPEND1(h, t, Sg_MakeWhoCondition(variable));
2998 }
2999 message = Sg_Sprintf(UC("unbound variable %S in library %A"),
3000 variable, SG_LIBRARY_NAME(lib));
3001 SG_APPEND1(h, t, Sg_MakeMessageCondition(message));
3002 Sg_Raise(Sg_Condition(h), FALSE);
3003 return SG_UNDEF;
3004 }
3005 SG_DEFINE_SUBR(unbound_variable_subr_rec, 3, 0, unbound_variable_subr,
3006 SG_FALSE, NULL);
3007 static SgClass *unbound_variable_SPEC[] = {
3008 SG_CLASS_TOP,
3009 SG_CLASS_TOP,
3010 SG_CLASS_TOP
3011 };
3012 static SG_DEFINE_METHOD(unbound_variable_rec, &Sg_GenericUnboundVariable,
3013 3, 0, unbound_variable_SPEC,
3014 &unbound_variable_subr_rec);
3015
Sg__InitClos()3016 void Sg__InitClos()
3017 {
3018 /* TODO library name */
3019 SgLibrary *lib = Sg_FindLibrary(SG_INTERN("(sagittarius clos)"), TRUE);
3020 static SgClass *nullcpa[1] = {NULL};
3021
3022 /* init lock */
3023 Sg_InitMutex(&class_world_lock.mutex, TRUE);
3024 Sg_InitCond(&class_world_lock.cv);
3025
3026 SG_CLASS_TOP->cpa = nullcpa;
3027 #define CINIT(cl, nam) \
3028 Sg_InitStaticClassWithMeta(cl, UC(nam), lib, NULL, SG_FALSE, NULL, 0)
3029
3030 #define BINIT(cl, nam, slots) Sg_InitStaticClass(cl, UC(nam), lib, slots, 0)
3031
3032 BINIT(SG_CLASS_CLASS, "<class>", class_slots);
3033 BINIT(SG_CLASS_TOP, "<top>", NULL);
3034 BINIT(SG_CLASS_OBJECT, "<object>", NULL);
3035 /* generic, method and next-method */
3036 BINIT(SG_CLASS_GENERIC, "<generic>", generic_slots);
3037 BINIT(SG_CLASS_METHOD, "<method>", method_slots);
3038 BINIT(SG_CLASS_NEXT_METHOD, "<next-method>", next_method_slots);
3039 BINIT(SG_CLASS_EQL_SPECIALIZER, "<eql-specializer>", NULL);
3040 BINIT(SG_CLASS_SLOT_ACCESSOR, "<slot-accessor>", slot_accessor_slots);
3041 /* set flags for above to make them applicable(procedure? returns #t) */
3042 SG_CLASS_GENERIC->flags |= SG_CLASS_APPLICABLE;
3043 SG_CLASS_METHOD->flags |= SG_CLASS_APPLICABLE;
3044 SG_CLASS_NEXT_METHOD->flags |= SG_CLASS_APPLICABLE;
3045
3046 /* primitives */
3047 CINIT(SG_CLASS_BOOL, "<boolean>");
3048 CINIT(SG_CLASS_CHAR, "<char>");
3049 CINIT(SG_CLASS_EOF_OBJECT, "<eof-object>");
3050 CINIT(SG_CLASS_UNDEFINED_OBJECT, "<undefined-object>");
3051 CINIT(SG_CLASS_UNKNOWN, "<unknown>");
3052
3053 CINIT(SG_CLASS_CHAR_SET, "<char-set>");
3054 CINIT(SG_CLASS_HASHTABLE, "<hashtable>");
3055
3056 CINIT(SG_CLASS_LIST, "<list>");
3057 CINIT(SG_CLASS_PAIR, "<pair>");
3058 CINIT(SG_CLASS_NULL, "<null>");
3059
3060 /* number */
3061 CINIT(SG_CLASS_NUMBER, "<number>");
3062 CINIT(SG_CLASS_COMPLEX, "<complex>");
3063 CINIT(SG_CLASS_REAL, "<real>");
3064 CINIT(SG_CLASS_RATIONAL, "<rational>");
3065 CINIT(SG_CLASS_INTEGER, "<integer>");
3066
3067 /* string */
3068 CINIT(SG_CLASS_STRING, "<string>");
3069
3070 /* symbol */
3071 CINIT(SG_CLASS_SYMBOL, "<symbol>");
3072 CINIT(SG_CLASS_GLOC, "<gloc>");
3073
3074 /* keyword */
3075 CINIT(SG_CLASS_KEYWORD, "<keyword>");
3076
3077 /* library */
3078 CINIT(SG_CLASS_LIBRARY, "<library>");
3079
3080 /* abstract collection */
3081 BINIT(SG_CLASS_COLLECTION, "<collection>", NULL);
3082 BINIT(SG_CLASS_SEQUENCE, "<sequence>", NULL);
3083 BINIT(SG_CLASS_DICTIONARY, "<dictionary>", NULL);
3084 BINIT(SG_CLASS_ORDERED_DICTIONARY, "<ordered-dictionary>", NULL);
3085
3086 /* hashtable */
3087 CINIT(SG_CLASS_HASHTABLE, "<hashtable>");
3088 /* treemap */
3089 CINIT(SG_CLASS_TREE_MAP, "<tree-map>");
3090
3091 /* vector */
3092 CINIT(SG_CLASS_VECTOR, "<vector>");
3093 /* bytevector */
3094 CINIT(SG_CLASS_BVECTOR, "<bytevector>");
3095 /* weak */
3096 CINIT(SG_CLASS_WEAK_VECTOR, "<weak-vector>");
3097 CINIT(SG_CLASS_WEAK_HASHTABLE, "<weak-hashtable>");
3098 CINIT(SG_CLASS_WEAK_BOX, "<weak-box>");
3099
3100 /* codec and transcoders */
3101 CINIT(SG_CLASS_CODEC, "<codec>");
3102 CINIT(SG_CLASS_TRANSCODER, "<transcoder>");
3103
3104 /* procedure */
3105 CINIT(SG_CLASS_PROCEDURE, "<procedure>");
3106 SG_CLASS_PROCEDURE->flags |= SG_CLASS_APPLICABLE;
3107
3108 /* code builder */
3109 CINIT(SG_CLASS_CODE_BUILDER, "<code-builder>");
3110
3111 #define GINIT(gf, nam) \
3112 Sg_InitBuiltinGeneric(gf, UC(nam), lib)
3113
3114 GINIT(&Sg_GenericMake, "make");
3115 GINIT(&Sg_GenericAllocateInstance, "allocate-instance");
3116 GINIT(&Sg_GenericInitialize, "initialize");
3117 GINIT(&Sg_GenericComputeCPL, "compute-cpl");
3118 GINIT(&Sg_GenericComputeSlots, "compute-slots");
3119 GINIT(&Sg_GenericAddMethod, "add-method");
3120 GINIT(&Sg_GenericRemoveMethod, "remove-method");
3121 GINIT(&Sg_GenericObjectEqualP, "object-equal?");
3122 GINIT(&Sg_GenericObjectCompare, "object-compare");
3123 GINIT(&Sg_GenericObjectHash, "object-hash");
3124 GINIT(&Sg_GenericObjectApply, "object-apply");
3125 GINIT(&Sg_GenericObjectSetter, "setter of object-apply");
3126 GINIT(&Sg_GenericComputeApplyGeneric, "compute-apply-generic");
3127 GINIT(&Sg_GenericComputeMethodMoreSpecificP, "compute-method-more-specific?");
3128 GINIT(&Sg_GenericComputeApplyMethods, "compute-apply-methods");
3129 GINIT(&Sg_GenericSlotUnbound, "slot-unbound");
3130 GINIT(&Sg_GenericSlotMissing, "slot-missing");
3131 GINIT(&Sg_GenericUnboundVariable, "unbound-variable");
3132 GINIT(&Sg_GenericComputeGetterAndSetter, "compute-getter-and-setter");
3133 GINIT(&Sg_GenericChangeClass, "change-class");
3134
3135 Sg_SetterSet(SG_PROCEDURE(&Sg_GenericObjectApply),
3136 SG_PROCEDURE(&Sg_GenericObjectSetter),
3137 TRUE);
3138
3139 /* methods */
3140 Sg_InitBuiltinMethod(&class_allocate_rec);
3141 Sg_InitBuiltinMethod(&object_initialize_rec);
3142 Sg_InitBuiltinMethod(&method_initialize_rec);
3143 Sg_InitBuiltinMethod(&compute_cpl_rec);
3144 Sg_InitBuiltinMethod(&compute_slots_rec);
3145 Sg_InitBuiltinMethod(&compute_gas_rec);
3146 Sg_InitBuiltinMethod(&add_method_rec);
3147 Sg_InitBuiltinMethod(&remove_method_rec);
3148 /* Sg_InitBuiltinMethod(&compute_applicable_methods_rec); */
3149 Sg_InitBuiltinMethod(&compute_method_more_specific_p_rec);
3150 Sg_InitBuiltinMethod(&object_equalp_rec);
3151 Sg_InitBuiltinMethod(&object_compare_rec);
3152 Sg_InitBuiltinMethod(&object_hash_rec);
3153 Sg_InitBuiltinMethod(&slot_unbound_rec);
3154 Sg_InitBuiltinMethod(&slot_missing_rec);
3155
3156 Sg_InitBuiltinMethod(&unbound_variable_rec);
3157 }
3158