Simplify how built-in foreign methods and classes are wired up.
This commit is contained in:
+122
-23
@@ -7,10 +7,44 @@
|
||||
#include "scheduler.wren.inc"
|
||||
#include "timer.wren.inc"
|
||||
|
||||
#include "io.h"
|
||||
#include "scheduler.h"
|
||||
#include "timer.h"
|
||||
extern void fileStartSize(WrenVM* vm);
|
||||
extern void schedulerCaptureMethods(WrenVM* vm);
|
||||
extern void timerStartTimer(WrenVM* vm);
|
||||
|
||||
// The maximum number of foreign methods a single class defines. Ideally, we
|
||||
// would use variable-length arrays for each class in the table below, but
|
||||
// C++98 doesn't have any easy syntax for nested global static data, so we
|
||||
// just use worst-case fixed-size arrays instead.
|
||||
//
|
||||
// If you add a new method to the longest class below, make sure to bump this.
|
||||
// Note that it also includes an extra slot for the sentinel value indicating
|
||||
// the end of the list.
|
||||
#define MAX_METHODS_PER_CLASS 2
|
||||
|
||||
// The maximum number of foreign classes a single built-in module defines.
|
||||
//
|
||||
// If you add a new class to the largest module below, make sure to bump this.
|
||||
// Note that it also includes an extra slot for the sentinel value indicating
|
||||
// the end of the list.
|
||||
#define MAX_CLASSES_PER_MODULE 2
|
||||
|
||||
// Describes one foreign method in a class.
|
||||
typedef struct
|
||||
{
|
||||
bool isStatic;
|
||||
const char* signature;
|
||||
WrenForeignMethodFn method;
|
||||
} MethodRegistry;
|
||||
|
||||
// Describes one class in a built-in module.
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
|
||||
MethodRegistry methods[MAX_METHODS_PER_CLASS];
|
||||
} ClassRegistry;
|
||||
|
||||
// Describes one built-in module.
|
||||
typedef struct
|
||||
{
|
||||
// The name of the module.
|
||||
@@ -21,29 +55,56 @@ typedef struct
|
||||
// expression so can't be used in the initializer below.
|
||||
const char **source;
|
||||
|
||||
// The function that binds foreign methods in this module.
|
||||
WrenForeignMethodFn (*bindMethodFn)(WrenVM* vm, const char* className,
|
||||
bool isStatic, const char* signature);
|
||||
ClassRegistry classes[MAX_CLASSES_PER_MODULE];
|
||||
} ModuleRegistry;
|
||||
|
||||
// The function that binds foreign classes in this module.
|
||||
WrenForeignClassMethods (*bindClassFn)(WrenVM* vm, const char* className);
|
||||
} BuiltInModule;
|
||||
// To locate foreign classes and modules, we build a big directory for them in
|
||||
// static data. The nested collection initializer syntax gets pretty noisy, so
|
||||
// define a couple of macros to make it easier.
|
||||
#define MODULE(name) { #name, &name##ModuleSource, { {
|
||||
#define END_MODULE }, {NULL, {}} } },
|
||||
|
||||
#define CLASS(name) #name, {
|
||||
#define END_CLASS {false, NULL, NULL} }
|
||||
|
||||
#define METHOD(signature, fn) {false, signature, fn},
|
||||
#define STATIC_METHOD(signature, fn) {true, signature, fn},
|
||||
|
||||
// The array of built-in modules.
|
||||
static BuiltInModule modules[] =
|
||||
static ModuleRegistry modules[] =
|
||||
{
|
||||
{"io", &ioModuleSource, ioBindForeign, NULL},
|
||||
{"scheduler", &schedulerModuleSource, schedulerBindForeign, NULL},
|
||||
{"timer", &timerModuleSource, timerBindForeign, NULL},
|
||||
MODULE(io)
|
||||
CLASS(File)
|
||||
STATIC_METHOD("startSize_(_,_)", fileStartSize)
|
||||
END_CLASS
|
||||
END_MODULE
|
||||
|
||||
// Sentinel marking the end of the list.
|
||||
{NULL, NULL, NULL, NULL}
|
||||
MODULE(scheduler)
|
||||
CLASS(Scheduler)
|
||||
STATIC_METHOD("captureMethods_()", schedulerCaptureMethods)
|
||||
END_CLASS
|
||||
END_MODULE
|
||||
|
||||
MODULE(timer)
|
||||
CLASS(Timer)
|
||||
STATIC_METHOD("startTimer_(_,_)", timerStartTimer)
|
||||
END_CLASS
|
||||
END_MODULE
|
||||
|
||||
{NULL, NULL, {}} // Sentinel.
|
||||
};
|
||||
|
||||
#undef MODULE
|
||||
#undef END_MODULE
|
||||
#undef CLASS
|
||||
#undef END_CLASS
|
||||
#undef METHOD
|
||||
#undef STATIC_METHOD
|
||||
|
||||
// Looks for a built-in module with [name].
|
||||
//
|
||||
// Returns the BuildInModule for it or NULL if not found.
|
||||
static BuiltInModule* findModule(const char* name)
|
||||
static ModuleRegistry* findModule(const char* name)
|
||||
{
|
||||
for (int i = 0; modules[i].name != NULL; i++)
|
||||
{
|
||||
@@ -53,9 +114,37 @@ static BuiltInModule* findModule(const char* name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Looks for a class with [name] in [module].
|
||||
static ClassRegistry* findClass(ModuleRegistry* module, const char* name)
|
||||
{
|
||||
for (int i = 0; module->classes[i].name != NULL; i++)
|
||||
{
|
||||
if (strcmp(name, module->classes[i].name) == 0) return &module->classes[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Looks for a method with [signature] in [clas].
|
||||
static WrenForeignMethodFn findMethod(ClassRegistry* clas,
|
||||
bool isStatic, const char* signature)
|
||||
{
|
||||
for (int i = 0; clas->methods[i].signature != NULL; i++)
|
||||
{
|
||||
MethodRegistry* method = &clas->methods[i];
|
||||
if (isStatic == method->isStatic &&
|
||||
strcmp(signature, method->signature) == 0)
|
||||
{
|
||||
return method->method;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* readBuiltInModule(const char* name)
|
||||
{
|
||||
BuiltInModule* module = findModule(name);
|
||||
ModuleRegistry* module = findModule(name);
|
||||
if (module == NULL) return NULL;
|
||||
|
||||
size_t length = strlen(*module->source);
|
||||
@@ -68,10 +157,14 @@ WrenForeignMethodFn bindBuiltInForeignMethod(
|
||||
WrenVM* vm, const char* moduleName, const char* className, bool isStatic,
|
||||
const char* signature)
|
||||
{
|
||||
BuiltInModule* module = findModule(moduleName);
|
||||
// TODO: Assert instead of return NULL?
|
||||
ModuleRegistry* module = findModule(moduleName);
|
||||
if (module == NULL) return NULL;
|
||||
|
||||
return module->bindMethodFn(vm, className, isStatic, signature);
|
||||
ClassRegistry* clas = findClass(module, className);
|
||||
if (clas == NULL) return NULL;
|
||||
|
||||
return findMethod(clas, isStatic, signature);
|
||||
}
|
||||
|
||||
WrenForeignClassMethods bindBuiltInForeignClass(
|
||||
@@ -79,8 +172,14 @@ WrenForeignClassMethods bindBuiltInForeignClass(
|
||||
{
|
||||
WrenForeignClassMethods methods = { NULL, NULL };
|
||||
|
||||
BuiltInModule* module = findModule(moduleName);
|
||||
ModuleRegistry* module = findModule(moduleName);
|
||||
if (module == NULL) return methods;
|
||||
|
||||
return module->bindClassFn(vm, className);
|
||||
}
|
||||
|
||||
ClassRegistry* clas = findClass(module, className);
|
||||
if (clas == NULL) return methods;
|
||||
|
||||
methods.allocate = findMethod(clas, true, "<allocate>");
|
||||
methods.finalize = findMethod(clas, true, "<finalize>");
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
#ifndef modules_h
|
||||
#define modules_h
|
||||
|
||||
// This wires up all of the foreign classes and methods defined by the built-in
|
||||
// modules bundled with the CLI.
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
// Returns the source for built-in module [name].
|
||||
char* readBuiltInModule(const char* module);
|
||||
|
||||
// Looks up a foreign method in a built-in module.
|
||||
|
||||
Reference in New Issue
Block a user