From c51bb82f621126438afc5d45544209ecc6d74607 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Fri, 16 Jan 2026 17:45:48 +1100 Subject: [PATCH 1/8] Continue struct parsing work --- src/interpreter.c | 37 ++++++++++++++++++++++++++++++++++++- src/interpreter.h | 3 ++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index f08d3af..2548776 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -234,6 +234,11 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio addVariable(scope->variables, name, createFunctionGroundValue(gf)); } +GroundStruct parseStruct(GroundProgram* in) { + GroundStruct gstruct = createStruct(); + return gstruct; +} + GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { GroundLabel* labels = NULL; GroundVariable* variables = NULL; @@ -246,7 +251,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { scope.labels = &labels; scope.variables = &variables; } - // Preprocess all labels and functions + // Preprocess all labels, structs and functions for (int i = 0; i < in->size; i++) { if (in->instructions[i].type == CREATELABEL) { addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); @@ -290,6 +295,36 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { } addVariable(scope.variables, functionName, createFunctionGroundValue(function)); } + if (in->instructions[i].type == STRUCT) { + if (in->instructions[i].args.length < 1) { + runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i); + } + if (in->instructions[i].args.length > 1) { + runtimeError(TOO_MANY_ARGS, "Expecting 1 arg", &in->instructions[i], i); + } + if (in->instructions[i].args.args[0].type != TYPEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expected arg 1 to be a typeref", &in->instructions[i], i); + } + char* name = in->instructions[i].args.args[0].value.refName; + i++; + + size_t counter = 1; + GroundProgram gp; + while (counter > 0) { + if (i >= in->size) { + runtimeError(PREMATURE_EOF, "Reached end of scope before struct definition ended", &in->instructions[i - 1], i - 1); + } + if (in->instructions[i].type == STRUCT) { + counter++; + } + if (in->instructions[i].type == ENDSTRUCT) { + counter--; + } + addInstructionToProgram(&gp, in->instructions[i]); + } + + GroundStruct gs = parseStruct(&gp); + } } for (int i = 0; i < in->size; i++) { if (in->instructions[i].type == FUN) { diff --git a/src/interpreter.h b/src/interpreter.h index b3a3db6..fd6f990 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -7,7 +7,7 @@ #include "include/uthash.h" typedef enum GroundRuntimeError { - ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME + ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, PREMATURE_EOF, FIXME } GroundRuntimeError; typedef enum GroundDebugInstructionType { @@ -36,6 +36,7 @@ typedef struct GroundDebugInstruction { char* arg; } GroundDebugInstruction; +GroundStruct parseStruct(GroundProgram* in); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); -- 2.47.3 From 96d7d9470a85a46f7b71559727fd4fb1b91451c6 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 12:21:43 +1100 Subject: [PATCH 2/8] Further struct work, fix lots of warnings --- src/interpreter.c | 65 +++++++++++++++++++++++++++++++++++++---------- src/interpreter.h | 6 +++-- src/types.c | 16 +++++++----- src/types.h | 4 +-- 4 files changed, 68 insertions(+), 23 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index 2548776..e904467 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -11,7 +11,7 @@ int currentInstruction = 0; -void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) { +[[noreturn]] void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where, int whereLine) { printf("Ground runtime error:\n ErrorType: "); switch (error) { case ARG_TYPE_MISMATCH: { @@ -46,6 +46,18 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where printf("MathError"); break; } + case RETURN_TYPE_MISMATCH: { + printf("ReturnTypeMismatch"); + break; + } + case PREMATURE_EOF: { + printf("PrematureEof"); + break; + } + case INVALID_INSTRUCTION: { + printf("InvalidInstruction"); + break; + } default: case FIXME: { printf("FIXME (please report issue to https://chsp.au/ground/cground)"); @@ -173,7 +185,7 @@ GroundDebugInstruction parseDebugInstruction(char* in) { } } - if (spacepos == -1) { + if (spacepos == (size_t) -1) { spacepos = insize; } @@ -234,8 +246,25 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio addVariable(scope->variables, name, createFunctionGroundValue(gf)); } -GroundStruct parseStruct(GroundProgram* in) { +GroundStruct parseStruct(GroundProgram* in, size_t errorOffset) { GroundStruct gstruct = createStruct(); + for (size_t i = 0; i < in->size; i++) { + switch (in->instructions[i].type) { + case SET: { + break; + } + case INIT: { + break; + } + case FUN: { + break; + } + default: { + runtimeError(INVALID_INSTRUCTION, "Unsupported instruction while inside struct", &in->instructions[i], errorOffset + i); + } + + } + } return gstruct; } @@ -252,7 +281,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { scope.variables = &variables; } // Preprocess all labels, structs and functions - for (int i = 0; i < in->size; i++) { + for (size_t i = 0; i < in->size; i++) { if (in->instructions[i].type == CREATELABEL) { addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); } @@ -309,7 +338,8 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { i++; size_t counter = 1; - GroundProgram gp; + GroundProgram gp = createGroundProgram(); + size_t errorOffset = i; while (counter > 0) { if (i >= in->size) { runtimeError(PREMATURE_EOF, "Reached end of scope before struct definition ended", &in->instructions[i - 1], i - 1); @@ -321,12 +351,13 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { counter--; } addInstructionToProgram(&gp, in->instructions[i]); + i++; } - GroundStruct gs = parseStruct(&gp); + GroundStruct gs = parseStruct(&gp, errorOffset); } } - for (int i = 0; i < in->size; i++) { + for (size_t i = 0; i < in->size; i++) { if (in->instructions[i].type == FUN) { int count = 1; while (count > 0) { @@ -463,7 +494,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop GroundInstruction* in = &copied_inst; // Insert variables prefixed with $ - for (int i = 0; i < in->args.length; i++) { + for (size_t i = 0; i < in->args.length; i++) { if (in->args.args[i].type == VALREF) { GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName); if (variable) { @@ -476,9 +507,11 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop } } switch (in->type) { - // We can safely ignore any CREATELABEL, FUN, and ENDFUN instructions, these have been preprocessed + // We can safely ignore these instructions, as they have been preprocessed case FUN: case ENDFUN: + case STRUCT: + case ENDSTRUCT: case CREATELABEL: { break; } @@ -551,7 +584,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction); } - for (int i = 0; i < in->args.length; i++) { + for (size_t i = 0; i < in->args.length; i++) { if (i != 0) printf(" "); printGroundArg(&in->args.args[i]); } @@ -561,7 +594,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", in, currentInstruction); } - for (int i = 0; i < in->args.length; i++) { + for (size_t i = 0; i < in->args.length; i++) { if (i != 0) printf(" "); printGroundArg(&in->args.args[i]); } @@ -653,9 +686,15 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop } case FUNCTION: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("function")); + break; + } + case STRUCTVAL: { + addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("struct")); + break; } case NONE: { addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none")); + break; } } @@ -690,7 +729,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction); } List newList = createList(); - for (int i = 1; i < in->args.length; i++) { + for (size_t 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); } @@ -1167,7 +1206,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); } char* str = in->args.args[0].value.value.data.stringVal; - int64_t idx = in->args.args[1].value.value.data.intVal; + size_t idx = in->args.args[1].value.value.data.intVal; if (idx < strlen(str)) { addVariable(scope->variables, in->args.args[2].value.refName, createCharGroundValue(str[idx])); } else { diff --git a/src/interpreter.h b/src/interpreter.h index fd6f990..83ce97e 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -7,7 +7,7 @@ #include "include/uthash.h" typedef enum GroundRuntimeError { - ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, PREMATURE_EOF, FIXME + ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, PREMATURE_EOF, INVALID_INSTRUCTION, FIXME } GroundRuntimeError; typedef enum GroundDebugInstructionType { @@ -36,9 +36,11 @@ typedef struct GroundDebugInstruction { char* arg; } GroundDebugInstruction; -GroundStruct parseStruct(GroundProgram* in); +GroundStruct parseStruct(GroundProgram* in, size_t errorOffset); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); + + #endif diff --git a/src/types.c b/src/types.c index 50271aa..d5b294f 100644 --- a/src/types.c +++ b/src/types.c @@ -74,7 +74,7 @@ GroundValue copyGroundValue(const GroundValue* gv) { break; case LIST: { List newList = createList(); - for (int i = 0; i < gv->data.listVal.size; i++) { + 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])); } @@ -93,6 +93,10 @@ GroundValue copyGroundValue(const GroundValue* gv) { // FIXME newGv.data.customVal = gv->data.customVal; break; + case NONE: + default: { + + } } return newGv; } @@ -125,7 +129,7 @@ void printGroundValue(GroundValue* gv) { } case LIST: { printf("["); - for (int i = 0; i < gv->data.listVal.size; i++) { + 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(", "); @@ -152,7 +156,7 @@ void freeGroundValue(GroundValue* gv) { } if (gv->type == LIST && gv->data.listVal.values != NULL) { List* list = &gv->data.listVal; - for (int i = 0; i < list->size; i++) { + for (size_t i = 0; i < list->size; i++) { freeGroundValue(&list->values[i]); } free(list->values); @@ -394,7 +398,7 @@ void printGroundInstruction(GroundInstruction* gi) { break; } if (gi->type != CREATELABEL) printf(" "); - for (int i = 0; i < gi->args.length; i++) { + 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]); @@ -428,7 +432,7 @@ void appendToList(List* list, GroundValue value) { list->values[list->size - 1] = value; } -ListAccess getListAt(List* list, int idx) { +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); @@ -446,7 +450,7 @@ ListAccess getListAt(List* list, int idx) { } } -ListAccessStatus setListAt(List* list, int idx, GroundValue value) { +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); diff --git a/src/types.h b/src/types.h index f5ac32e..b1803ee 100644 --- a/src/types.h +++ b/src/types.h @@ -234,10 +234,10 @@ void appendToList(List* list, GroundValue value); // Gets item at index (idx) from list (list). If there is an error, it // will be indicated in the status field. -ListAccess getListAt(List* list, int idx); +ListAccess getListAt(List* list, size_t idx); // Sets an item in list (list) at index (idx) to GroundValue (value). -ListAccessStatus setListAt(List* list, int idx, GroundValue value); +ListAccessStatus setListAt(List* list, size_t idx, GroundValue value); // Creates a Ground struct GroundStruct createStruct(); -- 2.47.3 From 100944cc1ecf28785e5007644f7a24e49267ba4e Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 19:58:21 +1100 Subject: [PATCH 3/8] init instruction, mroe struct stuff --- src/interpreter.c | 105 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index e904467..be2b232 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -251,6 +251,19 @@ GroundStruct parseStruct(GroundProgram* in, size_t errorOffset) { for (size_t i = 0; i < in->size; i++) { switch (in->instructions[i].type) { case SET: { + if (in->instructions[i].args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset); + } + if (in->instructions[i].args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset); + } + if (in->instructions[i].args.args[0].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &in->instructions[i], i + errorOffset); + } + if (in->instructions[i].args.args[1].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 2", &in->instructions[i], i + errorOffset); + } + addFieldToStruct(&gstruct, in->instructions[i].args.args[0].value.refName, in->instructions[i].args.args[1].value.value); break; } case INIT: { @@ -259,6 +272,9 @@ GroundStruct parseStruct(GroundProgram* in, size_t errorOffset) { case FUN: { break; } + case ENDSTRUCT: { + break; + } default: { runtimeError(INVALID_INSTRUCTION, "Unsupported instruction while inside struct", &in->instructions[i], errorOffset + i); } @@ -334,7 +350,8 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { if (in->instructions[i].args.args[0].type != TYPEREF) { runtimeError(ARG_TYPE_MISMATCH, "Expected arg 1 to be a typeref", &in->instructions[i], i); } - char* name = in->instructions[i].args.args[0].value.refName; + char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1); + strcpy(name, in->instructions[i].args.args[0].value.refName); i++; size_t counter = 1; @@ -354,7 +371,13 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { i++; } - GroundStruct gs = parseStruct(&gp, errorOffset); + GroundValue gv = { + .type = STRUCTVAL, + .data.structVal = malloc(sizeof(GroundStruct)) + }; + *gv.data.structVal = parseStruct(&gp, errorOffset); + + addVariable(scope.variables, name, gv); } } for (size_t i = 0; i < in->size; i++) { @@ -1702,6 +1725,84 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop break; } + case INIT: { + if (in->args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", in, currentInstruction); + } + if (in->args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", in, currentInstruction); + } + if (in->args.args[0].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", in, currentInstruction); + } + if (in->args.args[1].type != TYPEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", in, currentInstruction); + } + + GroundValue gv; + + switch (stringToValueType(in->args.args[0].value.refName)) { + case INT: { + gv = createIntGroundValue(0); + break; + } + case DOUBLE: { + gv = createDoubleGroundValue(0); + break; + } + case STRING: { + gv = createStringGroundValue(""); + break; + } + case CHAR: { + gv = createCharGroundValue('\0'); + break; + } + case BOOL: { + gv = createBoolGroundValue(false); + break; + } + case LIST: { + gv = createListGroundValue(createList()); + break; + } + case FUNCTION: { + gv = createFunctionGroundValue(createGroundFunction()); + break; + } + case STRUCTVAL: { + gv.type = STRUCTVAL; + gv.data.structVal = malloc(sizeof(GroundStruct)); + *gv.data.structVal = createStruct(); + break; + } + case CUSTOM: { + GroundVariable* var = findVariable(*scope->variables, in->args.args[1].value.refName); + if (var == NULL) { + runtimeError(UNKNOWN_VARIABLE, "Couldn't find the specified type", in, currentInstruction); + } + if (var->value.type != STRUCTVAL) { + runtimeError(ARG_TYPE_MISMATCH, "TypeRef does not reference a struct", in, currentInstruction); + } + GroundStruct* gstruct = var->value.data.structVal; + gv.type = CUSTOM; + gv.data.customVal = malloc(sizeof(GroundObject)); + *gv.data.customVal = createObject(*gstruct); + break; + } + case NONE: { + gv.type = NONE; + break; + } + default: { + runtimeError(FIXME, "Reached should-be-impossible state", in, currentInstruction); + break; + } + } + + break; + } + case DROP: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction); -- 2.47.3 From 1c5300d27e76c46b97ccb3368c377b5e436f8245 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 20:04:18 +1100 Subject: [PATCH 4/8] Struct init --- src/interpreter.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++- src/interpreter.h | 2 +- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index be2b232..bd89520 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -246,7 +246,7 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio addVariable(scope->variables, name, createFunctionGroundValue(gf)); } -GroundStruct parseStruct(GroundProgram* in, size_t errorOffset) { +GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset) { GroundStruct gstruct = createStruct(); for (size_t i = 0; i < in->size; i++) { switch (in->instructions[i].type) { @@ -267,6 +267,81 @@ GroundStruct parseStruct(GroundProgram* in, size_t errorOffset) { break; } case INIT: { + if (in->instructions[i].args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], currentInstruction); + } + if (in->instructions[i].args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &in->instructions[i], currentInstruction); + } + if (in->instructions[i].args.args[0].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 1", &in->instructions[i], currentInstruction); + } + if (in->instructions[i].args.args[1].type != TYPEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], currentInstruction); + } + + GroundValue gv; + + switch (stringToValueType(in->instructions[i].args.args[0].value.refName)) { + case INT: { + gv = createIntGroundValue(0); + break; + } + case DOUBLE: { + gv = createDoubleGroundValue(0); + break; + } + case STRING: { + gv = createStringGroundValue(""); + break; + } + case CHAR: { + gv = createCharGroundValue('\0'); + break; + } + case BOOL: { + gv = createBoolGroundValue(false); + break; + } + case LIST: { + gv = createListGroundValue(createList()); + break; + } + case FUNCTION: { + gv = createFunctionGroundValue(createGroundFunction()); + break; + } + case STRUCTVAL: { + gv.type = STRUCTVAL; + gv.data.structVal = malloc(sizeof(GroundStruct)); + *gv.data.structVal = createStruct(); + break; + } + case CUSTOM: { + GroundVariable* var = findVariable(*scope->variables, in->instructions[i].args.args[1].value.refName); + if (var == NULL) { + runtimeError(UNKNOWN_VARIABLE, "Couldn't find the specified type", &in->instructions[i], currentInstruction); + } + if (var->value.type != STRUCTVAL) { + runtimeError(ARG_TYPE_MISMATCH, "TypeRef does not reference a struct", &in->instructions[i], currentInstruction); + } + GroundStruct* gstruct = var->value.data.structVal; + gv.type = CUSTOM; + gv.data.customVal = malloc(sizeof(GroundObject)); + *gv.data.customVal = createObject(*gstruct); + break; + } + case NONE: { + gv.type = NONE; + break; + } + default: { + runtimeError(FIXME, "Reached should-be-impossible state", &in->instructions[i], currentInstruction); + break; + } + } + addFieldToStruct(&gstruct, in->instructions[i].args.args[0].value.refName, gv); + break; } case FUN: { @@ -1799,6 +1874,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop break; } } + addVariable(scope->variables, in->args.args[0].value.refName, gv); break; } diff --git a/src/interpreter.h b/src/interpreter.h index 83ce97e..72354d0 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -36,7 +36,7 @@ typedef struct GroundDebugInstruction { char* arg; } GroundDebugInstruction; -GroundStruct parseStruct(GroundProgram* in, size_t errorOffset); +GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); -- 2.47.3 From 46bfa7fbf0b83af4376e309623842768cacc2ff4 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 20:07:24 +1100 Subject: [PATCH 5/8] I forgot to add this lmao --- src/interpreter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter.c b/src/interpreter.c index bd89520..272a66b 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -450,7 +450,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { .type = STRUCTVAL, .data.structVal = malloc(sizeof(GroundStruct)) }; - *gv.data.structVal = parseStruct(&gp, errorOffset); + *gv.data.structVal = parseStruct(&gp, &scope, errorOffset); addVariable(scope.variables, name, gv); } -- 2.47.3 From 52e1e8d3d46044f57329d1a39073b83b664c59b8 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 20:30:14 +1100 Subject: [PATCH 6/8] Refactor function parsing --- src/interpreter.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++- src/interpreter.h | 1 + 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/interpreter.c b/src/interpreter.c index 272a66b..f613259 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -246,6 +246,41 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio addVariable(scope->variables, name, createFunctionGroundValue(gf)); } +GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset) { + GroundFunction* function = createGroundFunction(); + for (size_t i = 0; i < in->size; i++) { + if (in->instructions[i].args.length < 2) { + function->returnType = NONE; + } else { + if (in->instructions[i].args.args[1].type != TYPEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], errorOffset + i); + } + GroundArg* args = in->instructions[i].args.args; + function->returnType = stringToValueType(args[1].value.refName); + size_t length = in->instructions[i].args.length; + for (size_t j = 2; j < length; j += 2) { + if (args[j].type != TYPEREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef", &in->instructions[i], errorOffset + i); + } + if (j + 1 >= length) { + runtimeError(TOO_FEW_ARGS, "Expecting a DirectRef after a TypeRef", &in->instructions[i], errorOffset + i); + } + if (args[j + 1].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef after a TypeRef", &in->instructions[i], errorOffset + i); + } + addArgsToGroundFunction(function, stringToValueType(args[j].value.refName), args[j + 1].value.refName); + } + } + i++; + while (in->instructions[i].type != ENDFUN) { + addInstructionToProgram(&function->program, in->instructions[i]); + i++; + } + break; + } + return function; +} + GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset) { GroundStruct gstruct = createStruct(); for (size_t i = 0; i < in->size; i++) { @@ -385,6 +420,32 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { if (in->instructions[i].args.args[0].type != FNREF) { runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i); } + char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1); + strcpy(name, in->instructions[i].args.args[0].value.refName); + + size_t counter = 1; + GroundProgram gp = createGroundProgram(); + addInstructionToProgram(&gp, in->instructions[i]); + size_t errorOffset = i; + i++; + while (counter > 0) { + if (i >= in->size) { + runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1); + } + if (in->instructions[i].type == FUN) { + counter++; + } + if (in->instructions[i].type == ENDFUN) { + counter--; + } + addInstructionToProgram(&gp, in->instructions[i]); + i++; + } + + GroundValue gv = createFunctionGroundValue(parseFunction(&gp, errorOffset)); + + addVariable(scope.variables, name, gv); + /* char* functionName = in->instructions[i].args.args[0].value.refName; if (in->instructions[i].args.length < 2) { function->returnType = NONE; @@ -414,6 +475,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { i++; } addVariable(scope.variables, functionName, createFunctionGroundValue(function)); + */ } if (in->instructions[i].type == STRUCT) { if (in->instructions[i].args.length < 1) { @@ -1816,7 +1878,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop GroundValue gv; - switch (stringToValueType(in->args.args[0].value.refName)) { + switch (stringToValueType(in->args.args[1].value.refName)) { case INT: { gv = createIntGroundValue(0); break; diff --git a/src/interpreter.h b/src/interpreter.h index 72354d0..a2df833 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -37,6 +37,7 @@ typedef struct GroundDebugInstruction { } GroundDebugInstruction; GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset); +GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); -- 2.47.3 From 6b719dccbec69a5c30daf47455c0494c4669c42c Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sat, 17 Jan 2026 20:37:16 +1100 Subject: [PATCH 7/8] Fix bug for functions inside functions --- src/interpreter.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index f613259..e8def73 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -272,7 +272,7 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset) { } } i++; - while (in->instructions[i].type != ENDFUN) { + while (i < in->size) { addInstructionToProgram(&function->program, in->instructions[i]); i++; } @@ -445,37 +445,6 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { GroundValue gv = createFunctionGroundValue(parseFunction(&gp, errorOffset)); addVariable(scope.variables, name, gv); - /* - char* functionName = in->instructions[i].args.args[0].value.refName; - if (in->instructions[i].args.length < 2) { - function->returnType = NONE; - } else { - if (in->instructions[i].args.args[1].type != TYPEREF) { - runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], i); - } - GroundArg* args = in->instructions[i].args.args; - function->returnType = stringToValueType(args[1].value.refName); - size_t length = in->instructions[i].args.length; - for (size_t j = 2; j < length; j += 2) { - if (args[j].type != TYPEREF) { - runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef", &in->instructions[i], i); - } - if (j + 1 >= length) { - runtimeError(TOO_FEW_ARGS, "Expecting a DirectRef after a TypeRef", &in->instructions[i], i); - } - if (args[j + 1].type != DIRREF) { - runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef after a TypeRef", &in->instructions[i], i); - } - addArgsToGroundFunction(function, stringToValueType(args[j].value.refName), args[j + 1].value.refName); - } - } - i++; - while (in->instructions[i].type != ENDFUN) { - addInstructionToProgram(&function->program, in->instructions[i]); - i++; - } - addVariable(scope.variables, functionName, createFunctionGroundValue(function)); - */ } if (in->instructions[i].type == STRUCT) { if (in->instructions[i].args.length < 1) { -- 2.47.3 From 549eaedc04d8b6b767f9228d52b497c637d0bd1b Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sun, 18 Jan 2026 13:44:26 +1100 Subject: [PATCH 8/8] Function refactoring --- src/interpreter.c | 57 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/interpreter.c b/src/interpreter.c index e8def73..9b04845 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -380,6 +380,38 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs break; } case FUN: { + if (in->instructions[i].args.length < 1) { + runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i); + } + if (in->instructions[i].args.args[0].type != FNREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i); + } + char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1); + strcpy(name, in->instructions[i].args.args[0].value.refName); + + size_t counter = 1; + GroundProgram gp = createGroundProgram(); + addInstructionToProgram(&gp, in->instructions[i]); + size_t errorOffset = i; + i++; + while (counter > 0) { + if (i >= in->size) { + runtimeError(PREMATURE_EOF, "Reached end of scope before function definition ended", &in->instructions[i - 1], i - 1); + } + if (in->instructions[i].type == FUN) { + counter++; + } + if (in->instructions[i].type == ENDFUN) { + counter--; + } + addInstructionToProgram(&gp, in->instructions[i]); + i++; + } + + GroundFunction* function = parseFunction(&gp, errorOffset); + function->startLine = i; + GroundValue gv = createFunctionGroundValue(function); + addFieldToStruct(&gstruct, name, gv); break; } case ENDSTRUCT: { @@ -412,8 +444,6 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); } if (in->instructions[i].type == FUN) { - GroundFunction* function = createGroundFunction(); - function->startLine = i; if (in->instructions[i].args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i); } @@ -442,7 +472,9 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { i++; } - GroundValue gv = createFunctionGroundValue(parseFunction(&gp, errorOffset)); + GroundFunction* function = parseFunction(&gp, errorOffset); + function->startLine = i; + GroundValue gv = createFunctionGroundValue(function); addVariable(scope.variables, name, gv); } @@ -502,6 +534,21 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { } } } + if (in->instructions[i].type == STRUCT) { + int count = 1; + while (count > 0) { + i++; + if (i >= in->size) { + return createNoneGroundValue(); + } + if (in->instructions[i].type == STRUCT) { + count++; + } + if (in->instructions[i].type == ENDSTRUCT) { + count--; + } + } + } if (in->instructions[i].type == PAUSE || instructionsToPause == 0) { printf("Paused execution\n"); printf("Previous instruction: "); @@ -1873,7 +1920,9 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop break; } case FUNCTION: { - gv = createFunctionGroundValue(createGroundFunction()); + GroundFunction* gf = createGroundFunction(); + gf->returnType = NONE; + gv = createFunctionGroundValue(gf); break; } case STRUCTVAL: { -- 2.47.3