forked from ground/ground
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 932846362d | |||
| 39b6a49a9c | |||
| 159d86b76d | |||
| a2b0924018 | |||
| 9edb6b51ec | |||
| 5f7f2ea152 | |||
| 6c293f7c3f |
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#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
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user