/*#io Object ioDoc( docCopyright("Steve Dekorte", 2002) docLicense("BSD revised") docObject("Object") docInclude("_ioCode/Object.io") docDescription("""An Object is a key/value dictionary with string keys and values of any type. The prototype Object contains a clone slot that is a CFuntion that creates new objects. When cloned, an Object will call it's init slot (with no arguments).

Important note:

The data structure used for objects is optimized for objects with relatively few slots (less than 100). Objects become very memory inefficient (exponentially so) when they have a large number of slots. Objects should not be used as large hash tables or lists. Use a Hash or List primitive instead.

""") docCategory("Core") */ #include "IoState.h" #define IOOBJECT_C #include "IoObject.h" #undef IOOBJECT_C #include "IoCoroutine.h" #include "IoTag.h" #include "IoCFunction.h" #include "IoSeq.h" #include "IoNumber.h" #include "IoMessage.h" #include "IoMessage_parser.h" #include "IoCFunction.h" #include "IoBlock.h" #include "IoList.h" #include "IoObject.h" #include "IoFile.h" #include "IoSeq.h" #include #include IoObject *IoObject_activateFunc(IoObject *self, IoObject *target, IoObject *locals, IoMessage *m, IoObject *slotContext); IoTag *IoObject_tag(void *state) { IoTag *tag = IoTag_newWithName_("Object"); tag->state = state; tag->cloneFunc = (TagCloneFunc *)IoObject_rawClone; tag->activateFunc = (TagActivateFunc *)NULL; // IoObject_activateFunc; return tag; } IoObject *IoObject_proto(void *state) { IoObject *self = calloc(1, sizeof(IoObject)); IoObject_setupProtos(self); self->slots = PHash_new(); self->ownsSlots = 1; self->tag = IoObject_tag(state); self->state = state; IoObject_setDataPointer_(self, NULL); IoState_registerProtoWithFunc_((IoState *)state, self, IoObject_proto); return self; } IoObject *IoObject_protoFinish(void *state) { IoMethodTable methodTable[] = { {"clone", IoObject_clone}, {"cloneWithoutInit", IoObject_cloneWithoutInit}, {"shallowCopy", IoObject_shallowCopy}, {"duplicate", IoObject_duplicate}, //{"print", IoObject_protoPrint}, {"write", IoObject_protoWrite}, {"writeln", IoObject_protoWriteLn}, {"type", IoObject_type}, // logic {"compare", IoObject_protoCompare}, {"<", IoObject_isLessThan_}, {">", IoObject_isGreaterThan_}, {">=", IoObject_isGreaterThanOrEqualTo_}, {"<=", IoObject_isLessThanOrEqualTo_}, // comparison {"isIdenticalTo", IoObject_isIdenticalTo}, {"==", IoObject_equals}, {"!=", IoObject_notEquals}, // introspection //{"self", IoObject_self}, {"setSlot", IoObject_protoSet_to_}, {"setSlotWithType", IoObject_protoSetSlotWithType}, {"updateSlot", IoObject_protoUpdateSlot_to_}, {"getSlot", IoObject_protoGetSlot_}, {"getLocalSlot", IoObject_protoGetLocalSlot_}, {"hasLocalSlot", IoObject_protoHasLocalSlot}, {"hasProto", IoObject_protoHasProto_}, {"removeSlot", IoObject_protoRemoveSlot}, {"slotNames", IoObject_protoSlotNames}, // method invocation {"perform", IoObject_protoPerform}, {"performWithArgList", IoObject_protoPerformWithArgList}, {"ancestorWithSlot", IoObject_ancestorWithSlot}, {"contextWithSlot", IoObject_contextWithSlot}, // control {"block", IoObject_block}, {"method", IoBlock_method}, {"for", IoObject_for}, {"if", IoObject_if}, {"", IoObject_evalArg}, {"evalArg", IoObject_evalArg}, {"evalArgAndReturnSelf", IoObject_evalArgAndReturnSelf}, {"evalArgAndReturnNil", IoObject_evalArgAndReturnNil}, {"return", IoObject_return}, {"returnIfNonNil", IoObject_returnIfNonNil}, {"loop", IoObject_loop}, {"while", IoObject_while}, {"break", IoObject_break}, {"continue", IoObject_continue}, {";", IoObject_eol}, // utility {"print", IoObject_lobbyPrint}, {"do", IoObject_do}, {"message", IoObject_message}, {"doMessage", IoObject_doMessage}, {"doString", IoObject_doString}, {"doFile", IoObject_doFile}, //{"unpack", IoObject_unpack}, // reflection {"uniqueId", IoObject_uniqueId}, // memory utilities //{"memorySize", IoObject_memorySizeMethod}, //{"compact", IoObject_compactMethod}, {"init", IoObject_self}, // enumeration {"foreachSlot", IoObject_foreachSlot}, {"-", IoObject_subtract}, {"thisContext", IoObject_self}, {"thisMessage", IoObject_thisMessage}, {"thisLocalContext", IoObject_locals}, // protos {"setProto", IoObject_setProto}, {"setProtos", IoObject_setProtos}, {"appendProto", IoObject_appendProto}, {"prependProto", IoObject_prependProto}, {"removeProto", IoObject_removeProto}, {"removeAllProtos", IoObject_removeAllProtos}, {"protos", IoObject_protos}, {"proto", IoObject_objectProto}, //{"tailCall", IoObject_tailCall}, {"setIsActivatable", IoObject_setIsActivatable}, {"isActivatable", IoObject_isActivatable}, {"argIsActivationRecord", IoObject_argIsActivationRecord}, {"argIsCall", IoObject_argIsCall}, {NULL, NULL}, }; IoObject *self = IoState_protoWithInitFunction_((IoState *)state, IoObject_proto); IoObject_addMethodTable_(self, methodTable); return self; } #include IoObject *IoObject_localsProto(void *state) { IoObject *self = IoObject_new(state); IoObject *proto = IoObject_firstProto(self); IoObject_createSlotsIfNeeded(self); PHash_copy_(self->slots, proto->slots); IoObject_rawRemoveAllProtos(self); IoObject_removeSlot_(self, IOSYMBOL("delegate")); IoObject_addMethod_(self, IOSYMBOL("forward"), IoObject_localsForward); IoObject_addMethod_(self, IOSYMBOL("setSlot"), IoObject_protoSet_to_); IoObject_addMethod_(self, IOSYMBOL("setSlotWithType"), IoObject_protoSetSlotWithType); IoObject_addMethod_(self, IOSYMBOL("updateSlot"), IoObject_localsUpdateSlot); return self; } IoObject *IoObject_addMethod_(IoObject *self, IoSymbol *slotName, IoMethodFunc *fp) { IoTag *t = self->tag; IoObject *proto = IoState_protoWithInitFunction_(IOSTATE, IoObject_proto); IoCFunction *f; if (t == proto->tag) { t = NULL; } f = IoCFunction_newWithFunctionPointer_tag_name_(IOSTATE, (IoUserFunction *)fp, t, CSTRING(slotName)); IoObject_setSlot_to_(self, slotName, f); return f; } void IoObject_addMethodTable_(IoObject *self, IoMethodTable *methodTable) { IoMethodTable *entry = methodTable; while (entry->name) { IoObject_addMethod_(self, IOSYMBOL(entry->name), entry->func); entry ++; } } IoObject *IoObject_new(void *state) { IoObject *proto = IoState_protoWithInitFunction_((IoState *)state, IoObject_proto); return IOCLONE(proto); } IoObject *IoObject_justClone(IoObject *self) { return (self->tag->cloneFunc)(self); } void IoObject_createSlots(IoObject *self) { self->slots = PHash_new(); self->ownsSlots = 1; } inline void IoObject_freeData(IoObject *self) { //if (!self->doesNotOwnData) { TagFreeFunc *func = self->tag->freeFunc; if (func) { (*func)(self); } else if (IoObject_dataPointer(self)) { free(IoObject_dataPointer(self)); } } IoObject_setDataPointer_(self, NULL); } #define IOOBJECT_RECYCLE #ifdef IOOBJECT_RECYCLE /*static int recycleHighPoint = 0;*/ void IoObject_clearMark(IoObject *self) { memset(&(self->marker), 0, sizeof(CollectorMarker)); self->hasDoneLookup = 0; //self->ownsSlots = 0; self->isSymbol = 0; self->isDirty = 0; //self->doesNotOwnData = 0; self->isLocals = 0; self->isActivatable = 0; } inline IoObject *IoObject_alloc(IoObject *self) { IoObject *pchild = List_pop(IOSTATE->recycledObjects); IoObject *child = pchild; if (!child) { child = (IoObject *)calloc(1, sizeof(IoObject)); IoObject_setupProtos(child); } IoObject_clearMark(child); //memset(child->tag, 0x0, sizeof(IoTag)); //child->tag->performFunc = NULL; child->state = self->tag->state; return child; } inline void IoObject_unalloc(IoObject *self) { if (IOSTATE->recycledObjects) { self->isSymbol = 0; /*printf("recycling %p\n", (void *)self);*/ List_append_(IOSTATE->recycledObjects, self); /* if (List_size(IOSTATE->recycledObjects) > recycleHighPoint) { recycleHighPoint = List_size(IOSTATE->recycledObjects); printf("recycleHighPoint %i\n", recycleHighPoint); } */ } else { IoObject_dealloc(self); } } #else inline IoObject *IoObject_alloc(IoObject *self) { IoObject *child = calloc(1, sizeof(IoObject)); IoObject_setupProtos(self); child->state = self->tag->state; return child; } #endif inline void IoObject_setProtoTo_(IoObject *self, IoObject *proto) { IoObject_rawRemoveAllProtos(self); IoObject_rawSetProto_(self, proto); if (!self->slots) { self->slots = proto->slots; self->ownsSlots = 0; // should be redundant } } IoObject *IoObject_rawClone(IoObject *proto) { IoObject *self = IoObject_alloc(proto); self->tag = proto->tag; IoObject_setProtoTo_(self, proto); IoObject_setDataPointer_(self, IoObject_dataPointer(proto)); // is this right? self->isDirty = 1; return self; } IoObject *IoObject_rawClonePrimitive(IoObject *proto) { IoObject *self = IoObject_alloc(proto); self->tag = proto->tag; IoObject_setProtoTo_(self, proto); IoObject_setDataPointer_(self, NULL); self->isDirty = 1; return self; } // protos --------------------------------------------- void IoObject_rawPrintProtos(IoObject *self) { IoObject **proto = self->protos; int count = 0; while (*proto) { printf("%i : %p\n", count, (void *)(*proto)); proto ++; count ++; } printf("\n"); } void IoObject_setupProtos(IoObject *self) { self->protos = (IoObject **)calloc(2, sizeof(IoObject *)); } int IoObject_hasProtos(IoObject *self) { return (self->protos[0] != NULL); } int IoObject_rawProtosCount(IoObject *self) { IoObject **proto = self->protos; int count = 0; while (*proto) { proto ++; count ++; } return count; } void IoObject_rawAppendProto_(IoObject *self, IoObject *p) { int count = IoObject_rawProtosCount(self); self->protos = realloc(self->protos, (count + 2) * sizeof(IoObject *)); self->protos[count] = IOREF(p); self->protos[count + 1] = NULL; } void IoObject_rawPrependProto_(IoObject *self, IoObject *p) { int count = IoObject_rawProtosCount(self); int oldSize = (count + 1) * sizeof(IoObject *); int newSize = oldSize + sizeof(IoObject *); self->protos = realloc(self->protos, newSize); { void *src = self->protos; void *dst = self->protos + 1; memmove(dst, src, oldSize); } self->protos[0] = IOREF(p); } void IoObject_rawRemoveProto_(IoObject *self, IoObject *p) { IoObject **proto = self->protos; int count = IoObject_rawProtosCount(self); int index = 0; while (*proto) { if (*proto == p) { memcpy(proto, proto + 1, (count - index) * sizeof(IoObject *)); } else { proto ++; } index ++; } } #include /* void IoObject_testProtosCode(IoObject *self) { IoObject *o1 = (IoObject *)0x1; IoObject *o2 = (IoObject *)0x2; int c; IoObject_rawRemoveAllProtos(self); c = IoObject_rawProtosCount(self); assert(c == 0); IoObject_rawAppendProto_(self, o1); assert(IoObject_rawProtoAt_(self, 0) == o1); assert(IoObject_rawProtoAt_(self, 1) == NULL); assert(IoObject_rawProtosCount(self) == 1); IoObject_rawPrependProto_(self, (IoObject *)0x2); assert(IoObject_rawProtosCount(self) == 2); assert(IoObject_rawProtoAt_(self, 0) == o2); assert(IoObject_rawProtoAt_(self, 1) == o1); assert(IoObject_rawProtoAt_(self, 2) == NULL); IoObject_rawRemoveAllProtos(self); c = IoObject_rawProtosCount(self); assert(c == 0); } */ void IoObject_rawSetProto_(IoObject *self, IoObject *proto) { self->protos[0] = IOREF(proto); } IoObject *IoObject_objectProto(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("proto", "Same as; method(self protos first)") */ IoObject *proto = self->protos[0]; return proto ? proto : IONIL(self); } IoObject *IoObject_setProto(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("setProto(anObject)", "Sets the first proto of the receiver to anObject, replacing the current one, if any. Returns self.") */ IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0); IoObject_rawSetProto_(self, proto); return self; } IoObject *IoObject_appendProto(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("appendProto(anObject)", "Appends anObject to the receiver's proto list. Returns self.") */ IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0); IoObject_rawAppendProto_(self, proto); return self; } IoObject *IoObject_prependProto(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("prependProto(anObject)", "Prepends anObject to the receiver's proto list. Returns self.") */ IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0); IoObject_rawPrependProto_(self, proto); return self; } IoObject *IoObject_removeProto(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("removeProto(anObject)", "Remove's anObject from the receiver's proto list if it is present. Returns self.") */ IoObject *proto = IoMessage_locals_valueArgAt_(m, locals, 0); IoObject_rawRemoveProto_(self, proto); return self; } IoObject *IoObject_removeAllProtos(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("removeAllProtos", "Remove's all of the receiver's protos. Returns self. ") */ IoObject_rawRemoveAllProtos(self); return self; } IoObject *IoObject_setProtos(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("setProtos(aList)", "Replaces the receiver's protos with a copy of aList. Returns self.") */ IoList *ioList = IoMessage_locals_listArgAt_(m, locals, 0); List *list = IoList_rawList(ioList); IoObject_rawRemoveAllProtos(self); List_target_do_(list, self, (ListDoWithCallback *)IoObject_rawAppendProto_); return self; } IoObject *IoObject_protos(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("protos", "Returns a copy of the receiver's protos list.") */ IoList *ioList = IoList_new(IOSTATE); List *list = IoList_rawList(ioList); IoObject **proto = self->protos; while (*proto) { List_append_(list, *proto); proto ++; } return ioList; } // -------------------------------------------------------- inline void IoObject_freeSlots(IoObject *self) // prepare for free and possibly recycle { if (self->ownsSlots) { PHash_free(self->slots); self->slots = NULL; self->ownsSlots = 0; } self->slots = NULL; } /* void IoObject_listenNotification(IoObject *self, void *notification) { self->tag->notificationFunc(self, notification); } */ void IoObject_free(IoObject *self) // prepare for free and possibly recycle { /* if (self->isLocals) { printf("free %p locals\n", (void *)self); } else { printf("free %p %s\n", (void *)self, IoObject_name(self)); } */ if (self->listeners) { LIST_FOREACH(self->listeners, i, v, ((IoObject *)v)->tag->notificationFunc(v, NULL)); } self->isLocals = 0; IoObject_freeData(self); //self->tag = NULL; IoObject_rawRemoveAllProtos(self); self->persistentId = 0; #ifdef IOOBJECT_RECYCLE if (self->ownsSlots) { PHash_clean(self->slots); } else { self->slots = NULL; } IoObject_unalloc(self); #else IoObject_dealloc(self); #endif } void IoObject_dealloc(IoObject *self) // really free it { if (self->ownsSlots) { PHash_free(self->slots); } free(self->protos); memset(self, 0, sizeof(IoObject)); // temp free(self); } // ---------------------------------------------------------------- IoObject *IoObject_protoCompare(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("compare(anObject)", "Returns a number containing the comparison value of the target with anObject.") */ IOASSERT(IoMessage_argCount(m), "compare requires argument"); { IoSymbol *other = IoMessage_locals_valueArgAt_(m, locals, 0); return IONUMBER(IoObject_compare(self, other)); } } // slot lookups with lookup loop detection unsigned int IoObject_rawHasProto_(IoObject *self, IoObject *p) { if (self == p) { return 1; } if (IoObject_hasDoneLookup(self)) { return 0; } else { IoObject **proto = self->protos; IoObject_setHasDoneLookup_(self, 1); while (*proto) { if (IoObject_rawHasProto_(*proto, p)) { IoObject_setHasDoneLookup_(self, 0); return 1; } proto ++; } IoObject_setHasDoneLookup_(self, 0); return 0; } } IoObject *IoObject_protoHasProto_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("hasProto(anObject)", "Returns true if anObject is found in the proto path of the target, false otherwise.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_rawHasProto_(self, v)); } // ------------------------------------------------------ IoObject *IoObject_getSlot_(IoObject *self, IoSymbol *slotName) { IoObject *v = IoObject_rawGetSlot_(self, slotName); return v ? v : IONIL(self); } double IoObject_doubleGetSlot_(IoObject *self, IoSymbol *slotName) { IoObject *v = IoObject_rawGetSlot_(self, slotName); if (!v) { IoState_error_(IOSTATE, NULL, "missing slot %s in %s", CSTRING(slotName), IoObject_name(self)); } if (!ISNUMBER(v)) { IoState_error_(IOSTATE, NULL, "slot %s in %s must be a number, not a %s", CSTRING(slotName), IoObject_name(self), IoObject_name(v)); } return CNUMBER(v); } IoObject *IoObject_symbolGetSlot_(IoObject *self, IoSymbol *slotName) { IoObject *v = IoObject_rawGetSlot_(self, slotName); if (!v) { IoState_error_(IOSTATE, NULL, "missing slot %s in %s", CSTRING(slotName), IoObject_name(self)); } if (!ISSYMBOL(v)) { IoState_error_(IOSTATE, NULL, "slot %s in %s must be a symbol, not a %s", CSTRING(slotName), IoObject_name(self), IoObject_name(v)); } return v; } IoObject *IoObject_seqGetSlot_(IoObject *self, IoSymbol *slotName) { IoObject *v = IoObject_rawGetSlot_(self, slotName); if (!v) { IoState_error_(IOSTATE, NULL, "missing slot %s in %s", CSTRING(slotName), IoObject_name(self)); } if (!ISSEQ(v)) { IoState_error_(IOSTATE, NULL, "slot %s in %s must be a sequence, not a %s", CSTRING(slotName), IoObject_name(self), IoObject_name(v)); } return v; } IoObject *IoObject_activateFunc(IoObject *self, IoObject *target, IoObject *locals, IoMessage *m, IoObject *slotContext) { IoState *state = IOSTATE; if (self->isActivatable) { IoObject *context; IoObject *slotValue = IoObject_rawGetSlot_context_(self, state->activateSymbol, &context); if (slotValue) { //return IoObject_activate(slotValue, self, locals, m, context); return IoObject_activate(slotValue, target, locals, m, context); } } return self; } // ----------------------------------------------------------- void IoObject_setSlot_to_(IoObject *self, IoSymbol *slotName, IoObject *value) { IoObject_inlineSetSlot_to_(self, slotName, value); } void IoObject_removeSlot_(IoObject *self, IoSymbol *slotName) { IoObject_createSlotsIfNeeded(self); PHash_removeKey_(self->slots, slotName); } IoObject *IoObject_rawGetSlot_target_(IoObject *self, IoSymbol *slotName, IoObject **target) { IoObject *slotValue = IoObject_rawGetSlot_(self, slotName); if (!slotValue) { IoObject *selfDelegate = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol); if (selfDelegate && selfDelegate != self) { slotValue = IoObject_rawGetSlot_(selfDelegate, slotName); if (slotValue) { *target = selfDelegate; } } } return slotValue; } /*printf("%p %s\n",self, CSTRING(IoMessage_name(m)));*/ IoObject *IoObject_localsForward(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("localsForward", "CFunction used by Locals prototype for forwarding.") */ //IoObject *selfDelegate = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol); IoObject *selfDelegate = PHash_at_(self->slots, IOSTATE->selfSymbol); // cheating a bit here if (selfDelegate && selfDelegate != self) { return IoObject_perform(selfDelegate, locals, m); } return IONIL(self); } // name ------------------------------------------------------ int IoObject_isObject(IoObject *self) { return (strcmp(IoObject_name(self), "Object") == 0); } IoObject *IoObject_lobbyPrint(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("print", "Prints a string representation of the object. Returns Nil.") */ IoState *state = IOSTATE; const char *name = IoObject_name(self); IoSymbol *key; IoObject_createSlotsIfNeeded(self); key = PHash_firstKey(self->slots); IoState_print_(IOSTATE, "%s_%p do(\n", name, (void *)self, name); IoState_print_(IOSTATE, " appendProto("); { IoObject **proto = self->protos; while (*proto) { IoState_print_(IOSTATE, "%s_%p", name, (void *)*proto, name); proto ++; if (*proto) { IoState_print_(IOSTATE, ", "); } } } IoState_print_(IOSTATE, ")\n"); while (key) { IoObject *value = PHash_at_(self->slots, key); IoState_print_(state, " %s := ", CSTRING(key)); if (ISSYMBOL(value)) IoState_print_(state, "\""); IoObject_defaultPrint(value); if (ISSYMBOL(value)) IoState_print_(state, "\""); IoState_print_(state, "\n"); key = PHash_nextKey(self->slots); } IoState_print_(IOSTATE, ")\n"); return state->ioNil; } size_t IoObject_memorySizeFunc(IoObject *self) { size_t t = sizeof(IoObject) + PHash_memorySize(self->slots); return t; } void IoObject_compactFunc(IoObject *self) { PHash_compact(self->slots); } // proto methods ---------------------------------------------- IoObject *IoObject_protoPerform(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("perform(methodName, , , ...)", "Performs the method corresponding to methodName with the arguments supplied.") */ IoObject *slotName = IoMessage_locals_valueArgAt_(m, locals, 0); if (ISMESSAGE(slotName)) { IOASSERT(IoMessage_argCount(m)==1, "perform takes a single argument when using a Message as an argument"); return IoObject_perform(self, locals, slotName); } IOASSERT(ISSYMBOL(slotName), "perform requires a String or Message argument"); { IoObject *context; IoObject *v = IoObject_rawGetSlot_context_(self, slotName, &context); IoMessage *newMessage = IoMessage_newWithName_(IOSTATE, slotName); if (v) { int i; List *args = IoMessage_rawArgList(m); for (i = 1; i < List_size(args); i ++) { IoMessage_addArg_(newMessage, IoMessage_deepCopyOf_(List_at_(args, i))); } return IoObject_activate(v, self, locals, newMessage, context); } return IoObject_forward(self, locals, newMessage); } return IoObject_forward(self, locals, m); } IoObject *IoObject_protoPerformWithArgList(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("performWithArgList(methodName, argList)", "Performs the method corresponding to methodName with the arguments in the argList. ") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoList *args = IoMessage_locals_listArgAt_(m, locals, 1); List *argList = IoList_rawList(args); IoObject *context; IoObject *v = IoObject_rawGetSlot_context_(self, slotName, &context); if (v) { IoMessage *newMessage = IoMessage_newWithName_(IOSTATE, slotName); int i, max = List_size(argList); for (i = 0; i < max; i ++) { IoMessage_addCachedArg_(newMessage, LIST_AT_(argList, i)); } return IoObject_activate(v, self, locals, newMessage, context); } return IoObject_forward(self, locals, m); } IoObject *IoObject_protoWrite(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("write()", "Sends a print message to the evaluated result of each argument. Returns Nil.") */ int n, max = IoMessage_argCount(m); IoState *state = IOSTATE; for (n = 0; n < max; n ++) { IoObject *v = IoMessage_locals_valueArgAt_(m, locals, n); IoMessage_locals_performOn_(state->printMessage, locals, v); } return IONIL(self); } IoObject *IoObject_protoWriteLn(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("writeln()", "Same as write() but also writes a return character at the end. Returns Nil.") */ IoObject_protoWrite(self, locals, m); IoState_print_(IOSTATE, "\n"); return IONIL(self); } inline IoObject *IoObject_initClone_(IoObject *self, IoObject *locals, IoMessage *m, IoObject *newObject) { IoState *state = IOSTATE; IoObject *context; IoObject *initSlotValue = IoObject_rawGetSlot_context_(newObject, state->initSymbol, &context); if (initSlotValue) { IoObject_activate(initSlotValue, newObject, locals, state->initMessage, context); } return newObject; } IoObject *IOCLONE(IoObject *self) { IoState *state = IOSTATE; IoObject *newObject; IoState_pushCollectorPause(state); newObject = self->tag->cloneFunc(self); IoState_addValue_(state, newObject); IoState_popCollectorPause(state); return newObject; } IoObject *IoObject_clone(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("clone", "Returns a clone of the receiver.") */ IoObject *newObject = IOCLONE(self); return IoObject_initClone_(self, locals, m, newObject); } IoObject *IoObject_cloneWithoutInit(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("cloneWithoutInit", "Returns a clone of the receiver but does not call init.") */ return IOCLONE(self); } IoObject *IoObject_shallowCopy(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("shallowCopy", "Returns a shallow copy of the receiver.") */ IoObject *newObject = IoObject_new(IOSTATE); IoSymbol *key = PHash_firstKey(self->slots); while (key) { IoObject *value = PHash_at_(self->slots, key); IoObject_setSlot_to_(newObject, key, value); key = PHash_nextKey(self->slots); } return newObject; } IoObject *IoObject_duplicate(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("duplicate", "Creates a new copy of the receiver, including its proto list.") */ IoObject *newObject; IoState *state = IOSTATE; IoState_pushCollectorPause(state); newObject = IoObject_new(state); memmove(newObject, self, sizeof(*self)); IoState_addValue_(state, newObject); IoState_popCollectorPause(state); return newObject; } // lobby methods ---------------------------------------------- IoObject *IoObject_protoSet_to_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("setSlot(slotNameString, valueObject)", "Sets the slot slotNameString in the receiver to hold valueObject. Returns valueObject.") */ //IoSymbol *slotName = IoMessage_locals_firstStringArg(m, locals); //IoObject *slotValue = IoMessage_locals_quickValueArgAt_(m, locals, 1); IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1); IoObject_inlineSetSlot_to_(self, slotName, slotValue); return slotValue; } IoObject *IoObject_protoSetSlotWithType(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("setSlotWithType(slotNameString, valueObject)", "Sets the slot slotNameString in the receiver to hold valueObject and sets the type slot of valueObject to be slotNameString. Returns valueObject.") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1); IoObject_inlineSetSlot_to_(self, slotName, slotValue); if (PHash_at_(slotValue->slots, IOSTATE->typeSymbol) == NULL) { IoObject_inlineSetSlot_to_(slotValue, IOSTATE->typeSymbol, slotName); } return slotValue; } IoObject *IoObject_localsUpdateSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("updateLocalSlot(slotNameString, valueObject)", "") */ IoSymbol *slotName = IoMessage_locals_firstStringArg(m, locals); //IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject *obj = IoObject_rawGetSlot_(self, slotName); if (obj) { //IoObject *slotValue = IoMessage_locals_valueArgAt_(m, locals, 1); IoObject *slotValue = IoMessage_locals_quickValueArgAt_(m, locals, 1); IoObject_inlineSetSlot_to_(self, slotName, slotValue); return slotValue; } else { IoObject *theSelf = IoObject_rawGetSlot_(self, IOSTATE->selfSymbol); if (theSelf) { return IoObject_perform(theSelf, locals, m); /* obj = IoObject_rawGetSlot_(theSelf, slotName); if (obj) { IoObject_inlineSetSlot_to_(theSelf, slotName, slotValue); return slotValue; } */ } } IoState_error_(IOSTATE, m, "updateSlot - slot with name `%s' not found in `%s'. Use := to create slots.", CSTRING(slotName), IoObject_name(self)); return IONIL(self); } IoObject *IoObject_protoUpdateSlot_to_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("updateSlot(slotNameString, valueObject)", "Same as setSlot(), but raises an error if the slot does not already exist in the receiver's slot lookup path.") */ IoSymbol *slotName = IoMessage_locals_firstStringArg(m, locals); IoObject *slotValue = IoMessage_locals_quickValueArgAt_(m, locals, 1); IoObject *obj = IoObject_rawGetSlot_(self, slotName); if (obj) { IoObject_inlineSetSlot_to_(self, slotName, slotValue); } else { IoState_error_(IOSTATE, m, "Slot %s not found. Must define slot using := operator before updating.", CSTRING(slotName)); } return slotValue; } IoObject *IoObject_protoGetSlot_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("getSlot(slotNameString)", "Returns the value of the slot named slotNameString (following the lookup path) or nil if no such slot is found.") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); return IoObject_getSlot_(self, slotName); } IoObject *IoObject_protoGetLocalSlot_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("getLocalSlot(slotNameString)", "Returns the value of the slot named slotNameString (not looking in the object's protos) or nil if no such slot is found.") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); if (self->ownsSlots) { IoObject *v = PHash_at_(self->slots, slotName); if (v) return v; } return IONIL(self); } IoObject *IoObject_protoHasLocalSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("hasLocalSlot(slotNameString)", "Returns true if the slot exists in the receiver or false otherwise.") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject_createSlotsIfNeeded(self); return IOBOOL(self, PHash_at_(self->slots, slotName) != NULL); } IoObject *IoObject_protoRemoveSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("removeSlot(slotNameString)", "Removes the specified slot (only) in the receiver if it exists. Returns self.") */ IoSymbol *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject_createSlotsIfNeeded(self); PHash_removeKey_(self->slots, slotName); return self; } IoObject *IoObject_protoSlotNames(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("slotNames", "Returns a list of strings containing the names of the slots in the receiver (but not in it's lookup path).") */ IoObject_createSlotsIfNeeded(self); { IoList *slotNames = IoList_new(IOSTATE); IoSymbol *slotName = PHash_firstKey(self->slots); while (slotName) { IoList_rawAppend_(slotNames, slotName); slotName = PHash_nextKey(self->slots); } return slotNames; } } /* docSlot("forward") docDescription("""Called when the receiver is sent a message it doesn't recognize. Default implementation raises an "Object doesNotRespond" exception. Subclasses can override this method to implement proxies or special error handling.""") Example:
 myProxy forward = method(
					 messageName := thisMessage name
					 arguments := thisMessage arguments
					 myObject doMessage(thisMessage)
					 )
 
*/ /* IoObject *IoObject_forward_(IoObject *self, IoObject *locals, IoMessage *m) { IoState_error_(IOSTATE, m, "%s does not respond to message '%s'", IoObject_name(self), CSTRING(IoMessage_name(m))); return IONIL(self); } */ IoObject *IoObject_ancestorWithSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("ancestorWithSlot(slotName)", "Returns the first ancestor of the receiver that contains a slot of the specified name or Nil if none is found.") */ IoObject *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject **proto = self->protos; while (*proto) { IoObject *context = NULL; IoObject *v = IoObject_rawGetSlot_context_((*proto), slotName, &context); if (v) { return context; } proto ++; } return IONIL(self); } IoObject *IoObject_contextWithSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("contextWithSlot(slotName)", "Returns the first context (starting with the receiver and following the lookup path) that contains a slot of the specified name or Nil if none is found.") */ IoObject *slotName = IoMessage_locals_symbolArgAt_(m, locals, 0); IoObject *context = NULL; IoObject_rawGetSlot_context_(self, slotName, &context); return context ? context : IONIL(self); } // --------------------------------------------------------------------------- IoObject *IoObject_rawDoString_label_(IoObject *self, IoSymbol *string, IoSymbol *label) { IoMessage *cm = NULL; IoMessage *messageForString = NULL; IoMessage *newMessage = NULL; IoState *state = IOSTATE; if(!ISSEQ(string)) { IoState_error_(state, NULL, "IoObject_rawDoString_label_ requires a string argument"); } { IoSymbol *internal; IoState_pushCollectorPause(state); internal = IOSYMBOL("[internal]"); cm = IoMessage_newWithName_label_(state, IOSYMBOL("Compiler"), internal); messageForString = IoMessage_newWithName_label_(state, IOSYMBOL("messageForString"), internal); //IoMessage_rawSetAttachedMessage(cm, messageForString); IoMessage_rawSetNext(cm, messageForString); IoMessage_addCachedArg_(messageForString, string); IoMessage_addCachedArg_(messageForString, label); //printf("cm = %p\n", (void *)cm); //printf("messageForString = %p\n", (void *)messageForString); newMessage = IoMessage_locals_performOn_(cm, self, self); IoState_stackRetain_(state, newMessage); // needed? IoState_popCollectorPause(state); //IoMessage *newMessage = IoMessage_newFromText_label_(state, CSTRING(string), CSTRING(label)); if (newMessage) { return IoMessage_locals_performOn_(newMessage, self, self); } IoState_error_(state, NULL, "no message compiled\n"); return IONIL(self); } } IoObject *IoObject_doMessage(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("doMessage(aMessage, optionalContext)", "Evaluates the message object in the context of the receiver. Returns the result. optionalContext can be used to specific the locals context in which the message is evaluated.") */ IoMessage *aMessage = IoMessage_locals_messageArgAt_(m, locals, 0); IoObject *context = self; if (IoMessage_argCount(m) > 1) { context = IoMessage_locals_valueArgAt_(m, locals, 1); } return IoMessage_locals_performOn_(aMessage, context, self); } IoObject *IoObject_doString(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("doString(aString)", "Evaluates the string in the context of the receiver. Returns the result. ") */ IoSymbol *string = IoMessage_locals_seqArgAt_(m, locals, 0); IoSymbol *label; IoObject *result; if (IoMessage_argCount(m) > 1) { label = IoMessage_locals_symbolArgAt_(m, locals, 1); } else { label = IOSYMBOL("doString"); } IoState_pushRetainPool(IOSTATE); result = IoObject_rawDoString_label_(self, string, label); IoState_popRetainPoolExceptFor_(IOSTATE, result); return result; } IoObject *IoObject_doFile(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("doFile(pathString)", "Evaluates the File in the context of the receiver. Returns the result. ") */ IoSymbol *path = IoMessage_locals_symbolArgAt_(m, locals, 0); IoFile *file = IoFile_newWithPath_(IOSTATE, path); IoSymbol *string = (IoSymbol *)IoSeq_rawAsSymbol(IoFile_contents(file, locals, m)); if (IoSeq_rawSize(string)) { IoList *argsList = IoList_new(IOSTATE); int argn = 1; IoObject *arg = IoMessage_locals_valueArgAt_(m, locals, argn); while (arg && !ISNIL(arg)) { IoList_rawAppend_(argsList, arg); argn ++; arg = IoMessage_locals_valueArgAt_(m, locals, argn); } if (IoList_rawSize(argsList)) { IoObject_setSlot_to_(self, IOSYMBOL("args"), argsList); } return IoObject_rawDoString_label_(self, string, path); } return IONIL(self); } IoObject *IoObject_isIdenticalTo(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isIdenticalTo(aValue)", "Returns true if the receiver is identical to aValue, false otherwise. ") */ IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, self == other); } IoObject *IoObject_equals(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("==(aValue)", "Returns true if receiver and aValue are equal, false otherwise. ") */ IOASSERT(IoMessage_argCount(m), "compare requires argument"); { IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, other) == 0); } } IoObject *IoObject_notEquals(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("!=(aValue)", "Returns true the receiver is not equal to aValue, false otherwise. ") */ IoObject *other = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, other) != 0); } IoObject *IoObject_foreachSlot(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("foreach([name,] value, message)", """For each slot, set name to the slot's name and value to the slot's value and execute message. Example:
myObject foreach(n, v, 
				 writeln("slot ", n, " = ", v type)
				 )
myObject foreach(v, 
				 writeln("slot type ", v type)
				 )
""") */ IoSymbol *keyName; IoSymbol *valueName; IoMessage *doMessage; IoObject *key = PHash_firstKey(self->slots); IoObject *result = IONIL(self); IoState_pushRetainPool(IOSTATE); IoMessage_foreachArgs(m, self, &keyName, &valueName, &doMessage); while (key) { IoState_clearTopPool(IOSTATE); { IoObject *value = PHash_at_(self->slots, key); if (keyName) { IoObject_setSlot_to_(locals, keyName, key); } IoObject_setSlot_to_(locals, valueName, value); result = IoMessage_locals_performOn_(doMessage, locals, locals); if (IoState_handleStatus(IOSTATE)) { goto done; } key = PHash_nextKey(self->slots); } } done: IoState_popRetainPoolExceptFor_(IOSTATE, result); return result; } IoObject *IoObject_subtract(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("-(aNumber)", "Returns the negative version of aNumber. Raises an exception if argument is not a number.") */ IoNumber *num = IoMessage_locals_numberArgAt_(m, locals, 0); return IONUMBER(- IoNumber_asDouble(num)); } IoObject *IoObject_self(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("self", "Returns self.") */ return self; } IoObject *IoObject_thisMessage(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("thisMessage", "Returns the calling message.") */ return m; } IoObject *IoObject_locals(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("thisLocalContext", "Returns current locals.") */ return locals; } // message callbacks -------------------------------------- const char *IoObject_name(IoObject *self) { return IoTag_name(self->tag); } int IoObject_compare(IoObject *self, IoObject *v) { if (self == v) { return 0; } if (self->tag->compareFunc) { return (self->tag->compareFunc)(self, v); } return IoObject_defaultCompare(self, v); } int IoObject_defaultCompare(IoObject *self, IoObject *v) { int d = -((ptrdiff_t)self->tag - (ptrdiff_t)v->tag); if (d == 0) { return ((ptrdiff_t)self) - ((ptrdiff_t)v); } return d; } int IoObject_sortCompare(IoObject **self, IoObject **v) { return IoObject_compare(*self, *v); } size_t IoObject_memorySize(IoObject *self) { return (self->tag->memorySizeFunc) ? (self->tag->memorySizeFunc)(self) : 0; } void IoObject_compact(IoObject *self) { if (self->tag->compactFunc) { (self->tag->compactFunc)(self); } } // lobby methods ---------------------------------------------- IoObject *IoObject_memorySizeMethod(IoObject *self, IoObject *locals, IoMessage *m) { /* docSlot("memorySize", "Return the amount of memory used by the object.") */ return IONUMBER(IoObject_memorySize(self)); } IoObject *IoObject_compactMethod(IoObject *self, IoObject *locals, IoMessage *m) { /* docSlot("compact", "Compact the memory for the object if possible. Returns self.") */ IoObject_compact(self); return self; } IoObject *IoObject_type(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("type", "Returns a string containing the name of the type of Object (Number, String, etc).") */ return IOSYMBOL((char *)IoObject_name(self)); } void IoObject_defaultPrint(IoObject *self) { if (ISSYMBOL(self)) { IoSeq_rawPrint(self); } else if (ISNUMBER(self)) { IoNumber_print(self); } else { IoState_print_(IOSTATE, "%s_%p", IoObject_name(self), self); if (ISMESSAGE(self)) { IoState_print_(IOSTATE, " '%s'", CSTRING(IoMessage_name(self))); } } } void IoObject_print(IoObject *self) { IoMessage_locals_performOn_(IOSTATE->printMessage, self, self); // using self as locals hack } IoObject *IoObject_evalArg(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("(expression)", "The '' method evaluates the argument and returns the result.") */ /*#io docSlot("evalArg(expression)", "The '' method evaluates the argument and returns the result.") */ IOASSERT(IoMessage_argCount(m) > 0, "argument required\n"); /* eval the arg and return a non-Nil so an attached else() won't get performed */ return IoMessage_locals_valueArgAt_(m, locals, 0); } IoObject *IoObject_evalArgAndReturnSelf(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("evalArgAndReturnSelf(expression)", "Evaluates the argument and returns the target.") */ IoObject_evalArg(self, locals, m); return self; } IoObject *IoObject_evalArgAndReturnNil(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("evalArgAndReturnNil(expression)", "Evaluates the argument and returns nil.") */ IoObject_evalArg(self, locals, m); return IONIL(self); } IoObject *IoObject_isLessThan_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("<(expression)", "Evaluates argument and returns self if self is less or Nil if not.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, v) < 0); } IoObject *IoObject_isLessThanOrEqualTo_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("<=(expression)", "Evaluates argument and returns self if self is less than or equal to it, or Nil if not.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, v) <= 0); } IoObject *IoObject_isGreaterThan_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot(">(expression)", "Evaluates argument and returns self if self is greater than it, or Nil if not.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, v) > 0); } IoObject *IoObject_isGreaterThanOrEqualTo_(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot(">=(expression)", "Evaluates argument and returns self if self is greater than or equal to it, or Nil if not.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); return IOBOOL(self, IoObject_compare(self, v) >= 0); } IoObject *IoObject_uniqueId(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("uniqueId", "Returns a Number containing a unique id for the receiver.") */ return IONUMBER((double)((size_t)self)); } IoObject *IoObject_do(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("do(expression)", "Evaluates the message in the context of the receiver. Returns self.") */ if (IoMessage_argCount(m) != 0) { IoMessage *argMessage = IoMessage_rawArgAt_(m, 0); IoMessage_locals_performOn_(argMessage, self, self); } return self; } IoObject *IoObject_message(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("message(expression)", "Return the message object for the argument or Nil if there is no argument.") */ return IoMessage_argCount(m) ? IoMessage_rawArgAt_(m, 0) : IONIL(self); } // inline these ------------------------------------------------- int IoObject_hasCloneFunc_(IoObject *self, TagCloneFunc *func) { /* if (ISWAITINGFUTURE(self)) { IoFuture_rawWaitOnResult(self); } */ return (self->tag->cloneFunc == func); } // -------------------------------------------- char *IoObject_markColorName(IoObject *self) { return Collector_colorNameFor_(IOCOLLECTOR, self); } void IoSymbol_println(IoSymbol *self) { printf("%s\n", CSTRING(self)); } void IoObject_show(IoObject *self) { printf(" %p %s\n", (void *)self, IoObject_name(self)); PHash_doOnKeys_(self->slots, (PHashDoCallback *)IoSymbol_println); } IoObject *IoObject_setIsActivatable(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("setIsActivatable(aValue)", "When called with a non-Nil aValue, sets the object to call it's activate slot when accessed as a value. Turns this behavior off if aValue is Nil. Only works on Objects which are not Activatable Primitives (such as CFunction or Block). Returns self.") */ IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); IoObject *objectProto = IoState_protoWithInitFunction_(IOSTATE, (IoStateProtoFunc *)IoObject_proto); objectProto->tag->activateFunc = (TagActivateFunc *)IoObject_activateFunc; self->isActivatable = ISTRUE(v); return self; } IoObject *IoObject_isActivatable(IoObject *self, IoObject *locals, IoMessage *m) { /*#io docSlot("isActivatable", "Returns true if the receiver is activatable, false otherwise.") */ return self->isActivatable ? IOTRUE(self) : IOFALSE(self); } /* IoNumber *IoObject_getNumberSlot(IoObject *self, IoObject *locals, IoMessage *m, IoSymbol *slotName) { IoObject *v = IoObject_getSlot_(self, slotName); IOASSERT(ISNUMBER(v), CSTRING(slotName)); return v; } */ ByteArray *IoObject_rawGetByteArraySlot(IoObject *self, IoObject *locals, IoMessage *m, IoSymbol *slotName) { IoSeq *seq = IoObject_getSlot_(self, slotName); IOASSERT(ISSEQ(seq), CSTRING(slotName)); return IoSeq_rawByteArray(seq); } ByteArray *IoObject_rawGetMutableByteArraySlot(IoObject *self, IoObject *locals, IoMessage *m, IoSymbol *slotName) { IoSeq *seq = IoObject_getSlot_(self, slotName); IOASSERT(ISSEQ(seq), CSTRING(slotName)); return IoSeq_rawByteArray(seq); } IoObject *IoObject_argIsActivationRecord(IoObject *self, IoObject *locals, IoMessage *m) { return IOBOOL(self, PHash_at_(self->slots, IOSTATE->callSymbol) != NULL); } IoObject *IoObject_argIsCall(IoObject *self, IoObject *locals, IoMessage *m) { IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 0); //printf("v->tag->name = '%s'\n", v->tag->name); return IOBOOL(self, ISACTIVATIONCONTEXT(v)); } /* IoObject *IoObject_unpack(IoObject *self, IoObject *locals, IoMessage *m) { const char *const s = IoMessage_locals_cStringArgAt_(m, locals, 0); return IoUnpack_unpack(IOSTATE, s); } */ // free listeners --------------------------------------------- void IoObject_addListener_(IoObject *self, void *listener) { if (self->listeners == NULL) { self->listeners = List_new(); } List_append_(self->listeners, listener); } void IoObject_removeListener_(IoObject *self, void *listener) { if (self->listeners) { List_remove_(self->listeners, listener); if (List_size(self->listeners) == 0) { List_free(self->listeners); self->listeners = NULL; } } }