Function calling
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
34
src/types.h
34
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user