151 lines
4.5 KiB
C
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);
|
|
}
|