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);
|
||||
if (!file) {
|
||||
fclose(fp);
|
||||
fputs("memory allocation fail when reading file", stderr);
|
||||
fprintf(stderr, "memory allocation fail when reading file %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -373,11 +373,59 @@ GroundFunction* parseFunction(GroundProgram* in, size_t errorOffset) {
|
||||
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 gstruct = createStruct();
|
||||
for (size_t i = 0; i < in->size; i++) {
|
||||
switch (in->instructions[i].type) {
|
||||
case SET: {
|
||||
GroundValue resolved = resolveInstructionVariables(&in->instructions[i], scope);
|
||||
if (resolved.type == ERROR) {
|
||||
throwError(&resolved.data.errorVal);
|
||||
}
|
||||
if (in->instructions[i].args.length < 2) {
|
||||
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;
|
||||
}
|
||||
|
||||
GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
GroundLabel* labels = NULL;
|
||||
GroundVariable* variables = NULL;
|
||||
@@ -537,51 +584,11 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
}
|
||||
scope.isMainScope = isMainScopeGlobal;
|
||||
isMainScopeGlobal = false;
|
||||
// Preprocess all labels, structs and functions
|
||||
// Preprocess all labels
|
||||
for (size_t i = 0; i < in->size; i++) {
|
||||
if (in->instructions[i].type == CREATELABEL) {
|
||||
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++) {
|
||||
if (in->instructions[i].type == FUN) {
|
||||
@@ -621,37 +628,47 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
|
||||
|
||||
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) {
|
||||
int count = 1;
|
||||
while (count > 0) {
|
||||
i++;
|
||||
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) {
|
||||
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) {
|
||||
count++;
|
||||
counter++;
|
||||
}
|
||||
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) {
|
||||
printf("Paused execution\n");
|
||||
@@ -784,53 +801,19 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
|
||||
GroundInstruction copied_inst = copyGroundInstruction(&inst);
|
||||
GroundInstruction* in = &copied_inst;
|
||||
|
||||
// Insert variables prefixed with $
|
||||
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); // 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);
|
||||
}
|
||||
}
|
||||
GroundValue resolved = resolveInstructionVariables(in, scope);
|
||||
if (resolved.type == ERROR) {
|
||||
freeGroundInstruction(in);
|
||||
return resolved;
|
||||
}
|
||||
|
||||
switch (in->type) {
|
||||
// We can safely ignore these instructions, as they have been preprocessed
|
||||
case FUN:
|
||||
case ENDFUN:
|
||||
case STRUCT:
|
||||
case ENDSTRUCT:
|
||||
case CREATELABEL: {
|
||||
// We can safely ignore these instructions, as they have been preprocessed
|
||||
case FUN:
|
||||
case ENDFUN:
|
||||
case STRUCT:
|
||||
case ENDSTRUCT:
|
||||
case CREATELABEL: {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user