Add lists (MEMORY ERRORS)
This commit is contained in:
@@ -30,6 +30,10 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where
|
|||||||
printf("UnknownVariable");
|
printf("UnknownVariable");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LIST_ERROR: {
|
||||||
|
printf("ListError");
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
case FIXME: {
|
case FIXME: {
|
||||||
printf("FIXME (please report issue to https://chsp.au/ground/cground)");
|
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) {
|
void addVariable(GroundVariable **head, const char *id, GroundValue data) {
|
||||||
GroundVariable* variable = findVariable(*head, id);
|
GroundVariable* variable = findVariable(*head, id);
|
||||||
if (variable) {
|
if (variable) {
|
||||||
|
freeGroundValue(&variable->value);
|
||||||
deleteVariable(head, variable);
|
deleteVariable(head, variable);
|
||||||
}
|
}
|
||||||
GroundVariable* item = malloc(sizeof(GroundVariable));
|
GroundVariable* item = malloc(sizeof(GroundVariable));
|
||||||
@@ -243,9 +248,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
|
|||||||
* VARIABLES AND LISTS
|
* VARIABLES AND LISTS
|
||||||
* These instructions are for initializing variables and lists.
|
* These instructions are for initializing variables and lists.
|
||||||
* Instructions:
|
* Instructions:
|
||||||
* set, gettype, exists
|
* set, gettype, exists, setlist, setlistat, getlistat, getlistsize, listappend
|
||||||
* WIP Instructions:
|
|
||||||
* setlist, setlistat, getlistat, getlistsize, listappend
|
|
||||||
*/
|
*/
|
||||||
case SET: {
|
case SET: {
|
||||||
if (in->args.length < 2) {
|
if (in->args.length < 2) {
|
||||||
@@ -333,6 +336,145 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
|
|||||||
|
|
||||||
break;
|
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
|
* MATHS
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "include/uthash.h"
|
#include "include/uthash.h"
|
||||||
|
|
||||||
typedef enum GroundRuntimeError {
|
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;
|
} GroundRuntimeError;
|
||||||
|
|
||||||
typedef struct GroundLabel {
|
typedef struct GroundLabel {
|
||||||
|
|||||||
29
src/types.c
29
src/types.c
@@ -37,6 +37,13 @@ GroundValue createBoolGroundValue(bool in) {
|
|||||||
return gv;
|
return gv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundValue createListGroundValue(List in) {
|
||||||
|
GroundValue gv;
|
||||||
|
gv.data.listVal = in;
|
||||||
|
gv.type = LIST;
|
||||||
|
return gv;
|
||||||
|
}
|
||||||
|
|
||||||
void printGroundValue(GroundValue* gv) {
|
void printGroundValue(GroundValue* gv) {
|
||||||
switch (gv->type) {
|
switch (gv->type) {
|
||||||
case INT: {
|
case INT: {
|
||||||
@@ -74,6 +81,13 @@ void freeGroundValue(GroundValue* gv) {
|
|||||||
if (gv->type == STRING && gv->data.stringVal != NULL) {
|
if (gv->type == STRING && gv->data.stringVal != NULL) {
|
||||||
free(gv->data.stringVal);
|
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) {
|
GroundArg createValueGroundArg(GroundValue value) {
|
||||||
@@ -159,6 +173,19 @@ GroundInstruction copyGroundInstruction(const GroundInstruction* inst) {
|
|||||||
if (inst->args.args[i].value.value.type == STRING) {
|
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);
|
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 {
|
} else {
|
||||||
newInst.args.args[i].value.refName = strdup(inst->args.args[i].value.refName);
|
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");
|
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);
|
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) {
|
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");
|
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);
|
exit(EXIT_FAILURE);
|
||||||
|
|||||||
25
src/types.h
25
src/types.h
@@ -27,6 +27,16 @@ struct GroundValue;
|
|||||||
|
|
||||||
struct List;
|
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.
|
* Stores literal values created in a Ground program.
|
||||||
* Associated functions:
|
* Associated functions:
|
||||||
@@ -41,21 +51,11 @@ typedef struct GroundValue {
|
|||||||
char* stringVal;
|
char* stringVal;
|
||||||
char charVal;
|
char charVal;
|
||||||
bool boolVal;
|
bool boolVal;
|
||||||
struct List* listVal;
|
List listVal;
|
||||||
void* customVal;
|
void* customVal;
|
||||||
} data;
|
} data;
|
||||||
} GroundValue;
|
} 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.
|
* Indicates status when accessing a list.
|
||||||
* Associated functions:
|
* Associated functions:
|
||||||
@@ -107,6 +107,9 @@ GroundValue createCharGroundValue(char in);
|
|||||||
// Creates a GroundValue containing (in), with type BOOl.
|
// Creates a GroundValue containing (in), with type BOOl.
|
||||||
GroundValue createBoolGroundValue(bool in);
|
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.
|
// If (gv) contains any data stored on the heap, frees it.
|
||||||
void freeGroundValue(GroundValue* gv);
|
void freeGroundValue(GroundValue* gv);
|
||||||
|
|
||||||
|
|||||||
14
tests/list.grnd
Normal file
14
tests/list.grnd
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# A cool list
|
||||||
|
setlist &favWords "hello" "there" "general" "kenobi"
|
||||||
|
println $favWords
|
||||||
|
|
||||||
|
set &count 0
|
||||||
|
set &passedThrough true
|
||||||
|
|
||||||
|
@jmpbck
|
||||||
|
getlistat &favWords $count &tmp
|
||||||
|
println $tmp
|
||||||
|
add $count 1 &count
|
||||||
|
getlistsize &favWords &tmp2
|
||||||
|
inequal $count $tmp2 &tmp3
|
||||||
|
if $tmp3 %jmpbck
|
||||||
Reference in New Issue
Block a user