Start working on functions

This commit is contained in:
2025-12-02 09:00:21 +11:00
parent 6d782d65b7
commit 571d3bcc34
5 changed files with 143 additions and 20 deletions

View File

@@ -34,6 +34,14 @@ void runtimeError(GroundRuntimeError error, char* what, GroundInstruction* where
printf("ListError");
break;
}
case STRING_ERROR: {
printf("StringError");
break;
}
case MATH_ERROR: {
printf("MathError");
break;
}
default:
case FIXME: {
printf("FIXME (please report issue to https://chsp.au/ground/cground)");
@@ -99,27 +107,115 @@ void addVariable(GroundVariable **head, const char *id, GroundValue data) {
HASH_ADD_STR(*head, id, item);
}
void interpretGroundProgram(GroundProgram* in) {
GroundFunction createGroundFunction() {
GroundFunction gf;
gf.argSize = 0;
gf.args = malloc(sizeof(GroundFunctionArgs));
gf.program = createGroundProgram();
return gf;
}
void addArgsToGroundFunction(GroundFunction* function, GroundValueType type, char* name) {
GroundFunctionArgs arg;
arg.type = type;
arg.name = name;
function->argSize ++;
GroundFunctionArgs* ptr = realloc(function->args, function->argSize * sizeof(GroundFunctionArgs));
if (ptr == NULL) {
printf("Failed to allocate memory for arg of GroundFunction");
function->argSize --;
return;
}
function->args = ptr;
function->args[function->argSize - 1] = arg;
};
GroundValueType stringToValueType(char* in) {
if (strcmp(in, "int") == 0) {
return INT;
}
if (strcmp(in, "double") == 0) {
return DOUBLE;
}
if (strcmp(in, "bool") == 0) {
return BOOL;
}
if (strcmp(in, "string") == 0) {
return STRING;
}
if (strcmp(in, "char") == 0) {
return CHAR;
}
if (strcmp(in, "list") == 0) {
return LIST;
}
return CUSTOM;
}
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
GroundLabel* labels = NULL;
GroundVariable* variables = NULL;
GroundFunctionWrapper* functions = NULL;
GroundScope scope;
scope.labels = &labels;
scope.variables = &variables;
if (inScope != NULL) {
scope = *inScope;
} else {
scope.labels = &labels;
scope.variables = &variables;
scope.functions = &functions;
}
// Preprocess all labels
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);
}
if (in->instructions[i].type == FUN) {
char* functionName;
GroundFunction function = createGroundFunction();
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);
}
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);
}
functionName = in->instructions[i].args.args[0].value.refName;
GroundArg* args = in->instructions[i].args.args;
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++;
}
}
}
while (currentInstruction < in->size) {
interpretGroundInstruction(in->instructions[currentInstruction], &scope);
currentInstruction++;
}
return createIntGroundValue(0);
}
void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
GroundInstruction copied_inst = copyGroundInstruction(&inst);
GroundInstruction* in = &copied_inst;
@@ -137,7 +233,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
}
}
switch (in->type) {
// We can safely ignore any CREATELABEL instructions, these have been preprocessed
// We can safely ignore any CREATELABEL, FUN, and ENDFUN instructions, these have been preprocessed
case FUN:
case ENDFUN:
case CREATELABEL: {
break;
}
@@ -310,6 +408,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("custom"));
break;
}
case NONE: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none"));
}
}
break;
@@ -380,7 +481,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
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;
break;
case LIST_OUT_OF_BOUNDS:
runtimeError(LIST_ERROR, "Out of bounds index", in, currentInstruction);
case LIST_FIXME:
@@ -571,9 +672,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
double result = 0;
if (left->type == INT) {
result -= left->data.intVal;
result = left->data.intVal;
} else if (left->type == DOUBLE) {
result -= left->data.doubleVal;
result = left->data.doubleVal;
}
if (right->type == INT) {
@@ -618,7 +719,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
}
if (left->type == DOUBLE || right->type == DOUBLE) {
double result = 0;
double result = 1.0;
if (left->type == INT) {
result *= left->data.intVal;
@@ -668,16 +769,16 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
}
if (right->type == INT && right->data.intVal == 0) {
runtimeError(MATH_ERROR, "Division by zero", in, currentInstruction);
}
if (left->type == DOUBLE || right->type == DOUBLE) {
double result = 0;
if (left->type == INT) {
result /= left->data.intVal;
result = left->data.intVal;
} else if (left->type == DOUBLE) {
result /= left->data.doubleVal;
result = left->data.doubleVal;
}
if (right->type == INT) {
@@ -895,7 +996,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
bool condition = !in->args.args[1].value.value.data.boolVal;
bool condition = !in->args.args[0].value.value.data.boolVal;
addVariable(scope->variables, in->args.args[1].value.refName, createBoolGroundValue(condition));
}

View File

@@ -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, FIXME
ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, FIXME
} GroundRuntimeError;
typedef struct GroundLabel {
@@ -22,13 +22,32 @@ typedef struct GroundVariable {
UT_hash_handle hh;
} GroundVariable;
typedef struct GroundFunctionArgs {
GroundValueType type;
char* name;
} GroundFunctionArgs;
typedef struct GroundFunction {
GroundFunctionArgs* args;
size_t argSize;
GroundValueType returnType;
GroundProgram program;
} GroundFunction;
typedef struct GroundFunctionWrapper {
char id[MAX_ID_LEN];
GroundFunction function;
UT_hash_handle hh;
} GroundFunctionWrapper;
typedef struct GroundScope {
GroundLabel** labels;
GroundVariable** variables;
GroundFunctionWrapper** functions;
} GroundScope;
void interpretGroundProgram(GroundProgram* in);
void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
#endif

View File

@@ -46,5 +46,5 @@ int main(int argc, char** argv) {
char* file = getFileContents(argv[1]);
GroundProgram program = parseFile(file);
free(file);
interpretGroundProgram(&program);
interpretGroundProgram(&program, NULL);
}

View File

@@ -12,7 +12,7 @@ typedef enum GroundInstType {
} GroundInstType;
typedef enum GroundValueType {
INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM
INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM, NONE
} GroundValueType;
typedef enum GroundArgType {
@@ -159,4 +159,4 @@ ListAccess getListAt(List* list, int idx);
// Sets an item in list (list) at index (idx) to GroundValue (value).
ListAccessStatus setListAt(List* list, int idx, GroundValue value);
#endif
#endif

3
tests/function.grnd Normal file
View File

@@ -0,0 +1,3 @@
fun !dingus -string -int &x
endfun