ctr_object* ctr_string_skip(ctr_object* myself, ctr_argument* argumentList) { ctr_argument* argument1; ctr_argument* argument2; if (myself->value.svalue->vlen < argumentList->object->value.nvalue) return ctr_build_string("",0); argument1 = CTR_CREATE_ARGUMENT(); argument2 = CTR_CREATE_ARGUMENT(); argument1->object = argumentList->object; argument1->next = argument2; argument2->object = ctr_build_number_from_float(myself->value.svalue->vlen - argumentList->object->value.nvalue); return ctr_string_from_length(myself, argument1); }
int ctr_sort_cmp(const void * a, const void * b) { ctr_argument* arg1 = CTR_CREATE_ARGUMENT(); ctr_argument* arg2 = CTR_CREATE_ARGUMENT(); ctr_object* result; ctr_object* numResult; arg1->next = arg2; arg1->object = *((ctr_object**) a); arg2->object = *((ctr_object**) b); result = ctr_block_run(temp_sorter, arg1, temp_sorter); numResult = ctr_internal_cast2number(result); return (int) numResult->value.nvalue; }
/** * ifFalse * * Executes a block of code if the value of the boolean * object is True. * * Usage: * (some expression) ifFalse: {\ ... }. * */ ctr_object* ctr_bool_ifFalse(ctr_object* myself, ctr_argument* argumentList) { if (!myself->value.bvalue) { ctr_object* codeBlock = argumentList->object; ctr_argument* arguments = CTR_CREATE_ARGUMENT(); arguments->object = myself; return ctr_block_run(codeBlock, arguments, codeBlock); } if (CtrStdError == CtrStdNil) CtrStdError = NULL; /* consume break */ return myself; }
/** * CTRMessageSend * * Sends a message to a receiver object. */ ctr_object* ctr_send_message(ctr_object* receiverObject, char* message, long vlen, ctr_argument* argumentList) { char toParent = 0; ctr_object* me; ctr_object* methodObject; ctr_object* searchObject; ctr_argument* argCounter; ctr_argument* mesgArgument; ctr_object* result; ctr_object* (*funct)(ctr_object* receiverObject, ctr_argument* argumentList); int argCount; if (CtrStdError != NULL) return NULL; /* Error mode, ignore subsequent messages until resolved. */ methodObject = NULL; searchObject = receiverObject; if (vlen > 1 && message[0] == '`') { me = ctr_internal_object_find_property(ctr_contexts[ctr_context_id], ctr_build_string_from_cstring("me\0"), 0); if (searchObject == me) { toParent = 1; message = message + 1; vlen--; } } while(!methodObject) { methodObject = ctr_internal_object_find_property(searchObject, ctr_build_string(message, vlen), 1); if (methodObject && toParent) { toParent = 0; methodObject = NULL; } if (methodObject) break; if (!searchObject->link) break; searchObject = searchObject->link; } if (!methodObject) { argCounter = argumentList; argCount = 0; while(argCounter->next && argCount < 4) { argCounter = argCounter->next; argCount ++; } mesgArgument = CTR_CREATE_ARGUMENT(); mesgArgument->object = ctr_build_string(message, vlen); mesgArgument->next = argumentList; if (argCount == 0 || argCount > 2) { return ctr_send_message(receiverObject, "respondTo:", 10, mesgArgument); } else if (argCount == 1) { return ctr_send_message(receiverObject, "respondTo:with:", 15, mesgArgument); } else if (argCount == 2) { return ctr_send_message(receiverObject, "respondTo:with:and:", 19, mesgArgument); } } if (methodObject->info.type == CTR_OBJECT_TYPE_OTNATFUNC) { funct = methodObject->value.fvalue; result = funct(receiverObject, argumentList); } if (methodObject->info.type == CTR_OBJECT_TYPE_OTBLOCK) { result = ctr_block_run(methodObject, argumentList, receiverObject); } return result; }
/** * [Array] from: [Begin] to: [End] * * Copies part of an array indicated by from and to and * returns a new array consisting of a copy of this region. */ ctr_object* ctr_array_from_to(ctr_object* myself, ctr_argument* argumentList) { ctr_argument* pushArg; ctr_argument* elnumArg; ctr_object* elnum; ctr_object* startElement = ctr_internal_cast2number(argumentList->object); ctr_object* count = ctr_internal_cast2number(argumentList->next->object); int start = (int) startElement->value.nvalue; int len = (int) count->value.nvalue; int i = 0; ctr_object* newArray = ctr_array_new(CtrStdArray, NULL); for(i = start; i < start + len; i++) { pushArg = CTR_CREATE_ARGUMENT(); elnumArg = CTR_CREATE_ARGUMENT(); elnum = ctr_build_number_from_float((ctr_number) i); elnumArg->object = elnum; pushArg->object = ctr_array_get(myself, elnumArg); ctr_array_push(newArray, pushArg); } return newArray; }
/** * [Array] map: [Block]. * * Iterates over the array. Passing each element as a key-value pair to the * specified block. * * Usage: * * files map: showName. * files map: { key filename | Pen write: filename, brk. }. */ ctr_object* ctr_array_map(ctr_object* myself, ctr_argument* argumentList) { ctr_object* block = argumentList->object; int i = 0; if (block->info.type != CTR_OBJECT_TYPE_OTBLOCK) { CtrStdError = ctr_build_string_from_cstring("Expected Block.\0"); } block->info.sticky = 1; for(i = 0; i < myself->value.avalue->head; i++) { ctr_argument* arguments = CTR_CREATE_ARGUMENT(); ctr_argument* argument2 = CTR_CREATE_ARGUMENT(); arguments->object = ctr_build_number_from_float((double) i); argument2->object = *(myself->value.avalue->elements + i); arguments->next = argument2; ctr_block_run(block, arguments, myself); if (CtrStdError == CtrStdContinue) CtrStdError = NULL; if (CtrStdError) break; } if (CtrStdError == CtrStdBreak) CtrStdError = NULL; /* consume break */ block->info.mark = 0; block->info.sticky = 0; return myself; }
/** * [Map] each: [Block] * * Iterates over the map, passing key-value pairs to the specified block. */ ctr_object* ctr_map_each(ctr_object* myself, ctr_argument* argumentList) { ctr_object* block = argumentList->object; ctr_mapitem* m; if (block->info.type != CTR_OBJECT_TYPE_OTBLOCK) { CtrStdError = ctr_build_string_from_cstring("Expected Block.\0"); } block->info.sticky = 1; m = myself->properties->head; while(m && !CtrStdError) { ctr_argument* arguments = CTR_CREATE_ARGUMENT(); ctr_argument* argument2 = CTR_CREATE_ARGUMENT(); arguments->object = m->key; argument2->object = m->value; arguments->next = argument2; ctr_block_run(block, arguments, myself); if (CtrStdError == CtrStdContinue) CtrStdError = NULL; m = m->next; } if (CtrStdError == CtrStdBreak) CtrStdError = NULL; block->info.mark = 0; block->info.sticky = 0; return myself; }
/** * [Array] + [Array] * * Returns a new array, containing elements of itself and the other * array. */ ctr_object* ctr_array_add(ctr_object* myself, ctr_argument* argumentList) { ctr_object* otherArray = argumentList->object; ctr_object* newArray = ctr_array_new(CtrStdArray, NULL); int i; for(i = myself->value.avalue->tail; i<myself->value.avalue->head; i++) { ctr_argument* pushArg = CTR_CREATE_ARGUMENT(); ctr_argument* elnumArg = CTR_CREATE_ARGUMENT(); ctr_object* elnum = ctr_build_number_from_float((ctr_number) i); elnumArg->object = elnum; pushArg->object = ctr_array_get(myself, elnumArg); ctr_array_push(newArray, pushArg); } if (otherArray->info.type == CTR_OBJECT_TYPE_OTARRAY) { for(i = otherArray->value.avalue->tail; i<otherArray->value.avalue->head; i++) { ctr_argument* pushArg = CTR_CREATE_ARGUMENT(); ctr_argument* elnumArg = CTR_CREATE_ARGUMENT(); ctr_object* elnum = ctr_build_number_from_float((ctr_number) i); elnumArg->object = elnum; pushArg->object = ctr_array_get(otherArray, elnumArg); ctr_array_push(newArray, pushArg); } } return newArray; }
ctr_object* ctr_number_add(ctr_object* myself, ctr_argument* argumentList) { ctr_argument* newArg; ctr_object* otherNum = argumentList->object; ctr_number a; ctr_number b; ctr_object* strObject; if (otherNum->info.type == CTR_OBJECT_TYPE_OTSTRING) { strObject = ctr_internal_create_object(CTR_OBJECT_TYPE_OTSTRING); strObject = ctr_internal_cast2string(myself); newArg = CTR_CREATE_ARGUMENT(); newArg->object = otherNum; return ctr_string_concat(strObject, newArg); } a = myself->value.nvalue; b = otherNum->value.nvalue; return ctr_build_number_from_float((a+b)); }
/** * BlockRun * * Runs a block of code. */ ctr_object* ctr_block_run(ctr_object* myself, ctr_argument* argList, ctr_object* my) { ctr_object* result; ctr_tnode* node = myself->value.block; ctr_tlistitem* codeBlockParts = node->nodes; ctr_tnode* codeBlockPart1 = codeBlockParts->node; ctr_tnode* codeBlockPart2 = codeBlockParts->next->node; ctr_tlistitem* parameterList = codeBlockPart1->nodes; ctr_tnode* parameter; ctr_object* a; ctr_open_context(); if (parameterList && parameterList->node) { parameter = parameterList->node; while(1) { if (parameter && argList->object) { a = argList->object; ctr_assign_value_to_local(ctr_build_string(parameter->value, parameter->vlen), a); } if (!argList->next) break; argList = argList->next; if (!parameterList->next) break; parameterList = parameterList->next; parameter = parameterList->node; } } ctr_assign_value_to_local(ctr_build_string("me",2), my); ctr_assign_value_to_local(ctr_build_string("thisBlock",9), myself); /* otherwise running block may get gc'ed. */ result = ctr_cwlk_run(codeBlockPart2); if (result == NULL) result = my; ctr_close_context(); if (CtrStdError != NULL && CtrStdError != CtrStdNil) { ctr_object* catchBlock = malloc(sizeof(ctr_object)); catchBlock = ctr_internal_object_find_property(myself, ctr_build_string("catch",5), 0); if (catchBlock != NULL) { ctr_argument* a = CTR_CREATE_ARGUMENT(); a->object = CtrStdError; CtrStdError = NULL; ctr_block_run(catchBlock, a, my); result = myself; } } return result; }
/** * BlockTimes * * Runs the specified code block N times. * * Usage: * { ... } * 7. */ ctr_object* ctr_block_times(ctr_object* myself, ctr_argument* argumentList) { ctr_object* indexNumber; ctr_object* block = myself; ctr_argument* arguments; int t; int i; if (block->info.type != CTR_OBJECT_TYPE_OTBLOCK) { printf("Expected code block."); exit(1); } block->info.sticky = 1; t = ctr_internal_cast2number(argumentList->object)->value.nvalue; for(i=0; i<t; i++) { indexNumber = ctr_build_number_from_float((ctr_number) i); arguments = CTR_CREATE_ARGUMENT(); arguments->object = indexNumber; ctr_block_run(block, arguments, block); if (CtrStdError) break; } if (CtrStdError == CtrStdNil) CtrStdError = NULL; /* consume break */ block->info.mark = 0; block->info.sticky = 0; return myself; }
/** * @internal * * Shell Object uses a fluid API. */ ctr_object* ctr_shell_respond_to_with(ctr_object* myself, ctr_argument* argumentList) { ctr_object* commandObj; ctr_object* prefix; ctr_object* suffix; ctr_argument* newArgumentList; char* command; int len; prefix = ctr_internal_cast2string(argumentList->object); suffix = ctr_internal_cast2string(argumentList->next->object); len = prefix->value.svalue->vlen + suffix->value.svalue->vlen; if (len == 0) return myself; command = (char*) malloc(len); /* actually we need +1 for the space between commands, but we dont because we remove the colon : !*/ strncpy(command, prefix->value.svalue->value, prefix->value.svalue->vlen - 1); /* remove colon, gives room for space */ strncpy(command + (prefix->value.svalue->vlen - 1), " ", 1); /* space to separate commands */ strncpy(command + (prefix->value.svalue->vlen), suffix->value.svalue->value, suffix->value.svalue->vlen); commandObj = ctr_build_string(command, len); newArgumentList = CTR_CREATE_ARGUMENT(); newArgumentList->object = commandObj; ctr_shell_call(myself, newArgumentList); return myself; }
ctr_object* ctr_number_to_by_do(ctr_object* myself, ctr_argument* argumentList) { double startValue = myself->value.nvalue; double endValue = ctr_internal_cast2number(argumentList->object)->value.nvalue; double incValue = ctr_internal_cast2number(argumentList->next->object)->value.nvalue; double curValue = startValue; ctr_object* codeBlock = argumentList->next->next->object; ctr_argument* arguments; int forward = 0; if (startValue == endValue) return myself; forward = (startValue < endValue); if (codeBlock->info.type != CTR_OBJECT_TYPE_OTBLOCK) { CtrStdError = ctr_build_string_from_cstring("Expected block.\0"); return myself; } while(((forward && curValue <= endValue) || (!forward && curValue >= endValue)) && !CtrStdError) { arguments = CTR_CREATE_ARGUMENT(); arguments->object = ctr_build_number_from_float(curValue); ctr_block_run(codeBlock, arguments, codeBlock); curValue += incValue; } if (CtrStdError == CtrStdNil) CtrStdError = NULL; /* consume break */ return myself; }
/** * [Array] put: [Element] at: [Index] * * Puts a value in the array at the specified index. * Array will be automatically expanded if the index is higher than * the maximum index of the array. * * Usage: * * fruits := Array new. * fruits put: 'apples' at: 5. */ ctr_object* ctr_array_put(ctr_object* myself, ctr_argument* argumentList) { ctr_object* putValue = argumentList->object; ctr_object* putIndex = ctr_internal_cast2number(argumentList->next->object); ctr_size putIndexNumber; ctr_size head; ctr_size tail; if (putIndex->value.nvalue < 0) { CtrStdError = ctr_build_string_from_cstring("Index out of bounds.\0"); return myself; } head = (ctr_size) myself->value.avalue->head; tail = (ctr_size) myself->value.avalue->tail; putIndexNumber = (ctr_size) putIndex->value.nvalue; if (head <= putIndexNumber) { ctr_size j; for(j = head; j <= putIndexNumber; j++) { ctr_argument* argument; argument = CTR_CREATE_ARGUMENT(); argument->object = CtrStdNil; ctr_array_push(myself, argument); } myself->value.avalue->head = putIndexNumber + 1; } if (putIndexNumber < tail) { ctr_size j; for(j = tail; j > putIndexNumber; j--) { *(myself->value.avalue->elements + j) = CtrStdNil; } myself->value.avalue->tail = putIndexNumber; } *(myself->value.avalue->elements + putIndexNumber) = putValue; return myself; }