diff --git a/src/interface.c b/src/interface.c index 544eef2..403dfbd 100644 --- a/src/interface.c +++ b/src/interface.c @@ -43,66 +43,76 @@ GroundValue groundCreateValue(GroundValueType type, ...) { va_list args; va_start(args, type); + GroundValue gv; switch (type) { case INT: { - return createIntGroundValue(va_arg(args, int64_t)); + gv = createIntGroundValue(va_arg(args, int64_t)); break; } case DOUBLE: { - return createDoubleGroundValue(va_arg(args, double)); + gv = createDoubleGroundValue(va_arg(args, double)); break; } case STRING: { - return createStringGroundValue(va_arg(args, char*)); + gv = createStringGroundValue(va_arg(args, char*)); break; } case CHAR: { - return createCharGroundValue((char)va_arg(args, int)); + gv = createCharGroundValue((char)va_arg(args, int)); break; } case BOOL: { - return createBoolGroundValue((bool)va_arg(args, int)); + gv = createBoolGroundValue((bool)va_arg(args, int)); break; } case LIST: { - return createListGroundValue(va_arg(args, List)); + gv = createListGroundValue(va_arg(args, List)); break; } case FUNCTION: { - return createFunctionGroundValue(va_arg(args, GroundFunction*)); + gv = createFunctionGroundValue(va_arg(args, GroundFunction*)); break; } case STRUCTVAL: { - GroundValue gv; gv.type = STRUCTVAL; gv.data.structVal = malloc(sizeof(GroundStruct)); *gv.data.structVal = va_arg(args, GroundStruct); - return gv; + break; } case NONE: { - return createNoneGroundValue(); + gv = createNoneGroundValue(); break; } case CUSTOM: { // CUSTOM values are created from structs - GroundValue gv; GroundStruct* gstruct = va_arg(args, GroundStruct*); gv.type = CUSTOM; gv.data.customVal = malloc(sizeof(GroundObject)); *gv.data.customVal = createObject(*gstruct); - gv.customType = gstruct; + + // Deep copy the struct definition so it stays valid + gv.customType = malloc(sizeof(GroundStruct)); + gv.customType->size = gstruct->size; + gv.customType->fields = malloc(gstruct->size * sizeof(GroundStructField)); + for (size_t i = 0; i < gstruct->size; i++) { + strncpy(gv.customType->fields[i].id, gstruct->fields[i].id, 64); + gv.customType->fields[i].value = copyGroundValue(&gstruct->fields[i].value); + } break; } case ERROR: { // FIXME - return createNoneGroundValue(); + gv = createNoneGroundValue(); + break; + } + default: { + gv = createNoneGroundValue(); break; } } - return createNoneGroundValue(); - va_end(args); + return gv; } GroundValue groundRunProgram(GroundProgram* program) { diff --git a/src/types.c b/src/types.c index 6123b32..dc31026 100644 --- a/src/types.c +++ b/src/types.c @@ -128,7 +128,6 @@ GroundValue copyGroundValue(const GroundValue* gv) { break; } case CUSTOM: { - newGv.customType = gv->customType; newGv.data.customVal = malloc(sizeof(GroundObject)); if (newGv.data.customVal == NULL) { printf("Couldn't allocate memory for GroundObject copy\n"); @@ -137,6 +136,15 @@ GroundValue copyGroundValue(const GroundValue* gv) { newGv.data.customVal->fields = NULL; + // Deep copy the struct definition as well + newGv.customType = malloc(sizeof(GroundStruct)); + newGv.customType->size = gv->customType->size; + newGv.customType->fields = malloc(gv->customType->size * sizeof(GroundStructField)); + for (size_t i = 0; i < gv->customType->size; i++) { + strncpy(newGv.customType->fields[i].id, gv->customType->fields[i].id, 64); + newGv.customType->fields[i].value = copyGroundValue(&gv->customType->fields[i].value); + } + GroundObjectField *field, *tmp; HASH_ITER(hh, gv->data.customVal->fields, field, tmp) { GroundObjectField* newField = malloc(sizeof(GroundObjectField)); @@ -267,6 +275,20 @@ void freeGroundValue(GroundValue* gv) { freeGroundStruct(gstruct); free(gstruct); } + if (gv->type == CUSTOM && gv->data.customVal != NULL) { + freeGroundObject(gv->data.customVal); + free(gv->data.customVal); + gv->data.customVal = NULL; + + if (gv->customType != NULL) { + for (size_t i = 0; i < gv->customType->size; i++) { + freeGroundValue(&gv->customType->fields[i].value); + } + free(gv->customType->fields); + free(gv->customType); + gv->customType = NULL; + } + } if (gv->type == ERROR) { GroundError* error = &gv->data.errorVal; if (error->type != NULL) {