diff --git a/src/Bytecode/Instruction/execute.c b/src/Bytecode/Instruction/execute.c index 2524001..9917b84 100644 --- a/src/Bytecode/Instruction/execute.c +++ b/src/Bytecode/Instruction/execute.c @@ -31,8 +31,11 @@ static void printValue(GroundBytecodeValue* val) { case GroundType_String: printf("%s", val->as.String.cstr); break; + case GroundType_Function: + printf(""); + break; default: - printf(""); + printf("", val->type.type); break; } } @@ -714,22 +717,22 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns Ground.Flags.error = true; return CONTINUE; } + } else { + free(function->closure->heap); } - GroundBytecodeHeap newHeap = { - .capacity = heap->capacity, - .len = heap->len, - .heap = malloc(sizeof(GroundBytecodeValue) * heap->capacity) - }; + function->closure->capacity = heap->capacity; + function->closure->len = heap->len; + function->closure->heap = malloc(sizeof(GroundBytecodeValue) * heap->capacity); - if (newHeap.heap == NULL) { + if (function->closure->heap == NULL) { Ground.Log.Error("malloc failed in Ground.Bytecode.Instruction.execute"); Ground.Flags.error = true; return CONTINUE; } for (GroundSize i = 0; i < heap->len; i++) { - newHeap.heap[i] = Ground.Copy.BytecodeValue(&heap->heap[i]); + function->closure->heap[i] = Ground.Copy.BytecodeValue(&heap->heap[i]); } return CONTINUE; @@ -766,14 +769,14 @@ struct GroundExecutionResult _GroundBytecodeInstructionExecute(GroundBytecodeIns return CONTINUE; } - // load function arguments into the heap + // load function arguments into the heap for (GroundSize i = 0; i < function->args.count; i++) { - newHeap.heap[i] = Ground.Copy.BytecodeValue(HEAP_GET(heap, i + 1)); // +1 because arg 1 is where fn args start + newHeap.heap[i] = Ground.Copy.BytecodeValue(HEAP_GET(heap, instruction->args.at[i + 1])); } - // function arguments are the first indexes, copy after + // function arguments are the first indexes, copy closure after for (GroundSize i = function->args.count; i < newHeap.len; i++) { - newHeap.heap[i] = Ground.Copy.BytecodeValue(&function->closure->heap[i]); + newHeap.heap[i] = Ground.Copy.BytecodeValue(&function->closure->heap[i - function->args.count]); } // Now we run the thingy diff --git a/src/Bytecode/load.c b/src/Bytecode/load.c index 3b2f13e..60dad9a 100644 --- a/src/Bytecode/load.c +++ b/src/Bytecode/load.c @@ -47,6 +47,97 @@ static GroundBytecodeValue readValue(FILE* f) { v.as.String.len = len; break; } + case 5: { + v.type.type = GroundType_Function; + + uint8_t isNative; + fread(&isNative, 1, 1, f); + v.as.Function.isNativeFunction = isNative ? true : false; + + uint64_t argCount; + fread(&argCount, 8, 1, f); + v.as.Function.args.count = argCount; + v.as.Function.args.capacity = argCount; + if (argCount > 0) { + v.as.Function.args.at = malloc(sizeof(GroundFunctionArg) * argCount); + if (v.as.Function.args.at == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + for (uint64_t i = 0; i < argCount; i++) { + uint64_t nameLen; + fread(&nameLen, 8, 1, f); + GroundIdentifier* id = malloc(sizeof(GroundIdentifier)); + if (id == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + id->string = malloc(nameLen + 1); + if (id->string == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + if (nameLen > 0) { + fread(id->string, 1, nameLen, f); + } + id->string[nameLen] = '\0'; + id->referenceCount = 1; + v.as.Function.args.at[i].as.id = id; + } + } else { + v.as.Function.args.at = NULL; + } + + v.as.Function.program.ground = malloc(sizeof(GroundBytecodeProgram)); + if (v.as.Function.program.ground == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + uint64_t instCount; + fread(&instCount, 8, 1, f); + if (instCount > 0) { + v.as.Function.program.ground->at = malloc(sizeof(GroundBytecodeInstruction) * instCount); + if (v.as.Function.program.ground->at == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + for (uint64_t i = 0; i < instCount; i++) { + uint8_t type; + fread(&type, 1, 1, f); + v.as.Function.program.ground->at[i].type = (enum GroundInstructionType)type; + + uint64_t instArgCount; + fread(&instArgCount, 8, 1, f); + if (instArgCount > 0) { + v.as.Function.program.ground->at[i].args.at = malloc(sizeof(GroundSize) * instArgCount); + if (v.as.Function.program.ground->at[i].args.at == NULL) { + Ground.Log.Error("malloc failed in Ground.Bytecode.load"); + Ground.Flags.error = true; + return v; + } + fread(v.as.Function.program.ground->at[i].args.at, sizeof(GroundSize), instArgCount, f); + } else { + v.as.Function.program.ground->at[i].args.at = NULL; + } + v.as.Function.program.ground->at[i].args.len = instArgCount; + v.as.Function.program.ground->at[i].args.capacity = instArgCount; + } + v.as.Function.program.ground->len = instCount; + v.as.Function.program.ground->capacity = instCount; + } else { + v.as.Function.program.ground->at = NULL; + v.as.Function.program.ground->len = 0; + v.as.Function.program.ground->capacity = 0; + } + + v.as.Function.closure = NULL; + break; + } default: { Ground.Log.Error("unknown value type in Ground.Bytecode.load"); Ground.Flags.error = true; diff --git a/src/Bytecode/save.c b/src/Bytecode/save.c index b92d2da..f7efb43 100644 --- a/src/Bytecode/save.c +++ b/src/Bytecode/save.c @@ -1,5 +1,20 @@ #include "../../include/ground.h" #include +#include + +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) { @@ -35,6 +50,32 @@ static void writeValue(FILE* f, GroundBytecodeValue* v) { 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; + } default: { uint8_t tag = 0xFF; fwrite(&tag, 1, 1, f); @@ -61,15 +102,7 @@ void _GroundBytecodeSave(GroundBytecode* bytecode, const char* path) { writeValue(f, &bytecode->heap.heap[i]); } - count = bytecode->program.len; - fwrite(&count, 8, 1, f); - for (GroundSize i = 0; i < count; i++) { - uint8_t type = (uint8_t)bytecode->program.at[i].type; - fwrite(&type, 1, 1, f); - uint64_t argCount = bytecode->program.at[i].args.len; - fwrite(&argCount, 8, 1, f); - fwrite(bytecode->program.at[i].args.at, 8, argCount, f); - } + writeProgram(f, &bytecode->program); fclose(f); }