Start working on functions
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user