Files
ground-rewrite/src/Bytecode/save.c
2026-07-27 21:37:08 +10:00

151 lines
4.5 KiB
C

#include "../../include/ground.h"
#include <stdio.h>
#include <string.h>
static void writeProgram(FILE* f, GroundBytecodeProgram* program) {
uint64_t count = program->len;
fwrite(&count, 8, 1, f);
for (GroundSize i = 0; i < count; i++) {
uint8_t type = (uint8_t)program->at[i].type;
fwrite(&type, 1, 1, f);
uint64_t argCount = program->at[i].args.len;
fwrite(&argCount, 8, 1, f);
if (argCount > 0) {
fwrite(program->at[i].args.at, sizeof(GroundSize), argCount, f);
}
}
}
static void writeValue(FILE* f, GroundBytecodeValue* v) {
switch (v->type.type) {
case GroundType_Int: {
uint8_t tag = 0;
fwrite(&tag, 1, 1, f);
fwrite(&v->as.Int, 8, 1, f);
break;
}
case GroundType_Double: {
uint8_t tag = 1;
fwrite(&tag, 1, 1, f);
fwrite(&v->as.Double, 8, 1, f);
break;
}
case GroundType_Char: {
uint8_t tag = 2;
fwrite(&tag, 1, 1, f);
fwrite(&v->as.Char, 1, 1, f);
break;
}
case GroundType_Bool: {
uint8_t tag = 3;
fwrite(&tag, 1, 1, f);
fwrite(&v->as.Bool, 1, 1, f);
break;
}
case GroundType_String: {
uint8_t tag = 4;
fwrite(&tag, 1, 1, f);
uint64_t len = v->as.String.len;
fwrite(&len, 8, 1, f);
fwrite(v->as.String.cstr, 1, len, f);
break;
}
case GroundType_Function: {
uint8_t tag = 5;
fwrite(&tag, 1, 1, f);
uint8_t isNative = v->as.Function.isNativeFunction ? 1 : 0;
fwrite(&isNative, 1, 1, f);
uint64_t argCount = v->as.Function.args.count;
fwrite(&argCount, 8, 1, f);
for (GroundSize i = 0; i < argCount; i++) {
char* name = v->as.Function.args.at[i].as.id != NULL
? v->as.Function.args.at[i].as.id->string : "";
uint64_t len = strlen(name);
fwrite(&len, 8, 1, f);
fwrite(name, 1, len, f);
}
if (!v->as.Function.isNativeFunction && v->as.Function.program.ground != NULL) {
writeProgram(f, v->as.Function.program.ground);
} else {
uint64_t zero = 0;
fwrite(&zero, 8, 1, f);
}
// closures are generated at runtime, not persisted
break;
}
case GroundType_List: {
uint8_t tag = 6;
fwrite(&tag, 1, 1, f);
uint64_t count = v->as.List.count;
fwrite(&count, 8, 1, f);
for (GroundSize i = 0; i < count; i++) {
writeValue(f, &v->as.List.at[i]);
}
break;
}
case GroundType_Struct: {
uint8_t tag = 7;
fwrite(&tag, 1, 1, f);
uint64_t size = v->as.Struct.size;
fwrite(&size, 8, 1, f);
for (GroundSize i = 0; i < size; i++) {
writeValue(f, &v->as.Struct.values[i]);
}
break;
}
case GroundType_Object: {
uint8_t tag = 8;
fwrite(&tag, 1, 1, f);
uint64_t size = v->as.Object.size;
fwrite(&size, 8, 1, f);
for (GroundSize i = 0; i < size; i++) {
writeValue(f, &v->as.Object.values[i]);
}
break;
}
case GroundType_Undefined: {
uint8_t tag = 9;
fwrite(&tag, 1, 1, f);
break;
}
case GroundType_CoreType: {
uint8_t tag = 10;
fwrite(&tag, 1, 1, f);
uint8_t coreType = (uint8_t)v->as.CoreType;
fwrite(&coreType, 1, 1, f);
break;
}
default: {
uint8_t tag = 0xFF;
fwrite(&tag, 1, 1, f);
break;
}
}
}
void _GroundBytecodeSave(GroundBytecode* bytecode, const char* path) {
FILE* f = fopen(path, "wb");
if (f == NULL) {
Ground.Log.Error("failed to open file for writing in Ground.Bytecode.save");
Ground.Flags.error = true;
return;
}
fwrite("GRNDbc\0", 7, 1, f);
uint32_t version = 1;
fwrite(&version, 4, 1, f);
uint64_t count = bytecode->heap.len;
fwrite(&count, 8, 1, f);
for (GroundSize i = 0; i < count; i++) {
writeValue(f, &bytecode->heap.heap[i]);
}
writeProgram(f, &bytecode->program);
fclose(f);
}