#include "../../include/ground.h" #include #include #include static inline void doLabels(GroundProgram* program, GroundState* state) { for (size_t 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, 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, 2047); label->name[2047] = '\0'; label->lineNum = i; HASH_ADD_STR(state->labels, name, label); } } } } for (size_t i = 0; i < program->len; i++) { GroundInstruction* instruction = &program->at[i]; if (instruction->type == GroundInstruction_JUMP) { GroundArg* arg = &instruction->args.at[0]; size_t* line = Ground.State.findLabel(state, arg->as.ref); 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, 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]; size_t* line = Ground.State.findLabel(state, arg->as.ref); 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, 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]; size_t* line = Ground.State.findLabel(state, arg->as.ref); 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, i); Ground.Log.Error(buf); Ground.Flags.error = true; return; } arg->_offset = *line; } } } /* * Assigns an offset to each variable referenced. */ static inline size_t doOffsets(GroundProgram* program, GroundState* state) { size_t size = 0; for (size_t i = 0; i < program->len; i++) { for (size_t j = 0; j < program->at[i].args.len; j++) { GroundArg* arg = &program->at[i].args.at[j]; if ( arg->type == GroundArg_Value || arg->type == GroundArg_Label || arg->type == GroundArg_LineRef ) continue; GroundVariable* item = NULL; HASH_FIND_STR(state->variables, arg->as.ref, 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, 2047); item->_offset = size++; HASH_ADD_STR(state->variables, name, item); } arg->_offset = item->_offset; size++; } } return size; } void _GroundInternalRun(GroundProgram* program, GroundState* state) { // Precompute some really cool stuff doLabels(program, state); if (Ground.Flags.error) return; size_t size = doOffsets(program, state); if (Ground.Flags.error) return; GroundValue* heap = malloc(sizeof(GroundValue) * size); for (size_t i = 0; i < program->len; i++) { GroundInstruction instruction = Ground.Copy.Instruction(&program->at[i]); int64_t status = Ground.Instruction.execute(&instruction, heap); switch (status) { case -2: return; case -1: break; default: if (status < program->len) { i = status; } else { Ground.Log.Error("out of bounds jump in Ground.Internal.Run()"); Ground.Flags.error = true; return; } } Ground.Free.Instruction(&instruction); } }