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;
|
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user