From 750ebd1f99f2a6a4e82e344d4f0c2a2b9da7b225 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Wed, 20 May 2026 13:48:52 +1000 Subject: [PATCH] Added 'range' to standard library, adjusted native functions --- repl/standard_library.c | 56 +++++++++++++++++++++++++++++++++++------ scripts/for-theory.toy | 6 ++++- source/toy_attributes.c | 34 ++++++++++++++++++------- source/toy_function.c | 27 +++++++++++++------- source/toy_function.h | 6 ++++- source/toy_vm.c | 2 +- 6 files changed, 103 insertions(+), 28 deletions(-) diff --git a/repl/standard_library.c b/repl/standard_library.c index 2da068f..ee78518 100644 --- a/repl/standard_library.c +++ b/repl/standard_library.c @@ -15,18 +15,21 @@ typedef struct CallbackPairs { } CallbackPairs; //example callbacks -void debug(Toy_VM* vm) { +static void answer(Toy_VM* vm, Toy_FunctionNative* self) { (void)vm; - Toy_print("This function returns the integer '42' to the calling scope."); + (void)self; + Toy_print(TOY_CC_DEBUG "This function returns the integer '42' to the calling scope." TOY_CC_RESET); Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(42)); } -void identity(Toy_VM* vm) { +static void identity(Toy_VM* vm, Toy_FunctionNative* self) { //does nothing, but any arguements are left on the stack as results (void)vm; + (void)self; } -void echo(Toy_VM* vm) { +static void echo(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; //pops one argument, and prints it Toy_Value value = Toy_popStack(&vm->stack); Toy_String* string = Toy_stringifyValue(&vm->memoryBucket, value); @@ -39,10 +42,49 @@ void echo(Toy_VM* vm) { Toy_freeValue(value); } +static void next(Toy_VM* vm, Toy_FunctionNative* self) { + //used by 'range' + if (self->meta2 < self->meta1) { + Toy_Value result = TOY_VALUE_FROM_INTEGER(self->meta2); + Toy_pushStack(&vm->stack, result); + self->meta2++; + } + else { + Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL()); + } +} + +static void range(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + + //one arg to represent the number of iterations + Toy_Value value = Toy_popStack(&vm->stack); + + //check types + if (!TOY_VALUE_IS_INTEGER(value)) { + char buffer[256]; + snprintf(buffer, 256, "Expected Integer argument in 'range', found '%s'", Toy_getValueTypeAsCString(value.type)); + Toy_error(buffer); + Toy_freeValue(value); + return; + } + + //make the callback + Toy_Function* fn = Toy_createFunctionFromCallback(&vm->memoryBucket, next); + fn->native.meta1 = TOY_VALUE_AS_INTEGER(value); //fake a closure + fn->native.meta2 = 0; //counter + + Toy_Value result = TOY_VALUE_FROM_FUNCTION(fn); + + Toy_pushStack(&vm->stack, result); +} + + CallbackPairs callbackPairs[] = { - {"debug", debug}, - {"identity", identity}, - {"echo", echo}, + {"dbg_answer", answer}, + {"dbg_identity", identity}, + {"dbg_echo", echo}, + {"range", range}, {NULL, NULL}, }; diff --git a/scripts/for-theory.toy b/scripts/for-theory.toy index 39ba6c6..94d494c 100644 --- a/scripts/for-theory.toy +++ b/scripts/for-theory.toy @@ -1,10 +1,14 @@ //WARN: This is just a scratch pad, don't use it +//TODO: table.hasValue or table.getKeyFromValue? + //for (var i in array) print i; +//for (var i in table) print i; //for (var i in range(10)) print i; +//for (range(10)) print "ha"; -//example of a `range` function +//example of a `range`-like function fn range(limit: Int) { var counter: Int = 0; diff --git a/source/toy_attributes.c b/source/toy_attributes.c index 8e9b5d9..1ccd0e8 100644 --- a/source/toy_attributes.c +++ b/source/toy_attributes.c @@ -45,7 +45,9 @@ Toy_Value Toy_private_handleStringAttributes(Toy_VM* vm, Toy_Value compound, Toy } } -static void attr_arrayPushBack(Toy_VM* vm) { +static void attr_arrayPushBack(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value element = Toy_popStack(&vm->stack); @@ -69,7 +71,9 @@ static void attr_arrayPushBack(Toy_VM* vm) { array->count++; } -static void attr_arrayPopBack(Toy_VM* vm) { +static void attr_arrayPopBack(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Array* array = TOY_VALUE_AS_ARRAY(compound); @@ -86,7 +90,9 @@ static void attr_arrayPopBack(Toy_VM* vm) { Toy_pushStack(&vm->stack, element); } -static void attr_arrayForEach(Toy_VM* vm) { +static void attr_arrayForEach(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value callback = Toy_popStack(&vm->stack); @@ -133,7 +139,7 @@ static void attr_arrayForEach(Toy_VM* vm) { for (unsigned int iterator = 0; iterator < array->count; iterator++) { Toy_pushStack(&subVM.stack, Toy_copyValue(&subVM.memoryBucket, array->data[iterator])); - fn->native.callback(&subVM); //NOTE: try not to leave anything on the stack afterwards + fn->native.callback(&subVM, &fn->native); //NOTE: try not to leave anything on the stack afterwards } } break; @@ -147,8 +153,10 @@ static void attr_arrayForEach(Toy_VM* vm) { Toy_freeVM(&subVM); } -static void attr_arraySort(Toy_VM* vm) { +static void attr_arraySort(Toy_VM* vm, Toy_FunctionNative* self) { (void)vm; + (void)self; + //URGENT: attr_arraySort } @@ -180,7 +188,9 @@ Toy_Value Toy_private_handleArrayAttributes(Toy_VM* vm, Toy_Value compound, Toy_ } } -static void attr_tableInsert(Toy_VM* vm) { +static void attr_tableInsert(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value value = Toy_popStack(&vm->stack); //NOTE: the args are still backwards, except compound Toy_Value key = Toy_popStack(&vm->stack); @@ -202,7 +212,9 @@ static void attr_tableInsert(Toy_VM* vm) { } } -static void attr_tableHasKey(Toy_VM* vm) { +static void attr_tableHasKey(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value key = Toy_popStack(&vm->stack); @@ -214,7 +226,9 @@ static void attr_tableHasKey(Toy_VM* vm) { Toy_pushStack(&vm->stack, result); } -static void attr_tableRemove(Toy_VM* vm) { +static void attr_tableRemove(Toy_VM* vm, Toy_FunctionNative* self) { + (void)self; + Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value key = Toy_popStack(&vm->stack); @@ -223,8 +237,10 @@ static void attr_tableRemove(Toy_VM* vm) { Toy_removeTable(&table, key); } -static void attr_tableForEach(Toy_VM* vm) { +static void attr_tableForEach(Toy_VM* vm, Toy_FunctionNative* self) { (void)vm; + (void)self; + //URGENT: attr_tableForEach } diff --git a/source/toy_function.c b/source/toy_function.c index 29b8c37..37561dc 100644 --- a/source/toy_function.c +++ b/source/toy_function.c @@ -16,6 +16,8 @@ Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nati fn->type = TOY_FUNCTION_NATIVE; fn->native.callback = callback; + fn->native.meta1 = 0; //BUGFIX: Workaround for native functions lacking access to a closure-like scope + fn->native.meta2 = 0; return fn; } @@ -23,15 +25,22 @@ Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nati 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; + switch(original->type) { + case 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); + } + break; + + case TOY_FUNCTION_NATIVE: { + fn->type = original->type; + fn->native.callback = original->native.callback; + fn->native.meta1 = original->native.meta1; + fn->native.meta2 = original->native.meta2; + } + break; } return fn; diff --git a/source/toy_function.h b/source/toy_function.h index f0a8acd..3215819 100644 --- a/source/toy_function.h +++ b/source/toy_function.h @@ -7,7 +7,9 @@ //forward declare struct Toy_VM; -typedef void (*Toy_nativeCallback)(struct Toy_VM*); +struct Toy_FunctionNative; + +typedef void (*Toy_nativeCallback)(struct Toy_VM*, struct Toy_FunctionNative* self); typedef enum Toy_FunctionType { TOY_FUNCTION_CUSTOM, @@ -23,6 +25,8 @@ typedef struct Toy_FunctionBytecode { typedef struct Toy_FunctionNative { Toy_FunctionType type; Toy_nativeCallback callback; + int meta1; + int meta2; } Toy_FunctionNative; typedef union Toy_Function_t { diff --git a/source/toy_vm.c b/source/toy_vm.c index 8795b24..9f09b1f 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -405,7 +405,7 @@ static void processInvoke(Toy_VM* vm) { case TOY_FUNCTION_NATIVE: { //NOTE: arguments are on the stack, leave results on the stack - fn->native.callback(vm); + fn->native.callback(vm, &fn->native); } break;