From b289448f56ed2ce2d48808d27f8fbbd2cf9f059d Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Wed, 21 Jan 2026 18:41:24 +1100 Subject: [PATCH] Add struct field access --- README.md | 2 +- src/interpreter.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++ src/parser.c | 2 ++ src/types.h | 2 +- tests/struct.grnd | 17 ++++++++++++ 5 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 tests/struct.grnd diff --git a/README.md b/README.md index acfb242..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 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