mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 14:18:42 +01:00
Let the host application control how System prints text.
This commit is contained in:
@ -145,6 +145,11 @@ static WrenForeignClassMethods bindForeignClass(
|
||||
return methods;
|
||||
}
|
||||
|
||||
static void write(WrenVM* vm, const char* text)
|
||||
{
|
||||
printf("%s", text);
|
||||
}
|
||||
|
||||
static void initVM()
|
||||
{
|
||||
WrenConfiguration config;
|
||||
@ -153,6 +158,7 @@ static void initVM()
|
||||
config.bindForeignMethodFn = bindForeignMethod;
|
||||
config.bindForeignClassFn = bindForeignClass;
|
||||
config.loadModuleFn = readModule;
|
||||
config.writeFn = write;
|
||||
|
||||
// Since we're running in a standalone process, be generous with memory.
|
||||
config.initialHeapSize = 1024 * 1024 * 100;
|
||||
|
||||
@ -48,6 +48,9 @@ typedef WrenForeignMethodFn (*WrenBindForeignMethodFn)(WrenVM* vm,
|
||||
bool isStatic,
|
||||
const char* signature);
|
||||
|
||||
// Displays a string of text to the user.
|
||||
typedef void (*WrenWriteFn)(WrenVM* vm, const char* text);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// The callback invoked when the foreign object is created.
|
||||
@ -111,6 +114,12 @@ typedef struct
|
||||
// stored in the foreign object when an instance is created.
|
||||
WrenBindForeignClassFn bindForeignClassFn;
|
||||
|
||||
// The callback Wren uses to display text when `System.print()` or the other
|
||||
// related functions are called.
|
||||
//
|
||||
// If this is `NULL`, Wren discards any printed text.
|
||||
WrenWriteFn writeFn;
|
||||
|
||||
// The number of bytes Wren will allocate before triggering the first garbage
|
||||
// collection.
|
||||
//
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
@ -1049,7 +1047,11 @@ DEF_PRIMITIVE(system_clock)
|
||||
|
||||
DEF_PRIMITIVE(system_writeString)
|
||||
{
|
||||
printf("%s", AS_CSTRING(args[1]));
|
||||
if (vm->config.writeFn != NULL)
|
||||
{
|
||||
vm->config.writeFn(vm, AS_CSTRING(args[1]));
|
||||
}
|
||||
|
||||
RETURN_VAL(args[1]);
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wren.h"
|
||||
@ -37,40 +35,26 @@ static void* defaultReallocate(void* ptr, size_t newSize)
|
||||
return realloc(ptr, newSize);
|
||||
}
|
||||
|
||||
void wrenInitConfiguration(WrenConfiguration* configuration)
|
||||
void wrenInitConfiguration(WrenConfiguration* config)
|
||||
{
|
||||
configuration->reallocateFn = NULL;
|
||||
configuration->loadModuleFn = NULL;
|
||||
configuration->bindForeignMethodFn = NULL;
|
||||
configuration->bindForeignClassFn = NULL;
|
||||
configuration->initialHeapSize = 1024 * 1024 * 10;
|
||||
configuration->minHeapSize = 1024 * 1024;
|
||||
configuration->heapGrowthPercent = 50;
|
||||
config->reallocateFn = defaultReallocate;
|
||||
config->loadModuleFn = NULL;
|
||||
config->bindForeignMethodFn = NULL;
|
||||
config->bindForeignClassFn = NULL;
|
||||
config->writeFn = NULL;
|
||||
config->initialHeapSize = 1024 * 1024 * 10;
|
||||
config->minHeapSize = 1024 * 1024;
|
||||
config->heapGrowthPercent = 50;
|
||||
}
|
||||
|
||||
WrenVM* wrenNewVM(WrenConfiguration* configuration)
|
||||
WrenVM* wrenNewVM(WrenConfiguration* config)
|
||||
{
|
||||
WrenReallocateFn reallocate = defaultReallocate;
|
||||
if (configuration->reallocateFn != NULL)
|
||||
{
|
||||
reallocate = configuration->reallocateFn;
|
||||
}
|
||||
|
||||
WrenVM* vm = (WrenVM*)reallocate(NULL, sizeof(*vm));
|
||||
WrenVM* vm = (WrenVM*)config->reallocateFn(NULL, sizeof(*vm));
|
||||
memset(vm, 0, sizeof(WrenVM));
|
||||
memcpy(&vm->config, config, sizeof(WrenConfiguration));
|
||||
|
||||
vm->reallocate = reallocate;
|
||||
vm->bindForeignMethod = configuration->bindForeignMethodFn;
|
||||
vm->bindForeignClass = configuration->bindForeignClassFn;
|
||||
vm->loadModule = configuration->loadModuleFn;
|
||||
vm->nextGC = configuration->initialHeapSize;
|
||||
vm->minNextGC = configuration->minHeapSize;
|
||||
vm->nextGC = config->initialHeapSize;
|
||||
|
||||
// +100 here because the configuration gives us the *additional* size of
|
||||
// the heap relative to the in-use memory, while heapScalePercent is the
|
||||
// *total* size of the heap relative to in-use.
|
||||
vm->heapScalePercent = 100 + configuration->heapGrowthPercent;
|
||||
|
||||
wrenSymbolTableInit(&vm->methodNames);
|
||||
|
||||
ObjString* name = AS_STRING(CONST_STRING(vm, "core"));
|
||||
@ -188,8 +172,11 @@ void wrenCollectGarbage(WrenVM* vm)
|
||||
}
|
||||
}
|
||||
|
||||
vm->nextGC = vm->bytesAllocated * vm->heapScalePercent / 100;
|
||||
if (vm->nextGC < vm->minNextGC) vm->nextGC = vm->minNextGC;
|
||||
// +100 here because the configuration gives us the *additional* size of
|
||||
// the heap relative to the in-use memory, while heapScalePercent is the
|
||||
// *total* size of the heap relative to in-use.
|
||||
vm->nextGC = vm->bytesAllocated * (100 + vm->config.heapGrowthPercent) / 100;
|
||||
if (vm->nextGC < vm->config.minHeapSize) vm->nextGC = vm->config.minHeapSize;
|
||||
|
||||
#if WREN_DEBUG_TRACE_MEMORY || WREN_DEBUG_TRACE_GC
|
||||
double elapsed = ((double)clock() / CLOCKS_PER_SEC) - startTime;
|
||||
@ -227,7 +214,7 @@ void* wrenReallocate(WrenVM* vm, void* memory, size_t oldSize, size_t newSize)
|
||||
if (newSize > 0 && vm->bytesAllocated > vm->nextGC) wrenCollectGarbage(vm);
|
||||
#endif
|
||||
|
||||
return vm->reallocate(memory, newSize);
|
||||
return vm->config.reallocateFn(memory, newSize);
|
||||
}
|
||||
|
||||
// Captures the local variable [local] into an [Upvalue]. If that local is
|
||||
@ -298,9 +285,9 @@ static WrenForeignMethodFn findForeignMethod(WrenVM* vm,
|
||||
bool isStatic,
|
||||
const char* signature)
|
||||
{
|
||||
if (vm->bindForeignMethod == NULL) return NULL;
|
||||
if (vm->config.bindForeignMethodFn == NULL) return NULL;
|
||||
|
||||
return vm->bindForeignMethod(vm, moduleName, className, isStatic, signature);
|
||||
return vm->config.bindForeignMethodFn(vm, moduleName, className, isStatic, signature);
|
||||
}
|
||||
|
||||
// Defines [methodValue] as a method on [classObj].
|
||||
@ -484,7 +471,7 @@ static Value importModule(WrenVM* vm, Value name)
|
||||
if (!IS_UNDEFINED(wrenMapGet(vm->modules, name))) return NULL_VAL;
|
||||
|
||||
// Load the module's source code from the embedder.
|
||||
char* source = vm->loadModule(vm, AS_CSTRING(name));
|
||||
char* source = vm->config.loadModuleFn(vm, AS_CSTRING(name));
|
||||
if (source == NULL)
|
||||
{
|
||||
// Couldn't load the module.
|
||||
@ -585,10 +572,10 @@ static Value validateSuperclass(WrenVM* vm, Value name, Value superclassValue,
|
||||
static void bindForeignClass(WrenVM* vm, ObjClass* classObj, ObjModule* module)
|
||||
{
|
||||
// TODO: Make this a runtime error?
|
||||
ASSERT(vm->bindForeignClass != NULL,
|
||||
ASSERT(vm->config.bindForeignClassFn != NULL,
|
||||
"Cannot declare foreign classes without a bindForeignClassFn.");
|
||||
|
||||
WrenForeignClassMethods methods = vm->bindForeignClass(
|
||||
WrenForeignClassMethods methods = vm->config.bindForeignClassFn(
|
||||
vm, module->name->value, classObj->name->value);
|
||||
|
||||
Method method;
|
||||
@ -1492,7 +1479,7 @@ Value wrenImportModule(WrenVM* vm, const char* name)
|
||||
}
|
||||
|
||||
// Load the module's source code from the embedder.
|
||||
char* source = vm->loadModule(vm, name);
|
||||
char* source = vm->config.loadModuleFn(vm, name);
|
||||
if (source == NULL)
|
||||
{
|
||||
wrenPopRoot(vm); // nameValue.
|
||||
|
||||
@ -57,9 +57,6 @@ struct WrenVM
|
||||
|
||||
// Memory management data:
|
||||
|
||||
// The externally-provided function used to allocate memory.
|
||||
WrenReallocateFn reallocate;
|
||||
|
||||
// The number of bytes that are known to be currently allocated. Includes all
|
||||
// memory that was proven live after the last GC, as well as any new bytes
|
||||
// that were allocated since then. Does *not* include bytes for objects that
|
||||
@ -69,14 +66,6 @@ struct WrenVM
|
||||
// The number of total allocated bytes that will trigger the next GC.
|
||||
size_t nextGC;
|
||||
|
||||
// The minimum value for [nextGC] when recalculated after a collection.
|
||||
size_t minNextGC;
|
||||
|
||||
// The scale factor used to calculate [nextGC] from the current number of in
|
||||
// use bytes, as a percent. For example, 150 here means that nextGC will be
|
||||
// 50% larger than the current number of in-use bytes.
|
||||
int heapScalePercent;
|
||||
|
||||
// The first object in the linked list of all currently allocated objects.
|
||||
Obj* first;
|
||||
|
||||
@ -104,15 +93,8 @@ struct WrenVM
|
||||
// to the function.
|
||||
int foreignCallNumArgs;
|
||||
|
||||
// The function used to locate foreign functions.
|
||||
WrenBindForeignMethodFn bindForeignMethod;
|
||||
WrenConfiguration config;
|
||||
|
||||
// The function used to locate foreign classes.
|
||||
WrenBindForeignClassFn bindForeignClass;
|
||||
|
||||
// The function used to load modules.
|
||||
WrenLoadModuleFn loadModule;
|
||||
|
||||
// Compiler and debugger data:
|
||||
|
||||
// The compiler that is currently compiling code. This is used so that heap
|
||||
|
||||
Reference in New Issue
Block a user