New doc system done for core
[io.git] / libs / iovm / source / IoBlock.c
blob6dac55b057934f9d61ed55a142b3fdd7906e2450
1 //metadoc Block copyright Steve Dekorte 2002
2 //metadoc Block license BSD revised
3 /*metadoc Block description
4 Blocks are anonymous functions (messages with their own locals object).
5 They are typically used to represent object methods.
6 */
7 //metadoc Block category Core
9 #include "IoBlock.h"
10 #include "IoMessage.h"
11 #include "IoMessage_parser.h"
12 #include "IoCFunction.h"
13 #include "IoSeq.h"
14 #include "IoNumber.h"
15 #include "IoList.h"
16 #include "UArray.h"
18 #define DATA(self) ((IoBlockData *)IoObject_dataPointer(self))
20 IoTag *IoBlock_newTag(void *state)
22 IoTag *tag = IoTag_newWithName_("Block");
23 IoTag_state_(tag, state);
24 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoBlock_rawClone);
25 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoBlock_mark);
26 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoBlock_free);
27 IoTag_activateFunc_(tag, (IoTagActivateFunc *)IoBlock_activate);
28 IoTag_writeToStreamFunc_(tag, (IoTagWriteToStreamFunc *)IoBlock_writeToStream_);
29 IoTag_readFromStreamFunc_(tag, (IoTagReadFromStreamFunc *)IoBlock_readFromStream_);
30 return tag;
33 void IoBlock_copy_(IoBlock *self, IoBlock *other)
35 DATA(self)->message = IOREF(DATA(other)->message);
38 List *l1 = DATA(self)->argNames;
39 List_removeAll(l1);
40 LIST_FOREACH(DATA(other)->argNames, i, v, List_append_(l1, IOREF(v)); );
43 if (DATA(other)->scope)
45 IOREF(DATA(other)->scope);
48 DATA(self)->scope = DATA(other)->scope;
51 void IoBlock_writeToStream_(IoBlock *self, BStream *stream)
53 UArray *ba = IoBlock_justCode(self);
54 BStream_writeTaggedUArray_(stream, ba);
55 //printf("write block '%s'\n", UArray_asCString(ba));
56 UArray_free(ba);
58 if (DATA(self)->scope)
60 BStream_writeTaggedInt32_(stream, IoObject_pid(DATA(self)->scope));
62 else
64 BStream_writeTaggedInt32_(stream, 0);
68 void IoBlock_readFromStream_(IoBlock *self, BStream *stream)
70 IoBlock *newBlock = NULL;
71 UArray *ba = BStream_readTaggedUArray(stream);
73 //printf("read block [[[%s]]]]\n", UArray_asCString(ba));
74 newBlock = IoState_on_doCString_withLabel_(IOSTATE, IoState_lobby(IOSTATE), UArray_asCString(ba), "Block readFromStore");
76 if (!newBlock || !ISBLOCK(newBlock))
78 IoState_error_(IOSTATE, NULL, "Store found bad block code: %s", (char *)UArray_bytes(ba));
81 IoBlock_copy_(self, newBlock);
84 PID_TYPE pid = BStream_readTaggedInt32(stream);
86 if (pid)
88 DATA(self)->scope = IoState_objectWithPid_(IOSTATE, pid);
90 else
92 DATA(self)->scope = NULL;
97 IoBlock *IoBlock_proto(void *vState)
99 IoState *state = (IoState *)vState;
100 IoMethodTable methodTable[] = {
101 {"print", IoBlock_print},
102 {"code", IoBlock_code},
103 {"message", IoBlock_message},
104 {"setMessage", IoBlock_setMessage},
105 {"argumentNames", IoBlock_argumentNames},
106 {"setArgumentNames", IoBlock_argumentNames_},
107 {"setScope", IoBlock_setScope_},
108 {"scope", IoBlock_scope},
109 {"performOn", IoBlock_performOn},
110 {"call", IoBlock_call},
111 {"setPassStops", IoBlock_setPassStops_},
112 {"passStops", IoBlock_passStops},
113 {NULL, NULL},
116 IoObject *self = IoObject_new(state);
118 IoObject_setDataPointer_(self, io_calloc(1, sizeof(IoBlockData)));
119 IoObject_tag_(self, IoBlock_newTag(state));
120 DATA(self)->message = IOSTATE->nilMessage;
121 DATA(self)->argNames = List_new();
122 DATA(self)->scope = NULL;
123 IoState_registerProtoWithFunc_((IoState *)state, self, IoBlock_proto);
125 IoObject_addMethodTable_(self, methodTable);
126 return self;
129 IoBlock *IoBlock_rawClone(IoBlock *proto)
131 IoBlockData *protoData = DATA(proto);
132 IoObject *self = IoObject_rawClonePrimitive(proto);
133 IoObject_setDataPointer_(self, io_calloc(1, sizeof(IoBlockData)));
134 IoObject_tag_(self, IoObject_tag(proto));
135 DATA(self)->message = IoMessage_deepCopyOf_(protoData->message);
136 DATA(self)->argNames = List_clone(protoData->argNames);
137 DATA(self)->scope = protoData->scope;
138 IoObject_isActivatable_(self, IoObject_isActivatable(proto));
139 DATA(self)->passStops = DATA(proto)->passStops;
140 return self;
143 IoBlock *IoBlock_new(IoState *state)
145 IoObject *proto = IoState_protoWithInitFunction_((IoState *)state, IoBlock_proto);
146 return IOCLONE(proto);
149 void IoBlock_rawPrint(IoBlock *self)
151 UArray *ba = IoBlock_justCode(self);
152 printf("%s\n", (char *)UArray_bytes(ba));
155 void IoBlock_mark(IoBlock *self)
157 IoBlockData *bd = DATA(self);
158 IoObject_shouldMark(bd->message);
159 IoObject_shouldMarkIfNonNull(bd->scope);
160 LIST_DO_(bd->argNames, IoObject_shouldMark);
163 void IoBlock_free(IoBlock *self)
165 List_free(DATA(self)->argNames);;
166 io_free(IoObject_dataPointer(self));
169 void IoBlock_message_(IoBlock *self, IoMessage *m)
171 DATA(self)->message = IOREF(m);
174 // calling --------------------------------------------------------
176 IoObject *IoBlock_activate(IoBlock *self, IoObject *target, IoObject *locals, IoMessage *m, IoObject *slotContext)
178 IoState *state = IOSTATE;
179 intptr_t poolMark; // = IoState_pushRetainPool(state);
181 IoBlockData *selfData = DATA(self);
182 List *argNames = selfData->argNames;
183 IoObject *scope = selfData->scope;
185 IoObject *blockLocals = IOCLONE(state->localsProto);
186 IoObject *result;
187 IoObject *callObject;
189 IoObject_isLocals_(blockLocals, 1);
191 if (!scope)
193 scope = target;
196 IoObject_createSlotsIfNeeded(blockLocals);
198 callObject = IoCall_with(state,
199 locals,
200 target,
202 slotContext,
203 self,
204 state->currentCoroutine);
207 PHash *bslots = IoObject_slots(blockLocals);
208 PHash_at_put_(bslots, state->callSymbol, callObject);
209 PHash_at_put_(bslots, state->selfSymbol, scope);
210 PHash_at_put_(bslots, state->updateSlotSymbol, state->localsUpdateSlotCFunc);
213 IoObject_isReferenced_(blockLocals, 0);
214 IoObject_isReferenced_(callObject, 0);
216 tailCall:
217 poolMark = IoState_pushRetainPool(state);
219 LIST_FOREACH(argNames, i, name,
220 IoObject *arg = IoMessage_locals_valueArgAt_(m, locals, i);
221 // gc may kick in while evaling locals, so we need to be safe
222 IoObject_setSlot_to_(blockLocals, name, arg);
225 if (Coro_stackSpaceAlmostGone(IoCoroutine_cid(state->currentCoroutine)))
228 IoCoroutine *currentCoroutine = state->currentCoroutine;
229 Coro *coro = IoCoroutine_cid(currentCoroutine);
231 printf("%p-%p block overflow %i/%i\n",
232 (void *)currentCoroutine, (void *)coro, Coro_bytesLeftOnStack(coro), Coro_stackSize(coro));
233 printf("message = %s\n", CSTRING(IoMessage_name(selfData->message)));
236 IoCoroutine *newCoro = IoCoroutine_new(state);
237 IoCoroutine_try(newCoro, blockLocals, blockLocals, selfData->message);
238 result = IoCoroutine_rawResult(newCoro);
241 else
243 result = IoMessage_locals_performOn_(selfData->message, blockLocals, blockLocals);
246 if (DATA(self)->passStops == 0)
248 state->returnValue = result;
249 state->stopStatus = IoCall_rawStopStatus(callObject);
252 IoState_popRetainPool_(state, poolMark);
255 if(IOSTATE->tailCallMessage)
257 m = IOSTATE->tailCallMessage;
258 IOSTATE->tailCallMessage = NULL;
259 locals = blockLocals;
260 goto tailCall;
264 IoState_stackRetain_(state, result);
266 #ifdef IO_BLOCK_LOCALS_RECYCLING
267 #ifndef STACK_POP_CALLBACK
268 if(!IoObject_isReferenced(blockLocals) && !IoObject_isReferenced(callObject))
270 CollectorMarker_remove((CollectorMarker *)blockLocals);
271 IoObject_free(blockLocals);
273 CollectorMarker_remove((CollectorMarker *)callObject);
274 IoObject_free(callObject);
275 //IoObject_freeIfUnreferenced(blockLocals);
276 //IoObject_freeIfUnreferenced(callObject);
278 else
279 #endif
281 // since the callObject doesn't IOREF it's blockLocals pointer
282 if (IoObject_isReferenced(callObject))
284 IoObject_isReferenced_(blockLocals, 1);
287 #endif
288 return result;
291 // ------------------------------------------------------------------------
293 IoObject *IoBlock_method(IoObject *target, IoObject *locals, IoMessage *m)
295 IoBlock *const self = IoBlock_new(IoObject_state(target));
296 const int nargs = IoMessage_argCount(m);
297 IoMessage *const message = (nargs > 0) ? IoMessage_rawArgAt_(m, nargs - 1) : IOSTATE->nilMessage;
298 int i;
300 DATA(self)->message = IOREF(message);
301 IoObject_isActivatable_(self, 1);
303 for (i = 0; i < nargs - 1; i ++)
305 IoMessage *argMessage = IoMessage_rawArgAt_(m, i);
306 IoSymbol *name = IoMessage_name(argMessage);
307 List_append_(DATA(self)->argNames, IOREF(name));
310 return self;
313 IoObject *IoObject_block(IoObject *target, IoObject *locals, IoMessage *m)
315 IoBlock *self = (IoBlock *)IoBlock_method(target, locals, m);
316 DATA(self)->scope = IOREF(locals);
317 IoObject_isActivatable_(self, 0);
318 return self;
321 IoObject *IoBlock_print(IoBlock *self, IoObject *locals, IoMessage *m)
323 /*doc Block print
324 prints an Io source code representation of the block/method
327 UArray *ba = IoBlock_justCode(self);
328 IoState_print_(IOSTATE, UArray_asCString(ba));
329 return IONIL(self);
332 UArray *IoBlock_justCode(IoBlock *self)
334 UArray *ba = UArray_new();
336 if (DATA(self)->scope)
338 UArray_appendCString_(ba, "block(");
340 else
342 UArray_appendCString_(ba, "method(");
345 LIST_FOREACH(DATA(self)->argNames, i, argName,
346 UArray_append_(ba, IoSeq_rawUArray((IoSymbol *)argName));
347 UArray_appendCString_(ba, ", ");
351 UArray *d = IoMessage_description(DATA(self)->message);
352 UArray_append_(ba, d);
353 UArray_free(d);
356 UArray_appendCString_(ba, ")");
357 return ba;
360 IoObject *IoBlock_code(IoBlock *self, IoObject *locals, IoMessage *m)
362 /*doc Block code
363 Returns a string containing the decompiled code of the receiver.
366 return IoState_symbolWithUArray_copy_(IOSTATE, IoBlock_justCode(self), 0);
369 IoObject *IoBlock_code_(IoBlock *self, IoObject *locals, IoMessage *m)
371 /*doc Block setCode(aString)
372 Set's the reciever's message to a compiled version of aString. Returns self
375 IoSymbol *string = IoMessage_locals_symbolArgAt_(m, locals, 0);
376 char *s = CSTRING(string);
377 IoMessage *newM = IoMessage_newFromText_label_(IOSTATE, s, "[IoBlock_code_]");
379 if (newM)
381 DATA(self)->message = IOREF(newM);
383 else
385 IoState_error_(IOSTATE, m, "no messages found in compile string");
388 return self;
391 IoObject *IoBlock_message(IoBlock *self, IoObject *locals, IoMessage *m)
393 /*doc Block message
394 Returns the root message of the receiver.
397 return DATA(self)->message ? (IoObject *)DATA(self)->message : IONIL(self);
400 IoObject *IoBlock_setMessage(IoBlock *self, IoObject *locals, IoMessage *m)
402 /*doc Block setMessage(aMessage)
403 Sets the root message of the receiver to aMessage.
406 IoMessage *message = IoMessage_locals_messageArgAt_(m, locals, 0);
407 DATA(self)->message = IOREF(message);
408 return self;
411 IoObject *IoBlock_argumentNames(IoBlock *self, IoObject *locals, IoMessage *m)
413 /*doc Block argumentNames
414 Returns a List of strings containing the argument names of the receiver.
417 IoList *argsList = IoList_new(IOSTATE);
419 LIST_FOREACH(DATA(self)->argNames, i, v, IoList_rawAppend_(argsList, (IoObject *)v));
421 return argsList;
424 IoObject *IoBlock_argumentNames_(IoBlock *self, IoObject *locals, IoMessage *m)
426 /*doc Block setArgumentNames(aListOfStrings)
427 Sets the receiver's argument names to those specified in
428 aListOfStrings. Returns self.
431 IoList *newArgNames = IoMessage_locals_listArgAt_(m, locals, 0);
432 List *rawNewArgNames = IoList_rawList(newArgNames);
434 LIST_FOREACH(rawNewArgNames, i, v,
435 IOASSERT(ISSYMBOL(((IoObject *)v)), "argument names must be Strings");
438 List_copy_(DATA(self)->argNames, IoList_rawList(newArgNames));
439 return self;
442 IoObject *IoBlock_scope(IoBlock *self, IoObject *locals, IoMessage *m)
444 /*doc Block scope
445 Returns the scope used when the block is activated or
446 Nil if the target of the message is the scope.
449 IoObject *scope = DATA(self)->scope;
450 return scope ? scope : IONIL(self);
453 IoObject *IoBlock_setScope_(IoBlock *self, IoObject *locals, IoMessage *m)
455 /*doc Block setScope(anObjectOrNil)
456 If argument is an object, when the block is activated,
457 it will set the proto and self slots of it's locals to the specified
458 object. If Nil, it will set them to the target of the message.
461 IoObject *scope = IoMessage_locals_valueArgAt_(m, locals, 0);
462 DATA(self)->scope = ISNIL(scope) ? NULL : IOREF(scope);
463 return self;
466 IoObject *IoBlock_passStops(IoBlock *self, IoObject *locals, IoMessage *m)
468 /*doc Block passStops
469 Returns whether or not the receiver passes return/continue/break to caller.
472 return IOBOOL(self, DATA(self)->passStops);
475 IoObject *IoBlock_setPassStops_(IoBlock *self, IoObject *locals, IoMessage *m)
477 /*doc Block setPassStops(aBool)
478 Sets whether the receiver passes return/continue/break to caller.
481 DATA(self)->passStops = ISTRUE(IoMessage_locals_valueArgAt_(m, locals, 0));
482 return self;
485 IoObject *IoBlock_performOn(IoBlock *self, IoObject *locals, IoMessage *m)
487 /*doc Block performOn(anObject, optionalLocals, optionalMessage, optionalSlotContext)
488 Activates the receiver in the target context of anObject.
489 Returns the result.
492 IoObject *bTarget = IoMessage_locals_valueArgAt_(m, locals, 0);
493 IoObject *bLocals = locals;
494 IoObject *bMessage = m;
495 IoObject *bContext = bTarget;
496 int argCount = IoMessage_argCount(m);
498 if (argCount > 1)
500 bLocals = IoMessage_locals_valueArgAt_(m, locals, 1);
503 if (argCount > 2)
505 bMessage = IoMessage_locals_valueArgAt_(m, locals, 2);
508 if (argCount > 3)
510 bContext = IoMessage_locals_valueArgAt_(m, locals, 3);
513 return IoBlock_activate(self, bTarget, bLocals, bMessage, bContext);
516 IoObject *IoBlock_call(IoBlock *self, IoObject *locals, IoMessage *m)
518 /*doc Block call(arg0, arg1, ...)
519 Activates the receiver with the provided arguments.
522 return IoBlock_activate(self, locals, locals, m, locals);