mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-20 01:04:08 +10:00
Implemented native C functions called from Toy scripts
There's only example functions for now, but I'll add type-specific functions later.
This commit is contained in:
@@ -7,6 +7,8 @@
|
|||||||
#include "toy_compiler.h"
|
#include "toy_compiler.h"
|
||||||
#include "toy_vm.h"
|
#include "toy_vm.h"
|
||||||
|
|
||||||
|
#include "standard_library.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -337,6 +339,12 @@ int repl(const char* filepath, bool verbose) {
|
|||||||
Toy_VM vm;
|
Toy_VM vm;
|
||||||
Toy_initVM(&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
|
printf("%s> ", prompt); //shows the terminal prompt and begin
|
||||||
|
|
||||||
//read from the terminal
|
//read from the terminal
|
||||||
|
|||||||
53
repl/standard_library.c
Normal file
53
repl/standard_library.c
Normal file
@@ -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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
repl/standard_library.h
Normal file
5
repl/standard_library.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "toy_vm.h"
|
||||||
|
|
||||||
|
void initStandardLibrary(Toy_VM*);
|
||||||
@@ -11,8 +11,20 @@ Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned
|
|||||||
return fn;
|
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) {
|
TOY_API void Toy_freeFunction(Toy_Function* fn) {
|
||||||
if (fn->type == TOY_FUNCTION_CUSTOM) {
|
if (fn->type == TOY_FUNCTION_CUSTOM) {
|
||||||
Toy_private_decrementScopeRefCount(fn->bytecode.parentScope);
|
Toy_private_decrementScopeRefCount(fn->bytecode.parentScope);
|
||||||
}
|
}
|
||||||
|
else if (fn->type == TOY_FUNCTION_NATIVE) {
|
||||||
|
fn->native.callback = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,11 @@
|
|||||||
#include "toy_common.h"
|
#include "toy_common.h"
|
||||||
#include "toy_bucket.h"
|
#include "toy_bucket.h"
|
||||||
#include "toy_scope.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 {
|
typedef enum Toy_FunctionType {
|
||||||
TOY_FUNCTION_CUSTOM,
|
TOY_FUNCTION_CUSTOM,
|
||||||
@@ -17,7 +22,7 @@ typedef struct Toy_FunctionBytecode {
|
|||||||
|
|
||||||
typedef struct Toy_FunctionNative {
|
typedef struct Toy_FunctionNative {
|
||||||
Toy_FunctionType type;
|
Toy_FunctionType type;
|
||||||
void* ptr; //TODO: replace with the native function pointer
|
Toy_nativeCallback callback;
|
||||||
} Toy_FunctionNative;
|
} Toy_FunctionNative;
|
||||||
|
|
||||||
typedef union Toy_Function_t {
|
typedef union Toy_Function_t {
|
||||||
@@ -27,5 +32,6 @@ typedef union Toy_Function_t {
|
|||||||
} Toy_Function;
|
} Toy_Function;
|
||||||
|
|
||||||
TOY_API Toy_Function* Toy_createFunctionFromBytecode(Toy_Bucket** bucketHandle, unsigned char* bytecode, Toy_Scope* parentScope);
|
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);
|
TOY_API void Toy_freeFunction(Toy_Function* fn);
|
||||||
@@ -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) {
|
static Toy_ScopeEntry* adjustScopeEntries(Toy_Scope* scope, unsigned int newCapacity) {
|
||||||
//allocate and zero a new Toy_ScopeEntry array in memory
|
//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) {
|
if (newEntries == NULL) {
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate space for 'Toy_Scope' entries\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate space for 'Toy_Scope' entries\n" TOY_CC_RESET);
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) {
|
|||||||
return left.as.function->bytecode.code == right.as.function->bytecode.code;
|
return left.as.function->bytecode.code == right.as.function->bytecode.code;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return left.as.function->native.ptr == right.as.function->native.ptr;
|
return left.as.function->native.callback == right.as.function->native.callback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -419,7 +419,12 @@ static void processInvoke(Toy_VM* vm) {
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
Toy_error("Can't call an unknown function type");
|
Toy_error("Can't call an unknown function type");
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user