forked from ground/cground
585 lines
15 KiB
C
585 lines
15 KiB
C
#include "types.h"
|
|
#include <inttypes.h>
|
|
#include <stdlib.h>
|
|
|
|
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 createErrorGroundValue(GroundError in) {
|
|
GroundValue gv;
|
|
gv.data.errorVal = in;
|
|
gv.type = ERROR;
|
|
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 (size_t 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 STRUCTVAL: {
|
|
// do this later lmao
|
|
// FIXME
|
|
newGv.data.structVal = gv->data.structVal;
|
|
break;
|
|
}
|
|
case CUSTOM:
|
|
// also do this later
|
|
// FIXME
|
|
newGv.data.customVal = gv->data.customVal;
|
|
break;
|
|
case NONE:
|
|
default: {
|
|
|
|
}
|
|
}
|
|
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 (size_t 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("<function>");
|
|
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 (size_t i = 0; i < list->size; i++) {
|
|
freeGroundValue(&list->values[i]);
|
|
}
|
|
free(list->values);
|
|
list->values = NULL;
|
|
gv->data.listVal = createList();
|
|
}
|
|
if (gv->type == STRUCTVAL && gv->data.structVal->fields != NULL) {
|
|
GroundStruct* gstruct = gv->data.structVal;
|
|
freeGroundStruct(gstruct);
|
|
free(gstruct);
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 DROP:
|
|
printf("drop");
|
|
break;
|
|
case CREATELABEL:
|
|
break;
|
|
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]);
|
|
}
|
|
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, size_t 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, size_t 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;
|
|
}
|
|
}
|
|
|
|
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(¤t_field->value);
|
|
free(current_field);
|
|
}
|
|
object->fields = NULL;
|
|
}
|
|
|
|
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 {
|
|
ge.type = malloc(strlen("GenericError") + 1);
|
|
strcpy(ge.type, "GenericError");
|
|
}
|
|
|
|
if (where != NULL) {
|
|
ge.where = malloc(sizeof(GroundInstruction));
|
|
*ge.where = copyGroundInstruction(where);
|
|
} else {
|
|
ge.where = NULL;
|
|
}
|
|
|
|
if (line != NULL) {
|
|
ge.line = *line;
|
|
} else {
|
|
ge.line = 0;
|
|
ge.hasLine = false;
|
|
}
|
|
|
|
return ge;
|
|
}
|