/** * [List] + [List] * * Returns a new list, containing elements of itself and the other * list. * * In other languages: * Dutch: [Reeks] + [Reeks] | Geeft de reeks die bestaat uit de samenvoeging van gegeven reeksen. */ 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_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* elnumArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_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); ctr_heap_free( elnumArg ); ctr_heap_free( 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_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* elnumArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_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); ctr_heap_free( elnumArg ); ctr_heap_free( pushArg ); } } return newArray; }
ctr_object* ctr_json_create_object(json_t* root, ctr_object* gt) { switch(json_typeof(root)) { case JSON_OBJECT: { ctr_object* sub = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); ctr_set_link_all(sub, gt); // size_t size; const char *key; json_t *value; ctr_argument* argl = ctr_heap_allocate(sizeof(*argl)); argl->next = ctr_heap_allocate(sizeof(*argl)); // size = json_object_size(root); json_object_foreach(root, key, value) { char* k = (char*)key; ctr_object* ko = ctr_build_string_from_cstring(k); ctr_object* vo = ctr_json_create_object(value, gt); argl->object = vo; argl->next->object = ko; sub = ctr_map_put(sub, argl); } ctr_heap_free(argl->next); ctr_heap_free(argl); return sub; } case JSON_ARRAY: { ctr_object* arr = ctr_array_new(CtrStdArray, NULL); ctr_argument* arg = ctr_heap_allocate(sizeof(ctr_argument)); size_t i; size_t size = json_array_size(root); for (i = 0; i < size; i++) { arg->object = ctr_json_create_object(json_array_get(root, i), gt); ctr_array_push(arr, arg); } ctr_heap_free(arg); return arr; } case JSON_STRING: { ctr_object* str = ctr_build_string((char*)json_string_value(root), json_string_length(root)); return str; } case JSON_INTEGER: { return ctr_build_number_from_float(json_integer_value(root)); } case JSON_REAL: { return ctr_build_number_from_float(json_real_value(root)); } case JSON_FALSE: { return ctr_build_bool(0); } case JSON_TRUE: { return ctr_build_bool(1); } case JSON_NULL: { return ctr_build_nil(); } default: { CtrStdFlow = ctr_build_string_from_cstring("Unrecognized JSON type"); return CtrStdNil; } }
/** * StringLastIndexOf * * Returns the index (character number, not the byte!) of the * needle in the haystack. * * Usage: * 'find the needle' lastIndexOf: 'needle'. #9 */ ctr_object* ctr_string_last_index_of(ctr_object* myself, ctr_argument* argumentList) { ctr_object* sub = ctr_internal_cast2string(argumentList->object); long hlen = myself->value.svalue->vlen; long nlen = sub->value.svalue->vlen; ctr_size uchar_index; ctr_size byte_index; char* p = ctr_internal_memmem(myself->value.svalue->value, hlen, sub->value.svalue->value, nlen, 1); if (p == NULL) return ctr_build_number_from_float((float)-1); byte_index = (ctr_size) ( (uintptr_t) p - (uintptr_t) (myself->value.svalue->value) ); uchar_index = ctr_getutf8len(myself->value.svalue->value, byte_index); return ctr_build_number_from_float((float) uchar_index); }
/** * InternalNumberCast * * Casts an object to a number object. */ ctr_object* ctr_internal_cast2number(ctr_object* o) { if (o->info.type == CTR_OBJECT_TYPE_OTNUMBER) return o; if (o->info.type == CTR_OBJECT_TYPE_OTSTRING) { return ctr_build_number_from_string(o->value.svalue->value, o->value.svalue->vlen); } return ctr_build_number_from_float((ctr_number)0); }
/** * [List] map: [Block]. * * Iterates over the array. Passing each element as a key-value pair to the * specified block. * The map message will pass the following arguments to the block, the key, * the value and a reference to the array itself. The last argument might seem * redundant but allows for a more functional programming style. Instead of map, * you can also use each:. * * Usage: * * files map: showName. * files map: { * :key :filename :files * ✎ write: filename. * }. * * files each: { * :key :filename :files * ✎ write: filename. * }. * * In other languages: * Dutch: [Reeks] lijst: [Codeblok] | Maakt van een reeks */ 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) { CtrStdFlow = ctr_build_string_from_cstring( CTR_ERR_EXP_BLK ); CtrStdFlow->info.sticky = 1; } for(i = myself->value.avalue->tail; i < myself->value.avalue->head; i++) { ctr_argument* arguments = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* argument2 = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* argument3 = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); arguments->object = ctr_build_number_from_float((double) i); argument2->object = *(myself->value.avalue->elements + i); argument3->object = myself; arguments->next = argument2; argument2->next = argument3; /* keep receiver in block object otherwise, GC will destroy it */ ctr_gc_internal_pin(block); ctr_gc_internal_pin(myself); ctr_gc_internal_pin(argument2->object); ctr_block_run(block, arguments, myself); ctr_heap_free( arguments ); ctr_heap_free( argument2 ); ctr_heap_free( argument3 ); if (CtrStdFlow == CtrStdContinue) CtrStdFlow = NULL; if (CtrStdFlow) break; } if (CtrStdFlow == CtrStdBreak) CtrStdFlow = NULL; /* consume break */ return myself; }
/** * Factorial * * Calculates the factorial of a number. */ ctr_object* ctr_number_factorial(ctr_object* myself, ctr_argument* argumentList) { ctr_number t = myself->value.nvalue; int i; ctr_number a = 1; for(i = (int) t; i > 0; i--) { a = a * i; } return ctr_build_number_from_float(a); }
/** * [Array] sum * * Takes the sum of an array. This message will calculate the * sum of the numerical elements in the array. * * Usage: * * a := Array <- 1 ; 2 ; 3. * s := a sum. #6 * * In the example above, the sum of array will be stored in s and * it's value will be 6. */ ctr_object* ctr_array_sum(ctr_object* myself, ctr_argument* argumentList) { double sum = 0; ctr_object* el; size_t i = 0; for(i = 0; i < myself->value.avalue->head; i++) { el = *(myself->value.avalue->elements + i); sum += ctr_internal_cast2number(el)->value.nvalue; } return ctr_build_number_from_float(sum); }
/** * [Shell] call: [String] * * Performs a Shell operation. The Shell object uses a fluid API, so you can * mix shell code with programming logic. For instance to list the contents * of a directory use: * * Shell ls * * This will output the contents of the current working directly, you * can also pass keyword messages like so: * * Shell echo: 'Hello from the Shell!'. * * The example above will output the specified message to the console. * Every message you send will be turned into a string and dispatched to * the 'call:' message. */ ctr_object* ctr_shell_call(ctr_object* myself, ctr_argument* argumentList) { ctr_object* arg = ctr_internal_cast2string(argumentList->object); long vlen = arg->value.svalue->vlen; char* comString = malloc(vlen + 1); int r; memcpy(comString, arg->value.svalue->value, vlen); memcpy(comString+vlen,"\0",1); r = system(comString); return ctr_build_number_from_float( (ctr_number) r ); }
/** * StringByteAt * * Returns the byte at the specified position (in bytes). * * Usage: * ('abc' byteAt: 1). #98 */ ctr_object* ctr_string_byte_at(ctr_object* myself, ctr_argument* argumentList) { char x; ctr_object* fromPos = ctr_internal_cast2number(argumentList->object); long a = (fromPos->value.nvalue); long len = myself->value.svalue->vlen; if (a > len) return CtrStdNil; if (a < 0) return CtrStdNil; x = (char) *(myself->value.svalue->value + a); return ctr_build_number_from_float((double)x); }
ctr_object* ctr_number_modulo(ctr_object* myself, ctr_argument* argumentList) { ctr_object* otherNum = ctr_internal_cast2number(argumentList->object); ctr_number a = myself->value.nvalue; ctr_number b = otherNum->value.nvalue; if (b == 0) { CtrStdError = ctr_build_string_from_cstring("Division by zero."); return myself; } return ctr_build_number_from_float(fmod(a,b)); }
/** * Percolator new * * Creates a new instance of the percolator object. * * Usage: * * myPercolator := Percolator new. * cupOfCoffee := myPercolator coffee: 1 water: 2, brew. * */ ctr_object* ctr_percolator_new(ctr_object* myself, ctr_argument* argumentList) { ctr_object* percolatorInstance = ctr_internal_create_object(CTR_OBJECT_TYPE_OTOBJECT); percolatorInstance->link = myself; ctr_internal_object_set_property( percolatorInstance, ctr_build_string_from_cstring( "coffee" ), ctr_build_number_from_float(0), CTR_CATEGORY_PRIVATE_PROPERTY ); ctr_internal_object_set_property( percolatorInstance, ctr_build_string_from_cstring( "water" ), ctr_build_number_from_float(0), CTR_CATEGORY_PRIVATE_PROPERTY ); return percolatorInstance; }
ctr_object* ctr_number_multiply(ctr_object* myself, ctr_argument* argumentList) { ctr_object* otherNum; ctr_number a; ctr_number b; CTR_MIRROR_CALL(CTR_OBJECT_TYPE_OTBLOCK, ctr_block_times, mirror1); otherNum = ctr_internal_cast2number(argumentList->object); a = myself->value.nvalue; b = otherNum->value.nvalue; return ctr_build_number_from_float(a*b); }
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); }
/** * [List] replace: [Number] length: [Number] with: [List]. * * Returns a copy of the list with the specified elements replaced. * The first argument indicates the start index to begin the replacement. * Here, 0 means the beginning of the list. * The second argument (length) * must indicate the number of elements to delete in the copy, counting * from the starting point. Finally, one has to provide the replacement * list as the third argument. * If the replacement list is empty, the specified elements will only be * removed from the copy. * If the replacement is not an array an error will be thrown. * * Usage: * * ☞ buy := cakes * replace: 1 * length: 2 * with: ( List ← 'cinnamon' ; 'pineapple' ). * * In other languages: * Dutch: [Reeks] vervang: [Getal] lengte: [Getal] door: [Reeks] * Vervangt een deel van de reeks door een andere reeks. */ ctr_object* ctr_array_splice(ctr_object* myself, ctr_argument* argumentList) { ctr_object* newArray = ctr_array_new(CtrStdArray, NULL); ctr_object* start = ctr_internal_cast2number(argumentList->object); ctr_object* deleteCount = ctr_internal_cast2number(argumentList->next->object); ctr_object* replacement = argumentList->next->next->object; ctr_object* remainder; ctr_argument* sliceFromArg; ctr_argument* sliceLengthArg; ctr_argument* replacementArg; ctr_argument* remainderArg; ctr_size n; if ( replacement->info.type != CTR_OBJECT_TYPE_OTARRAY ) { CtrStdFlow = ctr_error_text( CTR_ERR_EXP_ARR ); return myself; } n = ( start->value.nvalue + deleteCount->value.nvalue ); sliceFromArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); sliceLengthArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); replacementArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); remainderArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); sliceFromArg->object = ctr_build_number_from_float(0); sliceLengthArg->object = start; sliceFromArg->next = sliceLengthArg; newArray = ctr_array_from_length( myself, sliceFromArg ); replacementArg->object = replacement; newArray = ctr_array_add(newArray, replacementArg); sliceFromArg->object = ctr_build_number_from_float( n ); if ( n < (myself->value.avalue->head - myself->value.avalue->tail) ) { sliceLengthArg->object = ctr_build_number_from_float( (myself->value.avalue->head - myself->value.avalue->tail) - n ); sliceFromArg->next = sliceLengthArg; remainder = ctr_array_from_length( myself, sliceFromArg ); remainderArg->object = remainder; newArray = ctr_array_add( newArray, remainderArg ); } ctr_heap_free( sliceFromArg ); ctr_heap_free( sliceLengthArg ); ctr_heap_free( replacementArg ); ctr_heap_free( remainderArg ); return newArray; }
/** * [File] writeBytes: [String]. * * Takes a string and writes the bytes in the string to the file * object. Returns the number of bytes actually written. * * Usage: * * f := File new: '/path/to/file.txt'. * f open: 'r+'. * n := f writeBytes: 'Hello World'. * f close. * * The example above writes 'Hello World' to the specified file as bytes. * The number of bytes written is returned in variable n. */ ctr_object* ctr_file_write_bytes(ctr_object* myself, ctr_argument* argumentList) { int bytes, written; ctr_object* string2write; char* buffer; if (myself->value.rvalue == NULL) return myself; if (myself->value.rvalue->type != 1) return myself; string2write = ctr_internal_cast2string(argumentList->object); buffer = ctr_heap_allocate_cstring( string2write ); bytes = string2write->value.svalue->vlen; written = fwrite(buffer, sizeof(char), (int)bytes, (FILE*)myself->value.rvalue->ptr); ctr_heap_free( buffer ); return ctr_build_number_from_float((double_t) written); }
/** * [File] size * * Returns the size of the file. */ ctr_object* ctr_file_size(ctr_object* myself, ctr_argument* argumentList) { ctr_object* path = ctr_internal_object_find_property(myself, ctr_build_string("path",4), 0); ctr_size vlen; char* pathString; FILE* f; int prev, sz; if (path == NULL) return ctr_build_number_from_float(0); vlen = path->value.svalue->vlen; pathString = malloc(vlen + 1); memcpy(pathString, path->value.svalue->value, vlen); memcpy(pathString+vlen,"\0",1); f = fopen(pathString, "r"); if (f == NULL) return ctr_build_number_from_float(0); prev = ftell(f); fseek(f, 0L, SEEK_END); sz=ftell(f); fseek(f,prev,SEEK_SET); if (f) { fclose(f); } return ctr_build_number_from_float( (ctr_number) sz ); }
/** * [List] maximum * * Returns the maximum value in a list. * In the example this will yield the number 16. * * Usage: * * a := List ← 8 ; 4 ; 2 ; 16. * m := a maximum. * * In other languages: * Dutch: [Reeks] maximum | Geeft de hoogste waarde uit de reeks terug. * */ ctr_object* ctr_array_max(ctr_object* myself, ctr_argument* argumentList) { double max = 0; double v = 0; ctr_object* el; size_t i = 0; for(i = 0; i < myself->value.avalue->head; i++) { el = *(myself->value.avalue->elements + i); v = ctr_internal_cast2number(el)->value.nvalue; if (i == 0 || max < v) { max = v; } } return ctr_build_number_from_float(max); }
/** * [List] copy * * Copies the list. The list object will answer this message by * returning a shallow copy of itself. This means that the values in the * newly returned list can be replaced or deleted without affecting * the original one. However, modifying the values in the list will * still cause their counterparts in the original list to be modified * as well. * In the example we replace the first item (1) in b with 999. * The first element in a will still be 1 though because we have created * copy b by sending the message 'copy' to a and assiging the result * to b. * * Usage: * * ☞ a := List ← 1 ; 2 ; 3. * ☞ b := a copy. * b put: 999 at: 1. * * In other languages: * Dutch: [Reeks] kopieer | Maakt een kopie van de reeks. */ ctr_object* ctr_array_copy(ctr_object* myself, ctr_argument* argumentList) { ctr_size i = 0; ctr_object* copy = ctr_array_new( CtrStdArray, argumentList ); ctr_argument* arg = ctr_heap_allocate(sizeof(ctr_argument)); ctr_argument* index = ctr_heap_allocate( sizeof( ctr_argument ) ); for(i = myself->value.avalue->tail; i<myself->value.avalue->head; i++) { index->object = ctr_build_number_from_float((ctr_number) i); arg->object = ctr_array_get( myself, index ); ctr_array_push( copy, arg ); } ctr_heap_free( arg ); ctr_heap_free( index ); return copy; }
/** * [List] find: [Object]. * * Checks whether the specified object occurs in the list * and returns the index number if so. * If not, the index number -1 will be returned. Note that the comparison * will be performed by converting both values to strings. * * In other languages: * Dutch: [Reeks] vind: [Object] * Geeft de positie van het object terug of -1 als niet gevonden. */ ctr_object* ctr_array_index_of( ctr_object* myself, ctr_argument* argumentList ) { int64_t found = -1, i = 0; ctr_object* needle = ctr_internal_cast2string(argumentList->object); ctr_object* element; for(i = myself->value.avalue->tail; i < myself->value.avalue->head; i++) { element = ctr_internal_cast2string( (ctr_object*) *(myself->value.avalue->elements + i) ); if ( element->value.svalue->vlen == needle->value.svalue->vlen && strncmp(element->value.svalue->value,needle->value.svalue->value,needle->value.svalue->vlen)==0) { found = i; break; } } return ctr_build_number_from_float(found); }
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)); }
/** * [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; }
/** * 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; }
/** * [List] by: [List]. * * Combines the first list with the second one, thus creating * a map. The keys of the newly generated map will be provided by the * first list while the values are extracted from the second one. * In the example we derive a temperature map from a pair of lists * (cities and temperatures). * * Usage: * * ☞ city := List ← 'London' ; 'Paris' ; 'Berlin'. * ☞ temperature := List ← '15' ; '16' ; '15'. * ☞ weather := temperature by: city. * * In other languages: * Dutch: [Reeks] per: [Reeks] * Maakt een Lijst door elementen uit de eerste reeks te koppelen * aan de elementen op dezelfde plek uit de tweede reeks. */ ctr_object* ctr_array_combine(ctr_object* myself, ctr_argument* argumentList) { ctr_size i; ctr_object* map = ctr_map_new( CtrStdMap, argumentList ); if (argumentList->object->info.type != CTR_OBJECT_TYPE_OTARRAY) { return map; } ctr_argument* key = ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* value = ctr_heap_allocate( sizeof( ctr_argument ) ); ctr_argument* index = ctr_heap_allocate( sizeof( ctr_argument ) ); for(i = myself->value.avalue->tail; i<myself->value.avalue->head; i++) { index->object = ctr_build_number_from_float((ctr_number) i); key->object = ctr_array_get( myself, index ); value->object = ctr_array_get( argumentList->object, index ); key->next = value; ctr_send_message( map, CTR_DICT_PUT_AT, strlen(CTR_DICT_PUT_AT), key); ctr_map_put( map, key ); } ctr_heap_free(key); ctr_heap_free(value); ctr_heap_free(index); return map; }
/** * [List] from: [Begin] length: [End] * * Copies part of an array indicated by from and to and * returns a new array consisting of a copy of this region. * * In other languages: * Dutch: [Reeks] van: [Getal] lengte: [Getal] | Geeft subreeks. */ ctr_object* ctr_array_from_length(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_argument*) ctr_heap_allocate( sizeof( ctr_argument ) ); elnumArg = (ctr_argument*) ctr_heap_allocate( sizeof( ctr_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); ctr_heap_free( elnumArg ); ctr_heap_free( 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; }
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; }
/** * StringLength * * Returns the length of the string in symbols. * This message is UTF-8 unicode aware. A 4 byte character will be counted as ONE. */ ctr_object* ctr_string_length(ctr_object* myself, ctr_argument* argumentList) { ctr_size n = ctr_getutf8len(myself->value.svalue->value, (ctr_size) myself->value.svalue->vlen); return ctr_build_number_from_float((ctr_number) n); }
/** * StringBytes * * Returns the number of bytes in a string. */ ctr_object* ctr_string_bytes(ctr_object* myself, ctr_argument* argumentList) { return ctr_build_number_from_float((float)myself->value.svalue->vlen); }
/** * BooleanToNumber * * Wrapper for cast function. * Returns 0 if boolean is False and 1 otherwise. */ ctr_object* ctr_bool_to_number(ctr_object* myself, ctr_argument* argumentList) { return ctr_build_number_from_float( (ctr_number) myself->value.bvalue ); }
ctr_object* ctr_number_log(ctr_object* myself, ctr_argument* argumentList) { return ctr_build_number_from_float(log(myself->value.nvalue)); }