#include "types.h" #include #include 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; } GroundValue createListGroundValue(List in) { GroundValue gv; gv.data.listVal = in; gv.type = LIST; return gv; } GroundValue createFunctionGroundValue(GroundFunction* in) { GroundValue gv; gv.data.fnVal = in; gv.type = FUNCTION; return gv; } GroundValue createNoneGroundValue() { GroundValue gv; gv.type = NONE; return gv; } 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 (int i = 0; i < gv->data.listVal.size; i++) { // Recursive call to handle nested lists and other types appendToList(&newList, copyGroundValue(&gv->data.listVal.values[i])); } newGv.data.listVal = newList; break; } case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break; case CUSTOM: newGv.data.customVal = gv->data.customVal; // Shallow copy for custom break; } return newGv; } 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; } case LIST: { printf("["); for (int i = 0; i < gv->data.listVal.size; i++) { printGroundValue(&gv->data.listVal.values[i]); if (i < gv->data.listVal.size - 1) { printf(", "); } } printf("]"); break; } case FUNCTION: { printf(""); break; } default: { printf("FIXME"); break; } } } void freeGroundValue(GroundValue* gv) { if (gv->type == STRING && gv->data.stringVal != NULL) { free(gv->data.stringVal); gv->data.stringVal = NULL; } if (gv->type == LIST && gv->data.listVal.values != NULL) { List* list = &gv->data.listVal; for (int i = 0; i < list->size; i++) { freeGroundValue(&list->values[i]); } free(list->values); list->values = NULL; gv->data.listVal = createList(); } } 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); } } 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; } } } 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]); } free(gi->args.args); } 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) { newInst.args.args[i].value.value = copyGroundValue(&inst->args.args[i].value.value); } else { newInst.args.args[i].value.refName = strdup(inst->args.args[i].value.refName); } } } else { newInst.args.args = NULL; } return newInst; } 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; } 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; 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 CREATELABEL: break; default: printf("FIXME"); break; } if (gi->type != CREATELABEL) printf(" "); for (int 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]); } printf(" "); } } 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); } GroundValue* ptr = realloc(list->values, (list->size + 1) * sizeof(GroundValue)); 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, int idx) { 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, int idx, 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); } if (idx < list->size) { list->values[idx] = value; return LIST_OKAY; } else { return LIST_OUT_OF_BOUNDS; } }