diff --git a/README.md b/README.md index 9240c35..96dd87f 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ build - [x] Return values (type checked) - [x] Arguments for functions - [x] Jumping within functions - - [ ] Custom data structures + - [x] Custom data structures - [ ] Working with external libraries ## Debugger @@ -114,6 +114,7 @@ Supported instructions so far: * inequal * greater * lesser +* not * jump * if * @ (label creation) diff --git a/include/groundvm.h b/include/groundvm.h index 58bb07a..7fbad50 100644 --- a/include/groundvm.h +++ b/include/groundvm.h @@ -14,7 +14,7 @@ #include typedef enum GroundInstType { - IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD + IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD } GroundInstType; typedef enum GroundValueType { @@ -58,6 +58,7 @@ typedef struct GroundError { */ typedef struct GroundValue { GroundValueType type; + struct GroundStruct* customType; union { int64_t intVal; double doubleVal; @@ -170,6 +171,7 @@ GroundProgram groundCreateProgram(); void groundAddInstructionToProgram(GroundProgram* program, GroundInstruction instruction); GroundValue groundRunProgram(GroundProgram* program); void groundPrintProgram(GroundProgram* program); +char* groundCompileProgram(GroundProgram* program); GroundInstruction groundCreateInstruction(GroundInstType type); void groundAddValueToInstruction(GroundInstruction* inst, GroundValue value); diff --git a/src/compiler.c b/src/compiler.c index 716aed9..b2c2dcb 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -221,6 +221,33 @@ char* compileGroundProgram(GroundProgram* program) { break; } + case NOT: { + if (gi.args.length < 2) { + runtimeError(TOO_FEW_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.length > 2) { + runtimeError(TOO_MANY_ARGS, "Expecting 2 args", &gi, i); + } + if (gi.args.args[0].type != VALUE && gi.args.args[0].type != VALREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Int (for now) for arg 1", &gi, i); + } + if (gi.args.args[1].type != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef", &gi, i); + } + + char* varName = gi.args.args[1].value.refName; + + APPEND_ESTR(start, " ; not\n"); + APPEND_ESTR(start, " mov rax, "); + APPEND_ESTR(start, processValueString(gi.args.args[0])); + APPEND_ESTR(start, "\n"); + APPEND_ESTR(start, " xor rax, 1\n"); + APPEND_ESTR(start, " mov ["); + APPEND_ESTR(start, varName); + APPEND_ESTR(start, "], rax\n"); + + break; + } case ADD: { if (gi.args.length < 3) { runtimeError(TOO_FEW_ARGS, "Expecting 2 args for add instruction", &gi, i); diff --git a/src/interface.c b/src/interface.c index 2f41515..511cb43 100644 --- a/src/interface.c +++ b/src/interface.c @@ -1,5 +1,6 @@ #include "parser.h" #include "interpreter.h" +#include "compiler.h" #include "types.h" #include @@ -123,3 +124,7 @@ void groundAddValueToScope(GroundScope* gs, const char* name, GroundValue value) void groundAddFieldToStruct(GroundStruct* gstruct, char* name, GroundValue field) { addFieldToStruct(gstruct, name, field); } + +char* groundCompileProgram(GroundProgram* program) { + return compileGroundProgram(program); +} diff --git a/src/interpreter.c b/src/interpreter.c index 0dbb3ca..dc4956e 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -2028,6 +2028,77 @@ GroundValue interpretGroundInstruction(GroundInstruction inst, GroundScope* scop break; } + /* + * OBJECTS + * Allows manipulation of Ground objects. + */ + // getfield $obj &field &result + case GETFIELD: { + 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); + } + if (in->args.args[0].type != VALUE) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting an Object for arg 1", in, currentInstruction); + } + if (in->args.args[0].value.value.type != CUSTOM) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting 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 != DIRREF) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef for arg 3", in, currentInstruction); + } + + GroundObjectField* field = findField(*in->args.args[0].value.value.data.customVal, in->args.args[1].value.refName); + if (field == NULL) { + runtimeError(UNKNOWN_VARIABLE, "Struct does not contain that field", in, currentInstruction); + } + addVariable(scope->variables, in->args.args[2].value.refName, field->value); + + break; + } + // setfield &obj &field $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); + } + 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); + } + + GroundVariable* var = findVariable(*scope->variables, in->args.args[0].value.refName); + if (var == NULL) { + runtimeError(UNKNOWN_VARIABLE, "Could not find that object", in, currentInstruction); + } + if (var->value.type != CUSTOM) { + runtimeError(ARG_TYPE_MISMATCH, "Expecting a DirectRef to an Object for arg 1", in, currentInstruction); + } + + GroundObjectField* field = findField(*var->value.data.customVal, in->args.args[1].value.refName); + 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) { + runtimeError(ARG_TYPE_MISMATCH, "Field type and provided type do not match", in, currentInstruction); + } + + field->value = copyGroundValue(&in->args.args[2].value.value); + break; + } + case DROP: { if (in->args.length < 1) { runtimeError(TOO_FEW_ARGS, "Expecting 1 arg", in, currentInstruction); diff --git a/src/parser.c b/src/parser.c index 57a3395..59a2b29 100644 --- a/src/parser.c +++ b/src/parser.c @@ -168,6 +168,8 @@ static GroundInstType getInstructionType(const char* inst) { if (strcmp(inst, "struct") == 0) return STRUCT; if (strcmp(inst, "endstruct") == 0) return ENDSTRUCT; if (strcmp(inst, "init") == 0) return INIT; + if (strcmp(inst, "getfield") == 0) return GETFIELD; + if (strcmp(inst, "setfield") == 0) return SETFIELD; if (strcmp(inst, "use") == 0) return USE; if (strcmp(inst, "extern") == 0) return EXTERN; if (strcmp(inst, "drop") == 0) return DROP; diff --git a/src/types.h b/src/types.h index 5085cd5..600322c 100644 --- a/src/types.h +++ b/src/types.h @@ -9,7 +9,7 @@ #include "include/uthash.h" typedef enum GroundInstType { - IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD + IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, GETFIELD, SETFIELD, USE, EXTERN, CREATELABEL, PAUSE, DROP, ERRORCMD } GroundInstType; typedef enum GroundValueType { diff --git a/tests/struct.grnd b/tests/struct.grnd new file mode 100644 index 0000000..852b4e7 --- /dev/null +++ b/tests/struct.grnd @@ -0,0 +1,17 @@ +struct -point + + init &x -int + init &y -int + +endstruct + +init &mypoint -point + +setfield &mypoint &x 53 +setfield &mypoint &y 32 + +getfield $mypoint &x &value +println $value + +getfield $mypoint &y &value +println $value