diff --git a/src/interpreter.c b/src/interpreter.c index 8f686d0..653833a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -107,11 +107,11 @@ void addVariable(GroundVariable **head, const char *id, GroundValue data) { HASH_ADD_STR(*head, id, item); } -GroundFunction createGroundFunction() { - GroundFunction gf; - gf.argSize = 0; - gf.args = malloc(sizeof(GroundFunctionArgs)); - gf.program = createGroundProgram(); +GroundFunction* createGroundFunction() { + GroundFunction* gf = malloc(sizeof(GroundFunction)); + gf->argSize = 0; + gf->args = malloc(sizeof(GroundFunctionArgs)); + gf->program = createGroundProgram(); return gf; } @@ -155,7 +155,6 @@ GroundValueType stringToValueType(char* in) { GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { GroundLabel* labels = NULL; GroundVariable* variables = NULL; - GroundFunctionWrapper* functions = NULL; GroundScope scope; if (inScope != NULL) { @@ -163,7 +162,6 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { } else { scope.labels = &labels; scope.variables = &variables; - scope.functions = &functions; } // Preprocess all labels for (int i = 0; i < in->size; i++) { @@ -171,21 +169,20 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { addLabel(scope.labels, in->instructions[i].args.args[0].value.refName, i); } if (in->instructions[i].type == FUN) { - char* functionName; - GroundFunction function = createGroundFunction(); + 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); } + char* functionName = in->instructions[i].args.args[0].value.refName; if (in->instructions[i].args.length < 2) { - function.returnType = NONE; + 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) { @@ -198,14 +195,19 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { 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); + 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]); + addInstructionToProgram(&function->program, in->instructions[i]); i++; } + if (&function->program.size == 0) { + addInstructionToProgram(&function->program, createGroundInstruction(PRINT)); + } + addVariable(scope.variables, functionName, createFunctionGroundValue(function)); + } } while (currentInstruction < in->size) { @@ -1115,7 +1117,49 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop } break; } + /* + * FUNCTIONS + * Allows execution of functions in Ground. + * Instructions: + * fun, return, endfun, pusharg, call + */ + case RETURN: { + break; + } + case CALL: { + 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 != FNREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", in, currentInstruction); + } + if (in->args.args[1].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); + } + GroundVariable* variables = NULL; + GroundLabel* labels = NULL; + GroundScope newScope; + newScope.variables = &variables; + newScope.labels = &labels; + GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName); + if (var == NULL) { + runtimeError(UNKNOWN_VARIABLE, "Function not found", in, currentInstruction); + } + GroundValue* value = &var->value; + if (value->type != FUNCTION) { + runtimeError(UNKNOWN_VARIABLE, "Provided reference does not reference a function", in, currentInstruction); + } + GroundFunction* function = value->data.fnVal; + GroundValue returnValue = interpretGroundProgram(&function->program, &newScope); + if (returnValue.type != function->returnType) { + runtimeError(RETURN_TYPE_MISMATCH, "Unexpected return value type from function", in, currentInstruction); + } + } } freeGroundInstruction(in); + return createIntGroundValue(0); } diff --git a/src/interpreter.h b/src/interpreter.h index 7509550..32b700f 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, FIXME + ARG_TYPE_MISMATCH, TOO_FEW_ARGS, TOO_MANY_ARGS, UNKNOWN_LABEL, UNKNOWN_VARIABLE, LIST_ERROR, STRING_ERROR, MATH_ERROR, RETURN_TYPE_MISMATCH, FIXME } GroundRuntimeError; typedef struct GroundLabel { @@ -22,28 +22,9 @@ 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; GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); diff --git a/src/parser.h b/src/parser.h index 083386f..3ba699d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -7,11 +7,6 @@ #include "types.h" #include "lexer.h" -typedef struct GroundProgram { - GroundInstruction* instructions; - size_t size; -} GroundProgram; - // Creates a new GroundProgram GroundProgram createGroundProgram(); diff --git a/src/types.c b/src/types.c index a389f43..8e6bdfd 100644 --- a/src/types.c +++ b/src/types.c @@ -44,6 +44,12 @@ GroundValue createListGroundValue(List in) { return gv; } +GroundValue createFunctionGroundValue(GroundFunction* in) { + GroundValue gv; + gv.data.fnVal = in; + gv.type = FUNCTION; + return gv; +} GroundValue copyGroundValue(const GroundValue* gv) { GroundValue newGv; @@ -69,6 +75,7 @@ GroundValue copyGroundValue(const GroundValue* gv) { newGv.data.listVal = newList; break; } + case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break; case CUSTOM: newGv.data.customVal = gv->data.customVal; // Shallow copy for custom break; diff --git a/src/types.h b/src/types.h index 31ceff4..2cdd6b8 100644 --- a/src/types.h +++ b/src/types.h @@ -12,7 +12,7 @@ typedef enum GroundInstType { } GroundInstType; typedef enum GroundValueType { - INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM, NONE + INT, DOUBLE, STRING, CHAR, BOOL, LIST, FUNCTION, CUSTOM, NONE } GroundValueType; typedef enum GroundArgType { @@ -24,6 +24,7 @@ typedef enum ListAccessStatus { } ListAccessStatus; struct GroundValue; +struct GroundFunction; struct List; @@ -52,6 +53,7 @@ typedef struct GroundValue { char charVal; bool boolVal; List listVal; + struct GroundFunction* fnVal; void* customVal; } data; } GroundValue; @@ -92,6 +94,33 @@ typedef struct GroundInstruction { } args; } GroundInstruction; +/* + * Represents a Ground program or function. + */ +typedef struct GroundProgram { + GroundInstruction* instructions; + size_t size; +} GroundProgram; + +/* + * Represents the argument typing for a GroundFunction. + */ +typedef struct GroundFunctionArgs { + GroundValueType type; + char* name; +} GroundFunctionArgs; + +/* + * Represents a Ground function. + */ +typedef struct GroundFunction { + GroundFunctionArgs* args; + size_t argSize; + GroundValueType returnType; + GroundProgram program; +} GroundFunction; + + // Creates a GroundValue containing (in), with type INT. GroundValue createIntGroundValue(int64_t in); @@ -110,6 +139,9 @@ GroundValue createBoolGroundValue(bool in); // Creates a GroundValue containing (in), with type LIST. GroundValue createListGroundValue(List in); +// Creates a GroundValue conatining (in), with type FUNCTION. +GroundValue createFunctionGroundValue(GroundFunction* in); + // Creates a deep copy of a GroundValue GroundValue copyGroundValue(const GroundValue* gv); diff --git a/tests/function.grnd b/tests/function.grnd index 71f3e89..bc98f01 100644 --- a/tests/function.grnd +++ b/tests/function.grnd @@ -1,3 +1,5 @@ fun !dingus -string -int &x endfun + +call !dingus &e