#include "../../include/ground.h" static inline void doLabels(GroundProgram* program, GroundState* state) { for (GroundSize i = 0; i < program->len; i++) { GroundInstruction* instruction = &program->at[i]; if (instruction->type == GroundInstruction_CREATELABEL) { if (instruction->args.len > 0) { GroundArg* arg = &instruction->args.at[0]; GroundLabel* label = NULL; HASH_FIND_STR(state->labels, arg->as.ref->string, label); if (label == NULL) { label = malloc(sizeof(GroundLabel)); if (label == NULL) { Ground.Log.Error("malloc failed in Ground.Internal.run()"); Ground.Flags.error = true; return; } strncpy(label->name, arg->as.ref->string, 2047); label->name[2047] = '\0'; label->lineNum = i; HASH_ADD_STR(state->labels, name, label); } } } } for (GroundSize i = 0; i < program->len; i++) { GroundInstruction* instruction = &program->at[i]; if (instruction->type == GroundInstruction_JUMP) { GroundArg* arg = &instruction->args.at[0]; 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); Ground.Log.Error(buf); Ground.Flags.error = true; return; } arg->_offset = *line; } else if (instruction->type == GroundInstruction_IF) { GroundArg* arg = &instruction->args.at[1]; 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); Ground.Log.Error(buf); Ground.Flags.error = true; return; } arg->_offset = *line; } else if (instruction->type == GroundInstruction_CATCH) { GroundArg* arg = &instruction->args.at[1]; 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); Ground.Log.Error(buf); Ground.Flags.error = true; return; } arg->_offset = *line; } } } /* * Assigns an offset to each variable referenced. */ static inline GroundSize doOffsets(GroundProgram* gp, GroundState* state, GroundBytecodeProgram* gbp) { GroundSize size = 0; // Add size of state and assign offsets to pre-existing variables GroundVariable *s, *tmp; HASH_ITER(hh, state->variables, s, tmp) { s->_offset = size++; } for (GroundSize i = 0; i < gp->len; i++) { for (GroundSize j = 0; j < gp->at[i].args.len; j++) { GroundArg* arg = &gp->at[i].args.at[j]; if ( arg->type == GroundArg_Label || arg->type == GroundArg_LineRef ) continue; if (arg->type == GroundArg_Value) { GroundVariable* item = malloc(sizeof(GroundVariable)); if (item == NULL) { Ground.Log.Error("malloc failed in Ground.Internal.run()"); Ground.Flags.error = true; return 0; } item->value = Ground.Copy.Value(&arg->as.value); if (Ground.Flags.error) return 0; item->_offset = size++; snprintf(item->name, sizeof(item->name) - 1, "_._.ground_internal_constant_%zu", item->_offset); HASH_ADD_STR(state->variables, name, item); arg->_offset = item->_offset; continue; } 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.Internal.run()"); 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; } // Convert to GroundBytecodeInstruction GroundBytecodeInstruction inst = { .type = gp->at[i].type, .args.at = malloc(sizeof(GroundSize) * gp->at[i].args.len), .args.len = gp->at[i].args.len, .args.capacity = gp->at[i].args.len }; if (inst.args.at == NULL) { Ground.Log.Error("malloc failed in Ground.Internal.run()"); Ground.Flags.error = true; return 0; } for (GroundSize j = 0; j < gp->at[i].args.len; j++) { inst.args.at[j] = gp->at[i].args.at[j]._offset; } gbp->at[i] = inst; gbp->len++; } return size; } GroundBytecode _GroundNewBytecode(GroundProgram* program, GroundState* state) { GroundBytecode bytecode = { .program = { .at = malloc(sizeof(GroundBytecodeInstruction) * program->len), .capacity = program->len, .len = 0, }, .heap = { .heap = NULL, .capacity = 0, .len = 0 } }; if (bytecode.program.at == NULL) { Ground.Log.Error("malloc failed in Ground.New.Bytecode"); Ground.Flags.error = true; return bytecode; } // Add core types to state for (unsigned int i = 0; i < (unsigned int)GroundType_Object; i++) { GroundVariable* var = malloc(sizeof(GroundVariable)); if (var == NULL) { Ground.Log.Error("malloc failed in Ground.New.Bytecode"); Ground.Flags.error = true; return bytecode; } var->value = (GroundValue) { .type = {GroundType_CoreType}, .as.CoreType = (enum GroundTypeType) i }; switch ((enum GroundTypeType) i) { case GroundType_Int: { sprintf(var->name, "int"); break; } case GroundType_Double: { sprintf(var->name, "double"); break; } case GroundType_Char: { sprintf(var->name, "char"); break; } case GroundType_Bool: { sprintf(var->name, "bool"); break; } case GroundType_String: { sprintf(var->name, "string"); break; } case GroundType_List: { sprintf(var->name, "list"); break; } case GroundType_Function: { sprintf(var->name, "function"); break; } case GroundType_Struct: { sprintf(var->name, "struct"); break; } default: break; // unreachable (in theory) } HASH_ADD_STR(state->variables, name, var); } state->_size += (unsigned int)GroundType_Object + 1; // Precompute some really cool stuff doLabels(program, state); if (Ground.Flags.error) return bytecode; GroundSize size = doOffsets(program, state, &bytecode.program); if (Ground.Flags.error) return bytecode; // Allocate heap bytecode.heap.heap = malloc(sizeof(GroundBytecodeValue) * size); if (bytecode.heap.heap == NULL) { Ground.Log.Error("malloc failed in Ground.New.Bytecode"); Ground.Flags.error = true; return bytecode; } bytecode.heap.capacity = size; bytecode.heap.len = size; GroundVariable *s, *tmp; // Copy constants into heap at their assigned offsets HASH_ITER(hh, state->variables, s, tmp) { bytecode.heap.heap[s->_offset] = Ground.New.BytecodeValue(Ground.Copy.Value(&s->value)); if (Ground.Flags.error) return bytecode; } return bytecode; }