/*#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;
}
}
}