From 05733c693cb4963a06870d856f422f57d00622b5 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Sun, 5 Jul 2026 18:01:09 +1000 Subject: [PATCH] Keep working on structs --- include/ground.h | 13 ++--- src/Copy/Object.c | 9 +--- src/Copy/Struct.c | 9 +--- src/Free/Object.c | 5 +- src/Free/Struct.c | 5 +- src/New/Bytecode.c | 100 ++++++++++++++++++++++++++++++++++++--- src/New/Object.c | 9 +--- src/Program/preprocess.c | 81 +++++++++++++++++++++++++++++-- src/Struct/addField.c | 15 ++---- 9 files changed, 187 insertions(+), 59 deletions(-) diff --git a/include/ground.h b/include/ground.h index 24a1166..71a36ed 100644 --- a/include/ground.h +++ b/include/ground.h @@ -105,12 +105,6 @@ struct GroundStruct { GroundObjectField* fields; }; -struct GroundObjectField { - char name[2048]; - GroundValue* value; - UT_hash_handle hh; -}; - struct GroundObject { GroundObjectField* fields; GroundStruct* type; @@ -159,6 +153,13 @@ struct GroundValue { GroundType type; }; + +struct GroundObjectField { + char name[2048]; + GroundValue value; + GroundSize offset; + UT_hash_handle hh; +}; enum GroundArgType { GroundArg_Value, GroundArg_ValueRef, GroundArg_DirectRef, diff --git a/src/Copy/Object.c b/src/Copy/Object.c index a384a57..a8813e7 100644 --- a/src/Copy/Object.c +++ b/src/Copy/Object.c @@ -22,14 +22,7 @@ GroundObject _GroundCopyObject(GroundObject* in) { strncpy(item->name, s->name, 2047); - item->value = malloc(sizeof(GroundValue)); - if (item->value == NULL) { - Ground.Log.Error("malloc failed in Ground.Copy.Object()"); - Ground.Flags.error = true; - return object; - } - - *item->value = Ground.Copy.Value(s->value); + item->value = Ground.Copy.Value(&s->value); if (Ground.Flags.error) { return object; diff --git a/src/Copy/Struct.c b/src/Copy/Struct.c index 7e2bf80..6351e98 100644 --- a/src/Copy/Struct.c +++ b/src/Copy/Struct.c @@ -21,14 +21,7 @@ GroundStruct _GroundCopyStruct(GroundStruct* in) { strncpy(item->name, s->name, 2047); - item->value = malloc(sizeof(GroundValue)); - if (item->value == NULL) { - Ground.Log.Error("malloc failed in Ground.Copy.Struct()"); - Ground.Flags.error = true; - return gs; - } - - *item->value = Ground.Copy.Value(s->value); + item->value = Ground.Copy.Value(&s->value); if (Ground.Flags.error) { return gs; diff --git a/src/Free/Object.c b/src/Free/Object.c index bd95458..877a78e 100644 --- a/src/Free/Object.c +++ b/src/Free/Object.c @@ -1,7 +1,5 @@ #include "../../include/ground.h" -#include - void _GroundFreeObject(GroundObject* in) { GroundObjectField *s, *tmp; @@ -9,7 +7,6 @@ void _GroundFreeObject(GroundObject* in) { HASH_DEL(in->fields, s); - Ground.Free.Value(s->value); - free(s->value); + Ground.Free.Value(&s->value); } } diff --git a/src/Free/Struct.c b/src/Free/Struct.c index c43230b..5e6f197 100644 --- a/src/Free/Struct.c +++ b/src/Free/Struct.c @@ -1,7 +1,5 @@ #include "../../include/ground.h" -#include - void _GroundFreeStruct(GroundStruct* in) { GroundObjectField *s, *tmp; @@ -9,7 +7,6 @@ void _GroundFreeStruct(GroundStruct* in) { HASH_DEL(in->fields, s); - Ground.Free.Value(s->value); - free(s->value); + Ground.Free.Value(&s->value); } } diff --git a/src/New/Bytecode.c b/src/New/Bytecode.c index 09e4660..7a72f4d 100644 --- a/src/New/Bytecode.c +++ b/src/New/Bytecode.c @@ -13,7 +13,7 @@ static inline void doLabels(GroundProgram* program, GroundState* state) { if (label == NULL) { label = malloc(sizeof(GroundLabel)); if (label == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Log.Error("malloc failed in Ground.New.Bytecode -> doLabels"); Ground.Flags.error = true; return; } @@ -33,7 +33,7 @@ static inline void doLabels(GroundProgram* program, GroundState* state) { GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); if (line == NULL) { char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction JUMP at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + snprintf(buf, 2047, "couldn't find label '%s' (instruction JUMP at %zu) in Ground.New.Bytecode -> doLabels", arg->as.ref->string, i); Ground.Log.Error(buf); Ground.Flags.error = true; return; @@ -46,7 +46,7 @@ static inline void doLabels(GroundProgram* program, GroundState* state) { GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); if (line == NULL) { char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction IF at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + snprintf(buf, 2047, "couldn't find label '%s' (instruction IF at %zu) in Ground.New.Bytecode -> doLabels", arg->as.ref->string, i); Ground.Log.Error(buf); Ground.Flags.error = true; return; @@ -59,7 +59,7 @@ static inline void doLabels(GroundProgram* program, GroundState* state) { GroundSize* line = Ground.State.findLabel(state, arg->as.ref->string); if (line == NULL) { char buf[2048]; - snprintf(buf, 2047, "couldn't find label '%s' (instruction CATCH at %zu) in Ground.Internal.Run()", arg->as.ref->string, i); + snprintf(buf, 2047, "couldn't find label '%s' (instruction CATCH at %zu) in Ground.New.Bytecode -> doLabels", arg->as.ref->string, i); Ground.Log.Error(buf); Ground.Flags.error = true; return; @@ -85,6 +85,92 @@ static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, Ground } for (GroundSize i = 0; i < gp->len; i++) { + // Handle instructions which deal with struct fields + switch (gp->at[i].type) { + case GroundInstruction_STRUCT: { + GroundInstruction* inst = &gp->at[i]; + GroundVariable* gsv = NULL; + HASH_FIND_STR(state->variables, inst->args.at[0].as.ref->string, gsv); + if (gsv == NULL) { + Ground.Log.Error("unexpected null variable in Ground.New.Bytecode -> doOffsets"); + Ground.Flags.error = true; + return 0; + } + if (gsv->value.type.type != GroundType_Struct) { + Ground.Log.Error("unexpected null variable in Ground.New.Bytecode -> doOffsets"); + Ground.Flags.error = true; + return 0; + } + GroundStruct* gs = &gsv->value.as.Struct; + + // Set offset for each struct field + GroundObjectField *s, *tmp; + GroundSize i = 0; + HASH_ITER(hh, gs->fields, s, tmp) { + s->offset = i++; + } + + // Now go through and add offsets to everything + for (GroundSize j = 0; j < inst->args.len; j++) { + // struct field name + GroundArg* arg = &inst->args.at[j]; + GroundObjectField* field = NULL; + HASH_FIND_STR(state->variables, arg->as.ref->string, field); + if (field == NULL) { + Ground.Log.Error("unexpected null struct field in Ground.New.Bytecode -> doOffsets"); + Ground.Flags.error = true; + return 0; + } + arg->_offset = field->offset; + // 2nd arg offset is already set, but what we do next depends on it + j++; + // 0 -> none + // 1 -> init + // 2 -> set + // 3 -> attach closure to function + switch (inst->args.at[j]._offset) { + case 0: case 3: break; // these do not require extra values + case 1: // but these do, so we process them + case 2: { // it's safe to assume that literals will have + j++; // been dealt with accordingly + arg = &inst->args.at[j]; + GroundVariable* item = NULL; + HASH_FIND_STR(state->variables, arg->as.ref->string, item); + + if (item == NULL) { + item = malloc(sizeof(GroundVariable)); + if (item == NULL) { + Ground.Log.Error("malloc failed in Ground.New.Bytecode -> doOffsets"); + Ground.Flags.error = true; + return 0; + } + item->value = Ground.New.Value.Int(0); + strncpy(item->name, arg->as.ref->string, 2047); + item->_offset = size++; + HASH_ADD_STR(state->variables, name, item); + } + + arg->_offset = item->_offset; + } + } + } + + continue; + } + case GroundInstruction_GETFIELD: { + + continue; + } + case GroundInstruction_SETFIELD: { + + continue; + } + case GroundInstruction_CALLMETHOD: { + + continue; + } + default: break; + } for (GroundSize j = 0; j < gp->at[i].args.len; j++) { GroundArg* arg = &gp->at[i].args.at[j]; @@ -96,7 +182,7 @@ static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, Ground if (arg->type == GroundArg_Value) { GroundVariable* item = malloc(sizeof(GroundVariable)); if (item == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Log.Error("malloc failed in Ground.New.Bytecode -> doOffsets"); Ground.Flags.error = true; return 0; } @@ -115,7 +201,7 @@ static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, Ground if (item == NULL) { item = malloc(sizeof(GroundVariable)); if (item == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Log.Error("malloc failed in Ground.New.Bytecode -> doOffsets"); Ground.Flags.error = true; return 0; } @@ -137,7 +223,7 @@ static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, Ground }; if (inst.args.at == NULL) { - Ground.Log.Error("malloc failed in Ground.Internal.run()"); + Ground.Log.Error("malloc failed in Ground.New.Bytecode -> doOffsets"); Ground.Flags.error = true; return 0; } diff --git a/src/New/Object.c b/src/New/Object.c index 21a8f2e..e26cccd 100644 --- a/src/New/Object.c +++ b/src/New/Object.c @@ -22,14 +22,7 @@ GroundObject _GroundNewObject(GroundStruct* in) { strncpy(item->name, s->name, 2047); - item->value = malloc(sizeof(GroundValue)); - if (item->value == NULL) { - Ground.Log.Error("malloc failed in Ground.New.Object()"); - Ground.Flags.error = true; - return object; - } - - *item->value = Ground.Copy.Value(s->value); + item->value = Ground.Copy.Value(&s->value); if (Ground.Flags.error) { return object; diff --git a/src/Program/preprocess.c b/src/Program/preprocess.c index 740a908..018a0c1 100644 --- a/src/Program/preprocess.c +++ b/src/Program/preprocess.c @@ -109,6 +109,7 @@ static void doFunction(GroundProgram* program, GroundProgram* newProgram, Ground static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundState* state, GroundSize* i); static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundState* state, GroundSize* i) { GroundIdentifier* structName = Ground.Copy.Identifier(program->at[*i].args.at[0].as.ref); + GroundStruct gs = Ground.New.Struct(); // The aim is to compile an instruction which looks like this: // struct &field OP $value &field OP $value &field OP $value... @@ -121,10 +122,13 @@ static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundSt // 3 -> attach closure to function // $value is either a type reference (OP=0), a value reference (OP=1), or none (OP=2) // Functions will be moved to the end of the struct, and a closure will be attached to all of them + // + // Oh yeah, we also need to make a GroundStruct value GroundSize structCount = 0; GroundInstruction output = Ground.New.Instruction(GroundInstruction_STRUCT); + Ground.Instruction.append(&output, Ground.New.Arg.TypeRef(structName)); // Parse struct body bool parsing = true; @@ -139,16 +143,71 @@ static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundSt GroundInstruction* instruction = &program->at[*i]; switch (instruction->type) { case GroundInstruction_SET: { + + GroundObjectField* field = malloc(sizeof(GroundObjectField)); + if (field == NULL) { + Ground.Log.Error("malloc failed in Ground.Program.preprocess -> doStruct"); + Ground.Flags.error = true; + return; + } + + snprintf(field->name, 2047, "%s", instruction->args.at[0].as.ref->string); + + // If we know the value type now, add it to the instruction + if (instruction->args.at[1].type == GroundArg_Value) { + field->value = Ground.Copy.Value(&instruction->args.at[1].as.value); + break; + } + + HASH_ADD_STR(gs.fields, name, field); + // set &field $value -> &field 2 $value Ground.Instruction.append(&output, Ground.Copy.Arg(&instruction->args.at[0])); - Ground.Instruction.append(&output, Ground.New.Arg.Value(Ground.New.Value.Int(2))); + Ground.Instruction.append(&output, (GroundArg) {.type = GroundArg_DirectRef, ._offset = 2}); Ground.Instruction.append(&output, Ground.Copy.Arg(&instruction->args.at[1])); break; } case GroundInstruction_INIT: { - // init &field -type -> &field 2 -type + GroundObjectField* field = malloc(sizeof(GroundObjectField)); + if (field == NULL) { + Ground.Log.Error("malloc failed in Ground.Program.preprocess -> doStruct"); + Ground.Flags.error = true; + return; + } + + snprintf(field->name, 2047, "%s", instruction->args.at[0].as.ref->string); + + // If we know the type now, add it to the instruction + if (strcmp(field->name, "int") == 0) { + field->value = Ground.New.Value.Int(0); + break; + } + if (strcmp(field->name, "double") == 0) { + field->value = Ground.New.Value.Double(0.0); + break; + } + if (strcmp(field->name, "string") == 0) { + field->value = Ground.New.Value.String(Ground.New.String("")); + break; + } + if (strcmp(field->name, "char") == 0) { + field->value = Ground.New.Value.Char(0); + break; + } + if (strcmp(field->name, "bool") == 0) { + field->value = Ground.New.Value.Bool(false); + break; + } + if (strcmp(field->name, "function") == 0) { + field->value = Ground.New.Value.Function(Ground.New.Function(state)); + break; + } + + HASH_ADD_STR(gs.fields, name, field); + + // init &field -type -> &field 1 -type Ground.Instruction.append(&output, Ground.Copy.Arg(&instruction->args.at[0])); - Ground.Instruction.append(&output, Ground.New.Arg.Value(Ground.New.Value.Int(1))); + Ground.Instruction.append(&output, (GroundArg) {.type = GroundArg_DirectRef, ._offset = 1}); Ground.Instruction.append(&output, Ground.Copy.Arg(&instruction->args.at[1])); break; } @@ -170,7 +229,7 @@ static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundSt newProgram->len--; // Add 3 to signal addition of closure - Ground.Instruction.append(&output, Ground.New.Arg.Value(Ground.New.Value.Int(3))); + Ground.Instruction.append(&output, (GroundArg) {.type = GroundArg_DirectRef, ._offset = 1}); break; } case GroundInstruction_ENDSTRUCT: { @@ -183,6 +242,18 @@ static void doStruct(GroundProgram* program, GroundProgram* newProgram, GroundSt } + GroundVariable* variable = malloc(sizeof(GroundVariable)); + if (variable == NULL) { + Ground.Log.Error("malloc failed in Ground.Program.Preprocess -> doStruct"); + Ground.Flags.error = true; + return; + } + + snprintf(variable->name, 2047, "%s", structName->string); + variable->value = Ground.New.Value.Struct(gs); + + HASH_ADD_STR(state->variables, name, variable); + } GroundProgram _GroundProgramPreprocess(GroundProgram* program, GroundState* state) { @@ -197,6 +268,8 @@ GroundProgram _GroundProgramPreprocess(GroundProgram* program, GroundState* stat break; } case GroundInstruction_STRUCT: { + doStruct(program, &newProgram, state, &i); + if (Ground.Flags.error) return newProgram; break; } default: { diff --git a/src/Struct/addField.c b/src/Struct/addField.c index 3a5ea69..13ea992 100644 --- a/src/Struct/addField.c +++ b/src/Struct/addField.c @@ -5,8 +5,8 @@ void _GroundStructAddField(GroundStruct* gs, const char* id, GroundValue value) HASH_FIND_STR(gs->fields, id, field); if (field != NULL) { - Ground.Free.Value(field->value); - *field->value = Ground.Copy.Value(&value); + Ground.Free.Value(&field->value); + field->value = Ground.Copy.Value(&value); strncpy(field->name, id, 2047); } else { @@ -18,16 +18,11 @@ void _GroundStructAddField(GroundStruct* gs, const char* id, GroundValue value) return; } - field->value = malloc(sizeof(GroundValue)); - if (field->value == NULL) { - Ground.Log.Error("malloc failed in Ground.Struct.addField()"); - Ground.Flags.error = true; - return; - } - - *field->value = Ground.Copy.Value(&value); + field->value = Ground.Copy.Value(&value); strncpy(field->name, id, 2047); + HASH_ADD_STR(gs->fields, name, field); + } }