Files
cground/src/types.c

712 lines
20 KiB
C
Raw Normal View History

2025-11-23 13:37:08 +11:00
#include "types.h"
2025-11-23 18:34:30 +11:00
#include <inttypes.h>
2025-11-28 09:23:43 +11:00
#include <stdlib.h>
2025-11-23 13:37:08 +11:00
GroundValue createIntGroundValue(int64_t in) {
GroundValue gv;
gv.data.intVal = in;
gv.type = INT;
return gv;
}
GroundValue createDoubleGroundValue(double in) {
GroundValue gv;
gv.data.doubleVal = in;
gv.type = DOUBLE;
return gv;
}
GroundValue createStringGroundValue(const char* in) {
GroundValue gv;
gv.data.stringVal = strdup(in);
gv.type = STRING;
return gv;
}
GroundValue createCharGroundValue(char in) {
GroundValue gv;
gv.data.charVal = in;
gv.type = CHAR;
return gv;
}
GroundValue createBoolGroundValue(bool in) {
GroundValue gv;
gv.data.boolVal = in;
gv.type = BOOL;
return gv;
}
2025-12-01 10:15:37 +11:00
GroundValue createListGroundValue(List in) {
GroundValue gv;
gv.data.listVal = in;
gv.type = LIST;
return gv;
}
2025-12-06 11:50:42 +11:00
GroundValue createFunctionGroundValue(GroundFunction* in) {
GroundValue gv;
gv.data.fnVal = in;
gv.type = FUNCTION;
return gv;
}
2025-12-01 10:36:09 +11:00
2026-01-18 20:49:50 +11:00
GroundValue createErrorGroundValue(GroundError in) {
GroundValue gv;
gv.data.errorVal = in;
gv.type = ERROR;
return gv;
}
2025-12-06 14:35:13 +11:00
GroundValue createNoneGroundValue() {
GroundValue gv;
gv.type = NONE;
return gv;
}
2025-12-01 10:36:09 +11:00
GroundValue copyGroundValue(const GroundValue* gv) {
GroundValue newGv;
newGv.type = gv->type;
switch(gv->type) {
case INT: newGv.data.intVal = gv->data.intVal; break;
case DOUBLE: newGv.data.doubleVal = gv->data.doubleVal; break;
case CHAR: newGv.data.charVal = gv->data.charVal; break;
case BOOL: newGv.data.boolVal = gv->data.boolVal; break;
case STRING:
if (gv->data.stringVal != NULL) {
newGv.data.stringVal = strdup(gv->data.stringVal);
} else {
newGv.data.stringVal = NULL;
}
break;
case LIST: {
List newList = createList();
for (size_t i = 0; i < gv->data.listVal.size; i++) {
2025-12-01 10:36:09 +11:00
// Recursive call to handle nested lists and other types
appendToList(&newList, copyGroundValue(&gv->data.listVal.values[i]));
}
newGv.data.listVal = newList;
break;
}
2025-12-06 11:50:42 +11:00
case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break;
2026-01-15 12:44:09 +11:00
case STRUCTVAL: {
newGv.data.structVal = malloc(sizeof(GroundStruct));
if (newGv.data.structVal == NULL) {
printf("Couldn't allocate memory for GroundStruct copy\n");
exit(1);
}
newGv.data.structVal->size = gv->data.structVal->size;
newGv.data.structVal->fields = malloc(gv->data.structVal->size * sizeof(GroundStructField));
if (newGv.data.structVal->fields == NULL && gv->data.structVal->size > 0) {
printf("Couldn't allocate memory for GroundStruct fields copy\n");
exit(1);
}
for (size_t i = 0; i < gv->data.structVal->size; i++) {
strncpy(newGv.data.structVal->fields[i].id,
gv->data.structVal->fields[i].id,
sizeof(newGv.data.structVal->fields[i].id) - 1);
newGv.data.structVal->fields[i].id[sizeof(newGv.data.structVal->fields[i].id) - 1] = '\0';
newGv.data.structVal->fields[i].value = copyGroundValue(&gv->data.structVal->fields[i].value);
}
2026-01-15 12:44:09 +11:00
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");
exit(1);
}
newGv.data.customVal->fields = NULL;
GroundObjectField *field, *tmp;
HASH_ITER(hh, gv->data.customVal->fields, field, tmp) {
GroundObjectField* newField = malloc(sizeof(GroundObjectField));
if (newField == NULL) {
printf("Couldn't allocate memory for GroundObjectField copy\n");
exit(1);
}
strncpy(newField->id, field->id, sizeof(newField->id) - 1);
newField->id[sizeof(newField->id) - 1] = '\0';
newField->value = copyGroundValue(&field->value);
HASH_ADD_STR(newGv.data.customVal->fields, id, newField);
}
2025-12-01 10:36:09 +11:00
break;
}
case NONE:
default: {
}
2025-12-01 10:36:09 +11:00
}
return newGv;
}
2025-11-23 18:34:30 +11:00
void printGroundValue(GroundValue* gv) {
switch (gv->type) {
case INT: {
printf("%" PRId64 "", gv->data.intVal);
break;
}
case DOUBLE: {
printf("%f", gv->data.doubleVal);
break;
}
case STRING: {
printf("%s", gv->data.stringVal);
break;
}
case CHAR: {
printf("%c", gv->data.charVal);
break;
}
case BOOL: {
if (gv->data.boolVal) {
printf("true");
} else {
printf("false");
}
break;
}
2025-12-01 10:36:09 +11:00
case LIST: {
printf("[");
for (size_t i = 0; i < gv->data.listVal.size; i++) {
2025-12-01 10:36:09 +11:00
printGroundValue(&gv->data.listVal.values[i]);
if (i < gv->data.listVal.size - 1) {
printf(", ");
}
}
printf("]");
break;
}
2025-12-08 11:08:08 +11:00
case FUNCTION: {
printf("<function>");
break;
}
2026-01-24 16:23:01 +11:00
case STRUCTVAL: {
printf("<struct fields: { ");
for (size_t i = 0; i < gv->data.structVal->size; i++) {
if (i != 0) {
printf(", ");
}
printf("%s: ", gv->data.structVal->fields[i].id);
if (gv->data.structVal->fields[i].value.type == STRING) {
printf("\"");
printGroundValue(&gv->data.structVal->fields[i].value);
printf("\"");
} else {
printGroundValue(&gv->data.structVal->fields[i].value);
}
}
printf(" }>");
break;
}
case CUSTOM: {
printf("<object fields: { ");
for (size_t i = 0; i < gv->customType->size; i++) {
if (i != 0) {
printf(", ");
}
printf("%s: ", gv->customType->fields[i].id);
GroundObjectField* field = findField(*gv->data.customVal, gv->customType->fields[i].id);
if (field == NULL) {
printf("<missing>");
} else {
printGroundValue(&field->value);
}
}
printf(" }>");
break;
}
case ERROR: {
printf("<error type: %s, what: %s>", gv->data.errorVal.type, gv->data.errorVal.what);
break;
}
case NONE: {
printf("<none>");
2025-11-23 18:34:30 +11:00
break;
}
}
}
2025-11-23 13:37:08 +11:00
void freeGroundValue(GroundValue* gv) {
if (gv->type == STRING && gv->data.stringVal != NULL) {
free(gv->data.stringVal);
2025-12-01 10:36:09 +11:00
gv->data.stringVal = NULL;
2025-11-23 13:37:08 +11:00
}
2025-12-01 10:15:37 +11:00
if (gv->type == LIST && gv->data.listVal.values != NULL) {
List* list = &gv->data.listVal;
for (size_t i = 0; i < list->size; i++) {
2025-12-01 10:15:37 +11:00
freeGroundValue(&list->values[i]);
}
free(list->values);
2025-12-01 10:36:09 +11:00
list->values = NULL;
gv->data.listVal = createList();
2025-12-01 10:15:37 +11:00
}
2026-01-15 12:44:09 +11:00
if (gv->type == STRUCTVAL && gv->data.structVal->fields != NULL) {
GroundStruct* gstruct = gv->data.structVal;
freeGroundStruct(gstruct);
free(gstruct);
}
2026-01-18 20:49:50 +11:00
if (gv->type == ERROR) {
GroundError* error = &gv->data.errorVal;
if (error->type != NULL) {
free(error->type);
}
if (error->what != NULL) {
free(error->what);
}
if (error->where != NULL) {
freeGroundInstruction(error->where);
}
}
2025-11-23 13:37:08 +11:00
}
GroundArg createValueGroundArg(GroundValue value) {
GroundArg ga;
ga.value.value = value;
ga.type = VALUE;
return ga;
}
GroundArg createRefGroundArg(GroundArgType type, const char* refname) {
GroundArg ga;
ga.value.refName = strdup(refname);
ga.type = type;
return ga;
}
void freeGroundArg(GroundArg* ga) {
if (ga->type == VALUE) {
freeGroundValue(&ga->value.value);
} else {
free(ga->value.refName);
}
}
2025-11-23 18:34:30 +11:00
void printGroundArg(GroundArg* ga) {
switch (ga->type) {
case VALUE: {
printGroundValue(&ga->value.value);
break;
}
case DIRREF: {
printf("&%s", ga->value.refName);
break;
}
case VALREF: {
printf("$%s", ga->value.refName);
break;
}
case LINEREF: {
printf("%%%s", ga->value.refName);
break;
}
case LABEL: {
printf("@%s", ga->value.refName);
break;
}
case FNREF: {
printf("!%s", ga->value.refName);
break;
}
case TYPEREF: {
printf("-%s", ga->value.refName);
break;
}
}
}
2025-11-23 13:37:08 +11:00
GroundInstruction createGroundInstruction(GroundInstType type) {
GroundInstruction gi;
gi.type = type;
gi.args.args = NULL;
gi.args.length = 0;
return gi;
}
void freeGroundInstruction(GroundInstruction* gi) {
for (size_t i = 0; i < gi-> args.length; i++) {
freeGroundArg(&gi->args.args[i]);
}
2025-11-24 10:15:53 +11:00
free(gi->args.args);
2025-11-23 13:37:08 +11:00
}
2025-11-24 10:15:53 +11:00
GroundInstruction copyGroundInstruction(const GroundInstruction* inst) {
GroundInstruction newInst;
newInst.type = inst->type;
newInst.args.length = inst->args.length;
if (inst->args.length > 0) {
newInst.args.args = malloc(inst->args.length * sizeof(GroundArg));
for (size_t i = 0; i < inst->args.length; i++) {
newInst.args.args[i].type = inst->args.args[i].type;
if (inst->args.args[i].type == VALUE) {
2025-12-01 10:36:09 +11:00
newInst.args.args[i].value.value = copyGroundValue(&inst->args.args[i].value.value);
2025-11-24 10:15:53 +11:00
} else {
newInst.args.args[i].value.refName = strdup(inst->args.args[i].value.refName);
}
}
} else {
newInst.args.args = NULL;
}
return newInst;
}
2025-11-23 13:37:08 +11:00
void addArgToInstruction(GroundInstruction* gi, GroundArg arg) {
gi->args.length ++;
GroundArg* newArgs = realloc(gi->args.args, gi->args.length * sizeof(GroundArg));
if (newArgs == NULL) {
perror("Failed to allocate memory for instruction argument");
exit(EXIT_FAILURE);
}
gi->args.args = newArgs;
gi->args.args[gi->args.length - 1] = arg;
}
2025-11-23 18:34:30 +11:00
void printGroundInstruction(GroundInstruction* gi) {
switch (gi->type) {
case IF:
printf("if");
break;
case JUMP:
printf("jump");
break;
case END:
printf("end");
break;
case INPUT:
printf("input");
break;
case PRINT:
printf("print");
break;
case PRINTLN:
printf("println");
break;
case SET:
printf("set");
break;
case GETTYPE:
printf("gettype");
break;
case EXISTS:
printf("exists");
break;
case SETLIST:
printf("setlist");
break;
case SETLISTAT:
printf("setlistat");
break;
case GETLISTAT:
printf("getlistat");
break;
case GETLISTSIZE:
printf("getlistsize");
break;
case LISTAPPEND:
printf("listappend");
break;
case GETSTRSIZE:
printf("getstrsize");
break;
case GETSTRCHARAT:
printf("getstrcharat");
break;
case ADD:
printf("add");
break;
case SUBTRACT:
printf("subtract");
break;
case MULTIPLY:
printf("multiply");
break;
case DIVIDE:
printf("divide");
break;
case EQUAL:
printf("equal");
break;
case INEQUAL:
printf("inequal");
break;
case NOT:
printf("not");
break;
case GREATER:
printf("greater");
break;
case LESSER:
printf("lesser");
break;
case STOI:
printf("stoi");
break;
case STOD:
printf("stod");
break;
2026-01-24 18:18:52 +11:00
case CTOI:
printf("ctoi");
break;
case ITOC:
printf("itoc");
break;
2025-11-23 18:34:30 +11:00
case TOSTRING:
printf("tostring");
break;
case FUN:
printf("fun");
break;
case RETURN:
printf("return");
break;
case ENDFUN:
printf("endfun");
break;
case PUSHARG:
printf("pusharg");
break;
case CALL:
printf("call");
break;
case STRUCT:
printf("struct");
break;
case ENDSTRUCT:
printf("endstruct");
break;
case INIT:
printf("init");
break;
case USE:
printf("use");
break;
case EXTERN:
printf("extern");
break;
case DROP:
printf("drop");
break;
2025-11-23 18:34:30 +11:00
case CREATELABEL:
break;
2026-01-19 21:14:48 +11:00
case ERRORCMD:
printf("error");
break;
2025-11-23 18:34:30 +11:00
default:
printf("FIXME");
break;
}
if (gi->type != CREATELABEL) printf(" ");
for (size_t i = 0; i < gi->args.length; i++) {
if (gi->args.args[i].type == VALUE && gi->args.args[i].value.value.type == STRING) {
printf("\"");
printGroundArg(&gi->args.args[i]);
printf("\"");
} else {
printGroundArg(&gi->args.args[i]);
}
2025-11-23 18:34:30 +11:00
printf(" ");
}
}
2025-11-28 09:23:43 +11:00
List createList() {
List list;
list.size = 0;
list.values = malloc(sizeof(GroundValue));
return list;
}
void appendToList(List* list, GroundValue value) {
if (list == NULL) {
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
exit(EXIT_FAILURE);
}
2025-12-01 10:15:37 +11:00
GroundValue* ptr = realloc(list->values, (list->size + 1) * sizeof(GroundValue));
2025-11-28 09:23:43 +11:00
if (ptr == NULL) {
printf("There was an error allocating memory for a list.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
exit(EXIT_FAILURE);
}
list->size++;
list->values = ptr;
list->values[list->size - 1] = value;
}
ListAccess getListAt(List* list, size_t idx) {
2025-11-28 09:23:43 +11:00
if (list == NULL) {
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
exit(EXIT_FAILURE);
}
if (idx < list->size) {
ListAccess retval;
retval.value = &list->values[idx];
retval.status = LIST_OKAY;
return retval;
} else {
ListAccess retval;
retval.value = NULL;
retval.status = LIST_OUT_OF_BOUNDS;
return retval;
}
}
ListAccessStatus setListAt(List* list, size_t idx, GroundValue value) {
2025-11-28 09:23:43 +11:00
if (list == NULL) {
printf("Expecting a List ptr, got a null pointer instead.\nThis is likely not an error with your Ground program.\nPlease report this issue to https://chsp.au/ground/cground\n");
exit(EXIT_FAILURE);
}
if (idx < list->size) {
list->values[idx] = value;
return LIST_OKAY;
} else {
return LIST_OUT_OF_BOUNDS;
}
}
2026-01-15 12:44:09 +11:00
GroundStruct createStruct() {
return (GroundStruct) {
.fields = malloc(sizeof(GroundStructField)),
.size = 0
};
}
void addFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) {
GroundStructField* tmpPointer = realloc(gstruct->fields, (gstruct->size + 1) * sizeof(GroundStructField));
if (tmpPointer == NULL) {
printf("Couldn't allocate memory for GroundStruct\n");
exit(1);
}
gstruct->size++;
gstruct->fields = tmpPointer;
gstruct->fields[gstruct->size - 1].value = field;
strncpy(gstruct->fields[gstruct->size - 1].id, name, sizeof(gstruct->fields->id) - 1);
gstruct->fields[gstruct->size - 1].id[sizeof(gstruct->fields[gstruct->size - 1].id) - 1] = '\0';
}
void freeGroundStruct(GroundStruct* gstruct) {
for (size_t i = 0; i < gstruct->size; i++) {
freeGroundValue(&gstruct->fields[i].value);
}
}
void addFieldToObject(GroundObject* object, const char *id, GroundValue data) {
GroundObjectField* field = malloc(sizeof(GroundObjectField));
if (field == NULL) {
printf("Couldnt allocate stuff lmao\n");
exit(1);
}
strncpy(field->id, id, sizeof(field->id) - 1);
field->id[sizeof(field->id) - 1] = '\0';
field->value = copyGroundValue(&data);
HASH_ADD_STR(object->fields, id, field);
}
GroundObject createObject(GroundStruct gstruct) {
GroundObject object;
object.fields = NULL;
for (size_t i = 0; i < gstruct.size; i++) {
addFieldToObject(&object, gstruct.fields[i].id, gstruct.fields[i].value);
}
return object;
}
GroundObjectField* findField(GroundObject head, const char *id) {
GroundObjectField* s;
HASH_FIND_STR(head.fields, id, s);
return s;
}
void freeGroundObject(GroundObject* object) {
GroundObjectField *current_field, *tmp;
HASH_ITER(hh, object->fields, current_field, tmp) {
HASH_DEL(object->fields, current_field);
freeGroundValue(&current_field->value);
free(current_field);
}
object->fields = NULL;
}
2026-01-18 20:49:50 +11:00
GroundError createGroundError(char* what, char* type, GroundInstruction* where, size_t* line) {
GroundError ge;
if (what != NULL) {
ge.what = malloc(strlen(what) + 1);
strcpy(ge.what, what);
} else {
ge.what = NULL;
}
if (type != NULL) {
ge.type = malloc(strlen(type) + 1);
strcpy(ge.type, type);
} else {
2026-01-18 21:37:46 +11:00
ge.type = malloc(strlen("GenericError") + 1);
strcpy(ge.type, "GenericError");
2026-01-18 20:49:50 +11:00
}
if (where != NULL) {
ge.where = malloc(sizeof(GroundInstruction));
*ge.where = copyGroundInstruction(where);
} else {
ge.where = NULL;
}
if (line != NULL) {
ge.line = *line;
} else {
2026-01-18 21:37:46 +11:00
ge.line = 0;
ge.hasLine = false;
2026-01-18 20:49:50 +11:00
}
return ge;
}
2026-01-20 19:55:38 +11:00
bool checkFnTypes(GroundValue* left, GroundFunctionArgs* right) {
if (left->type != right->type) {
return false;
}
if (left->type == CUSTOM) {
if (left->customType->size != right->customType->size) {
return false;
}
for (size_t i = 0; i < left->customType->size; i++) {
if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) {
return false;
}
if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) {
return false;
}
}
}
return true;
}
bool checkTypes(GroundValue* left, GroundValue* right) {
if (left->type != right->type) {
return false;
}
if (left->type == CUSTOM) {
if (left->customType->size != right->customType->size) {
return false;
}
for (size_t i = 0; i < left->customType->size; i++) {
if (strcmp(left->customType->fields[i].id, right->customType->fields[i].id) != 0) {
return false;
}
if (!checkTypes(&left->customType->fields[i].value, &right->customType->fields[i].value)) {
return false;
}
}
}
return true;
}