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"); printf("ListError");
break; break;
} }
case STRING_ERROR: {
printf("StringError");
break;
}
case MATH_ERROR: {
printf("MathError");
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)");
@@ -99,27 +107,115 @@ void addVariable(GroundVariable **head, const char *id, GroundValue data) {
HASH_ADD_STR(*head, id, item); 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; GroundLabel* labels = NULL;
GroundVariable* variables = NULL; GroundVariable* variables = NULL;
GroundFunctionWrapper* functions = NULL;
GroundScope scope; GroundScope scope;
scope.labels = &labels; if (inScope != NULL) {
scope.variables = &variables; scope = *inScope;
} else {
scope.labels = &labels;
scope.variables = &variables;
scope.functions = &functions;
}
// Preprocess all labels // Preprocess all labels
for (int i = 0; i < in->size; i++) { for (int i = 0; i < in->size; i++) {
if (in->instructions[i].type == CREATELABEL) { if (in->instructions[i].type == CREATELABEL) {
addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); 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) { while (currentInstruction < in->size) {
interpretGroundInstruction(in->instructions[currentInstruction], &scope); interpretGroundInstruction(in->instructions[currentInstruction], &scope);
currentInstruction++; currentInstruction++;
} }
return createIntGroundValue(0);
} }
void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) { GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
GroundInstruction copied_inst = copyGroundInstruction(&inst); GroundInstruction copied_inst = copyGroundInstruction(&inst);
GroundInstruction* in = &copied_inst; GroundInstruction* in = &copied_inst;
@@ -137,7 +233,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
} }
} }
switch (in->type) { 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: { case CREATELABEL: {
break; break;
} }
@@ -310,6 +408,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("custom")); addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("custom"));
break; break;
} }
case NONE: {
addVariable(scope->variables, in->args.args[1].value.refName, createStringGroundValue("none"));
}
} }
break; 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); ListAccessStatus status = setListAt(&value->data.listVal, in->args.args[1].value.value.data.intVal, in->args.args[2].value.value);
switch (status) { switch (status) {
case LIST_OKAY: case LIST_OKAY:
return; break;
case LIST_OUT_OF_BOUNDS: case LIST_OUT_OF_BOUNDS:
runtimeError(LIST_ERROR, "Out of bounds index", in, currentInstruction); runtimeError(LIST_ERROR, "Out of bounds index", in, currentInstruction);
case LIST_FIXME: case LIST_FIXME:
@@ -571,9 +672,9 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
double result = 0; double result = 0;
if (left->type == INT) { if (left->type == INT) {
result -= left->data.intVal; result = left->data.intVal;
} else if (left->type == DOUBLE) { } else if (left->type == DOUBLE) {
result -= left->data.doubleVal; result = left->data.doubleVal;
} }
if (right->type == INT) { if (right->type == INT) {
@@ -618,7 +719,7 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
} }
if (left->type == DOUBLE || right->type == DOUBLE) { if (left->type == DOUBLE || right->type == DOUBLE) {
double result = 0; double result = 1.0;
if (left->type == INT) { if (left->type == INT) {
result *= left->data.intVal; result *= left->data.intVal;
@@ -668,16 +769,16 @@ void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope) {
} }
if (right->type == INT && right->data.intVal == 0) { if (right->type == INT && right->data.intVal == 0) {
runtimeError(MATH_ERROR, "Division by zero", in, currentInstruction);
} }
if (left->type == DOUBLE || right->type == DOUBLE) { if (left->type == DOUBLE || right->type == DOUBLE) {
double result = 0; double result = 0;
if (left->type == INT) { if (left->type == INT) {
result /= left->data.intVal; result = left->data.intVal;
} else if (left->type == DOUBLE) { } else if (left->type == DOUBLE) {
result /= left->data.doubleVal; result = left->data.doubleVal;
} }
if (right->type == INT) { 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); 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)); addVariable(scope->variables, in->args.args[1].value.refName, createBoolGroundValue(condition));
} }

View File

@@ -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, 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; } GroundRuntimeError;
typedef struct GroundLabel { typedef struct GroundLabel {
@@ -22,13 +22,32 @@ typedef struct GroundVariable {
UT_hash_handle hh; UT_hash_handle hh;
} GroundVariable; } 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 { typedef struct GroundScope {
GroundLabel** labels; GroundLabel** labels;
GroundVariable** variables; GroundVariable** variables;
GroundFunctionWrapper** functions;
} GroundScope; } GroundScope;
void interpretGroundProgram(GroundProgram* in); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);
void interpretGroundInstruction(GroundInstruction inst, GroundScope* scope); GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scope);
#endif #endif

View File

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

View File

@@ -12,7 +12,7 @@ typedef enum GroundInstType {
} GroundInstType; } GroundInstType;
typedef enum GroundValueType { typedef enum GroundValueType {
INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM, NONE
} GroundValueType; } GroundValueType;
typedef enum GroundArgType { typedef enum GroundArgType {

3
tests/function.grnd Normal file
View File

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