summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Cerqueira <dan.git@lispclub.com>2025-08-30 19:48:22 +0100
committerDaniel Cerqueira <dan.git@lispclub.com>2025-08-30 19:49:28 +0100
commitbd1b8657e2c37ac2e7aef2f3c8caa8bf18c295ff (patch)
treeb0f204d3ec7fe3f9a08067556e8238fa89df6b7a
parent03395835c8719bf5f7a5aee9c97caa61a94f5eee (diff)
refactor and improve primitiveJoin()
-rw-r--r--liblali.c107
1 files changed, 88 insertions, 19 deletions
diff --git a/liblali.c b/liblali.c
index c2ec974..6696bc3 100644
--- a/liblali.c
+++ b/liblali.c
@@ -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) {