From 3ab18c7b14fc96ccbb5724979e619eb0d3e88eb1 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Fri, 15 May 2026 14:13:54 +1000 Subject: [PATCH] Fixed nagging issues, read more * A segfault from the inspector * multiple returns no longer a goal * Cleaned up the 'URGENT' comment tags * Narrowed down what is needed for alpha --- repl/bytecode_inspector.c | 2 -- repl/main.c | 25 ++++++++++++++++++++----- scripts/hello_world.toy | 8 -------- source/toy_attributes.c | 34 +++++++++++++++++++--------------- source/toy_compiler.c | 3 --- source/toy_parser.c | 2 +- source/toy_value.c | 1 - source/toy_vm.c | 31 ++++++++----------------------- source/toy_vm.h | 2 +- tests/scripts/test_arrays.toy | 2 -- tests/units/test_value.c | 1 + 11 files changed, 50 insertions(+), 61 deletions(-) diff --git a/repl/bytecode_inspector.c b/repl/bytecode_inspector.c index 292fd47..b7d71c5 100644 --- a/repl/bytecode_inspector.c +++ b/repl/bytecode_inspector.c @@ -385,5 +385,3 @@ int inspect_read(unsigned char* bytecode, unsigned int pc, unsigned int jumps_ad } } } - -//TODO: Check if strings are reused in the bytecode \ No newline at end of file diff --git a/repl/main.c b/repl/main.c index 499af6f..241c42d 100644 --- a/repl/main.c +++ b/repl/main.c @@ -321,8 +321,6 @@ int repl(const char* filepath, bool verbose) { char inputBuffer[INPUT_BUFFER_SIZE]; memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); //TODO: gc this - Toy_VM vm; Toy_initVM(&vm); @@ -347,14 +345,16 @@ int repl(const char* filepath, bool verbose) { } //parse the input, prep the VM for execution + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_Lexer lexer; Toy_bindLexer(&lexer, inputBuffer); Toy_Parser parser; Toy_bindParser(&parser, &lexer); - Toy_Ast* ast = Toy_scanParser(&bucket, &parser); //Ast is in the bucket, so it doesn't need to be freed + Toy_Ast* ast = Toy_scanParser(&bucket, &parser); //parsing error, retry - if (parser.error) { + if (parser.error || ast == NULL) { + Toy_freeBucket(&bucket); printf("%s> ", prompt); //shows the terminal prompt continue; } @@ -364,6 +364,12 @@ int repl(const char* filepath, bool verbose) { } unsigned char* bytecode = Toy_compileToBytecode(ast); + Toy_freeBucket(&bucket); //no need to for the GC here + + if (bytecode == NULL) { + printf("%s> ", prompt); + continue; + } if (verbose) { inspect_bytecode(bytecode); @@ -408,7 +414,6 @@ int repl(const char* filepath, bool verbose) { //cleanup all memory Toy_freeVM(&vm); - Toy_freeBucket(&bucket); return 0; } @@ -479,6 +484,12 @@ int main(int argc, const char* argv[]) { Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_Ast* ast = Toy_scanParser(&bucket, &parser); + if (ast == NULL) { + Toy_freeBucket(&bucket); + free(source); + return -1; + } + if (cmd.verbose) { inspect_ast(ast); } @@ -487,6 +498,10 @@ int main(int argc, const char* argv[]) { Toy_freeBucket(&bucket); free(source); + if (bytecode == NULL) { + return -1; + } + if (cmd.verbose) { inspect_bytecode(bytecode); } diff --git a/scripts/hello_world.toy b/scripts/hello_world.toy index e5d07c7..3c3ca71 100644 --- a/scripts/hello_world.toy +++ b/scripts/hello_world.toy @@ -1,5 +1,4 @@ -/* fn swap(a, b) { return b, a; } @@ -9,11 +8,4 @@ var b = 69; var c; var d; -//BUG: still causes a segfault c, d = swap(a, b); - -*/ - - -{ var str = "Hello"; var i = 0; while (i < 100) { str = str .. " World"; i++; } } - diff --git a/source/toy_attributes.c b/source/toy_attributes.c index 5c703d8..81f02dc 100644 --- a/source/toy_attributes.c +++ b/source/toy_attributes.c @@ -9,13 +9,17 @@ //if set, used for delegating to user-defined code static Toy_OpaqueAttributeHandler opaqueAttributeCallback = NULL; -//NOTE: there is no need to call 'Toy_freeValue' on the arguments, as the VM assumes you don't +//utils +#define MATCH_VALUE_AND_CSTRING(value, cstring) \ + ((TOY_VALUE_AS_STRING(value)->info.length == strlen(cstring)) && \ + (strncmp(cstring, TOY_VALUE_AS_STRING(value)->leaf.data, TOY_VALUE_AS_STRING(value)->info.length) == 0)) +//NOTE: there is no need to call 'Toy_freeValue' on the arguments, as the VM assumes you don't Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { - if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { + if (MATCH_VALUE_AND_CSTRING(attribute, "length")) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_STRING(compound)->info.length); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "asUpper", 7) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "asUpper")) { char* buffer = Toy_getStringRaw(TOY_VALUE_AS_STRING(compound)); for (int i = 0; buffer[i] != '\0'; i++) { buffer[i] = toupper(buffer[i]); @@ -24,7 +28,7 @@ Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy free(buffer); return TOY_VALUE_FROM_STRING(str); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "asLower", 7) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "asLower")) { char* buffer = Toy_getStringRaw(TOY_VALUE_AS_STRING(compound)); for (int i = 0; buffer[i] != '\0'; i++) { buffer[i] = tolower(buffer[i]); @@ -116,7 +120,7 @@ static void attr_arrayForEach(Toy_VM* vm) { Toy_declareScope(subVM.scope, Toy_copyString(name), paramType, Toy_copyValue(&subVM.memoryBucket, array->data[iterator]), true); Toy_freeString(name); - Toy_runVM(&subVM); //TODO: could use a 'map'-style method by storing the results + Toy_runVM(&subVM); Toy_resetVM(&subVM, false, true); } @@ -148,22 +152,22 @@ static void attr_arraySort(Toy_VM* vm) { } Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { - if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { + if (MATCH_VALUE_AND_CSTRING(attribute, "length")) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_ARRAY(compound)->count); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "pushBack", 8) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "pushBack")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_arrayPushBack); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "popBack", 7) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "popBack")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_arrayPopBack); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "forEach", 7) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "forEach")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_arrayForEach); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "sort", 4) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "sort")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_arraySort); return TOY_VALUE_FROM_FUNCTION(fn); } @@ -224,22 +228,22 @@ static void attr_tableForEach(Toy_VM* vm) { } Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { - if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "length", 6) == 0) { + if (MATCH_VALUE_AND_CSTRING(attribute, "length")) { return TOY_VALUE_FROM_INTEGER(TOY_VALUE_AS_ARRAY(compound)->count); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "insert", 6) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "insert")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableInsert); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "hasKey", 6) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "hasKey")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableHasKey); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "remove", 6) == 0) { + else if (MATCH_VALUE_AND_CSTRING(attribute, "remove")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableRemove); return TOY_VALUE_FROM_FUNCTION(fn); } - else if (strncmp(TOY_VALUE_AS_STRING(attribute)->leaf.data, "forEach", 7) == 0) { //URGENT: compare the contents AND length of these strings + else if (MATCH_VALUE_AND_CSTRING(attribute, "forEach")) { Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, attr_tableForEach); return TOY_VALUE_FROM_FUNCTION(fn); } diff --git a/source/toy_compiler.c b/source/toy_compiler.c index 8e0b4aa..51e4d05 100644 --- a/source/toy_compiler.c +++ b/source/toy_compiler.c @@ -820,9 +820,6 @@ static unsigned int writeInstructionVarDeclare(Toy_Bytecode** mb, Toy_AstVarDecl static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment) { unsigned int result = 0; - //BUG: flip the order of target & value, to allow chained assignment AND multiple return values - //do I need multiple return values? - //target is a variable name if (ast.target->type == TOY_AST_VALUE && TOY_VALUE_IS_STRING(ast.target->value.value)) { //name string diff --git a/source/toy_parser.c b/source/toy_parser.c index f28e90b..db26295 100644 --- a/source/toy_parser.c +++ b/source/toy_parser.c @@ -1066,7 +1066,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro return; } - //TODO: for-pre-clause-post-then + //URGENT: for-pre-clause-post-then //break else if (match(parser, TOY_TOKEN_KEYWORD_BREAK)) { diff --git a/source/toy_value.c b/source/toy_value.c index e7bf06e..9439366 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -494,7 +494,6 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) { return Toy_copyString(value.as.string); case TOY_VALUE_ARRAY: { - //TODO: concat + free is definitely a performance nightmare, could make an append function? Toy_Array* ptr = value.as.array; //if array is empty, skip below diff --git a/source/toy_vm.c b/source/toy_vm.c index 282b8f9..4820774 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -394,15 +394,8 @@ static void processInvoke(Toy_VM* vm) { //extract and store any results if (resultCount > 0) { - 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 - Toy_pushStack(&vm->stack, results->data[i]); - } - - //a bit naughty - free(results); + Toy_Value result = Toy_getReturnValueFromVM(vm, &subVM); + Toy_pushStack(&vm->stack, result); } //cleanup @@ -1104,7 +1097,7 @@ void Toy_resetVM(Toy_VM* vm, bool preserveScope, bool preserveStack) { //not sure how often to call teh GC if (vm->memoryBucket) { - Toy_collectBucketGarbage(&vm->memoryBucket); //URGENT: call GC after a certain number of bucket links allocated + Toy_collectBucketGarbage(&vm->memoryBucket); //WONTFIX: call GC after a certain number of bucket links allocated } } @@ -1189,19 +1182,11 @@ void Toy_freeVM(Toy_VM* vm) { } } -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 %s results requested from VM, exiting\n" TOY_CC_RESET, subVM->stack->count < resultCount ? "many":"few"); - exit(-1); +Toy_Value Toy_getReturnValueFromVM(Toy_VM* parentVM, Toy_VM* subVM) { + if (subVM->stack->count > 0) { + return Toy_copyValue(&parentVM->memoryBucket, subVM->stack->data[subVM->stack->count-1]); } - - Toy_Array* results = Toy_resizeArray(NULL, 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(&parentVM->memoryBucket, subVM->stack->data[offset + results->count]); + else { + return TOY_VALUE_FROM_NULL(); } - - return results; } diff --git a/source/toy_vm.h b/source/toy_vm.h index a0c8446..96ea7d0 100644 --- a/source/toy_vm.h +++ b/source/toy_vm.h @@ -51,5 +51,5 @@ 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* parentVM, Toy_VM* subVM, unsigned int resultCount); +TOY_API Toy_Value Toy_getReturnValueFromVM(Toy_VM* parentVM, Toy_VM* subVM); diff --git a/tests/scripts/test_arrays.toy b/tests/scripts/test_arrays.toy index f3cc2d7..db61c5e 100644 --- a/tests/scripts/test_arrays.toy +++ b/tests/scripts/test_arrays.toy @@ -24,5 +24,3 @@ print a; var b = []; print b; - -//TODO: utility functions are needed, see toy_array.h \ No newline at end of file diff --git a/tests/units/test_value.c b/tests/units/test_value.c index d49eb93..6f943ca 100644 --- a/tests/units/test_value.c +++ b/tests/units/test_value.c @@ -609,6 +609,7 @@ int main(void) { //TODO: references //TODO: type coersions + //TODO: opaques? return total; } \ No newline at end of file