7 Commits

5 changed files with 151 additions and 79 deletions

View File

@@ -376,6 +376,34 @@ bool checkForErrors(GroundProgram* program) {
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) {
if (!checkForErrors(program)) {
@@ -383,13 +411,23 @@ void compileGroundProgram(GroundProgram* program, char* name) {
return;
}
GroundState state = createGroundState();
Tram_Program tramProgram = Tram_Program_Create();
Tram_ParameterList parameters = Tram_ParameterList_Create(1, (Tram_Parameter[]){Tram_Parameter_Variable("main")});
Tram_Program_AddInstruction(&tramProgram, Tram_Instruction_Create(Tram_InstructionType_CreateLabel, parameters));
// Resolve labels
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);
@@ -406,46 +444,7 @@ void compileGroundProgram(GroundProgram* program, char* name) {
}
typedef struct GroundCompilerVariable {
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) {
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state) {
switch (instruction->type) {
case IF:
break;
@@ -542,7 +541,7 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
case EXTERN:
break;
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));
break;
}
@@ -557,4 +556,4 @@ void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* prog
}
}
#endif
#endif

View File

@@ -3,7 +3,18 @@
#include <tram.h>
#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);
#ifdef GROUND_COMPILE_WITH_TRAM
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program);
void compileGroundInstruction(GroundInstruction* instruction, Tram_Program* program, GroundState* state);
#endif

View File

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

View File

@@ -119,6 +119,10 @@ char* getFileContents(const char* filename);
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 *item;
HASH_FIND_STR(head, id, item);
@@ -318,14 +322,14 @@ GroundDebugInstruction parseDebugInstruction(char* in) {
free(instruction);
return gdi;
}
}
void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunction fn, GroundValueType returnType, int argCount, ...) {
GroundFunction* gf = createGroundFunction();
gf->isNative = true;
gf->nativeFn = fn;
gf->returnType = returnType;
va_list args;
va_start(args, argCount);
for(int i = 0; i < argCount; i++) {
@@ -334,7 +338,7 @@ void groundAddNativeFunction(GroundScope* scope, char* name, NativeGroundFunctio
addArgsToGroundFunction(gf, type, argName);
}
va_end(args);
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);
}
GroundDebugInstruction gdi = parseDebugInstruction(buffer);
bool shouldBreak = false;
switch (gdi.type) {
case CONTINUE: {
@@ -697,7 +701,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
break;
}
case DUMP: {
case DUMP: {
if (scope.variables == NULL) {
printf("Can't access variables");
break;
@@ -763,7 +767,7 @@ GroundValue interpretGroundProgram(GroundProgram* in, GroundScope* inScope) {
printf("Unknown instruction (type \"help\" for help)");
break;
}
}
}
if (shouldBreak) {
break;
}
@@ -822,7 +826,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
* These instructions are for controlling how the program is executed.
* Instructions:
* if, jump, end
*/
*/
case IF: {
if (in->args.length < 2) {
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) {
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) {
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) {
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;
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);
}
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);
}
if (function->isNative) {
List argsList = createList();
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);
}
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);
}
} 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);
}
}
appendToList(&argsList, in->args.args[i + 2].value.value);
appendToList(&argsList, in->args.args[i + fnRefPos + 1].value.value);
}
GroundScope newscope = {
@@ -2097,14 +2135,14 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
} else {
GroundScope newScope = copyGroundScope(&function->closure);
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);
}
//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);
}
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
addVariable(newScope.variables, "self", *obj);
@@ -2125,7 +2163,7 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (objvar == NULL) {
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;
@@ -2363,21 +2401,18 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
break;
}
// setfield &obj &field $value
// also allows setting nested fields with:
// setfield &obj &field1 &field2 &field3 ... $value
case SETFIELD: {
if (in->args.length < 3) {
runtimeError(TOO_FEW_ARGS, "Expecting 3 args", in, currentInstruction);
}
if (in->args.length > 3) {
runtimeError(TOO_MANY_ARGS, "Expecting 3 args", in, currentInstruction);
runtimeError(TOO_FEW_ARGS, "Expecting 3 or more args", in, currentInstruction);
}
if (in->args.args[0].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction);
}
if (in->args.args[1].type != DIRREF) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 2", in, currentInstruction);
}
if (in->args.args[2].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for arg 3", in, currentInstruction);
// Check everything is a DIRREF wihle looping through the fields
if (in->args.args[in->args.length - 1].type != VALUE) {
runtimeError(ARG_TYPE_MISMATCH, "Expecting a Value for last arg", in, currentInstruction);
}
GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName);
@@ -2392,11 +2427,28 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop
if (field == NULL) {
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);
}
field->value = copyGroundValue(&in->args.args[2].value.value);
field->value = copyGroundValue(&in->args.args[in->args.length - 1].value.value);
break;
}

View File

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