Add lists (MEMORY ERRORS)
This commit is contained in:
@@ -30,6 +30,10 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where
|
||||
printf("UnknownVariable");
|
||||
break;
|
||||
}
|
||||
case LIST_ERROR: {
|
||||
printf("ListError");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case FIXME: {
|
||||
printf("FIXME (please report issue to https://chsp.au/ground/cground)");
|
||||
@@ -86,6 +90,7 @@ void deleteVariable(GroundVariable** head, GroundVariable *item) {
|
||||
void addVariable(GroundVariable **head, const char *id, GroundValue data) {
|
||||
GroundVariable* variable = findVariable(*head, id);
|
||||
if (variable) {
|
||||
freeGroundValue(&variable->value);
|
||||
deleteVariable(head, variable);
|
||||
}
|
||||
GroundVariable* item = malloc(sizeof(GroundVariable));
|
||||
@@ -243,9 +248,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
|
||||
* VARIABLES AND LISTS
|
||||
* These instructions are for initializing variables and lists.
|
||||
* Instructions:
|
||||
* set, gettype, exists
|
||||
* WIP Instructions:
|
||||
* setlist, setlistat, getlistat, getlistsize, listappend
|
||||
* set, gettype, exists, setlist, setlistat, getlistat, getlistsize, listappend
|
||||
*/
|
||||
case SET: {
|
||||
if (in->args.length < 2) {
|
||||
@@ -333,6 +336,145 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
|
||||
|
||||
break;
|
||||
}
|
||||
case SETLIST: {
|
||||
if (in->args.length < 1) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction);
|
||||
}
|
||||
List newList = createList();
|
||||
for (int i = 1; i < in->args.length; i++) {
|
||||
if (in->args.args[i].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for all args after arg 1", in, currentInstruction);
|
||||
}
|
||||
appendToList(&newList, in->args.args[i].value.value);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[0].value.refName, createListGroundValue(newList));
|
||||
break;
|
||||
}
|
||||
case SETLISTAT: {
|
||||
if (in->args.length < 3) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != VALUE && in->args.args[1].value.value.type != INT) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int value for arg 2", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[2].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 3", in, currentInstruction);
|
||||
}
|
||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||
if (var == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
||||
}
|
||||
GroundValue* value = &var->value;
|
||||
if (value == NULL) {
|
||||
runtimeError(FIXME, NULL, in, currentInstruction);
|
||||
}
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
ListAccessStatus status = setListAt(&value->data.listVal, in->args.args[1].value.value.data.intVal, in->args.args[2].value.value);
|
||||
switch (status) {
|
||||
case LIST_OKAY:
|
||||
return;
|
||||
case LIST_OUT_OF_BOUNDS:
|
||||
runtimeError(LIST_ERROR, "Out of bounds index", in, currentInstruction);
|
||||
case LIST_FIXME:
|
||||
default:
|
||||
runtimeError(FIXME, "List related error", in, currentInstruction);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GETLISTAT: {
|
||||
if (in->args.length < 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != VALUE && in->args.args[1].value.value.type != INT) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting an integer value for arg 2", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[2].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 3", in, currentInstruction);
|
||||
}
|
||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||
if (var == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
||||
}
|
||||
GroundValue* value = &var->value;
|
||||
if (value == NULL) {
|
||||
runtimeError(FIXME, NULL, in, currentInstruction);
|
||||
}
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
ListAccess status = getListAt(&value->data.listVal, in->args.args[1].value.value.data.intVal);
|
||||
switch (status.status) {
|
||||
case LIST_OKAY: {
|
||||
addVariable(scope->variables, in->args.args[2].value.refName, *status.value);
|
||||
break;
|
||||
}
|
||||
case LIST_OUT_OF_BOUNDS:
|
||||
runtimeError(LIST_ERROR, "Out of bounds index", in, currentInstruction);
|
||||
case LIST_FIXME:
|
||||
default:
|
||||
runtimeError(FIXME, "List related error", in, currentInstruction);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GETLISTSIZE: {
|
||||
if (in->args.length < 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
|
||||
}
|
||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||
if (var == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
||||
}
|
||||
GroundValue* value = &var->value;
|
||||
if (value == NULL) {
|
||||
runtimeError(FIXME, NULL, in, currentInstruction);
|
||||
}
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
addVariable(scope->variables, in->args.args[1].value.refName, createIntGroundValue(value->data.listVal.size));
|
||||
break;
|
||||
}
|
||||
case LISTAPPEND: {
|
||||
if (in->args.length < 2) {
|
||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[0].type != DIRREF) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
if (in->args.args[1].type != VALUE) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", in, currentInstruction);
|
||||
}
|
||||
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
|
||||
if (var == NULL) {
|
||||
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
||||
}
|
||||
GroundValue* value = &var->value;
|
||||
if (value == NULL) {
|
||||
runtimeError(FIXME, NULL, in, currentInstruction);
|
||||
}
|
||||
if (value->type != LIST) {
|
||||
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to a List for arg 1", in, currentInstruction);
|
||||
}
|
||||
appendToList(&value->data.listVal, in->args.args[1].value.value);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* MATHS
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "include/uthash.h"
|
||||
|
||||
typedef enum GroundRuntimeError {
|
||||
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, FIXME
|
||||
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, FIXME
|
||||
} GroundRuntimeError;
|
||||
|
||||
typedef struct GroundLabel {
|
||||
|
||||
29
src/types.c
29
src/types.c
@@ -37,6 +37,13 @@ GroundValue createBoolGroundValue(bool in) {
|
||||
return gv;
|
||||
}
|
||||
|
||||
GroundValue createListGroundValue(List in) {
|
||||
GroundValue gv;
|
||||
gv.data.listVal = in;
|
||||
gv.type = LIST;
|
||||
return gv;
|
||||
}
|
||||
|
||||
void printGroundValue(GroundValue* gv) {
|
||||
switch (gv->type) {
|
||||
case INT: {
|
||||
@@ -74,6 +81,13 @@ void freeGroundValue(GroundValue* gv) {
|
||||
if (gv->type == STRING && gv->data.stringVal != NULL) {
|
||||
free(gv->data.stringVal);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
GroundArg createValueGroundArg(GroundValue value) {
|
||||
@@ -159,6 +173,19 @@ GroundInstruction copyGroundInstruction(const GroundInstruction* inst) {
|
||||
if (inst->args.args[i].value.value.type == STRING) {
|
||||
newInst.args.args[i].value.value.data.stringVal = strdup(inst->args.args[i].value.value.data.stringVal);
|
||||
}
|
||||
if (inst->args.args[i].value.value.type == LIST) {
|
||||
List* origList = &inst->args.args[i].value.value.data.listVal;
|
||||
List newList = createList();
|
||||
for (int j = 0; j < origList->size; j++) {
|
||||
GroundValue copiedValue = origList->values[j];
|
||||
if (copiedValue.type == STRING) {
|
||||
copiedValue.data.stringVal = strdup(copiedValue.data.stringVal);
|
||||
}
|
||||
// Note: this doesn't handle nested lists - you'd need full recursion for that
|
||||
appendToList(&newList, copiedValue);
|
||||
}
|
||||
newInst.args.args[i].value.value.data.listVal = newList;
|
||||
}
|
||||
} else {
|
||||
newInst.args.args[i].value.refName = strdup(inst->args.args[i].value.refName);
|
||||
}
|
||||
@@ -323,7 +350,7 @@ void appendToList(List* list, GroundValue value) {
|
||||
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, (list->size + 1) * sizeof(GroundValue));
|
||||
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);
|
||||
|
||||
25
src/types.h
25
src/types.h
@@ -27,6 +27,16 @@ struct GroundValue;
|
||||
|
||||
struct List;
|
||||
|
||||
/*
|
||||
* Custom data type that stores Ground values.
|
||||
* Associated functions:
|
||||
* createList(), appendToList(), getListAt(), setListAt()
|
||||
*/
|
||||
typedef struct List {
|
||||
size_t size;
|
||||
struct GroundValue* values;
|
||||
} List;
|
||||
|
||||
/*
|
||||
* Stores literal values created in a Ground program.
|
||||
* Associated functions:
|
||||
@@ -41,21 +51,11 @@ typedef struct GroundValue {
|
||||
char* stringVal;
|
||||
char charVal;
|
||||
bool boolVal;
|
||||
struct List* listVal;
|
||||
List listVal;
|
||||
void* customVal;
|
||||
} data;
|
||||
} GroundValue;
|
||||
|
||||
/*
|
||||
* Custom data type that stores Ground values.
|
||||
* Associated functions:
|
||||
* createList(), appendToList(), getListAt(), setListAt()
|
||||
*/
|
||||
typedef struct List {
|
||||
size_t size;
|
||||
GroundValue* values;
|
||||
} List;
|
||||
|
||||
/*
|
||||
* Indicates status when accessing a list.
|
||||
* Associated functions:
|
||||
@@ -107,6 +107,9 @@ GroundValue createCharGroundValue(char in);
|
||||
// Creates a GroundValue containing (in), with type BOOl.
|
||||
GroundValue createBoolGroundValue(bool in);
|
||||
|
||||
// Creates a GroundValue containing (in), with type LIST.
|
||||
GroundValue createListGroundValue(List in);
|
||||
|
||||
// If (gv) contains any data stored on the heap, frees it.
|
||||
void freeGroundValue(GroundValue* gv);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user