From 88100b128ab44fad6d47ad24fe5f29777f123d85 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Thu, 16 Apr 2026 21:14:42 +1000 Subject: [PATCH] Implemented native C functions called from Toy scripts There's only example functions for now, but I'll add type-specific functions later. --- repl/main.c | 8 +++++++ repl/standard_library.c | 53 +++++++++++++++++++++++++++++++++++++++++ repl/standard_library.h | 5 ++++ source/toy_function.c | 12 ++++++++++ source/toy_function.h | 8 ++++++- source/toy_scope.c | 2 +- source/toy_value.c | 2 +- source/toy_vm.c | 7 +++++- 8 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 repl/standard_library.c create mode 100644 repl/standard_library.h diff --git a/repl/main.c b/repl/main.c index 0a47ddb..225828f 100644 --- a/repl/main.c +++ b/repl/main.c @@ -7,6 +7,8 @@ #include "toy_compiler.h" #include "toy_vm.h" +#include "standard_library.h" + #include #include #include @@ -337,6 +339,12 @@ int repl(const char* filepath, bool verbose) { Toy_VM vm; Toy_initVM(&vm); + //hacky test + if (vm.scope == NULL) { + vm.scope = Toy_pushScope(&vm.memoryBucket, NULL); + initStandardLibrary(&vm); + } + printf("%s> ", prompt); //shows the terminal prompt and begin //read from the terminal diff --git a/repl/standard_library.c b/repl/standard_library.c new file mode 100644 index 0000000..aaa74dd --- /dev/null +++ b/repl/standard_library.c @@ -0,0 +1,53 @@ +#include "standard_library.h" +#include "toy_console_colors.h" + +#include "toy_print.h" +#include "toy_scope.h" +#include "toy_stack.h" + +#include +#include +#include + +typedef struct CallbackPairs { + const char* name; + Toy_nativeCallback callback; +} CallbackPairs; + +//example callbacks +void hello(Toy_VM* vm) { + (void)vm; + Toy_print("Hello world!"); +} + +void debug(Toy_VM* vm) { + (void)vm; + Toy_print("This function returns the integer '42' to the calling scope."); + Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(42)); +} + +CallbackPairs callbackPairs[] = { + {"hello", hello}, + {"debug", debug}, + {NULL, NULL}, +}; + +//exposed functions +void initStandardLibrary(Toy_VM* vm) { + if (vm == NULL || vm->scope == NULL || vm->memoryBucket == NULL) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't initialize standard library, exiting\n" TOY_CC_RESET); + exit(-1); + } + + //declare each pair + for (int i = 0; callbackPairs[i].name; i++) { + //cheat + Toy_String key = (Toy_String){ + .leaf = { ._padding = { .type = TOY_STRING_LEAF, .length = strlen(callbackPairs[i].name), .refCount = 1, .cachedHash = 0 }, .data = callbackPairs[i].name } + }; + + Toy_Function* fn = Toy_createFunctionFromCallback(&(vm->memoryBucket), callbackPairs[i].callback); + + Toy_declareScope(vm->scope, &key, TOY_VALUE_FUNCTION, TOY_VALUE_FROM_FUNCTION(fn), true); + } +} diff --git a/repl/standard_library.h b/repl/standard_library.h new file mode 100644 index 0000000..d06a24f --- /dev/null +++ b/repl/standard_library.h @@ -0,0 +1,5 @@ +#pragma once + +#include "toy_vm.h" + +void initStandardLibrary(Toy_VM*); \ No newline at end of file diff --git a/source/toy_function.c b/source/toy_function.c index 42e5227..2c7cd81 100644 --- a/source/toy_function.c +++ b/source/toy_function.c @@ -11,8 +11,20 @@ Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned return fn; } +Toy_Function* Toy_createFunctionFromCallback(Toy_Bucket** bucketHandle, Toy_nativeCallback callback) { + Toy_Function* fn = (Toy_Function*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Function)); + + fn->type = TOY_FUNCTION_NATIVE; + fn->native.callback = callback; + + return fn; +} + TOY_API void Toy_freeFunction(Toy_Function* fn) { if (fn->type == TOY_FUNCTION_CUSTOM) { Toy_private_decrementScopeRefCount(fn->bytecode.parentScope); } + else if (fn->type == TOY_FUNCTION_NATIVE) { + fn->native.callback = NULL; + } } \ No newline at end of file diff --git a/source/toy_function.h b/source/toy_function.h index 2149eaf..943baab 100644 --- a/source/toy_function.h +++ b/source/toy_function.h @@ -3,6 +3,11 @@ #include "toy_common.h" #include "toy_bucket.h" #include "toy_scope.h" +#include "toy_vm.h" + +//forward declare +struct Toy_VM; +typedef void (*Toy_nativeCallback)(struct Toy_VM*); typedef enum Toy_FunctionType { TOY_FUNCTION_CUSTOM, @@ -17,7 +22,7 @@ typedef struct Toy_FunctionBytecode { typedef struct Toy_FunctionNative { Toy_FunctionType type; - void* ptr; //TODO: replace with the native function pointer + Toy_nativeCallback callback; } Toy_FunctionNative; typedef union Toy_Function_t { @@ -27,5 +32,6 @@ typedef union Toy_Function_t { } Toy_Function; 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 void Toy_freeFunction(Toy_Function* fn); \ No newline at end of file diff --git a/source/toy_scope.c b/source/toy_scope.c index b21634c..e6bbe71 100644 --- a/source/toy_scope.c +++ b/source/toy_scope.c @@ -71,7 +71,7 @@ static void probeAndInsert(Toy_Scope* scope, Toy_String* key, Toy_Value value, T static Toy_ScopeEntry* adjustScopeEntries(Toy_Scope* scope, unsigned int newCapacity) { //allocate and zero a new Toy_ScopeEntry array in memory - Toy_ScopeEntry* newEntries = malloc(newCapacity * sizeof(Toy_ScopeEntry)); + Toy_ScopeEntry* newEntries = malloc(newCapacity * sizeof(Toy_ScopeEntry)); //URGENT: could use a bucket instead? if (newEntries == NULL) { fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate space for 'Toy_Scope' entries\n" TOY_CC_RESET); diff --git a/source/toy_value.c b/source/toy_value.c index aadf6ac..cb6157c 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -319,7 +319,7 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) { return left.as.function->bytecode.code == right.as.function->bytecode.code; } else { - return left.as.function->native.ptr == right.as.function->native.ptr; + return left.as.function->native.callback == right.as.function->native.callback; } } else { diff --git a/source/toy_vm.c b/source/toy_vm.c index 9e657d3..82f519e 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -419,7 +419,12 @@ static void processInvoke(Toy_VM* vm) { } break; - case TOY_FUNCTION_NATIVE: + case TOY_FUNCTION_NATIVE: { + //NOTE: arguments are on the stack, leave results on the stack + fn->native.callback(vm); + } + break; + default: Toy_error("Can't call an unknown function type"); break;