1
2 //metadoc Object category Core
3 //metadoc Object copyright Steve Dekorte 2002
4 //metadoc Object license BSD revised
5 /*metadoc Object description
6 An Object is a key/value dictionary with string keys and values of any type.
7 The prototype Object contains a clone slot that is a CFunction that creates new objects.
8 When cloned, an Object will call its init slot (with no arguments).
9 */
10
11 #include "IoState.h"
12 #define IOOBJECT_C
13 #include "IoObject.h"
14 #undef IOOBJECT_C
15 #include "IoCoroutine.h"
16 #include "IoTag.h"
17 #include "IoCFunction.h"
18 #include "IoSeq.h"
19 #include "IoNumber.h"
20 #include "IoMessage.h"
21 #include "IoMessage_parser.h"
22 #include "IoCFunction.h"
23 #include "IoBlock.h"
24 #include "IoList.h"
25 #include "IoObject.h"
26 #include "IoFile.h"
27 #include "IoSeq.h"
28 #include <string.h>
29 #include <stddef.h>
30
31 static const char *protoId = "Object";
32
33 IoObject *IoObject_activateFunc(IoObject *self,
34 IoObject *target,
35 IoObject *locals,
36 IoMessage *m,
37 IoObject *slotContext);
38
IoObject_newTag(void * state)39 IoTag *IoObject_newTag(void *state)
40 {
41 IoTag *tag = IoTag_newWithName_(protoId);
42 IoTag_state_(tag, state);
43 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoObject_rawClone);
44 IoTag_activateFunc_(tag, (IoTagActivateFunc *)NULL); // IoObject_activateFunc;
45 return tag;
46 }
47
IoObject_justAlloc(IoState * state)48 IoObject *IoObject_justAlloc(IoState *state)
49 {
50 IoObject *child = Collector_newMarker(state->collector);
51 CollectorMarker_setObject_(child, io_calloc(1, sizeof(IoObjectData)));
52 IoObject_protos_(child, (IoObject **)io_calloc(2, sizeof(IoObject *)));
53 return child;
54 }
55
IoObject_alloc(IoObject * self)56 IoObject *IoObject_alloc(IoObject *self)
57 {
58 IoObject *child;
59
60 #ifdef IOSTATE_RECYCLING_ON
61 child = List_pop(IOSTATE->recycledObjects);
62 if (!child)
63 #endif
64 {
65 child = IoObject_justAlloc(IOSTATE);
66 }
67
68 IoObject_markerCount_(child, 0);
69
70 return child;
71 }
72
IoObject_proto(void * state)73 IoObject *IoObject_proto(void *state)
74 {
75 IoObject *self = IoObject_justAlloc(state);
76
77 IoObject_tag_(self, IoObject_newTag(state));
78
79 IoObject_slots_(self, PHash_new());
80 IoObject_ownsSlots_(self, 1);
81 //IoObject_state_(self, state);
82 IoState_registerProtoWithId_((IoState *)state, self, protoId);
83 return self;
84 }
85
IO_METHOD(IoObject,protoOwnsSlots)86 IO_METHOD(IoObject, protoOwnsSlots)
87 {
88 /*doc Object ownsSlots
89 A debug method.
90 */
91 return IOBOOL(self, IoObject_ownsSlots(self));
92 }
93
IoObject_memorySize(IoObject * self)94 size_t IoObject_memorySize(IoObject *self)
95 {
96 //return (IoObject_tag(self)->memorySizeFunc) ? (IoObject_tag(self)->memorySizeFunc)(self) : 0;
97 size_t size = sizeof(IoObject);
98
99 if (IoObject_ownsSlots(self)) size += PHash_memorySize(IoObject_slots(self));
100
101 if (!ISNUMBER(self))
102 {
103 // if(IoObject_dataPointer(self)) size += io_memsize(IoObject_dataPointer(self));
104 }
105
106 return size;
107 }
108
109
IoObject_protoFinish(void * state)110 IoObject *IoObject_protoFinish(void *state)
111 {
112 IoMethodTable methodTable[] = {
113 {"clone", IoObject_clone},
114 {"cloneWithoutInit", IoObject_cloneWithoutInit},
115 {"shallowCopy", IoObject_shallowCopy},
116 {"write", IoObject_protoWrite},
117 {"writeln", IoObject_protoWriteLn},
118 {"type", IoObject_type},
119
120 // logic
121
122 {"compare", IoObject_protoCompare},
123 {"<", IoObject_isLessThan_},
124 {">", IoObject_isGreaterThan_},
125 {">=", IoObject_isGreaterThanOrEqualTo_},
126 {"<=", IoObject_isLessThanOrEqualTo_},
127 {"asBoolean", IoObject_asBoolean},
128
129 // comparison
130
131 {"isIdenticalTo", IoObject_isIdenticalTo},
132 {"==", IoObject_equals},
133 {"!=", IoObject_notEquals},
134
135 // introspection
136
137 //{"self", IoObject_self},
138 {"setSlot", IoObject_protoSet_to_},
139 {"setSlotWithType", IoObject_protoSetSlotWithType},
140 {"updateSlot", IoObject_protoUpdateSlot_to_},
141 {"getSlot", IoObject_protoGetSlot_},
142 {"getLocalSlot", IoObject_protoGetLocalSlot_},
143 {"hasLocalSlot", IoObject_protoHasLocalSlot},
144 {"hasProto", IoObject_protoHasProto_},
145 {"removeSlot", IoObject_protoRemoveSlot},
146 {"removeAllSlots", IoObject_protoRemoveAllSlots},
147 {"slotNames", IoObject_protoSlotNames},
148 {"slotValues", IoObject_protoSlotValues},
149
150 // method invocation
151
152 {"perform", IoObject_protoPerform},
153 {"performWithArgList", IoObject_protoPerformWithArgList},
154 {"ancestorWithSlot", IoObject_ancestorWithSlot},
155 {"contextWithSlot", IoObject_contextWithSlot},
156
157 // control
158
159 {"block", IoObject_block},
160 {"method", IoBlock_method},
161 {"for", IoObject_for},
162 {"if", IoObject_if},
163 {"", IoObject_evalArg},
164 //{"truthValueOfArg", IoObject_truthValueOfArg},
165 {"evalArg", IoObject_evalArg},
166 {"evalArgAndReturnSelf", IoObject_evalArgAndReturnSelf},
167 {"evalArgAndReturnNil", IoObject_evalArgAndReturnNil},
168
169 {"return", IoObject_return},
170 {"returnIfNonNil", IoObject_returnIfNonNil},
171 {"loop", IoObject_loop},
172 {"while", IoObject_while},
173 {"break", IoObject_break},
174 {"continue", IoObject_continue},
175 {"stopStatus", IoObject_stopStatus},
176
177 // utility
178
179 {"print", IoObject_lobbyPrint},
180 {"do", IoObject_do},
181 {"lexicalDo", IoObject_lexicalDo},
182 {"message", IoObject_message},
183 {"doMessage", IoObject_doMessage},
184 {"doString", IoObject_doString},
185 {"doFile", IoObject_doFile},
186
187 // reflection
188
189 {"uniqueId", IoObject_uniqueId},
190
191 //{"compact", IoObject_compactMethod},
192
193 {"init", IoObject_self},
194
195 // enumeration
196
197 {"foreachSlot", IoObject_foreachSlot},
198 {"-", IoObject_subtract},
199
200 {"thisContext", IoObject_self},
201 {"thisMessage", IoObject_thisMessage},
202 {"thisLocalContext", IoObject_locals},
203
204 // protos
205
206 {"setProto", IoObject_setProto},
207 {"setProtos", IoObject_setProtos},
208 {"appendProto", IoObject_appendProto},
209 {"prependProto", IoObject_prependProto},
210 {"removeProto", IoObject_removeProto},
211 {"removeAllProtos", IoObject_removeAllProtos},
212 {"protos", IoObject_protosMethod},
213 {"proto", IoObject_objectProto},
214 {"setIsActivatable", IoObject_setIsActivatableMethod},
215 {"isActivatable", IoObject_isActivatableMethod},
216 {"argIsActivationRecord", IoObject_argIsActivationRecord},
217 {"argIsCall", IoObject_argIsCall},
218 {"become", IoObject_become},
219
220 {"ownsSlots", IoObject_protoOwnsSlots}, // a debug method
221 {"memorySize", IoObject_memorySizeMethod},
222
223
224 {"hasDirtySlot", IoObject_hasDirtySlot_},
225 {"markClean", IoObject_markClean},
226
227 {NULL, NULL},
228 };
229
230 IoObject *self = IoState_protoWithId_((IoState *)state, protoId);
231
232 IoObject_addTaglessMethodTable_(self, methodTable);
233 return self;
234 }
235
IoObject_localsProto(void * state)236 IoObject *IoObject_localsProto(void *state)
237 {
238 IoObject *self = IoObject_new(state);
239
240 IoObject_createSlotsIfNeeded(self);
241 PHash_copy_(IoObject_slots(self), IoObject_slots(IoObject_firstProto(self)));
242
243 IoObject_rawRemoveAllProtos(self);
244
245 // Locals handles := and =
246 IoObject_addMethod_(self, IOSYMBOL("setSlot"), IoObject_protoSet_to_);
247 IoObject_addMethod_(self, IOSYMBOL("setSlotWithType"), IoObject_protoSetSlotWithType);
248 IoObject_addMethod_(self, IOSYMBOL("updateSlot"), IoObject_localsUpdateSlot);
249 IoObject_addMethod_(self, IOSYMBOL("thisLocalContext"), IoObject_locals);
250
251 // Everything else is forwarded to self
252 IoObject_addMethod_(self, IOSYMBOL("forward"), IoObject_localsForward);
253
254 return self;
255 }
256
IoObject_addMethod_(IoObject * self,IoSymbol * slotName,IoMethodFunc * fp)257 IoObject *IoObject_addMethod_(IoObject *self, IoSymbol *slotName, IoMethodFunc *fp)
258 {
259 IoTag *t = IoObject_tag(self);
260 IoCFunction *f;
261
262 f = IoCFunction_newWithFunctionPointer_tag_name_(IOSTATE, (IoUserFunction *)fp, t, CSTRING(slotName));
263 IoObject_setSlot_to_(self, slotName, f);
264 return f;
265 }
266
IoObject_addMethodTable_(IoObject * self,IoMethodTable * methodTable)267 void IoObject_addMethodTable_(IoObject *self, IoMethodTable *methodTable)
268 {
269 IoMethodTable *entry = methodTable;
270
271 while (entry->name)
272 {
273 IoObject_addMethod_(self, IOSYMBOL(entry->name), entry->func);
274 entry ++;
275 }
276 }
277
IoObject_addTaglessMethod_(IoObject * self,IoSymbol * slotName,IoMethodFunc * fp)278 IoObject *IoObject_addTaglessMethod_(IoObject *self, IoSymbol *slotName, IoMethodFunc *fp)
279 {
280 IoCFunction *f;
281
282 f = IoCFunction_newWithFunctionPointer_tag_name_(IOSTATE, (IoUserFunction *)fp, NULL, CSTRING(slotName));
283 IoObject_setSlot_to_(self, slotName, f);
284 return f;
285 }
286
IoObject_addTaglessMethodTable_(IoObject * self,IoMethodTable * methodTable)287 void IoObject_addTaglessMethodTable_(IoObject *self, IoMethodTable *methodTable)
288 {
289 IoMethodTable *entry = methodTable;
290
291 while (entry->name)
292 {
293 IoObject_addTaglessMethod_(self, IOSYMBOL(entry->name), entry->func);
294 entry ++;
295 }
296 }
297
IoObject_new(void * state)298 IoObject *IoObject_new(void *state)
299 {
300 IoObject *proto = IoState_protoWithId_((IoState *)state, protoId);
301 return IOCLONE(proto);
302 }
303
IoObject_justClone(IoObject * self)304 IoObject *IoObject_justClone(IoObject *self)
305 {
306 return (IoObject_tag(self)->cloneFunc)(self);
307 }
308
IoObject_createSlots(IoObject * self)309 void IoObject_createSlots(IoObject *self)
310 {
311 IoObject_slots_(self, PHash_new());
312 IoObject_ownsSlots_(self, 1);
313 }
314
315 //inline
IoObject_freeData(IoObject * self)316 void IoObject_freeData(IoObject *self)
317 {
318 IoTagFreeFunc *func = IoTag_freeFunc(IoObject_tag(self));
319
320 if (func)
321 {
322 //if(func == free)
323 {
324 //printf("Tag func is free\n");
325 //if (IoObject_name(self)) printf("free %s\n", IoObject_name(self));
326 }
327
328 (*func)(self);
329 }
330 else if (IoObject_dataPointer(self))
331 {
332 io_free(IoObject_dataPointer(self));
333 }
334
335 IoObject_setDataPointer_(self, NULL);
336 }
337
338 //inline
IoObject_setProtoTo_(IoObject * self,IoObject * proto)339 void IoObject_setProtoTo_(IoObject *self, IoObject *proto)
340 {
341 IoObject_rawSetProto_(self, proto);
342
343 if (!IoObject_slots(self))
344 {
345 IoObject_slots_(self, IoObject_slots(proto));
346 IoObject_ownsSlots_(self, 0); // should be redundant
347 }
348 }
349
IoObject_rawClone(IoObject * proto)350 IoObject *IoObject_rawClone(IoObject *proto)
351 {
352 IoObject *self = IoObject_alloc(proto);
353 IoObject_tag_(self, IoObject_tag(proto));
354 /*
355 {
356 IoObject **protos = IoObject_protos(self);
357 protos[0] = proto;
358 }
359 */
360 IoObject_setProtoTo_(self, proto);
361 IoObject_isActivatable_(self, IoObject_isActivatable(proto));
362
363 //IoObject_protos(self)[0] = proto;
364 //IoObject_setDataPointer_(self, IoObject_dataPointer(proto)); // is this right?
365 IoObject_isDirty_(self, 1);
366 return self;
367 }
368
IoObject_rawClonePrimitive(IoObject * proto)369 IoObject *IoObject_rawClonePrimitive(IoObject *proto)
370 {
371 IoObject *self = IoObject_alloc(proto);
372 IoObject_tag_(self, IoObject_tag(proto));
373 IoObject_setProtoTo_(self, proto);
374 IoObject_setDataPointer_(self, NULL);
375 IoObject_isDirty_(self, 1);
376 return self;
377 }
378
379 // protos ---------------------------------------------
380
IoObject_rawPrintProtos(IoObject * self)381 void IoObject_rawPrintProtos(IoObject *self)
382 {
383 int count = 0;
384
385 IOOBJECT_FOREACHPROTO(self, proto,
386 printf("%i : %p\n", count, (void *)(proto));
387 count++;
388 );
389
390 printf("\n");
391 }
392
IoObject_hasProtos(IoObject * self)393 int IoObject_hasProtos(IoObject *self)
394 {
395 return (IoObject_firstProto(self) != NULL);
396 }
397
IoObject_rawProtosCount(IoObject * self)398 int IoObject_rawProtosCount(IoObject *self)
399 {
400 int count = 0;
401 IOOBJECT_FOREACHPROTO(self, proto, if(proto) count ++);
402 return count;
403 }
404
IoObject_rawAppendProto_(IoObject * self,IoObject * p)405 void IoObject_rawAppendProto_(IoObject *self, IoObject *p)
406 {
407 int count = IoObject_rawProtosCount(self);
408 IoObject_protos_(self, io_realloc(IoObject_protos(self), (count + 2) * sizeof(IoObject *)));
409 IoObject_protos(self)[count] = IOREF(p);
410 IoObject_protos(self)[count + 1] = NULL;
411 }
412
IoObject_rawPrependProto_(IoObject * self,IoObject * p)413 void IoObject_rawPrependProto_(IoObject *self, IoObject *p)
414 {
415 int count = IoObject_rawProtosCount(self);
416 int oldSize = (count + 1) * sizeof(IoObject *);
417 int newSize = oldSize + sizeof(IoObject *);
418
419 IoObject_protos_(self, io_realloc(IoObject_protos(self), newSize));
420
421 {
422 void *src = IoObject_protos(self);
423 void *dst = IoObject_protos(self) + 1;
424 memmove(dst, src, oldSize);
425 }
426
427 IoObject_protoAtPut_(self, 0, IOREF(p));
428 }
429
IoObject_rawRemoveProto_(IoObject * self,IoObject * p)430 void IoObject_rawRemoveProto_(IoObject *self, IoObject *p)
431 {
432 IoObject **proto = IoObject_protos(self);
433 int count = IoObject_rawProtosCount(self);
434 int index = 0;
435
436 while (*proto)
437 {
438 if (*proto == p)
439 {
440 memmove(proto, proto + 1, (count - index) * sizeof(IoObject *));
441 }
442 else
443 {
444 proto ++;
445 }
446
447 index ++;
448 }
449 }
450
451 /*
452 #include <assert.h>
453
454 void IoObject_testProtosCode(IoObject *self)
455 {
456 IoObject *o1 = (IoObject *)0x1;
457 IoObject *o2 = (IoObject *)0x2;
458 int c;
459
460 IoObject_rawRemoveAllProtos(self);
461 c = IoObject_rawProtosCount(self);
462 assert(c == 0);
463
464 IoObject_rawAppendProto_(self, o1);
465 assert(IoObject_protoAt_(self, 0) == o1);
466 assert(IoObject_protoAt_(self, 1) == NULL);
467 assert(IoObject_rawProtosCount(self) == 1);
468
469 IoObject_rawPrependProto_(self, (IoObject *)0x2);
470 assert(IoObject_rawProtosCount(self) == 2);
471 assert(IoObject_protoAt_(self, 0) == o2);
472 assert(IoObject_protoAt_(self, 1) == o1);
473 assert(IoObject_protoAt_(self, 2) == NULL);
474
475 IoObject_rawRemoveAllProtos(self);
476 c = IoObject_rawProtosCount(self);
477 assert(c == 0);
478 }
479 */
480
IoObject_rawSetProto_(IoObject * self,IoObject * proto)481 void IoObject_rawSetProto_(IoObject *self, IoObject *proto)
482 {
483 IoObject_rawRemoveAllProtos(self);
484 IoObject_protos(self)[0] = IOREF(proto);
485 }
486
IO_METHOD(IoObject,objectProto)487 IO_METHOD(IoObject, objectProto)
488 {
489 /*doc Object proto
490 Same as; method(self protos first)
491 */
492
493 IoObject *proto = IoObject_firstProto(self);
494 return proto ? proto : IONIL(self);
495 }
496
IO_METHOD(IoObject,setProto)497 IO_METHOD(IoObject, setProto)
498 {
499 /*doc Object setProto(anObject)
500 Sets the first proto of the receiver to anObject, replacing the
501 current one, if any. Returns self.
502 */
503
504 IoObject_rawSetProto_(self, IoMessage_locals_valueArgAt_(m, locals, 0));
505 return self;
506 }
507
IO_METHOD(IoObject,appendProto)508 IO_METHOD(IoObject, appendProto)
509 {
510 /*doc Object appendProto(anObject)
511 Appends anObject to the receiver's proto list. Returns self.
512 */
513
514 IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0);
515 IoObject_rawAppendProto_(self, proto);
516 return self;
517 }
518
IO_METHOD(IoObject,prependProto)519 IO_METHOD(IoObject, prependProto)
520 {
521 /*doc Object prependProto(anObject)
522 Prepends anObject to the receiver's proto list. Returns self.
523 */
524
525 IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0);
526 IoObject_rawPrependProto_(self, proto);
527 return self;
528 }
529
IO_METHOD(IoObject,removeProto)530 IO_METHOD(IoObject, removeProto)
531 {
532 /*doc Object removeProto(anObject)
533 Removes anObject from the receiver's proto list if it
534 is present. Returns self.
535 */
536
537 IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0);
538 IoObject_rawRemoveProto_(self, proto);
539 return self;
540 }
541
IO_METHOD(IoObject,removeAllProtos)542 IO_METHOD(IoObject, removeAllProtos)
543 {
544 /*doc Object removeAllProtos
545 Removes all of the receiver's protos. Returns self.
546 */
547
548 IoObject_rawRemoveAllProtos(self);
549 return self;
550 }
551
IO_METHOD(IoObject,setProtos)552 IO_METHOD(IoObject, setProtos)
553 {
554 /*doc Object setProtos(aList)
555 Replaces the receiver's protos with a copy of aList. Returns self.
556 */
557
558 IoList *ioList = IoMessage_locals_listArgAt_(m, locals, 0);
559 IoObject_rawRemoveAllProtos(self);
560 LIST_FOREACH(IoList_rawList(ioList), i, v, IoObject_rawAppendProto_(self, (IoObject *)v));
561 return self;
562 }
563
564
IO_METHOD(IoObject,protosMethod)565 IO_METHOD(IoObject, protosMethod)
566 {
567 /*doc Object protos
568 Returns a copy of the receiver's protos list.
569 */
570
571 IoList *ioList = IoList_new(IOSTATE);
572 List *list = IoList_rawList(ioList);
573 IOOBJECT_FOREACHPROTO(self, proto, List_append_(list, proto));
574 return ioList;
575 }
576
577 // --------------------------------------------------------
578
579 //inline
IoObject_freeSlots(IoObject * self)580 void IoObject_freeSlots(IoObject *self) // prepare for io_free and possibly recycle
581 {
582 if (IoObject_ownsSlots(self))
583 {
584 PHash_free(IoObject_slots(self));
585 IoObject_slots_(self, NULL);
586 IoObject_ownsSlots_(self, 0);
587 }
588
589 IoObject_slots_(self, NULL);
590 }
591
IoObject_willFree(IoObject * self)592 void IoObject_willFree(IoObject *self)
593 {
594 /*
595 // disabled until we keep a list of coros and can make sure their stacks are marked after the
596 // willFree gc stage
597 if (IoObject_sentWillFree(self) == 0)
598 {
599 IoObject *context;
600 IoMessage *m = IOSTATE->willFreeMessage;
601 IoObject *finalizeSlotValue = IoObject_rawGetSlot_context_(self, IoMessage_name(m), &context);
602
603 if (finalizeSlotValue)
604 {
605 IoObject_perform(self, self, m);
606 IoObject_sentWillFree_(self, 1);
607 //IoObject_makeGray(self);
608 }
609 }
610 */
611 }
612
IoObject_free(IoObject * self)613 void IoObject_free(IoObject *self) // prepare for io_free and possibly recycle
614 {
615 #ifdef IOSTATE_RECYCLING_ON
616 if(List_size(IOSTATE->recycledObjects) >= IOSTATE->maxRecycledObjects)
617 #endif
618 {
619 IoObject_dealloc(self);
620 //CollectorMarker_free((CollectorMarker *)self);
621 }
622 #ifdef IOSTATE_RECYCLING_ON
623 else
624 {
625 //printf("recycling %p\n", (void *)self);
626 IoObject_rawRemoveAllProtos(self);
627
628 #ifdef IOOBJECT_PERSISTENCE
629 IoObject_isDirty_(self, 0);
630 #endif
631
632 IoObject_hasDoneLookup_(self, 0);
633 IoObject_isSymbol_(self, 0);
634 IoObject_isLocals_(self, 0);
635 IoObject_isActivatable_(self, 0);
636
637 //if (IoObject_ownsSlots(self))
638 {
639 //IoObject_freeSlots(self);
640 PHash_clean(IoObject_slots(self));
641 }
642 /*
643 else
644 {
645 IoObject_slots_(self, NULL);
646 }
647 */
648
649 List_append_(IOSTATE->recycledObjects, self);
650 }
651 #endif
652 }
653
IoObject_dealloc(IoObject * self)654 void IoObject_dealloc(IoObject *self) // really io_free it
655 {
656 if (IoObject_markerCount(self) == 0)
657 {
658 if (IoObject_listeners(self))
659 {
660 LIST_FOREACH(IoObject_listeners(self), i, v, IoObject_tag((IoObject *)v)->notificationFunc(v, self));
661 List_free(IoObject_listeners(self));
662 IoObject_listeners_(self, NULL);
663 }
664
665 IoObject_freeData(self);
666
667 if (IoObject_ownsSlots(self))
668 {
669 PHash_free(IoObject_slots(self));
670 }
671
672 io_free(IoObject_protos(self));
673 //memset(self, 0, sizeof(IoObjectData));
674 io_free(self->object);
675 }
676 else
677 {
678 //printf("IoObject_decrementMarkerCount(%p)\n", (void *)self);
679 IoObject_decrementMarkerCount(self)
680 }
681 }
682
683 // ----------------------------------------------------------------
684
IO_METHOD(IoObject,protoCompare)685 IO_METHOD(IoObject, protoCompare)
686 {
687 /*doc Object compare(anObject)
688 Returns a number containing the comparison value of the target with anObject.
689 */
690
691 IOASSERT(IoMessage_argCount(m), "compare requires argument");
692
693 {
694 IoSymbol *other = IoMessage_locals_valueArgAt_(m, locals, 0);
695 return IONUMBER(IoObject_compare(self, other));
696 }
697 }
698
699 // slot lookups with lookup loop detection
700
IoObject_rawHasProto_(IoObject * self,IoObject * p)701 unsigned int IoObject_rawHasProto_(IoObject *self, IoObject *p)
702 {
703 if (self == p)
704 {
705 return 1;
706 }
707
708 if (IoObject_hasDoneLookup(self))
709 {
710 return 0;
711 }
712 else
713 {
714 IoObject **proto = IoObject_protos(self);
715
716 IoObject_hasDoneLookup_(self, 1);
717
718 while (*proto)
719 {
720 if (IoObject_rawHasProto_(*proto, p))
721 {
722 IoObject_hasDoneLookup_(self, 0);
723 return 1;
724 }
725
726 proto ++;
727 }
728
729 IoObject_hasDoneLookup_(self, 0);
730 return 0;
731 }
732 }
733
IO_METHOD(IoObject,protoHasProto_)734 IO_METHOD(IoObject, protoHasProto_)
735 {
736 /*doc Object hasProto(anObject)
737 Returns true if anObject is found in the proto path of the target, false otherwise.
738 */
739
740 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
741 return IOBOOL(self, IoObject_rawHasProto_(self, v));
742 }
743
744 // ------------------------------------------------------
745
IoObject_getSlot_(IoObject * self,IoSymbol * slotName)746 IoObject *IoObject_getSlot_(IoObject *self, IoSymbol *slotName)
747 {
748 IoObject *v = IoObject_rawGetSlot_(self, slotName);
749 return v ? v : IONIL(self);
750 }
751
IoObject_doubleGetSlot_(IoObject * self,IoSymbol * slotName)752 double IoObject_doubleGetSlot_(IoObject *self, IoSymbol *slotName)
753 {
754 IoObject *v = IoObject_rawGetSlot_(self, slotName);
755
756 if (!v)
757 {
758 IoState_error_(IOSTATE, NULL, "missing slot %s in %s",
759 CSTRING(slotName), IoObject_name(self));
760 return 0;
761 }
762
763 if (!ISNUMBER(v))
764 {
765 IoState_error_(IOSTATE, NULL, "slot %s in %s must be a number, not a %s",
766 CSTRING(slotName), IoObject_name(self), IoObject_name(v));
767 return 0;
768 }
769
770 return CNUMBER(v);
771 }
772
IoObject_symbolGetSlot_(IoObject * self,IoSymbol * slotName)773 IoObject *IoObject_symbolGetSlot_(IoObject *self, IoSymbol *slotName)
774 {
775 IoObject *v = IoObject_rawGetSlot_(self, slotName);
776
777 if (!v)
778 {
779 IoState_error_(IOSTATE, NULL, "missing slot %s in %s",
780 CSTRING(slotName), IoObject_name(self));
781 return NULL;
782 }
783
784 if (!ISSYMBOL(v))
785 {
786 IoState_error_(IOSTATE, NULL, "slot %s in %s must be a symbol, not a %s",
787 CSTRING(slotName), IoObject_name(self), IoObject_name(v));
788 return NULL;
789 }
790
791 return v;
792 }
793
IoObject_seqGetSlot_(IoObject * self,IoSymbol * slotName)794 IoObject *IoObject_seqGetSlot_(IoObject *self, IoSymbol *slotName)
795 {
796 IoObject *v = IoObject_rawGetSlot_(self, slotName);
797
798 if (!v)
799 {
800 IoState_error_(IOSTATE, NULL, "missing slot %s in %s",
801 CSTRING(slotName), IoObject_name(self));
802 }
803
804 if (!ISSEQ(v))
805 {
806 IoState_error_(IOSTATE, NULL, "slot %s in %s must be a sequence, not a %s",
807 CSTRING(slotName), IoObject_name(self), IoObject_name(v));
808 }
809
810 return v;
811 }
812
IoObject_activateFunc(IoObject * self,IoObject * target,IoObject * locals,IoMessage * m,IoObject * slotContext)813 IoObject *IoObject_activateFunc(IoObject *self,
814 IoObject *target,
815 IoObject *locals,
816 IoMessage *m,
817 IoObject *slotContext)
818 {
819 IoState *state = IOSTATE;
820
821 if (IoObject_isActivatable(self))
822 {
823 IoObject *context;
824 IoObject *slotValue = IoObject_rawGetSlot_context_(self, state->activateSymbol, &context);
825
826 if (slotValue)
827 {
828 //return IoObject_activate(slotValue, self, locals, m, context);
829 return IoObject_activate(slotValue, target, locals, m, context);
830 }
831 }
832
833 return self;
834 }
835
836 // -----------------------------------------------------------
837
IoObject_setSlot_to_(IoObject * self,IoSymbol * slotName,IoObject * value)838 void IoObject_setSlot_to_(IoObject *self, IoSymbol *slotName, IoObject *value)
839 {
840 IoObject_inlineSetSlot_to_(self, slotName, value);
841 }
842
IoObject_removeSlot_(IoObject * self,IoSymbol * slotName)843 void IoObject_removeSlot_(IoObject *self, IoSymbol *slotName)
844 {
845 IoObject_createSlotsIfNeeded(self);
846 PHash_removeKey_(IoObject_slots(self), slotName);
847 }
848
IoObject_rawGetSlot_target_(IoObject * self,IoSymbol * slotName,IoObject ** target)849 IoObject *IoObject_rawGetSlot_target_(IoObject *self, IoSymbol *slotName, IoObject **target)
850 {
851 IoObject *slotValue = IoObject_rawGetSlot_(self, slotName);
852
853 if (!slotValue)
854 {
855 IoObject *selfDelegate = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol);
856
857 if (selfDelegate && selfDelegate != self)
858 {
859 slotValue = IoObject_rawGetSlot_(selfDelegate, slotName);
860
861 if (slotValue)
862 {
863 *target = selfDelegate;
864 }
865 }
866 }
867 return slotValue;
868 }
869
IO_METHOD(IoObject,localsForward)870 IO_METHOD(IoObject, localsForward)
871 {
872 /*doc Object localsForward
873 CFunction used by Locals prototype for forwarding.
874 */
875
876 //IoObject *selfDelegate = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol);
877 IoObject *selfDelegate = PHash_at_(IoObject_slots(self), IOSTATE->selfSymbol); // cheating a bit here
878
879 if (selfDelegate && selfDelegate != self)
880 {
881 return IoObject_perform(selfDelegate, locals, m);
882 }
883
884 return IONIL(self);
885 }
886
887 // name ------------------------------------------------------
888
IO_METHOD(IoObject,lobbyPrint)889 IO_METHOD(IoObject, lobbyPrint)
890 {
891 /*doc Object print
892 Prints a string representation of the object. Returns Nil.
893 */
894
895 IoState *state = IOSTATE;
896 const char *name = IoObject_name(self);
897
898 IoObject_createSlotsIfNeeded(self);
899
900 IoState_print_(state, "%s_%p do(\n", name, (void *)self, name);
901 IoState_print_(state, " appendProto(");
902
903 {
904 IoObject **proto = IoObject_protos(self);
905
906 while (*proto)
907 {
908 IoState_print_(state, "%s_%p", name, (void *)*proto, name);
909 proto ++;
910
911 if (*proto)
912 {
913 IoState_print_(state, ", ");
914 }
915 }
916 }
917
918 IoState_print_(state, ")\n");
919
920 return state->ioNil;
921 }
922
IoObject_memorySizeFunc(IoObject * self)923 size_t IoObject_memorySizeFunc(IoObject *self)
924 {
925 return sizeof(IoObjectData) + (IoObject_ownsSlots(self) ? PHash_memorySize(IoObject_slots(self)) : 0 );
926 }
927
IoObject_compactFunc(IoObject * self)928 void IoObject_compactFunc(IoObject *self)
929 {
930 PHash_compact(IoObject_slots(self));
931 }
932
933 // proto methods ----------------------------------------------
934
IO_METHOD(IoObject,protoPerform)935 IO_METHOD(IoObject, protoPerform)
936 {
937 /*doc Object perform(methodName, <arg1>, <arg2>, ...)
938 Performs the method corresponding to methodName with the arguments supplied.
939 */
940
941 IoObject *slotName = IoMessage_locals_valueArgAt_(m, locals, 0);
942
943 if (ISMESSAGE(slotName))
944 {
945 IOASSERT(IoMessage_argCount(m)==1, "perform takes a single argument when using a Message as an argument");
946 return IoObject_perform(self, locals, slotName);
947 }
948
949 IOASSERT(ISSYMBOL(slotName), "perform requires a Symbol or Message argument");
950
951 {
952 IoObject *context;
953 IoObject *v = IoObject_rawGetSlot_context_(self, slotName, &context);
954 IoMessage *newMessage = IoMessage_newWithName_label_(IOSTATE, slotName, IoMessage_rawLabel(m));
955 IoMessage_rawSetLineNumber_(newMessage, IoMessage_rawLineNumber(m));
956 if (v)
957 {
958 int i;
959 List *args = IoMessage_rawArgList(m);
960
961 for (i = 1; i < List_size(args); i ++)
962 {
963 IoMessage_addArg_(newMessage, IoMessage_deepCopyOf_(List_at_(args, i)));
964 }
965
966 return IoObject_activate(v, self, locals, newMessage, context);
967 }
968
969 return IoObject_forward(self, locals, newMessage);
970 }
971
972 return IoObject_forward(self, locals, m);
973 }
974
IO_METHOD(IoObject,protoPerformWithArgList)975 IO_METHOD(IoObject, protoPerformWithArgList)
976 {
977 /*doc Object performWithArgList(methodName, argList)
978 Performs the method corresponding to methodName with the arguments in the argList.
979 */
980
981 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
982 IoList *args = IoMessage_locals_listArgAt_(m, locals, 1);
983 List *argList = IoList_rawList(args);
984 IoObject *context;
985 IoObject *v = IoObject_rawGetSlot_context_(self, slotName, &context);
986
987 if (v)
988 {
989 IoMessage *newMessage = IoMessage_newWithName_(IOSTATE, slotName);
990 size_t i, max = List_size(argList);
991
992 for (i = 0; i < max; i ++)
993 {
994 IoMessage_addCachedArg_(newMessage, LIST_AT_(argList, i));
995 }
996
997 return IoObject_activate(v, self, locals, newMessage, context);
998 }
999
1000 return IoObject_forward(self, locals, m);
1001 }
1002
IO_METHOD(IoObject,protoWrite)1003 IO_METHOD(IoObject, protoWrite)
1004 {
1005 /*doc Object write(<any number of arguments>)
1006 Sends a print message to the evaluated result of each argument. Returns Nil.
1007 */
1008
1009 int n, max = IoMessage_argCount(m);
1010 IoState *state = IOSTATE;
1011
1012 for (n = 0; n < max; n ++)
1013 {
1014 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n);
1015 IoMessage_locals_performOn_(state->printMessage, locals, v);
1016 }
1017
1018 return IONIL(self);
1019 }
1020
IO_METHOD(IoObject,protoWriteLn)1021 IO_METHOD(IoObject, protoWriteLn)
1022 {
1023 /*doc Object writeln(<any number of arguments>)
1024 Same as write() but also writes a return character at the end. Returns Nil.
1025 */
1026
1027 IoObject_protoWrite(self, locals, m);
1028 IoState_print_(IOSTATE, "\n");
1029 return IONIL(self);
1030 }
1031
1032 //inline
IoObject_initClone_(IoObject * self,IoObject * locals,IoMessage * m,IoObject * newObject)1033 IoObject *IoObject_initClone_(IoObject *self, IoObject *locals, IoMessage *m, IoObject *newObject)
1034 {
1035 IoState *state = IOSTATE;
1036 IoObject *context;
1037 IoObject *initSlotValue = IoObject_rawGetSlot_context_(newObject, IoMessage_name(state->initMessage), &context);
1038
1039 if (initSlotValue)
1040 {
1041 IoObject_activate(initSlotValue, newObject, locals, state->initMessage, context);
1042 }
1043
1044 return newObject;
1045 }
1046
IOCLONE(IoObject * self)1047 IoObject *IOCLONE(IoObject *self)
1048 {
1049 IoState *state = IOSTATE;
1050 IoObject *newObject;
1051
1052 IoState_pushCollectorPause(state);
1053 newObject = IoObject_tag(self)->cloneFunc(self);
1054 IoState_addValueIfNecessary_(state, newObject);
1055 IoState_popCollectorPause(state);
1056 return newObject;
1057 }
1058
IO_METHOD(IoObject,clone)1059 IO_METHOD(IoObject, clone)
1060 {
1061 /*doc Object clone
1062 Returns a clone of the receiver.
1063 */
1064
1065 IoObject *newObject = IOCLONE(self);
1066 return IoObject_initClone_(self, locals, m, newObject);
1067 }
1068
IO_METHOD(IoObject,cloneWithoutInit)1069 IO_METHOD(IoObject, cloneWithoutInit)
1070 {
1071 /*doc Object cloneWithoutInit
1072 Returns a clone of the receiver but does not call init.
1073 */
1074
1075 return IOCLONE(self);
1076 }
1077
IO_METHOD(IoObject,shallowCopy)1078 IO_METHOD(IoObject, shallowCopy)
1079 {
1080 /*doc Object shallowCopy
1081 Returns a shallow copy of the receiver.
1082 */
1083
1084 IOASSERT(ISOBJECT(self), "shallowCopy doesn't work on primitives");
1085
1086 {
1087 IoObject *newObject = IoObject_new(IOSTATE);
1088 PHASH_FOREACH(IoObject_slots(self), k, v, IoObject_setSlot_to_(newObject, k, v) );
1089 return newObject;
1090 }
1091 }
1092
1093 // lobby methods ----------------------------------------------
1094
IO_METHOD(IoObject,protoSet_to_)1095 IO_METHOD(IoObject, protoSet_to_)
1096 {
1097 /*doc Object setSlot(slotNameString, valueObject)
1098 Sets the slot slotNameString in the receiver to
1099 hold valueObject. Returns valueObject.
1100 */
1101
1102 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1103 IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1);
1104 IoObject_inlineSetSlot_to_(self, slotName, slotValue);
1105 return slotValue;
1106 }
1107
IO_METHOD(IoObject,protoSetSlotWithType)1108 IO_METHOD(IoObject, protoSetSlotWithType)
1109 {
1110 /*doc Object setSlotWithType(slotNameString, valueObject)
1111 Sets the slot slotNameString in the receiver to
1112 hold valueObject and sets the type slot of valueObject
1113 to be slotNameString. Returns valueObject.
1114 */
1115
1116 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1117 IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1);
1118 IoObject_inlineSetSlot_to_(self, slotName, slotValue);
1119 IoObject_createSlotsIfNeeded(slotValue);
1120 if (PHash_at_(IoObject_slots(slotValue), IOSTATE->typeSymbol) == NULL)
1121 {
1122 IoObject_inlineSetSlot_to_(slotValue, IOSTATE->typeSymbol, slotName);
1123 }
1124 return slotValue;
1125 }
1126
IO_METHOD(IoObject,localsUpdateSlot)1127 IO_METHOD(IoObject, localsUpdateSlot)
1128 {
1129 /*doc Object localsUpdateSlot(slotNameString, valueObject)
1130 Local's version of updateSlot mthod.
1131 */
1132
1133 IoSymbol *slotName = IoMessage_locals_firstStringArg(m, locals);
1134 //IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1135 IoObject *obj = IoObject_rawGetSlot_(self, slotName);
1136
1137 if (obj)
1138 {
1139 //IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1);
1140 IoObject *slotValue = IoMessage_locals_quickValueArgAt_(m, locals, 1);
1141 IoObject_inlineSetSlot_to_(self, slotName, slotValue);
1142 return slotValue;
1143 }
1144 else
1145 {
1146 IoObject *theSelf = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol);
1147
1148 if (theSelf)
1149 {
1150 return IoObject_perform(theSelf, locals, m);
1151 }
1152 }
1153
1154 IoState_error_(IOSTATE, m,
1155 "updateSlot - slot with name `%s' not found in `%s'. Use := to create slots.",
1156 CSTRING(slotName), IoObject_name(self));
1157
1158 return IONIL(self);
1159 }
1160
IO_METHOD(IoObject,protoUpdateSlot_to_)1161 IO_METHOD(IoObject, protoUpdateSlot_to_)
1162 {
1163 /*doc Object updateSlot(slotNameString, valueObject)
1164 Same as setSlot(), but raises an error if the slot does not
1165 already exist in the receiver's slot lookup path.
1166 */
1167
1168 IoSymbol *slotName = IoMessage_locals_firstStringArg(m, locals);
1169 IoObject *slotValue = IoMessage_locals_quickValueArgAt_(m, locals, 1);
1170 IoObject *obj = IoObject_rawGetSlot_(self, slotName);
1171
1172 if (obj)
1173 {
1174 IoObject_inlineSetSlot_to_(self, slotName, slotValue);
1175 }
1176 else
1177 {
1178 IoState_error_(IOSTATE, m, "Slot %s not found. Must define slot using := operator before updating.",
1179 CSTRING(slotName));
1180 }
1181
1182 return slotValue;
1183 }
1184
IO_METHOD(IoObject,protoGetSlot_)1185 IO_METHOD(IoObject, protoGetSlot_)
1186 {
1187 /*doc Object getSlot(slotNameString)
1188 Returns the value of the slot named slotNameString
1189 (following the lookup path) or nil if no such slot is found.
1190 */
1191
1192 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1193 return IoObject_getSlot_(self, slotName);
1194 }
1195
IO_METHOD(IoObject,protoGetLocalSlot_)1196 IO_METHOD(IoObject, protoGetLocalSlot_)
1197 {
1198 /*doc Object getLocalSlot(slotNameString)
1199 Returns the value of the slot named slotNameString
1200 (not looking in the object's protos) or nil if no such slot is found.
1201 */
1202
1203 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1204
1205 if (IoObject_ownsSlots(self))
1206 {
1207 IoObject *v = PHash_at_(IoObject_slots(self), slotName);
1208 if (v) return v;
1209 }
1210
1211 return IONIL(self);
1212 }
1213
IO_METHOD(IoObject,protoHasLocalSlot)1214 IO_METHOD(IoObject, protoHasLocalSlot)
1215 {
1216 /*doc Object hasLocalSlot(slotNameString)
1217 Returns true if the slot exists in the receiver or false otherwise.
1218 */
1219
1220 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1221 IoObject_createSlotsIfNeeded(self);
1222 return IOBOOL(self, PHash_at_(IoObject_slots(self), slotName) != NULL);
1223 }
1224
IO_METHOD(IoObject,protoRemoveSlot)1225 IO_METHOD(IoObject, protoRemoveSlot)
1226 {
1227 /*doc Object removeSlot(slotNameString)
1228 Removes the specified slot (only) in the receiver if it exists. Returns self.
1229 */
1230
1231 IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1232 IoObject_createSlotsIfNeeded(self);
1233 PHash_removeKey_(IoObject_slots(self), slotName);
1234 return self;
1235 }
1236
IO_METHOD(IoObject,protoRemoveAllSlots)1237 IO_METHOD(IoObject, protoRemoveAllSlots)
1238 {
1239 /*doc Object removeAllSlots
1240 Removes all of the receiver's slots. Returns self.
1241 */
1242
1243 PHash_clean(IoObject_slots(self));
1244 return self;
1245 }
1246
IO_METHOD(IoObject,protoSlotNames)1247 IO_METHOD(IoObject, protoSlotNames)
1248 {
1249 /*doc Object slotNames
1250 Returns a list of strings containing the names of the
1251 slots in the receiver (but not in its lookup path).
1252 */
1253
1254 IoObject_createSlotsIfNeeded(self);
1255
1256 {
1257 IoList *slotNames = IoList_new(IOSTATE);
1258 PHASH_FOREACH(IoObject_slots(self), key, value, IoList_rawAppend_(slotNames, key); );
1259 return slotNames;
1260 }
1261 }
1262
IO_METHOD(IoObject,protoSlotValues)1263 IO_METHOD(IoObject, protoSlotValues)
1264 {
1265 /*doc Object slotValues
1266 Returns a list of the values held in the slots of the receiver.
1267 */
1268
1269 IoObject_createSlotsIfNeeded(self);
1270
1271 {
1272 IoList *slotNames = IoList_new(IOSTATE);
1273 PHASH_FOREACH(IoObject_slots(self), key, value, IoList_rawAppend_(slotNames, value); );
1274 return slotNames;
1275 }
1276
1277 }
1278
1279
1280 /*doc Object forward
1281 Called when the receiver is sent a message it doesn't recognize.
1282 Default implementation raises an "Object doesNotRespond" exception.
1283 Subclasses can override this method to implement proxies or special error handling.
1284 <p>
1285 Example:
1286 <p>
1287 <pre>
1288 myProxy forward = method(
1289 messageName := thisMessage name
1290 arguments := thisMessage arguments
1291 myObject doMessage(thisMessage)
1292 )
1293 </pre>
1294 */
1295
1296 /*
1297 IO_METHOD(IoObject, forward_)
1298 {
1299
1300 IoState_error_(IOSTATE, m, "%s does not respond to message '%s'",
1301 IoObject_name(self),
1302 CSTRING(IoMessage_name(m)));
1303 return IONIL(self);
1304 }
1305 */
1306
IO_METHOD(IoObject,ancestorWithSlot)1307 IO_METHOD(IoObject, ancestorWithSlot)
1308 {
1309 /*doc Object ancestorWithSlot(slotName)
1310 Returns the first ancestor of the receiver that contains
1311 a slot of the specified name or Nil if none is found.
1312 */
1313
1314 IoObject *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1315 IoObject **proto = IoObject_protos(self);
1316
1317 while (*proto)
1318 {
1319 IoObject *context = NULL;
1320 IoObject *v = IoObject_rawGetSlot_context_((*proto), slotName, &context);
1321
1322 if (v)
1323 {
1324 return context;
1325 }
1326
1327 proto ++;
1328 }
1329
1330 return IONIL(self);
1331 }
1332
IO_METHOD(IoObject,contextWithSlot)1333 IO_METHOD(IoObject, contextWithSlot)
1334 {
1335 /*doc Object contextWithSlot(slotName)
1336 Returns the first context (starting with the receiver and following the lookup path)
1337 that contains a slot of the specified name or Nil if none is found.
1338 */
1339
1340 IoObject *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
1341 IoObject *context = NULL;
1342 IoObject_rawGetSlot_context_(self, slotName, &context);
1343 return context ? context : IONIL(self);
1344 }
1345
1346 // ---------------------------------------------------------------------------
1347
IoObject_rawDoString_label_(IoObject * self,IoSymbol * string,IoSymbol * label)1348 IoObject *IoObject_rawDoString_label_(IoObject *self, IoSymbol *string, IoSymbol *label)
1349 {
1350 IoMessage *cm = NULL;
1351 IoMessage *messageForString = NULL;
1352 IoMessage *newMessage = NULL;
1353 IoState *state = IOSTATE;
1354
1355 if(!ISSEQ(string))
1356 {
1357 IoState_error_(state, NULL, "IoObject_rawDoString_label_ requires a string argument");
1358 }
1359
1360 {
1361 IoSymbol *internal;
1362 IoState_pushCollectorPause(state);
1363
1364 internal = IOSYMBOL("[internal]");
1365 cm = IoMessage_newWithName_label_(state, IOSYMBOL("Compiler"), internal);
1366 messageForString = IoMessage_newWithName_label_(state, IOSYMBOL("messageForString"), internal);
1367
1368 IoMessage_rawSetNext_(cm, messageForString);
1369 IoMessage_addCachedArg_(messageForString, string);
1370 IoMessage_addCachedArg_(messageForString, label);
1371
1372 newMessage = IoMessage_locals_performOn_(cm, self, self);
1373 IoState_stackRetain_(state, newMessage); // needed?
1374
1375 IoState_popCollectorPause(state);
1376
1377 if (newMessage)
1378 {
1379 return IoMessage_locals_performOn_(newMessage, self, self);
1380 }
1381
1382 IoState_error_(state, NULL, "no message compiled\n");
1383 return IONIL(self);
1384 }
1385 }
1386
IO_METHOD(IoObject,doMessage)1387 IO_METHOD(IoObject, doMessage)
1388 {
1389 /*doc Object doMessage(aMessage, optionalContext)
1390 Evaluates the message object in the context of the receiver.
1391 Returns the result. optionalContext can be used to specific the locals
1392 context in which the message is evaluated.
1393 */
1394
1395 IoMessage *aMessage = IoMessage_locals_messageArgAt_(m, locals, 0);
1396 IoObject *context = self;
1397
1398 if (IoMessage_argCount(m) >= 2)
1399 {
1400 context = IoMessage_locals_valueArgAt_(m, locals, 1);
1401 }
1402
1403 return IoMessage_locals_performOn_(aMessage, context, self);
1404 }
1405
IO_METHOD(IoObject,doString)1406 IO_METHOD(IoObject, doString)
1407 {
1408 /*doc Object doString(aString)
1409 Evaluates the string in the context of the receiver. Returns the result.
1410 */
1411
1412 IoSymbol *string = IoMessage_locals_seqArgAt_(m, locals, 0);
1413 IoSymbol *label;
1414 IoObject *result;
1415
1416 if (IoMessage_argCount(m) > 1)
1417 {
1418 label = IoMessage_locals_symbolArgAt_(m, locals, 1);
1419 }
1420 else
1421 {
1422 label = IOSYMBOL("doString");
1423 }
1424
1425 IoState_pushRetainPool(IOSTATE);
1426 result = IoObject_rawDoString_label_(self, string, label);
1427 IoState_popRetainPoolExceptFor_(IOSTATE, result);
1428 return result;
1429 }
1430
IO_METHOD(IoObject,doFile)1431 IO_METHOD(IoObject, doFile)
1432 {
1433 /*doc Object doFile(pathString)
1434 Evaluates the File in the context of the receiver. Returns the result.
1435 pathString is relative to the current working directory.
1436 */
1437
1438 IoSymbol *path = IoMessage_locals_symbolArgAt_(m, locals, 0);
1439 IoFile *file = IoFile_newWithPath_(IOSTATE, path);
1440 IoSymbol *string = (IoSymbol *)IoSeq_rawAsSymbol(IoFile_contents(file, locals, m));
1441
1442 if (IoSeq_rawSize(string))
1443 {
1444 return IoObject_rawDoString_label_(self, string, path);
1445 }
1446 else
1447 {
1448 return IONIL(self);
1449 }
1450 }
1451
IO_METHOD(IoObject,isIdenticalTo)1452 IO_METHOD(IoObject, isIdenticalTo)
1453 {
1454 /*doc Object isIdenticalTo(aValue)
1455 Returns true if the receiver is identical to aValue, false otherwise.
1456 */
1457
1458 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0);
1459 return IOBOOL(self, self == other);
1460 }
1461
IO_METHOD(IoObject,equals)1462 IO_METHOD(IoObject, equals)
1463 {
1464 /*doc Object ==(aValue)
1465 Returns true if receiver and aValue are equal, false otherwise.
1466 */
1467
1468 IOASSERT(IoMessage_argCount(m), "compare requires argument");
1469
1470 {
1471 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0);
1472 return IOBOOL(self, IoObject_compare(self, other) == 0);
1473 }
1474 }
1475
IO_METHOD(IoObject,notEquals)1476 IO_METHOD(IoObject, notEquals)
1477 {
1478 /*doc Object !=(aValue)
1479 Returns true the receiver is not equal to aValue, false otherwise.
1480 */
1481
1482 IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0);
1483 return IOBOOL(self, IoObject_compare(self, other) != 0);
1484 }
1485
IO_METHOD(IoObject,foreachSlot)1486 IO_METHOD(IoObject, foreachSlot)
1487 {
1488 /*doc Object foreach([name,] value, message)
1489 For each slot, set name to the slot's
1490 name and value to the slot's value and execute message. Examples:
1491 <p>
1492 <pre>
1493 myObject foreach(n, v,
1494 writeln("slot ", n, " = ", v type)
1495 )
1496
1497 myObject foreach(v,
1498 writeln("slot type ", v type)
1499 )
1500 </pre>
1501 */
1502
1503 IoSymbol *keyName;
1504 IoSymbol *valueName;
1505 IoMessage *doMessage;
1506 IoObject *result = IONIL(self);
1507
1508 IoState_pushRetainPool(IOSTATE);
1509 IoMessage_foreachArgs(m, self, &keyName, &valueName, &doMessage);
1510
1511 PHASH_FOREACH(IoObject_slots(self), key, value,
1512 IoState_clearTopPool(IOSTATE);
1513
1514 if (keyName)
1515 {
1516 IoObject_setSlot_to_(locals, keyName, key);
1517 }
1518
1519 IoObject_setSlot_to_(locals, valueName, value);
1520 result = IoMessage_locals_performOn_(doMessage, locals, locals);
1521
1522 if (IoState_handleStatus(IOSTATE))
1523 {
1524 goto done;
1525 }
1526 );
1527 done:
1528 IoState_popRetainPoolExceptFor_(IOSTATE, result);
1529 return result;
1530 }
1531
IO_METHOD(IoObject,subtract)1532 IO_METHOD(IoObject, subtract)
1533 {
1534 /*doc Object -(aNumber)
1535 Returns the negative version of aNumber.
1536 Raises an exception if argument is not a number.
1537 */
1538
1539 IoNumber *num = IoMessage_locals_numberArgAt_(m, locals, 0);
1540 return IONUMBER(- IoNumber_asDouble(num));
1541 }
1542
IO_METHOD(IoObject,self)1543 IO_METHOD(IoObject, self)
1544 {
1545 /*doc Object self
1546 Returns self.
1547 */
1548 /*doc Object thisContext
1549 Synonym to self.
1550 */
1551
1552 return self;
1553 }
1554
IO_METHOD(IoObject,thisMessage)1555 IO_METHOD(IoObject, thisMessage)
1556 {
1557 /*doc Object thisMessage
1558 Returns the calling message (i.e. thisMessage itself, huh).
1559 */
1560
1561 return m;
1562 }
1563
1564
IO_METHOD(IoObject,locals)1565 IO_METHOD(IoObject, locals)
1566 {
1567 /*doc Object thisLocalContext
1568 Returns current locals.
1569 */
1570
1571 return locals;
1572 }
1573
1574 // message callbacks --------------------------------------
1575
IoObject_name(IoObject * self)1576 const char *IoObject_name(IoObject *self)
1577 {
1578 // If self has a type slot which is a string, then use that instead of the tag name
1579 IoObject *type = IoObject_rawGetSlot_(self, IOSYMBOL("type"));
1580 if (type && ISSEQ(type))
1581 {
1582 return CSTRING(type);
1583 }
1584
1585 return IoTag_name(IoObject_tag(self));
1586 }
1587
IoObject_compare(IoObject * self,IoObject * v)1588 int IoObject_compare(IoObject *self, IoObject *v)
1589 {
1590 if (self == v)
1591 {
1592 return 0;
1593 }
1594
1595 if (IoObject_tag(self)->compareFunc)
1596 {
1597 return (IoObject_tag(self)->compareFunc)(self, v);
1598 }
1599
1600 return IoObject_defaultCompare(self, v);
1601 }
1602
IoObject_defaultCompare(IoObject * self,IoObject * v)1603 int IoObject_defaultCompare(IoObject *self, IoObject *v)
1604 {
1605
1606 //IoState_error_(IOSTATE, NULL, "attempt to compare %s to %s", IoObject_name(self), IoObject_name(v));
1607 //return 0;
1608
1609 ptrdiff_t d = -((ptrdiff_t)IoObject_tag(self) - (ptrdiff_t)IoObject_tag(v));
1610 //printf("warning: IoObject_defaultCompare attempt to compare %s to %s\n", IoObject_name(self), IoObject_name(v));
1611
1612 if (d == 0)
1613 {
1614 d = ((ptrdiff_t)self) - ((ptrdiff_t)v);
1615 }
1616
1617 if (d == 0) return 0;
1618
1619 return d > 0 ? 1 : -1;
1620 }
1621
IoObject_sortCompare(IoObject ** self,IoObject ** v)1622 int IoObject_sortCompare(IoObject **self, IoObject **v)
1623 {
1624 return IoObject_compare(*self, *v);
1625 }
1626
IoObject_compact(IoObject * self)1627 void IoObject_compact(IoObject *self)
1628 {
1629 /*
1630 if (IoObject_tag(self)->compactFunc)
1631 {
1632 (IoObject_tag(self)->compactFunc)(self);
1633 }
1634 */
1635 }
1636
1637 // lobby methods ----------------------------------------------
1638
IO_METHOD(IoObject,memorySizeMethod)1639 IO_METHOD(IoObject, memorySizeMethod)
1640 {
1641 /*doc Object memorySize
1642 Return the amount of memory used by the object.
1643 */
1644
1645 return IONUMBER(IoObject_memorySize(self));
1646 }
1647
1648 /*doc Object checkMemory()
1649 Accesses memory in the IoObjectData struct that should be accessible. Should cause a memory access
1650 exception if memory is corrupt.
1651 */
IoObject_rawCheckMemory(IoObject * self)1652 int IoObject_rawCheckMemory(IoObject *self)
1653 {
1654 return IOCOLLECTOR != 0x0;
1655 }
1656
IO_METHOD(IoObject,compactMethod)1657 IO_METHOD(IoObject, compactMethod)
1658 {
1659 /*doc Object compact
1660 Compact the memory for the object if possible. Returns self.
1661 */
1662
1663 IoObject_compact(self);
1664 return self;
1665 }
1666
IO_METHOD(IoObject,type)1667 IO_METHOD(IoObject, type)
1668 {
1669 /*doc Object type
1670 Returns a string containing the name of the type of Object (Number, String, etc).
1671 */
1672
1673 return IOSYMBOL((char *)IoObject_name(self));
1674 }
1675
IoObject_defaultPrint(IoObject * self)1676 void IoObject_defaultPrint(IoObject *self)
1677 {
1678 if (ISSYMBOL(self))
1679 {
1680 IoSeq_rawPrint(self);
1681 }
1682 else if (ISNUMBER(self))
1683 {
1684 IoNumber_print(self);
1685 }
1686 else
1687 {
1688 IoState_print_(IOSTATE, "%s_%p", IoObject_name(self), self);
1689
1690 if (ISMESSAGE(self))
1691 {
1692 IoState_print_(IOSTATE, " '%s'", CSTRING(IoMessage_name(self)));
1693 }
1694 }
1695 }
1696
IoObject_print(IoObject * self)1697 void IoObject_print(IoObject *self)
1698 {
1699 IoMessage_locals_performOn_(IOSTATE->printMessage, self, self);
1700 // using self as locals hack
1701 }
1702
1703 /*
1704 IO_METHOD(IoObject, truthValueOfArg);
1705 {
1706 //-doc Object The '' method evaluates the argument and returns the result.
1707
1708 IOASSERT(IoMessage_argCount(m) > 0, "argument required");
1709 return IoMessage_locals_valueArgAt_(m, locals, 0);
1710 }
1711 */
1712
IO_METHOD(IoObject,evalArg)1713 IO_METHOD(IoObject, evalArg)
1714 {
1715 /*doc Object (expression)
1716 The '' method evaluates the argument and returns the result.
1717 */
1718
1719 /*doc Object evalArg(expression)
1720 The '' method evaluates the argument and returns the result.
1721 */
1722
1723 IOASSERT(IoMessage_argCount(m) > 0, "argument required");
1724 /* eval the arg and return a non-Nil so an attached else() won't get performed */
1725 return IoMessage_locals_valueArgAt_(m, locals, 0);
1726 }
1727
IO_METHOD(IoObject,evalArgAndReturnSelf)1728 IO_METHOD(IoObject, evalArgAndReturnSelf)
1729 {
1730 /*doc Object evalArgAndReturnSelf(expression)
1731 Evaluates the argument and returns the target.
1732 */
1733
1734 IoObject_evalArg(self, locals, m);
1735 return self;
1736 }
1737
IO_METHOD(IoObject,evalArgAndReturnNil)1738 IO_METHOD(IoObject, evalArgAndReturnNil)
1739 {
1740 /*doc Object evalArgAndReturnNil(expression)
1741 Evaluates the argument and returns nil.
1742 */
1743
1744 IoObject_evalArg(self, locals, m);
1745 return IONIL(self);
1746 }
1747
IO_METHOD(IoObject,isLessThan_)1748 IO_METHOD(IoObject, isLessThan_)
1749 {
1750 /*doc Object <(expression)
1751 Evaluates argument and returns self if self is less or Nil if not.
1752 */
1753
1754 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1755 return IOBOOL(self, IoObject_compare(self, v) < 0);
1756 }
1757
IO_METHOD(IoObject,isLessThanOrEqualTo_)1758 IO_METHOD(IoObject, isLessThanOrEqualTo_)
1759 {
1760 /*doc Object <=(expression)
1761 Evaluates argument and returns self if self is less
1762 than or equal to it, or Nil if not.
1763 */
1764
1765 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1766 return IOBOOL(self, IoObject_compare(self, v) <= 0);
1767 }
1768
IO_METHOD(IoObject,asBoolean)1769 IO_METHOD(IoObject, asBoolean)
1770 {
1771 if (self == IOSTATE->ioFalse || self == IOSTATE->ioNil)
1772 return self;
1773 else
1774 return IOSTATE->ioTrue;
1775 }
1776
IO_METHOD(IoObject,isGreaterThan_)1777 IO_METHOD(IoObject, isGreaterThan_)
1778 {
1779 /*doc Object >(expression)
1780 Evaluates argument and returns self if self is greater than it, or Nil if not.
1781 */
1782
1783 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1784 return IOBOOL(self, IoObject_compare(self, v) > 0);
1785 }
1786
IO_METHOD(IoObject,isGreaterThanOrEqualTo_)1787 IO_METHOD(IoObject, isGreaterThanOrEqualTo_)
1788 {
1789 /*doc Object >=(expression)
1790 Evaluates argument and returns self if self is greater
1791 than or equal to it, or Nil if not.
1792 */
1793
1794 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1795 return IOBOOL(self, IoObject_compare(self, v) >= 0);
1796 }
1797
IO_METHOD(IoObject,uniqueId)1798 IO_METHOD(IoObject, uniqueId)
1799 {
1800 /*doc Object uniqueId
1801 Returns a Number containing a unique id for the receiver.
1802 */
1803 char s[32];
1804 #if defined(_MSC_VER) || defined(__MINGW32__)
1805 sprintf(s, "0x%p", (void *)IoObject_deref(self));
1806 #else
1807 sprintf(s, "%p", (void *)IoObject_deref(self));
1808 #endif
1809 return IOSYMBOL(s);
1810 //return IONUMBER((double)((size_t)IoObject_deref(self)));
1811 }
1812
IO_METHOD(IoObject,do)1813 IO_METHOD(IoObject, do)
1814 {
1815 /*doc Object do(expression)
1816 Evaluates the message in the context of the receiver. Returns self.
1817 */
1818
1819 if (IoMessage_argCount(m) != 0)
1820 {
1821 IoMessage *argMessage = IoMessage_rawArgAt_(m, 0);
1822 IoMessage_locals_performOn_(argMessage, self, self);
1823 }
1824
1825 return self;
1826 }
1827
IO_METHOD(IoObject,lexicalDo)1828 IO_METHOD(IoObject, lexicalDo)
1829 {
1830 /*doc Object lexicalDo(expression)
1831 Evaluates the message in the context of the receiver.
1832 The lexical context is added as a proto of the receiver while the argument is evaluated.
1833 Returns self.
1834 */
1835
1836 if (IoMessage_argCount(m) != 0)
1837 {
1838 IoMessage *argMessage = IoMessage_rawArgAt_(m, 0);
1839 IoObject_rawAppendProto_(self, locals);
1840 IoMessage_locals_performOn_(argMessage, self, self);
1841 IoObject_rawRemoveProto_(self, locals);
1842 }
1843
1844 return self;
1845 }
1846
IO_METHOD(IoObject,message)1847 IO_METHOD(IoObject, message)
1848 {
1849 /*doc Object message(expression)
1850 Return the message object for the argument or Nil if there is no argument.
1851 Note: returned object is a mutable singleton. Use "message(foo) clone" if
1852 you wish to modify it.
1853 */
1854
1855 return IoMessage_argCount(m) ? IoMessage_rawArgAt_(m, 0) : IONIL(self);
1856 }
1857
1858
1859 // inline these -------------------------------------------------
1860
IoObject_hasCloneFunc_(IoObject * self,IoTagCloneFunc * func)1861 int IoObject_hasCloneFunc_(IoObject *self, IoTagCloneFunc *func)
1862 {
1863 return (IoObject_tag(self)->cloneFunc == func);
1864 }
1865
1866 // --------------------------------------------
1867
IoObject_markColorName(IoObject * self)1868 char *IoObject_markColorName(IoObject *self)
1869 {
1870 return Collector_colorNameFor_(IOCOLLECTOR, self);
1871 }
1872
IoSymbol_println(IoSymbol * self)1873 void IoSymbol_println(IoSymbol *self)
1874 {
1875 printf("%s\n", CSTRING(self));
1876 }
1877
IoObject_show(IoObject * self)1878 void IoObject_show(IoObject *self)
1879 {
1880 printf(" %p %s\n", (void *)self, IoObject_name(self));
1881 //PHash_doOnKeys_(IoObject_slots(self), (PHashDoCallback *)IoSymbol_println);
1882 PHASH_FOREACH(IoObject_slots(self), k, v, IoSymbol_println(k));
1883 }
1884
IO_METHOD(IoObject,setIsActivatableMethod)1885 IO_METHOD(IoObject, setIsActivatableMethod)
1886 {
1887 /*doc Object setIsActivatable(aValue)
1888 When called with a non-Nil aValue, sets the object
1889 to call its activate slot when accessed as a value. Turns this behavior
1890 off if aValue is Nil. Only works on Objects which are not Activatable
1891 Primitives (such as CFunction or Block). Returns self.
1892 */
1893
1894 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1895 IoObject *objectProto = IoState_protoWithId_(IOSTATE, protoId);
1896
1897 IoTag_activateFunc_(IoObject_tag(objectProto), (IoTagActivateFunc *)IoObject_activateFunc);
1898
1899 IoObject_isActivatable_(self, ISTRUE(v))
1900 return self;
1901 }
1902
IO_METHOD(IoObject,isActivatableMethod)1903 IO_METHOD(IoObject, isActivatableMethod)
1904 {
1905 /*doc Object isActivatable
1906 Returns true if the receiver is activatable, false otherwise.
1907 */
1908
1909 return IoObject_isActivatable(self) ? IOTRUE(self) : IOFALSE(self);
1910 }
1911
1912
1913 /*
1914 IoNumber *IoObject_getNumberSlot(IoObject *self,
1915 IoObject *locals,
1916 IoMessage *m,
1917 IoSymbol *slotName)
1918 {
1919 IoObject *v = IoObject_getSlot_(self, slotName);
1920 IOASSERT(ISNUMBER(v), CSTRING(slotName));
1921 return v;
1922 }
1923 */
1924
IoObject_rawGetUArraySlot(IoObject * self,IoObject * locals,IoMessage * m,IoSymbol * slotName)1925 UArray *IoObject_rawGetUArraySlot(IoObject *self,
1926 IoObject *locals,
1927 IoMessage *m,
1928 IoSymbol *slotName)
1929 {
1930 IoSeq *seq = IoObject_getSlot_(self, slotName);
1931 IOASSERT(ISSEQ(seq), CSTRING(slotName));
1932 return IoSeq_rawUArray(seq);
1933 }
1934
IoObject_rawGetMutableUArraySlot(IoObject * self,IoObject * locals,IoMessage * m,IoSymbol * slotName)1935 UArray *IoObject_rawGetMutableUArraySlot(IoObject *self,
1936 IoObject *locals,
1937 IoMessage *m,
1938 IoSymbol *slotName)
1939 {
1940 IoSeq *seq = IoObject_getSlot_(self, slotName);
1941 IOASSERT(ISSEQ(seq), CSTRING(slotName));
1942 return IoSeq_rawUArray(seq);
1943 }
1944
IO_METHOD(IoObject,argIsActivationRecord)1945 IO_METHOD(IoObject, argIsActivationRecord)
1946 {
1947 /*doc Object argIsActivationRecord
1948 Note: seems to be an obsolete method.
1949 */
1950 return IOBOOL(self, PHash_at_(IoObject_slots(self), IOSTATE->callSymbol) != NULL);
1951 }
1952
1953 /*void *testStack(void *a)
1954 {
1955 int v[256];
1956 memset(v, 0x1, 128);
1957 return a + v[0];
1958 }*/
1959
IO_METHOD(IoObject,argIsCall)1960 IO_METHOD(IoObject, argIsCall)
1961 {
1962 /*doc Object argIsCall(arg)
1963 Returns true if arg is an activation context (i.e. Call object)
1964 <br/>
1965 Note: this is used internally in one place only (Coroutine callStack).
1966 Refactoring should be considered.
1967 */
1968
1969 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
1970 //printf("IoObject_tag(v)->name = '%s'\n", IoObject_tag(v)->name);
1971
1972 /*
1973 printf("Collector_checkObjectPointers\n");
1974 Collector_check(IOSTATE->collector);
1975 Collector_checkObjectPointers(IOSTATE->collector);
1976 printf("Collector_checkObjectPointers done\n");
1977 printf("self = %p\n", self);
1978 printf("v = %p\n", v);
1979 printf("tag = %p\n", IoObject_tag(self));
1980 */
1981 /*
1982 printf("tag->cloneFunc = %p\n", IoObject_tag(v)->cloneFunc);
1983 printf("IoCall_rawClone = %p\n", IoCall_rawClone);
1984
1985 //testStack(self);
1986 <<<<<<< HEAD
1987
1988
1989 printf("ISACTIVATIONCONTEXT = %i\n", isAct);
1990 */
1991
1992 int isAct = ((void *)(IoObject_tag(v)->cloneFunc) == (void *)IoCall_rawClone);
1993 IoObject *t = IOSTATE->ioTrue; //IOTRUE(self);
1994 IoObject *f = IOSTATE->ioFalse; //IOFALSE(self);
1995 //return isAct ? t : f;
1996 if(isAct)
1997 {
1998 return t;
1999 }
2000 return f;
2001 //return IOBOOL(self, ISACTIVATIONCONTEXT(v));
2002
2003 /*
2004 int isAct = ((void *)(IoObject_tag(self)->cloneFunc) == (void *)IoCall_rawClone);
2005
2006 // printf("ISACTIVATIONCONTEXT = %i\n", isAct);
2007
2008 void *t = IOTRUE(self);
2009 void *f = IOFALSE(self);
2010 return isAct ? t : f;
2011 */
2012
2013 return IOBOOL(self, ISACTIVATIONCONTEXT(v));
2014 }
2015
IO_METHOD(IoObject,become)2016 IO_METHOD(IoObject, become)
2017 {
2018 /*doc Object become(anotherObject)
2019 Replaces receiver with <tt>anotherObject</tt> and returns self.
2020 Useful for implementing transparent proxies. See also <tt>FutureProxy</tt> and <tt>Object @</tt>.
2021 <br/>
2022 Note: primitives cannot become new values.
2023 */
2024
2025 IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0);
2026
2027 if(self == v || IoObject_deref(v) == IoObject_deref(self)) return self;
2028
2029 //IOASSERT(!IoObject_isSymbol(self), "Symbols cannot become new values");
2030 IOASSERT(ISOBJECT(self), "Primitives cannot become new values");
2031 //printf("IoObject_become(%p, %p) data %p\n", (void *)self, (void *)v, (void *)IoObject_deref(v));
2032 IoObject_incrementMarkerCount(v);
2033 IoObject_dealloc(self);
2034 CollectorMarker_setObject_(self, IoObject_deref(v));
2035 return self;
2036 }
2037
IoObject_hasDirtySlot_(IoObject * self,IoObject * locals,IoMessage * m)2038 IOVM_API IoObject *IoObject_hasDirtySlot_(IoObject *self, IoObject *locals, IoMessage *m)
2039 {
2040 //IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0);
2041 int result = PHash_hasDirtyKey_(IoObject_slots(self), IOREF(IoMessage_locals_symbolArgAt_(m, locals, 0)));
2042 return IOBOOL(self, result);
2043 }
2044
IoObject_protoClean(IoObject * self)2045 void IoObject_protoClean(IoObject *self)
2046 {
2047 IoObject_isDirty_(self, 0);
2048 PHash_cleanSlots(IoObject_slots(self));
2049 }
2050
IO_METHOD(IoObject,markClean)2051 IO_METHOD(IoObject, markClean)
2052 {
2053 //doc Object markClean Cleans object's slots.
2054 PHash_cleanSlots(IoObject_slots(self));
2055 return self;
2056 }
2057
2058 // io_free listeners ---------------------------------------------
2059
IoObject_addListener_(IoObject * self,void * listener)2060 void IoObject_addListener_(IoObject *self, void *listener)
2061 {
2062 if (IoObject_listeners(self) == NULL)
2063 {
2064 IoObject_listeners_(self, List_new());
2065 }
2066
2067 List_append_(IoObject_listeners(self), listener);
2068 }
2069
IoObject_removeListener_(IoObject * self,void * listener)2070 void IoObject_removeListener_(IoObject *self, void *listener)
2071 {
2072 List *listeners = IoObject_listeners(self);
2073
2074 if (listeners)
2075 {
2076 List_remove_(listeners, listener);
2077
2078 if (List_size(listeners) == 0)
2079 {
2080 List_free(listeners);
2081 IoObject_listeners_(self, NULL);
2082 }
2083 }
2084 }
2085
2086 // persistence ------------------------------------------------
2087
2088 /*
2089 PID_TYPE IoObject_pid(IoObject *self)
2090 {
2091 return 0;
2092 }
2093 */
2094
2095 // asString helper
2096
IoObject_asString_(IoObject * self,IoMessage * m)2097 IoSeq *IoObject_asString_(IoObject *self, IoMessage *m)
2098 {
2099 IoSeq *result = IoMessage_locals_performOn_(IOSTATE->asStringMessage, self, self);
2100 /*
2101 IoSymbol *string = IOSYMBOL("asString");
2102 IoSymbol *label = string;
2103 IoSeq *result;
2104
2105 IoState_pushRetainPool(IOSTATE);
2106
2107 result = IoObject_rawDoString_label_(self, string, label);
2108 IoState_popRetainPoolExceptFor_(IOSTATE, result);
2109 */
2110
2111 if (!ISSEQ(result))
2112 {
2113 IoState_error_(IOSTATE, m, "%s asString didn't return a Sequence", IoObject_name(self));
2114 }
2115
2116 return result;
2117 }
2118