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