diff options
Diffstat (limited to 'liblali.c')
| -rw-r--r-- | liblali.c | 107 |
1 files changed, 88 insertions, 19 deletions
@@ -1112,30 +1112,99 @@ Object *primitiveJoin(Object **args, GC_PARAM) { if ((*args)->car == nil) exception("cannot join an empty list"); + // check if the list argument is indeed a list + if ((*args)->car->type != TYPE_CONS) + exceptionWithObject((*args)->car, "must be a list"); + + // determine what is the result type + int resType = (*args)->car->car->type; + if (isSplittedNumber((*args)->car)) + resType = TYPE_NUMBER; + else if (resType != TYPE_STRING && + resType != TYPE_SYMBOL) + exceptionWithObject((*args)->car, "cannot be joined"); + + // check that there are only symbols or strings + // also get the size for result string + unsigned long long size = 0; + Object *list = (*args)->car; + if (resType == TYPE_STRING) + for (;;) { + if (list->car->type != TYPE_SYMBOL && + list->car->type != TYPE_STRING ) + exceptionWithObject((*args)->car, + "can only have first-level elements of or symbols or strings"); + + size += strlen(list->car->string); + if (list->cdr == nil) break; + list = list->cdr; + } + else if (resType == TYPE_SYMBOL) + for (;;) { + if (list->car->type != TYPE_SYMBOL) + exceptionWithObject((*args)->car, "can only have first-level elements of symbol"); + + size += strlen(list->car->string); + if (list->cdr == nil) break; + list = list->cdr; + } + else if (resType == TYPE_NUMBER) { + Object *lcar = nil; + ++size; + list = list->cdr; + + for (;;) { + lcar = list->car; + for (;;) { + ++size; // just use the first digit + if (lcar->cdr == nil) break; + lcar = lcar->cdr; + } + + if (list->cdr == nil) break; + ++size; + list = list->cdr; + } } - char symbolResult[i+1]; - - tmpCons = (*args)->car; - unsigned long wordLength = strlen(tmpCons->car->string); - unsigned long j = 0; - // first list element - for (; j < wordLength; j++) - symbolResult[j] = tmpCons->car->string[j]; - // rest of list elements - if (tmpCons->cdr->car != nil) { - for (i = wordLength; tmpCons->cdr != nil; tmpCons = tmpCons->cdr) { - wordLength = strlen(tmpCons->cdr->car->string); - for (j = 0; j < wordLength; j++) - symbolResult[i+j] = tmpCons->cdr->car->string[j]; - i += j; + + char result[size+1]; // +1 for '\0' + + // copy to result string + list = (*args)->car; + strcpy(result, list->car->string); + char noPrefixNumber[2]; + + if (resType == TYPE_NUMBER) { + Object *lcar = nil; + list = list->cdr; + for (;;) { + lcar = list->car; + for (;;) { + noPrefixNumber[0] = lcar->car->string[1]; + noPrefixNumber[1] = '\0'; + strcat(result, noPrefixNumber); + + if (lcar->cdr == nil) break; + lcar = lcar->cdr; + } + + if (list->cdr == nil) break; + strcat(result, "."); + list = list->cdr; } + return newNumber(result, GC_ROOTS); } - symbolResult[i] = '\0'; - if (elementsType == TYPE_STRING) - return newString(symbolResult, GC_ROOTS); + for (; list->cdr != nil; list = list->cdr) + strcat(result, list->cdr->car->string); + + // the return + if (resType == TYPE_STRING) + return newString(result, GC_ROOTS); + else if (resType == TYPE_SYMBOL) + return newSymbol(result, GC_ROOTS); else - return newSymbol(symbolResult, GC_ROOTS); + exception("this join error should not happen"); } Object *primitiveSplit(Object **args, GC_PARAM) { |
