Function calling

This commit is contained in:
2025-12-06 11:50:42 +11:00
parent 571d3bcc34
commit 9553934db5
6 changed files with 100 additions and 39 deletions

View File

@@ -107,11 +107,11 @@ void addVariable(GroundVariable **head, const char *id, GroundValue data) {
HASH_ADD_STR(*head, id, item); HASH_ADD_STR(*head, id, item);
} }
GroundFunction createGroundFunction() { GroundFunction* createGroundFunction() {
GroundFunction gf; GroundFunction* gf = malloc(sizeof(GroundFunction));
gf.argSize = 0; gf->argSize = 0;
gf.args = malloc(sizeof(GroundFunctionArgs)); gf->args = malloc(sizeof(GroundFunctionArgs));
gf.program = createGroundProgram(); gf->program = createGroundProgram();
return gf; return gf;
} }
@@ -155,7 +155,6 @@ GroundValueType stringToValueType(char* in) {
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) { 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) { if (inScope != NULL) {
@@ -163,7 +162,6 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
} else { } 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++) {
@@ -171,21 +169,20 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
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) { if (in->instructions[i].type == FUN) {
char* functionName; GroundFunction* function = createGroundFunction();
GroundFunction function = createGroundFunction();
if (in->instructions[i].args.length < 1) { if (in->instructions[i].args.length < 1) {
runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i); runtimeError(TOO_FEW_ARGS, "Expecting 1 or more args", &in->instructions[i], i);
} }
if (in->instructions[i].args.args[0].type != FNREF) { if (in->instructions[i].args.args[0].type != FNREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 1", &in->instructions[i], i); 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) { if (in->instructions[i].args.length < 2) {
function.returnType = NONE; function->returnType = NONE;
} else { } else {
if (in->instructions[i].args.args[1].type != TYPEREF) { if (in->instructions[i].args.args[1].type != TYPEREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a TypeRef for arg 2", &in->instructions[i], i); 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; GroundArg* args = in->instructions[i].args.args;
size_t length = in->instructions[i].args.length; size_t length = in->instructions[i].args.length;
for (size_t j = 2; j < length; j += 2) { 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) { if (args[j + 1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef after a TypeRef", &in->instructions[i], i); 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++; i++;
while (in->instructions[i].type != ENDFUN) { while (in->instructions[i].type != ENDFUN) {
addInstructionToProgram(&function.program, in->instructions[i]); addInstructionToProgram(&function->program, in->instructions[i]);
i++; i++;
} }
if (&function->program.size == 0) {
addInstructionToProgram(&function->program, createGroundInstruction(PRINT));
}
addVariable(scope.variables, functionName, createFunctionGroundValue(function));
} }
} }
while (currentInstruction < in->size) { while (currentInstruction < in->size) {
@@ -1115,7 +1117,49 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
} }
break; 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); freeGroundInstruction(in);
return createIntGroundValue(0);
} }

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, 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; } GroundRuntimeError;
typedef struct GroundLabel { typedef struct GroundLabel {
@@ -22,28 +22,9 @@ 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;
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope); GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope);

View File

@@ -7,11 +7,6 @@
#include "types.h" #include "types.h"
#include "lexer.h" #include "lexer.h"
typedef struct GroundProgram {
GroundInstruction* instructions;
size_t size;
} GroundProgram;
// Creates a new GroundProgram // Creates a new GroundProgram
GroundProgram createGroundProgram(); GroundProgram createGroundProgram();

View File

@@ -44,6 +44,12 @@ GroundValue createListGroundValue(List in) {
return gv; return gv;
} }
GroundValue createFunctionGroundValue(GroundFunction* in) {
GroundValue gv;
gv.data.fnVal = in;
gv.type = FUNCTION;
return gv;
}
GroundValue copyGroundValue(const GroundValue* gv) { GroundValue copyGroundValue(const GroundValue* gv) {
GroundValue newGv; GroundValue newGv;
@@ -69,6 +75,7 @@ GroundValue copyGroundValue(const GroundValue* gv) {
newGv.data.listVal = newList; newGv.data.listVal = newList;
break; break;
} }
case FUNCTION: newGv.data.fnVal = gv->data.fnVal; break;
case CUSTOM: case CUSTOM:
newGv.data.customVal = gv->data.customVal; // Shallow copy for custom newGv.data.customVal = gv->data.customVal; // Shallow copy for custom
break; break;

View File

@@ -12,7 +12,7 @@ typedef enum GroundInstType {
} GroundInstType; } GroundInstType;
typedef enum GroundValueType { typedef enum GroundValueType {
INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM, NONE INT, DOUBLE, STRING, CHAR, BOOL, LIST, FUNCTION, CUSTOM, NONE
} GroundValueType; } GroundValueType;
typedef enum GroundArgType { typedef enum GroundArgType {
@@ -24,6 +24,7 @@ typedef enum ListAccessStatus {
} ListAccessStatus; } ListAccessStatus;
struct GroundValue; struct GroundValue;
struct GroundFunction;
struct List; struct List;
@@ -52,6 +53,7 @@ typedef struct GroundValue {
char charVal; char charVal;
bool boolVal; bool boolVal;
List listVal; List listVal;
struct GroundFunction* fnVal;
void* customVal; void* customVal;
} data; } data;
} GroundValue; } GroundValue;
@@ -92,6 +94,33 @@ typedef struct GroundInstruction {
} args; } args;
} GroundInstruction; } 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. // Creates a GroundValue containing (in), with type INT.
GroundValue createIntGroundValue(int64_t in); GroundValue createIntGroundValue(int64_t in);
@@ -110,6 +139,9 @@ GroundValue createBoolGroundValue(bool in);
// Creates a GroundValue containing (in), with type LIST. // Creates a GroundValue containing (in), with type LIST.
GroundValue createListGroundValue(List in); GroundValue createListGroundValue(List in);
// Creates a GroundValue conatining (in), with type FUNCTION.
GroundValue createFunctionGroundValue(GroundFunction* in);
// Creates a deep copy of a GroundValue // Creates a deep copy of a GroundValue
GroundValue copyGroundValue(const GroundValue* gv); GroundValue copyGroundValue(const GroundValue* gv);

View File

@@ -1,3 +1,5 @@
fun !dingus -string -int &x fun !dingus -string -int &x
endfun endfun
call !dingus &e