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.
7 //metadoc Block category Core
10 #include "IoMessage.h"
11 #include "IoMessage_parser.h"
12 #include "IoCFunction.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_
);
33 void IoBlock_copy_(IoBlock
*self
, IoBlock
*other
)
35 DATA(self
)->message
= IOREF(DATA(other
)->message
);
38 List
*l1
= DATA(self
)->argNames
;
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));
58 if (DATA(self
)->scope
)
60 BStream_writeTaggedInt32_(stream
, IoObject_pid(DATA(self
)->scope
));
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
);
88 DATA(self
)->scope
= IoState_objectWithPid_(IOSTATE
, pid
);
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
},
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
);
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
;
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
);
187 IoObject
*callObject
;
189 IoObject_isLocals_(blockLocals
, 1);
196 IoObject_createSlotsIfNeeded(blockLocals
);
198 callObject
= IoCall_with(state
,
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);
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
);
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;
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);
281 // since the callObject doesn't IOREF it's blockLocals pointer
282 if (IoObject_isReferenced(callObject
))
284 IoObject_isReferenced_(blockLocals
, 1);
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
;
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
));
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);
321 IoObject
*IoBlock_print(IoBlock
*self
, IoObject
*locals
, IoMessage
*m
)
324 prints an Io source code representation of the block/method
327 UArray
*ba
= IoBlock_justCode(self
);
328 IoState_print_(IOSTATE
, UArray_asCString(ba
));
332 UArray
*IoBlock_justCode(IoBlock
*self
)
334 UArray
*ba
= UArray_new();
336 if (DATA(self
)->scope
)
338 UArray_appendCString_(ba
, "block(");
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
);
356 UArray_appendCString_(ba
, ")");
360 IoObject
*IoBlock_code(IoBlock
*self
, IoObject
*locals
, IoMessage
*m
)
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_]");
381 DATA(self
)->message
= IOREF(newM
);
385 IoState_error_(IOSTATE
, m
, "no messages found in compile string");
391 IoObject
*IoBlock_message(IoBlock
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
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
));
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
));
442 IoObject
*IoBlock_scope(IoBlock
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
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));
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.
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
);
500 bLocals
= IoMessage_locals_valueArgAt_(m
, locals
, 1);
505 bMessage
= IoMessage_locals_valueArgAt_(m
, locals
, 2);
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
);