7 Commits

5 changed files with 151 additions and 79 deletions

View File

@@ -376,6 +376,34 @@ bool checkForErrors(GroundProgram* program) {
return true; return true;
} }
GroundState createGroundState() {
GroundState state = {
.variables = NULL,
.labels = NULL
};
return state;
}
GroundCompilerVariable* cFindVariable(GroundState* state, const char* id) {
GroundCompilerVariable* var;
HASH_FIND_STR(state->variables, id, var);
return var;
}
void cDeleteVariable(GroundState* state, const char* id) {
GroundCompilerVariable* var;
HASH_FIND_STR(state->variables, id, var);
HASH_DEL(state->variables, var);
}
GroundCompilerVariable* cAddVariable(GroundState* state, const char* id, GroundValueType type) {
GroundCompilerVariable* var = malloc(sizeof(GroundCompilerVariable));
snprintf(var->id, MAX_ID_LEN, "%s", id);
var->type = type;
HASH_ADD_STR(state->variables, id, var);
return var;
}
void compileGroundProgram(GroundProgram* program, char* name) { void compileGroundProgram(GroundProgram* program, char* name) {
if (!checkForErrors(program)) { if (!checkForErrors(program)) {
@@ -383,13 +411,23 @@ void compileGroundProgram(GroundProgram* program, char* name) {
return; return;
} }
GroundState state = createGroundState();
Tram_Program tramProgram = Tram_Program_Create(); Tram_Program tramProgram = Tram_Program_Create();
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")}); Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters)); Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
// Resolve labels
for (size_t i = 0; i < program->size; i++) { for (size_t i = 0; i < program->size; i++) {
compileGroundInstruction(&program->instructions[i], &tramProgram); if (program->instructions[i].type == CREATELABEL) {
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable(program->instructions[i].args.args[0].value.refName)});
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
}
}
for (size_t i = 0; i < program->size; i++) {
compileGroundInstruction(&program->instructions[i], &tramProgram, &state);
} }
Tram_Compiler* compiler = Tram_Compiler_Create(tramProgram); Tram_Compiler* compiler = Tram_Compiler_Create(tramProgram);
@@ -406,46 +444,7 @@ void compileGroundProgram(GroundProgram* program, char* name) {
} }
typedef struct GroundCompilerVariable { void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state) {
GroundValueType type;
char id[MAX_ID_LEN];
UT_hash_handle hh;
} GroundCompilerVariable;
typedef struct GroundState {
GroundCompilerVariable* variables;
GroundLabel* labels;
} GroundState;
GroundState createGroundState() {
GroundState state = {
.variables = NULL,
.labels = NULL
};
return state;
}
GroundCompilerVariable* cFindVariable(GroundState* state, const char* id) {
GroundCompilerVariable* var;
HASH_FIND_STR(state->variables, id, var);
return var;
}
GroundCompilerVariable* cDeleteVariable(GroundState* state, const char* id) {
GroundCompilerVariable* var;
HASH_FIND_STR(state->variables, id, var);
HASH_DEL(state->variables, var);
}
GroundCompilerVariable* cAddVariable(GroundState* state, const char* id, GroundValueType type) {
GroundCompilerVariable* var = malloc(sizeof(GroundCompilerVariable));
snprintf(var->id, MAX_ID_LEN, "%s", id);
var->type = type;
HASH_ADD_STR(state->variables, id, var);
return var;
}
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program) {
switch (instruction->type) { switch (instruction->type) {
case IF: case IF:
break; break;
@@ -542,7 +541,7 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
case EXTERN: case EXTERN:
break; break;
case CREATELABEL: { case CREATELABEL: {
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")}); Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable(instruction->args.args[0].value.refName)});
Tram_Program_AddInstruction(program, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters)); Tram_Program_AddInstruction(program, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
break; break;
} }
@@ -557,4 +556,4 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
} }
} }
#endif #endif

View File

@@ -3,7 +3,18 @@
#include <tram.h> #include <tram.h>
#endif #endif
typedef struct GroundCompilerVariable {
GroundValueType type;
char id[MAX_ID_LEN];
UT_hash_handle hh;
} GroundCompilerVariable;
typedef struct GroundState {
GroundCompilerVariable* variables;
GroundLabel* labels;
} GroundState;
void compileGroundProgram(GroundProgram* program, char* name); void compileGroundProgram(GroundProgram* program, char* name);
#ifdef GROUND_COMPILE_WITH_TRAM #ifdef GROUND_COMPILE_WITH_TRAM
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program); void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state);
#endif #endif

View File

@@ -5,7 +5,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <signal.h>
char* getFileContents(const char* filename) { char* getFileContents(const char* filename) {
// https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c // https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c
FILE* fp; FILE* fp;
@@ -125,7 +126,7 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
gv.type = CUSTOM; gv.type = CUSTOM;
gv.data.customVal = malloc(sizeof(GroundObject)); gv.data.customVal = malloc(sizeof(GroundObject));
*gv.data.customVal = createObject(*gstruct); *gv.data.customVal = createObject(*gstruct);
// Deep copy the struct definition so it stays valid // Deep copy the struct definition so it stays valid
gv.customType = malloc(sizeof(GroundStruct)); gv.customType = malloc(sizeof(GroundStruct));
gv.customType->size = gstruct->size; gv.customType->size = gstruct->size;
@@ -151,7 +152,10 @@ GroundValue groundCreateValue(GroundValueType type, ...) {
return gv; return gv;
} }
void segfaultHandle(int signal);
GroundValue groundRunProgram(GroundProgram* program) { GroundValue groundRunProgram(GroundProgram* program) {
signal(SIGSEGV, segfaultHandle);
GroundVariable* variables = NULL; GroundVariable* variables = NULL;
GroundLabel* labels = NULL; GroundLabel* labels = NULL;
GroundScope scope = { GroundScope scope = {

View File

@@ -119,6 +119,10 @@ char* getFileContents(const char* filename);
exit(1); exit(1);
} }
void segfaultHandle(int signal) {
runtimeError(FIXME, "The Ground interpreter has crashed due to a segmentation fault. Please report this issue as soon as possible, with as much detail as possible.", NULL, currentInstruction);
}
GroundLabel* findLabel(GroundLabel* head, const char *id) { GroundLabel* findLabel(GroundLabel* head, const char *id) {
GroundLabel *item; GroundLabel *item;
HASH_FIND_STR(head, id, item); HASH_FIND_STR(head, id, item);
@@ -318,14 +322,14 @@ GroundDebugInstruction parseDebugInstruction(char* in) {
free(instruction); free(instruction);
return gdi; return gdi;
} }
void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunction fn, GroundValueType returnType, int argCount, ...) { void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunction fn, GroundValueType returnType, int argCount, ...) {
GroundFunction* gf = createGroundFunction(); GroundFunction* gf = createGroundFunction();
gf->isNative = true; gf->isNative = true;
gf->nativeFn = fn; gf->nativeFn = fn;
gf->returnType = returnType; gf->returnType = returnType;
va_list args; va_list args;
va_start(args, argCount); va_start(args, argCount);
for(int i = 0; i < argCount; i++) { for(int i = 0; i < argCount; i++) {
@@ -334,7 +338,7 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio
addArgsToGroundFunction(gf, type, argName); addArgsToGroundFunction(gf, type, argName);
} }
va_end(args); va_end(args);
addVariable(scope->variables, name, createFunctionGroundValue(gf)); addVariable(scope->variables, name, createFunctionGroundValue(gf));
} }
@@ -685,7 +689,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
runtimeError(FIXME, "Failed to read input from console with fgets", NULL, -1); runtimeError(FIXME, "Failed to read input from console with fgets", NULL, -1);
} }
GroundDebugInstruction gdi = parseDebugInstruction(buffer); GroundDebugInstruction gdi = parseDebugInstruction(buffer);
bool shouldBreak = false; bool shouldBreak = false;
switch (gdi.type) { switch (gdi.type) {
case CONTINUE: { case CONTINUE: {
@@ -697,7 +701,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
break; break;
} }
case DUMP: { case DUMP: {
if (scope.variables == NULL) { if (scope.variables == NULL) {
printf("Can't access variables"); printf("Can't access variables");
break; break;
@@ -763,7 +767,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
printf("Unknown instruction (type \"help\" for help)"); printf("Unknown instruction (type \"help\" for help)");
break; break;
} }
} }
if (shouldBreak) { if (shouldBreak) {
break; break;
} }
@@ -822,7 +826,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
* These instructions are for controlling how the program is executed. * These instructions are for controlling how the program is executed.
* Instructions: * Instructions:
* if, jump, end * if, jump, end
*/ */
case IF: { case IF: {
if (in->args.length < 2) { if (in->args.length < 2) {
runtimeError(TOO_FEW_ARGS, "Expecting 2 arguments", in, currentInstruction); runtimeError(TOO_FEW_ARGS, "Expecting 2 arguments", in, currentInstruction);
@@ -2005,9 +2009,6 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (in->args.args[0].type != DIRREF) { if (in->args.args[0].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an object for arg 1", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an object for arg 1", in, currentInstruction);
} }
if (in->args.args[1].type != FNREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef for arg 2", in, currentInstruction);
}
if (in->args.args[in->args.length - 1].type != DIRREF) { if (in->args.args[in->args.length - 1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef as the last arg", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef as the last arg", in, currentInstruction);
} }
@@ -2025,32 +2026,69 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (fnvar == NULL) { if (fnvar == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Method not found inside specified object", in, currentInstruction); runtimeError(UNKNOWN_VARIABLE, "Method not found inside specified object", in, currentInstruction);
} }
if (fnvar->value.type != FUNCTION) {
runtimeError(UNKNOWN_VARIABLE, "Provided reference does not reference a method", in, currentInstruction); size_t fnRefPos = 0;
for (size_t i = 2; i < in->args.length; i++) {
if (in->args.args[i].type == FNREF) {
if (fnvar == NULL) {
runtimeError(FIXME, "fnvar is null (this should not happen)", in, currentInstruction);
}
if (fnvar->value.type != CUSTOM) {
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
}
obj = &fnvar->value;
fnvar = findField(*fnvar->value.data.customVal, in->args.args[i].value.refName);
if (fnvar == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
}
if (fnvar->value.type != FUNCTION) {
runtimeError(ARG_TYPE_MISMATCH, "Field is not a method", in, currentInstruction);
}
fnRefPos = i;
break;
} else if (in->args.args[i].type == DIRREF) {
if (fnvar == NULL) {
runtimeError(FIXME, "fnvar is null (this should not happen)", in, currentInstruction);
}
if (fnvar->value.type != CUSTOM) {
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
}
fnvar = findField(*fnvar->value.data.customVal, in->args.args[i].value.refName);
if (fnvar == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
}
} else {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef or FnRef for callmethod args", in, currentInstruction);
}
} }
if (fnRefPos == 0) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a FunctionRef after field list", in, currentInstruction);
}
GroundFunction* function = fnvar->value.data.fnVal; GroundFunction* function = fnvar->value.data.fnVal;
if (function->argSize < in->args.length - 3) { if (function->argSize < in->args.length - fnRefPos - 2) {
runtimeError(TOO_FEW_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction); runtimeError(TOO_FEW_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction);
} }
if (function->argSize > in->args.length - 3) { if (function->argSize > in->args.length - fnRefPos - 2) {
runtimeError(TOO_MANY_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction); runtimeError(TOO_MANY_ARGS, "Incorrect amount of arguments provided for function", in, currentInstruction);
} }
if (function->isNative) { if (function->isNative) {
List argsList = createList(); List argsList = createList();
for (size_t i = 0; i < function->argSize; i++) { for (size_t i = 0; i < function->argSize; i++) {
if (in->args.args[i + 2].type != VALUE) { if (in->args.args[i + fnRefPos + 1].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
} }
if (function->nativeFn) { if (function->nativeFn) {
if (function->args[i].type != ANY && in->args.args[i + 2].value.value.type != function->args[i].type) { if (function->args[i].type != ANY && in->args.args[i + fnRefPos + 1].value.value.type != function->args[i].type) {
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
} }
} else { } else {
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + 2].value.value, &function->args[i])) { if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + fnRefPos + 1].value.value, &function->args[i])) {
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
} }
} }
appendToList(&argsList, in->args.args[i + 2].value.value); appendToList(&argsList, in->args.args[i + fnRefPos + 1].value.value);
} }
GroundScope newscope = { GroundScope newscope = {
@@ -2097,14 +2135,14 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
} else { } else {
GroundScope newScope = copyGroundScope(&function->closure); GroundScope newScope = copyGroundScope(&function->closure);
for (size_t i = 0; i < function->argSize; i++) { for (size_t i = 0; i < function->argSize; i++) {
if (in->args.args[i + 2].type != VALUE) { if (in->args.args[i + fnRefPos + 1].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value", in, currentInstruction);
} }
//if (in->args.args[i + 1].value.value.type != function->args[i].type) { //if (in->args.args[i + 1].value.value.type != function->args[i].type) {
if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + 2].value.value, &function->args[i])) { if (function->args[i].type != ANY && !checkFnTypes(&in->args.args[i + fnRefPos + 1].value.value, &function->args[i])) {
runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Mismatched function argument types", in, currentInstruction);
} }
addVariable(newScope.variables, function->args[i].name, in->args.args[i + 2].value.value); addVariable(newScope.variables, function->args[i].name, in->args.args[i + fnRefPos + 1].value.value);
} }
// Add the object to the scope // Add the object to the scope
addVariable(newScope.variables, "self", *obj); addVariable(newScope.variables, "self", *obj);
@@ -2125,7 +2163,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (objvar == NULL) { if (objvar == NULL) {
runtimeError(UNKNOWN_VARIABLE, "self not found in scope, did you drop the object?", in, currentInstruction); runtimeError(UNKNOWN_VARIABLE, "self not found in scope, did you drop the object?", in, currentInstruction);
} }
addVariable(scope->variables, in->args.args[0].value.refName, objvar->value); *obj = objvar->value;
} }
break; break;
@@ -2363,21 +2401,18 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
break; break;
} }
// setfield &obj &field $value // setfield &obj &field $value
// also allows setting nested fields with:
// setfield &obj &field1 &field2 &field3 ... $value
case SETFIELD: { case SETFIELD: {
if (in->args.length < 3) { if (in->args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction); runtimeError(TOO_FEW_ARGS, "Expecting 3 or more args", in, currentInstruction);
}
if (in->args.length > 3) {
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
} }
if (in->args.args[0].type != DIRREF) { if (in->args.args[0].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction);
} }
if (in->args.args[1].type != DIRREF) { // Check everything is a DIRREF wihle looping through the fields
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction); if (in->args.args[in->args.length - 1].type != VALUE) {
} runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for last arg", in, currentInstruction);
if (in->args.args[2].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 3", in, currentInstruction);
} }
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName); GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
@@ -2392,11 +2427,28 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (field == NULL) { if (field == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction); runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
} }
if (field->value.type != in->args.args[2].value.value.type) {
for (size_t i = 2; i < in->args.length - 1; i++) {
if (field == NULL) {
runtimeError(FIXME, "Field is null, this should have errored beforehand", in, currentInstruction);
}
if (in->args.args[i].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for field setter args", in, currentInstruction);
}
if (field->value.type != CUSTOM) {
runtimeError(ARG_TYPE_MISMATCH, "Field is not an object", in, currentInstruction);
}
field = findField(*field->value.data.customVal, in->args.args[i].value.refName);
if (field == NULL) {
runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction);
}
}
if (field->value.type != in->args.args[in->args.length - 1].value.value.type) {
runtimeError(ARG_TYPE_MISMATCH, "Field type and provided type do not match", in, currentInstruction); runtimeError(ARG_TYPE_MISMATCH, "Field type and provided type do not match", in, currentInstruction);
} }
field->value = copyGroundValue(&in->args.args[2].value.value); field->value = copyGroundValue(&in->args.args[in->args.length - 1].value.value);
break; break;
} }

View File

@@ -4,12 +4,18 @@
#include "types.h" #include "types.h"
#include "serialize.h" #include "serialize.h"
#include "repl.h" #include "repl.h"
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
void segfaultHandle(int signal);
char* getFileContents(const char* filename); char* getFileContents(const char* filename);
int main(int argc, char** argv) { int main(int argc, char** argv) {
signal(SIGSEGV, segfaultHandle);
if (argc == 1) { if (argc == 1) {
exit(repl()); exit(repl());
} }