forked from ground/ground
refactor to facilitate solstice stuff
This commit is contained in:
@@ -25,7 +25,7 @@ char* getFileContents(const char* filename) {
|
|||||||
file = calloc(1, lSize + 1);
|
file = calloc(1, lSize + 1);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
fputs("memory allocation fail when reading file", stderr);
|
fprintf(stderr, "memory allocation fail when reading file %s\n", filename);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -373,11 +373,59 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset) {
|
|||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundValue resolveInstructionVariables(GroundInstruction* in, GroundScope* scope) {
|
||||||
|
for (size_t i = 0; i < in->args.length; i++) {
|
||||||
|
if (in->args.args[i].type == VALREF) {
|
||||||
|
GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName);
|
||||||
|
if (variable) {
|
||||||
|
// If there is a duplicator, call it (except when returning and getting fields)
|
||||||
|
if (variable->value.type == CUSTOM && in->type != RETURN && in->type != GETFIELD) {
|
||||||
|
GroundObject* obj = variable->value.data.customVal;
|
||||||
|
GroundObjectField* duplicator = findField(*obj, "duplicator");
|
||||||
|
if (duplicator != NULL) {
|
||||||
|
if (duplicator->value.type != FUNCTION) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "duplicator is not a function", in, currentInstruction);
|
||||||
|
}
|
||||||
|
GroundInstruction gi = createGroundInstruction(CALLMETHOD);
|
||||||
|
addArgToInstruction(&gi, createRefGroundArg(DIRREF, in->args.args[i].value.refName));
|
||||||
|
addArgToInstruction(&gi, createRefGroundArg(FNREF, "duplicator"));
|
||||||
|
addArgToInstruction(&gi, createValueGroundArg(variable->value));
|
||||||
|
addArgToInstruction(&gi, createRefGroundArg(DIRREF, "__ground_tmp_duplicate"));
|
||||||
|
GroundValue gv = interpretGroundInstruction(gi, scope);
|
||||||
|
if (gv.type == ERROR) {
|
||||||
|
return gv;
|
||||||
|
}
|
||||||
|
GroundVariable* tmp = findVariable(*scope->variables, "__ground_tmp_duplicate");
|
||||||
|
if (tmp == NULL) {
|
||||||
|
runtimeError(FIXME, "Couldn't find temporary variable (this should never happen)", in, currentInstruction);
|
||||||
|
}
|
||||||
|
in->args.args[i].value.value = copyGroundValue(&tmp->value);
|
||||||
|
in->args.args[i].type = VALUE;
|
||||||
|
deleteVariable(scope->variables, tmp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(in->args.args[i].value.refName);
|
||||||
|
in->args.args[i].value.value = copyGroundValue(&variable->value);
|
||||||
|
in->args.args[i].type = VALUE;
|
||||||
|
} else {
|
||||||
|
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createNoneGroundValue();
|
||||||
|
}
|
||||||
|
|
||||||
GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset) {
|
GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffset) {
|
||||||
GroundStruct gstruct = createStruct();
|
GroundStruct gstruct = createStruct();
|
||||||
for (size_t i = 0; i < in->size; i++) {
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
switch (in->instructions[i].type) {
|
switch (in->instructions[i].type) {
|
||||||
case SET: {
|
case SET: {
|
||||||
|
GroundValue resolved = resolveInstructionVariables(&in->instructions[i], scope);
|
||||||
|
if (resolved.type == ERROR) {
|
||||||
|
throwError(&resolved.data.errorVal);
|
||||||
|
}
|
||||||
if (in->instructions[i].args.length < 2) {
|
if (in->instructions[i].args.length < 2) {
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset);
|
runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &in->instructions[i], i + errorOffset);
|
||||||
}
|
}
|
||||||
@@ -520,7 +568,6 @@ GroundStruct parseStruct(GroundProgram* in, GroundScope* scope, size_t errorOffs
|
|||||||
}
|
}
|
||||||
return gstruct;
|
return gstruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||||
GroundLabel* labels = NULL;
|
GroundLabel* labels = NULL;
|
||||||
GroundVariable* variables = NULL;
|
GroundVariable* variables = NULL;
|
||||||
@@ -537,51 +584,11 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
}
|
}
|
||||||
scope.isMainScope = isMainScopeGlobal;
|
scope.isMainScope = isMainScopeGlobal;
|
||||||
isMainScopeGlobal = false;
|
isMainScopeGlobal = false;
|
||||||
// Preprocess all labels, structs and functions
|
// Preprocess all labels
|
||||||
for (size_t i = 0; i < in->size; i++) {
|
for (size_t 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 == STRUCT) {
|
|
||||||
if (in->instructions[i].args.length < 1) {
|
|
||||||
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].args.length > 1) {
|
|
||||||
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].args.args[0].type != TYPEREF) {
|
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "Expected arg 1 to be a typeref", &in->instructions[i], i);
|
|
||||||
}
|
|
||||||
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
|
||||||
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
size_t counter = 1;
|
|
||||||
GroundProgram gp = createGroundProgram();
|
|
||||||
size_t errorOffset = i;
|
|
||||||
while (counter > 0) {
|
|
||||||
if (i >= in->size) {
|
|
||||||
runtimeError(PREMATURE_EOF, "Reached end of scope before struct definition ended", &in->instructions[i - 1], i - 1);
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == STRUCT) {
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == ENDSTRUCT) {
|
|
||||||
counter--;
|
|
||||||
}
|
|
||||||
addInstructionToProgram(&gp, in->instructions[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
i--;
|
|
||||||
|
|
||||||
GroundValue gv = {
|
|
||||||
.type = STRUCTVAL,
|
|
||||||
.data.structVal = malloc(sizeof(GroundStruct))
|
|
||||||
};
|
|
||||||
*gv.data.structVal = parseStruct(&gp, &scope, errorOffset);
|
|
||||||
|
|
||||||
addVariable(scope.variables, name, gv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < in->size; i++) {
|
for (size_t i = 0; i < in->size; i++) {
|
||||||
if (in->instructions[i].type == FUN) {
|
if (in->instructions[i].type == FUN) {
|
||||||
@@ -621,37 +628,47 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
|||||||
|
|
||||||
addVariable(scope.variables, name, gv);
|
addVariable(scope.variables, name, gv);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (in->instructions[i].type == FUN) {
|
|
||||||
int count = 1;
|
|
||||||
while (count > 0) {
|
|
||||||
i++;
|
|
||||||
if (i >= in->size) {
|
|
||||||
return createNoneGroundValue();
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == FUN) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if (in->instructions[i].type == ENDFUN) {
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if (in->instructions[i].type == STRUCT) {
|
if (in->instructions[i].type == STRUCT) {
|
||||||
int count = 1;
|
if (in->instructions[i].args.length < 1) {
|
||||||
while (count > 0) {
|
runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.length > 1) {
|
||||||
|
runtimeError(TOO_MANY_ARGS, "Expecting 1 arg", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
if (in->instructions[i].args.args[0].type != TYPEREF) {
|
||||||
|
runtimeError(ARG_TYPE_MISMATCH, "Expected arg 1 to be a typeref", &in->instructions[i], i);
|
||||||
|
}
|
||||||
|
char* name = malloc(strlen(in->instructions[i].args.args[0].value.refName) + 1);
|
||||||
|
strcpy(name, in->instructions[i].args.args[0].value.refName);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
|
size_t counter = 1;
|
||||||
|
GroundProgram gp = createGroundProgram();
|
||||||
|
size_t errorOffset = i;
|
||||||
|
while (counter > 0) {
|
||||||
if (i >= in->size) {
|
if (i >= in->size) {
|
||||||
return createNoneGroundValue();
|
runtimeError(PREMATURE_EOF, "Reached end of scope before struct definition ended", &in->instructions[i - 1], i - 1);
|
||||||
}
|
}
|
||||||
if (in->instructions[i].type == STRUCT) {
|
if (in->instructions[i].type == STRUCT) {
|
||||||
count++;
|
counter++;
|
||||||
}
|
}
|
||||||
if (in->instructions[i].type == ENDSTRUCT) {
|
if (in->instructions[i].type == ENDSTRUCT) {
|
||||||
count--;
|
counter--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GroundInstruction structInstruction = copyGroundInstruction(&in->instructions[i]);
|
||||||
|
addInstructionToProgram(&gp, structInstruction);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
i--;
|
||||||
|
|
||||||
|
GroundValue gv = {
|
||||||
|
.type = STRUCTVAL,
|
||||||
|
.data.structVal = malloc(sizeof(GroundStruct))
|
||||||
|
};
|
||||||
|
*gv.data.structVal = parseStruct(&gp, &scope, errorOffset);
|
||||||
|
|
||||||
|
addVariable(scope.variables, name, gv);
|
||||||
}
|
}
|
||||||
if (in->instructions[i].type == PAUSE || instructionsToPause == 0) {
|
if (in->instructions[i].type == PAUSE || instructionsToPause == 0) {
|
||||||
printf("Paused execution\n");
|
printf("Paused execution\n");
|
||||||
@@ -784,46 +801,12 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
|||||||
GroundInstruction copied_inst = copyGroundInstruction(&inst);
|
GroundInstruction copied_inst = copyGroundInstruction(&inst);
|
||||||
GroundInstruction* in = &copied_inst;
|
GroundInstruction* in = &copied_inst;
|
||||||
|
|
||||||
// Insert variables prefixed with $
|
GroundValue resolved = resolveInstructionVariables(in, scope);
|
||||||
for (size_t i = 0; i < in->args.length; i++) {
|
if (resolved.type == ERROR) {
|
||||||
if (in->args.args[i].type == VALREF) {
|
freeGroundInstruction(in);
|
||||||
GroundVariable* variable = findVariable(*scope->variables, in->args.args[i].value.refName);
|
return resolved;
|
||||||
if (variable) {
|
|
||||||
// If there is a duplicator, call it (except when returning and getting fields)
|
|
||||||
if (variable->value.type == CUSTOM && in->type != RETURN && in->type != GETFIELD) {
|
|
||||||
GroundObject* obj = variable->value.data.customVal;
|
|
||||||
GroundObjectField* duplicator = findField(*obj, "duplicator");
|
|
||||||
if (duplicator != NULL) {
|
|
||||||
if (duplicator->value.type != FUNCTION) {
|
|
||||||
runtimeError(ARG_TYPE_MISMATCH, "duplicator is not a function", in, currentInstruction);
|
|
||||||
}
|
|
||||||
GroundInstruction gi = createGroundInstruction(CALLMETHOD);
|
|
||||||
addArgToInstruction(&gi, createRefGroundArg(DIRREF, in->args.args[i].value.refName));
|
|
||||||
addArgToInstruction(&gi, createRefGroundArg(FNREF, "duplicator"));
|
|
||||||
addArgToInstruction(&gi, createValueGroundArg(variable->value));
|
|
||||||
addArgToInstruction(&gi, createRefGroundArg(DIRREF, "__ground_tmp_duplicate"));
|
|
||||||
GroundValue gv = interpretGroundInstruction(gi, scope);
|
|
||||||
if (gv.type == ERROR) {
|
|
||||||
return gv;
|
|
||||||
}
|
|
||||||
GroundVariable* tmp = findVariable(*scope->variables, "__ground_tmp_duplicate");
|
|
||||||
if (tmp == NULL) {
|
|
||||||
runtimeError(FIXME, "Couldn't find temporary variable (this should never happen)", in, currentInstruction);
|
|
||||||
}
|
|
||||||
in->args.args[i].value.value = copyGroundValue(&tmp->value);
|
|
||||||
in->args.args[i].type = VALUE;
|
|
||||||
deleteVariable(scope->variables, tmp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(in->args.args[i].value.refName); // Free the strdup'd refName
|
|
||||||
in->args.args[i].value.value = copyGroundValue(&variable->value);
|
|
||||||
in->args.args[i].type = VALUE;
|
|
||||||
} else {
|
|
||||||
runtimeError(UNKNOWN_VARIABLE, NULL, in, currentInstruction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (in->type) {
|
switch (in->type) {
|
||||||
// We can safely ignore these instructions, as they have been preprocessed
|
// We can safely ignore these instructions, as they have been preprocessed
|
||||||
case FUN:
|
case FUN:
|
||||||
|
|||||||
Reference in New Issue
Block a user