Start working on functions
This commit is contained in:
@@ -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;
|
||||||
|
if (inScope != NULL) {
|
||||||
|
scope = *inScope;
|
||||||
|
} else {
|
||||||
scope.labels = &labels;
|
scope.labels = &labels;
|
||||||
scope.variables = &variables;
|
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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
3
tests/function.grnd
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fun !dingus -string -int &x
|
||||||
|
|
||||||
|
endfun
|
||||||
Reference in New Issue
Block a user