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