diff --git a/.notes/bytecode-format.txt b/.notes/bytecode-format.txt index 251d8ad..ec3ac86 100644 --- a/.notes/bytecode-format.txt +++ b/.notes/bytecode-format.txt @@ -34,7 +34,7 @@ Bytecode Format Structure .header: N total size # size of this routine, including all data and subroutines N .jumps count # the number of entries in the jump table (should be data count + routine count) - N .param count # the number of parameter fields expected (used for subroutines) + N .param count # the number of parameter fields expected (a secondary jump table, used for subroutine parameters) N .data count # the number of data fields present N .subs count # the number of subroutines present .code start # absolute address of .code; mandatory @@ -48,14 +48,14 @@ Bytecode Format Structure # opcode instructions read and 'executed' by the interpreter (aligned to 4-byte widths) [READ, TOY_VALUE_STRING, Toy_StringType, stringLength] [jumpIndex] -.param: - # a list of names, stored in .data, to be used for any provided function arguments - -.jumptable: +.jumps: # a layer of indirection for quickly looking up values in .data and .subs 0 -> {string, 0x00} 4 -> {fn, 0xFF} +.param: + # a list of names, stored in .data, to be used for any provided function arguments + .data: # data that can't be cleanly embedded into .code, such as strings "Hello world\0" diff --git a/repl/bytecode_inspector.c b/repl/bytecode_inspector.c index 6ae7d29..da5b2fd 100644 --- a/repl/bytecode_inspector.c +++ b/repl/bytecode_inspector.c @@ -6,6 +6,7 @@ #include #include +#include int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr); int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr); @@ -15,31 +16,34 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad // void inspect_data(unsigned char* bytecode, unsigned int pc, unsigned int size); // void inspect_subs(unsigned char* bytecode, unsigned int pc, unsigned int size); +#define ISPRINT_SANITIZE(x) (isprint((int)x) > 0 ? (x) : '_') + #define MARKER_VALUE(pc, type) \ (pc * sizeof(type)) -#define MARKER "\033[" TOY_CC_FONT_BLACK "m" " %lu\t" TOY_CC_RESET +#define MARKER "\t\033[" TOY_CC_FONT_BLACK "m" " %lu\t" TOY_CC_RESET +#define FONT_BLACK "\033[" TOY_CC_FONT_BLACK "m" //exposed functions -void inspect_bytecode(unsigned char* bytecode) { +int inspect_bytecode(unsigned char* bytecode) { //TODO: handle version info - unsigned int const header_size = 0; - unsigned int const header_jumps = 1; - unsigned int const header_param = 2; - unsigned int const header_data = 3; - unsigned int const header_subs = 4; + unsigned int const bytecodeSize = ((unsigned int*)(bytecode))[0]; + unsigned int const jumpsSize = ((unsigned int*)(bytecode))[1]; + unsigned int const paramSize = ((unsigned int*)(bytecode))[2]; + unsigned int const dataSize = ((unsigned int*)(bytecode))[3]; + unsigned int const subsSize = ((unsigned int*)(bytecode))[4]; - //header size - printf(MARKER TOY_CC_NOTICE "Bytecode Size: \t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_size, unsigned int), ((unsigned int*)(bytecode))[header_size]); + printf(FONT_BLACK ".header:\r" TOY_CC_RESET); + + //bytecode size + printf(MARKER TOY_CC_NOTICE "Bytecode Size: \t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(0, unsigned int), bytecodeSize); //header counts - printf(MARKER TOY_CC_NOTICE "Jumps Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_jumps, unsigned int), ((unsigned int*)(bytecode))[header_jumps]); - printf(MARKER TOY_CC_NOTICE "Param Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_param, unsigned int), ((unsigned int*)(bytecode))[header_param]); - printf(MARKER TOY_CC_NOTICE "Data Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_data, unsigned int), ((unsigned int*)(bytecode))[header_data]); - printf(MARKER TOY_CC_NOTICE "Subs Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(header_subs, unsigned int), ((unsigned int*)(bytecode))[header_subs]); - - printf("\n---\n"); + printf(MARKER TOY_CC_NOTICE "Jumps Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(1, unsigned int), jumpsSize); + printf(MARKER TOY_CC_NOTICE "Param Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(2, unsigned int), paramSize); + printf(MARKER TOY_CC_NOTICE "Data Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(3, unsigned int), dataSize); + printf(MARKER TOY_CC_NOTICE "Subs Size:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(4, unsigned int), subsSize); //some addresses may be absent unsigned int addr_pc = 4; @@ -49,6 +53,8 @@ void inspect_bytecode(unsigned char* bytecode) { unsigned int data_addr = 0; unsigned int subs_addr = 0; + //bugfix + unsigned int code_end = 0; //header addresses if (true) { @@ -57,42 +63,93 @@ void inspect_bytecode(unsigned char* bytecode) { code_addr = ((unsigned int*)(bytecode))[addr_pc]; } - if (((unsigned int*)(bytecode))[header_jumps] > 0) { + if (jumpsSize > 0) { addr_pc++; printf(MARKER TOY_CC_NOTICE "Jumps Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]); jumps_addr = ((unsigned int*)(bytecode))[addr_pc]; + if (code_end == 0) code_end = jumps_addr; } - if (((unsigned int*)(bytecode))[header_param] > 0) { + if (paramSize > 0) { addr_pc++; printf(MARKER TOY_CC_NOTICE "Param Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]); param_addr = ((unsigned int*)(bytecode))[addr_pc]; + if (code_end == 0) code_end = param_addr; } - if (((unsigned int*)(bytecode))[header_data] > 0) { + if (dataSize > 0) { addr_pc++; printf(MARKER TOY_CC_NOTICE "Data Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]); data_addr = ((unsigned int*)(bytecode))[addr_pc]; + if (code_end == 0) code_end = data_addr; } - if (((unsigned int*)(bytecode))[header_subs] > 0) { + if (subsSize > 0) { addr_pc++; printf(MARKER TOY_CC_NOTICE "Subs Address:\t\t%u" TOY_CC_RESET "\n", MARKER_VALUE(addr_pc, unsigned int), ((unsigned int*)(bytecode))[addr_pc]); subs_addr = ((unsigned int*)(bytecode))[addr_pc]; + if (code_end == 0) code_end = subs_addr; } - printf("\n---\n"); + if (code_end == 0) code_end = bytecodeSize; //very hacky + + printf(FONT_BLACK ".code:\r" TOY_CC_RESET); unsigned int pc = code_addr; - while(bytecode[pc] != TOY_OPCODE_RETURN) { + while(pc < code_end) { pc += inspect_instruction(bytecode, pc, jumps_addr, data_addr); } - pc += inspect_instruction(bytecode, pc, jumps_addr, data_addr); //one more for the final return - (void)jumps_addr; - (void)param_addr; - (void)data_addr; - (void)subs_addr; + //jumps + if (jumpsSize > 0) { + printf(FONT_BLACK ".jumps:\r" TOY_CC_RESET); + + for (unsigned int i = 0; (i*4) < jumpsSize; i++) { + printf(MARKER TOY_CC_NOTICE "%u (data %u)" TOY_CC_RESET "\n", MARKER_VALUE(jumps_addr + i, unsigned int), + i, + ((unsigned int*)(bytecode + jumps_addr))[i] + data_addr + ); + } + } + + //param + if (paramSize > 0) { + printf(FONT_BLACK ".param:\r" TOY_CC_RESET); + + for (unsigned int i = 0; (i*4) < paramSize; i += 2) { + printf(MARKER TOY_CC_NOTICE "%u (type %s, data %u)" TOY_CC_RESET "\n", MARKER_VALUE(param_addr + i, unsigned int), + i, + Toy_private_getValueTypeAsCString(((unsigned int*)(bytecode + param_addr))[i + 1]), + ((unsigned int*)(bytecode + param_addr))[i] + data_addr + ); + } + } + + //data; assume there's only strings for now + if (dataSize > 0) { + printf(FONT_BLACK ".data:\r" TOY_CC_RESET); + + for (unsigned int i = 0; (i*4) < dataSize; i++) { + printf(MARKER TOY_CC_NOTICE "%c %c %c %c" TOY_CC_RESET "\n", MARKER_VALUE(data_addr + i, unsigned int), + ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[0]), + ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[1]), + ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[2]), + ISPRINT_SANITIZE(((char*)(bytecode + data_addr + (i*4)))[3]) + ); + } + } + + //subs + if (subsSize > 0) { + printf(FONT_BLACK ".subs:\n" TOY_CC_RESET); + + unsigned int i = 0; + while (i < subsSize) { + i += inspect_bytecode(bytecode + subs_addr + i); + } + } + + return bytecodeSize; } int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int jumps_addr, unsigned int data_addr) { @@ -129,7 +186,7 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j return 4; case TOY_OPCODE_INVOKE: - printf(MARKER "INVOKE %s (%d args)\n", MARKER_VALUE(pc, unsigned char), + printf(MARKER "INVOKE as '%s' (%d parameters)\n", MARKER_VALUE(pc, unsigned char), Toy_private_getValueTypeAsCString(bytecode[pc + 1]), bytecode[pc + 2]); return 4; @@ -143,23 +200,23 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j return 4; case TOY_OPCODE_ADD: - printf(MARKER "ADD %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : ""); + printf(MARKER "ADD %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : ""); return 4; case TOY_OPCODE_SUBTRACT: - printf(MARKER "SUBTRACT %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : ""); + printf(MARKER "SUBTRACT %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : ""); return 4; case TOY_OPCODE_MULTIPLY: - printf(MARKER "MULTIPLY %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : ""); + printf(MARKER "MULTIPLY %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : ""); return 4; case TOY_OPCODE_DIVIDE: - printf(MARKER "DIVIDE %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : ""); + printf(MARKER "DIVIDE %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : ""); return 4; case TOY_OPCODE_MODULO: - printf(MARKER "MODULO %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "ASSIGN" : ""); + printf(MARKER "MODULO %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : ""); return 4; case TOY_OPCODE_COMPARE_EQUAL: @@ -291,6 +348,7 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad case TOY_VALUE_STRING: { Toy_StringType stringType = (Toy_StringType)(*(bytecode + pc + 2)); //Probably not needed int len = bytecode[pc + 3]; //only used for names? + (void)len; (void)stringType; @@ -298,13 +356,13 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad unsigned int jumpValue = *((unsigned int*)(bytecode + jumps_addr + indexValue)); char* cstr = ((char*)(bytecode + data_addr + jumpValue)); - printf(MARKER "READ STRING (%d) %s\n", MARKER_VALUE(pc, unsigned char), len, cstr); + printf(MARKER "READ STRING %u '%s'\n", MARKER_VALUE(pc, unsigned char), indexValue, cstr); return 8; } case TOY_VALUE_FUNCTION: - printf(MARKER "READ FUNCTION (%d params)\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 2]); + printf(MARKER "READ FUNCTION '%u' (%d params)\n", MARKER_VALUE(pc, unsigned char), *((unsigned int*)(bytecode + pc + 4)), bytecode[pc + 2]); return 8; case TOY_VALUE_ARRAY: diff --git a/repl/bytecode_inspector.h b/repl/bytecode_inspector.h index f444ea2..f9605d1 100644 --- a/repl/bytecode_inspector.h +++ b/repl/bytecode_inspector.h @@ -1,3 +1,3 @@ #pragma once -void inspect_bytecode(unsigned char* bytecode); +int inspect_bytecode(unsigned char* bytecode); diff --git a/scripts/leapyear.toy b/scripts/leapyear.toy index bdd2348..7acdac6 100644 --- a/scripts/leapyear.toy +++ b/scripts/leapyear.toy @@ -4,6 +4,16 @@ fn isLeapYear(n: int) { if (n % 100 == 0) return false; return n % 4 == 0; } -print isLeapYear(1999); -print isLeapYear(2000); -print isLeapYear(2004); + +//check for string reuse +{ + print isLeapYear(1999); +} + +{ + print isLeapYear(2000); +} + +{ + print isLeapYear(2004); +} diff --git a/source/toy_compiler.c b/source/toy_compiler.c index cf1efca..4311cef 100644 --- a/source/toy_compiler.c +++ b/source/toy_compiler.c @@ -1222,10 +1222,13 @@ static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast) { writeBytecodeFromAst(&mb, ast); - EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator - EMIT_BYTE(&mb, code, 0); //4-byte alignment - EMIT_BYTE(&mb, code, 0); - EMIT_BYTE(&mb, code, 0); + //append an extra return if needed + if (mb->codeCount <= 4 || mb->code[mb->codeCount - 4] != TOY_OPCODE_RETURN) { //if empty or no return statement + EMIT_BYTE(&mb, code, TOY_OPCODE_RETURN); //end terminator + EMIT_BYTE(&mb, code, 0); //4-byte alignment + EMIT_BYTE(&mb, code, 0); + EMIT_BYTE(&mb, code, 0); + } } static unsigned char* collateBytecodeBody(Toy_Bytecode* mb) { diff --git a/source/toy_function.c b/source/toy_function.c index 2c7cd81..6da0ed5 100644 --- a/source/toy_function.c +++ b/source/toy_function.c @@ -20,6 +20,23 @@ Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nati return fn; } +Toy_Function* Toy_copyFunction(Toy_Bucket** bucketHandle, Toy_Function* original) { + Toy_Function* fn = (Toy_Function*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Function)); + + if (original->type == TOY_FUNCTION_CUSTOM) { + fn->type = original->type; + fn->bytecode.code = original->bytecode.code; + fn->bytecode.parentScope = original->bytecode.parentScope; + Toy_private_incrementScopeRefCount(fn->bytecode.parentScope); + } + else if (fn->type == TOY_FUNCTION_NATIVE) { + fn->type = original->type; + fn->native.callback = original->native.callback; + } + + return fn; +} + TOY_API void Toy_freeFunction(Toy_Function* fn) { if (fn->type == TOY_FUNCTION_CUSTOM) { Toy_private_decrementScopeRefCount(fn->bytecode.parentScope); diff --git a/source/toy_function.h b/source/toy_function.h index 943baab..f0a8acd 100644 --- a/source/toy_function.h +++ b/source/toy_function.h @@ -34,4 +34,5 @@ typedef union Toy_Function_t { TOY_API Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned char* bytecode, Toy_Scope* parentScope); TOY_API Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nativeCallback callback); +TOY_API Toy_Function* Toy_copyFunction(Toy_Bucket** bucketHandle, Toy_Function* fn); TOY_API void Toy_freeFunction(Toy_Function* fn); \ No newline at end of file diff --git a/source/toy_value.c b/source/toy_value.c index cb6157c..28c7e98 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -90,7 +90,7 @@ unsigned int Toy_hashValue(Toy_Value value) { return 0; } -Toy_Value Toy_copyValue(Toy_Value value) { +Toy_Value Toy_copyValue(Toy_Bucket** bucketHandle, Toy_Value value) { MAYBE_UNWRAP(value); switch(value.type) { @@ -104,13 +104,13 @@ Toy_Value Toy_copyValue(Toy_Value value) { return TOY_VALUE_FROM_STRING(Toy_copyString(value.as.string)); } - case TOY_VALUE_ARRAY: { + case TOY_VALUE_ARRAY: { //TODO: switch to buckets //arrays probably won't get copied much Toy_Array* ptr = value.as.array; Toy_Array* result = Toy_resizeArray(NULL, ptr->capacity); for (unsigned int i = 0; i < ptr->count; i++) { - result->data[i] = Toy_copyValue(ptr->data[i]); + result->data[i] = Toy_copyValue(bucketHandle, ptr->data[i]); } result->capacity = ptr->capacity; @@ -119,15 +119,15 @@ Toy_Value Toy_copyValue(Toy_Value value) { return TOY_VALUE_FROM_ARRAY(result); } - case TOY_VALUE_TABLE: { + case TOY_VALUE_TABLE: { //TODO: switch to buckets //tables probably won't get copied much Toy_Table* ptr = value.as.table; Toy_Table* result = Toy_private_adjustTableCapacity(NULL, ptr->capacity); for (unsigned int i = 0; i < ptr->capacity; i++) { if (TOY_VALUE_IS_NULL(ptr->data[i].key) != true) { - result->data[i].key = Toy_copyValue(ptr->data[i].key); - result->data[i].value = Toy_copyValue(ptr->data[i].value); + result->data[i].key = Toy_copyValue(bucketHandle, ptr->data[i].key); + result->data[i].value = Toy_copyValue(bucketHandle, ptr->data[i].value); } } @@ -137,9 +137,8 @@ Toy_Value Toy_copyValue(Toy_Value value) { return TOY_VALUE_FROM_TABLE(result); } - case TOY_VALUE_FUNCTION: //TODO: implement function duplication elsewhere - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't copy a function (use a reference instead), exiting\n" TOY_CC_RESET); - exit(-1); + case TOY_VALUE_FUNCTION: + return TOY_VALUE_FROM_FUNCTION(Toy_copyFunction(bucketHandle, value.as.function)); case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: diff --git a/source/toy_value.h b/source/toy_value.h index 36a15ae..fe12bbe 100644 --- a/source/toy_value.h +++ b/source/toy_value.h @@ -2,9 +2,9 @@ #include "toy_common.h" #include "toy_print.h" +#include "toy_bucket.h" //forward declarations -struct Toy_Bucket; union Toy_String_t; struct Toy_Array; struct Toy_Table; @@ -79,7 +79,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS TOY_API Toy_Value Toy_unwrapValue(Toy_Value value); TOY_API unsigned int Toy_hashValue(Toy_Value value); -TOY_API Toy_Value Toy_copyValue(Toy_Value value); +TOY_API Toy_Value Toy_copyValue(struct Toy_Bucket** bucketHandle, Toy_Value value); TOY_API void Toy_freeValue(Toy_Value value); TOY_API bool Toy_checkValueIsTruthy(Toy_Value value); diff --git a/source/toy_vm.c b/source/toy_vm.c index 82f519e..13203e1 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -159,7 +159,7 @@ static void processRead(Toy_VM* vm) { unsigned int addr = (unsigned int)READ_INT(vm); //create and push the function value - Toy_Function* function = Toy_createFunctionFromBytecode(&vm->memoryBucket, vm->code + vm->subsAddr + addr, vm->scope); + Toy_Function* function = Toy_createFunctionFromBytecode(&vm->memoryBucket, vm->code + vm->subsAddr + addr, vm->scope); //BUG: functions don't have the jumps indirection? value = TOY_VALUE_FROM_FUNCTION(function); break; @@ -227,7 +227,7 @@ static void processAssign(Toy_VM* vm) { //in case of chaining, leave a copy on the stack bool chainedAssignment = READ_BYTE(vm); if (chainedAssignment) { - Toy_pushStack(&vm->stack, Toy_copyValue(value)); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value)); } //cleanup @@ -253,7 +253,7 @@ static void processAssignCompound(Toy_VM* vm) { target = TOY_REFERENCE_FROM_POINTER(valuePtr); } else { - target = Toy_copyValue(*valuePtr); + target = Toy_copyValue(&vm->memoryBucket, *valuePtr); } } @@ -280,12 +280,12 @@ static void processAssignCompound(Toy_VM* vm) { } //set the value - array->data[index] = Toy_copyValue(TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value); + array->data[index] = Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value); //in case of chaining, leave a copy on the stack bool chainedAssignment = READ_BYTE(vm); if (chainedAssignment) { - Toy_pushStack(&vm->stack, Toy_copyValue(value)); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value)); } //cleanup @@ -296,12 +296,12 @@ static void processAssignCompound(Toy_VM* vm) { Toy_Table* table = TOY_VALUE_AS_TABLE(target); //set the value - Toy_insertTable(&table, Toy_copyValue(TOY_VALUE_IS_REFERENCE(key) ? Toy_unwrapValue(key) : key), Toy_copyValue(TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value)); + Toy_insertTable(&table, Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(key) ? Toy_unwrapValue(key) : key), Toy_copyValue(&vm->memoryBucket, TOY_VALUE_IS_REFERENCE(value) ? Toy_unwrapValue(value) : value)); //in case of chaining, leave a copy on the stack bool chainedAssignment = READ_BYTE(vm); if (chainedAssignment) { - Toy_pushStack(&vm->stack, Toy_copyValue(value)); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, value)); } //cleanup @@ -335,7 +335,7 @@ static void processAccess(Toy_VM* vm) { Toy_pushStack(&vm->stack, ref); } else { - Toy_pushStack(&vm->stack, Toy_copyValue(*valuePtr)); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, *valuePtr)); } //cleanup @@ -403,7 +403,7 @@ static void processInvoke(Toy_VM* vm) { //extract and store any results if (resultCount > 0) { - Toy_Array* results = Toy_extractResultsFromVM(&subVM, resultCount); + Toy_Array* results = Toy_extractResultsFromVM(vm, &subVM, resultCount); for (unsigned int i = 0; i < results->count; i++) { //NOTE: since the results array is being immediately freed, just push each element without a call to copy @@ -432,7 +432,7 @@ static void processInvoke(Toy_VM* vm) { } static void processDuplicate(Toy_VM* vm) { - Toy_Value value = Toy_copyValue(Toy_peekStack(&vm->stack)); + Toy_Value value = Toy_copyValue(&vm->memoryBucket, Toy_peekStack(&vm->stack)); Toy_pushStack(&vm->stack, value); //check for compound assignments @@ -878,7 +878,7 @@ static void processIndex(Toy_VM* vm) { Toy_pushStack(&vm->stack, ref); } else { - Toy_pushStack(&vm->stack, Toy_copyValue(array->data[i])); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, array->data[i])); } } @@ -911,7 +911,7 @@ static void processIndex(Toy_VM* vm) { Toy_pushStack(&vm->stack, ref); } else { - Toy_pushStack(&vm->stack, Toy_copyValue(entry->value)); + Toy_pushStack(&vm->stack, Toy_copyValue(&vm->memoryBucket, entry->value)); } } @@ -1146,7 +1146,7 @@ void Toy_freeVM(Toy_VM* vm) { } } -Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount) { +Toy_Array* Toy_extractResultsFromVM(Toy_VM* parentVM, Toy_VM* subVM, unsigned int resultCount) { if (subVM->stack->count < resultCount) { fprintf(stderr, TOY_CC_ERROR "ERROR: Too many results requested from VM, exiting\n" TOY_CC_RESET); exit(-1); @@ -1156,8 +1156,8 @@ Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount) { const unsigned int offset = subVM->stack->count - resultCount; //first element to extract - for (/* EMPTY */; results->count < resultCount; results->count++) { - results->data[results->count] = Toy_copyValue(subVM->stack->data[offset + results->count]); + for (/* EMPTY */; results->count < resultCount; results->count++) { //TODO: make sure the parent bucket adopts the child bucket's responsibilities + results->data[results->count] = Toy_copyValue(&parentVM->memoryBucket, subVM->stack->data[offset + results->count]); } return results; diff --git a/source/toy_vm.h b/source/toy_vm.h index 2600218..3b705b3 100644 --- a/source/toy_vm.h +++ b/source/toy_vm.h @@ -51,6 +51,6 @@ void Toy_bindVM(Toy_VM* vm, unsigned char* bytecode, Toy_Scope* parentScope); TOY_API unsigned int Toy_runVM(Toy_VM* vm); TOY_API void Toy_freeVM(Toy_VM* vm); -TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_VM* subVM, unsigned int resultCount); +TOY_API Toy_Array* Toy_extractResultsFromVM(Toy_VM* parentVM, Toy_VM* subVM, unsigned int resultCount); //TODO: inject extra data (hook system for external libraries) diff --git a/tests/units/test_value.c b/tests/units/test_value.c index 6cedf74..d49eb93 100644 --- a/tests/units/test_value.c +++ b/tests/units/test_value.c @@ -102,15 +102,21 @@ int test_value_creation(void) { int test_value_copying(void) { //test simple integer copy { + //setup + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + Toy_Value original = TOY_VALUE_FROM_INTEGER(42); - Toy_Value result = Toy_copyValue(original); + Toy_Value result = Toy_copyValue(&bucket, original); if (!TOY_VALUE_IS_INTEGER(result) || TOY_VALUE_AS_INTEGER(result) != 42 ) { fprintf(stderr, TOY_CC_ERROR "ERROR: copy an integer value failed\n" TOY_CC_RESET); + Toy_freeBucket(&bucket); return -1; } + + Toy_freeBucket(&bucket); } //test string copy @@ -119,7 +125,7 @@ int test_value_copying(void) { Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_Value original = TOY_VALUE_FROM_STRING(Toy_createStringLength(&bucket, "Hello world!", 12)); - Toy_Value result = Toy_copyValue(original); + Toy_Value result = Toy_copyValue(&bucket, original); if (TOY_VALUE_IS_STRING(result) == false || TOY_VALUE_AS_STRING(result)->info.type != TOY_STRING_LEAF || @@ -143,6 +149,8 @@ int test_value_copying(void) { //test copy arrays { //setup + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + Toy_Array* array = Toy_resizeArray(NULL, TOY_ARRAY_INITIAL_CAPACITY); TOY_ARRAY_PUSHBACK(array, TOY_VALUE_FROM_INTEGER(42)); TOY_ARRAY_PUSHBACK(array, TOY_VALUE_FROM_INTEGER(69)); @@ -150,7 +158,7 @@ int test_value_copying(void) { Toy_Value original = TOY_VALUE_FROM_ARRAY(array); - Toy_Value result = Toy_copyValue(original); + Toy_Value result = Toy_copyValue(&bucket, original); if (TOY_VALUE_AS_ARRAY(result) == false || TOY_VALUE_AS_ARRAY(result)->capacity != 8 || @@ -163,12 +171,14 @@ int test_value_copying(void) { fprintf(stderr, TOY_CC_ERROR "ERROR: copy an array value failed\n" TOY_CC_RESET); Toy_freeValue(original); Toy_freeValue(result); + Toy_freeBucket(&bucket); return -1; } //cleanup Toy_freeValue(original); Toy_freeValue(result); + Toy_freeBucket(&bucket); } //arrays can't be compared