A vertical slice of real libuv integration.
This adds a "timer" module to the CLI that provides a Timer class with a static sleep() method. Not the most exciting functionality in the world, but it requires the full hunk of libuv integration: - The CLI sets up libuv and runs the event loop. - Added a new directory src/module for CLI modules. - Updated all the make scripts to handle it. - Reorganized some other CLI code.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "io.h"
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
char const* rootDirectory = NULL;
|
||||
|
||||
// Reads the contents of the file at [path] and returns it as a heap allocated
|
||||
@@ -71,6 +73,8 @@ char* wrenFilePath(const char* name)
|
||||
|
||||
char* readModule(WrenVM* vm, const char* module)
|
||||
{
|
||||
if (strcmp(module, "timer") == 0) return timerGetSource();
|
||||
|
||||
// First try to load the module with a ".wren" extension.
|
||||
char* modulePath = wrenFilePath(module);
|
||||
char* moduleContents = readFile(modulePath);
|
||||
|
||||
+2
-33
@@ -5,37 +5,6 @@
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#define MAX_LINE_LENGTH 1024 // TODO: Something less arbitrary.
|
||||
|
||||
static int runRepl()
|
||||
{
|
||||
WrenVM* vm = createVM(NULL);
|
||||
|
||||
printf("\\\\/\"-\n");
|
||||
printf(" \\_/ wren v0.0.0\n");
|
||||
|
||||
char line[MAX_LINE_LENGTH];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
printf("> ");
|
||||
|
||||
if (!fgets(line, MAX_LINE_LENGTH, stdin))
|
||||
{
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle failure.
|
||||
wrenInterpret(vm, "Prompt", line);
|
||||
|
||||
// TODO: Automatically print the result of expressions.
|
||||
}
|
||||
|
||||
wrenFreeVM(vm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 1 || argc > 2)
|
||||
@@ -43,14 +12,14 @@ int main(int argc, const char* argv[])
|
||||
fprintf(stderr, "Usage: wren [file]\n");
|
||||
return 64; // EX_USAGE.
|
||||
}
|
||||
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
runRepl();
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
runFile(NULL, argv[1]);
|
||||
runFile(argv[1], NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+100
-9
@@ -3,12 +3,41 @@
|
||||
|
||||
#include "io.h"
|
||||
#include "vm.h"
|
||||
#include "timer.h"
|
||||
|
||||
WrenVM* createVM(WrenBindForeignMethodFn bindForeign)
|
||||
#define MAX_LINE_LENGTH 1024 // TODO: Something less arbitrary.
|
||||
|
||||
// The single VM instance that the CLI uses.
|
||||
WrenVM* vm;
|
||||
|
||||
WrenBindForeignMethodFn externalBindForeign;
|
||||
|
||||
uv_loop_t* loop;
|
||||
|
||||
static WrenForeignMethodFn bindForeignMethod(WrenVM* vm,
|
||||
const char* module,
|
||||
const char* className,
|
||||
bool isStatic,
|
||||
const char* signature)
|
||||
{
|
||||
if (strcmp(module, "timer") == 0)
|
||||
{
|
||||
return timerBindForeign(vm, className, isStatic, signature);
|
||||
}
|
||||
|
||||
if (externalBindForeign != NULL)
|
||||
{
|
||||
return externalBindForeign(vm, module, className, isStatic, signature);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void initVM()
|
||||
{
|
||||
WrenConfiguration config;
|
||||
|
||||
config.bindForeignMethodFn = bindForeign;
|
||||
config.bindForeignMethodFn = bindForeignMethod;
|
||||
config.loadModuleFn = readModule;
|
||||
|
||||
// Since we're running in a standalone process, be generous with memory.
|
||||
@@ -18,12 +47,28 @@ WrenVM* createVM(WrenBindForeignMethodFn bindForeign)
|
||||
config.reallocateFn = NULL;
|
||||
config.minHeapSize = 0;
|
||||
config.heapGrowthPercent = 0;
|
||||
|
||||
return wrenNewVM(&config);
|
||||
|
||||
vm = wrenNewVM(&config);
|
||||
|
||||
// Initialize the event loop.
|
||||
loop = (uv_loop_t*)malloc(sizeof(uv_loop_t));
|
||||
uv_loop_init(loop);
|
||||
}
|
||||
|
||||
void runFile(WrenBindForeignMethodFn bindForeign, const char* path)
|
||||
static void freeVM()
|
||||
{
|
||||
timerReleaseMethods();
|
||||
|
||||
uv_loop_close(loop);
|
||||
free(loop);
|
||||
|
||||
wrenFreeVM(vm);
|
||||
}
|
||||
|
||||
void runFile(const char* path, WrenBindForeignMethodFn bindForeign)
|
||||
{
|
||||
externalBindForeign = bindForeign;
|
||||
|
||||
// Use the directory where the file is as the root to resolve imports
|
||||
// relative to.
|
||||
char* root = NULL;
|
||||
@@ -42,12 +87,18 @@ void runFile(WrenBindForeignMethodFn bindForeign, const char* path)
|
||||
fprintf(stderr, "Could not find file \"%s\".\n", path);
|
||||
exit(66);
|
||||
}
|
||||
|
||||
WrenVM* vm = createVM(bindForeign);
|
||||
|
||||
|
||||
initVM();
|
||||
|
||||
WrenInterpretResult result = wrenInterpret(vm, path, source);
|
||||
|
||||
if (result == WREN_RESULT_SUCCESS)
|
||||
{
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
wrenFreeVM(vm);
|
||||
freeVM();
|
||||
|
||||
free(source);
|
||||
free(root);
|
||||
|
||||
@@ -55,3 +106,43 @@ void runFile(WrenBindForeignMethodFn bindForeign, const char* path)
|
||||
if (result == WREN_RESULT_COMPILE_ERROR) exit(65); // EX_DATAERR.
|
||||
if (result == WREN_RESULT_RUNTIME_ERROR) exit(70); // EX_SOFTWARE.
|
||||
}
|
||||
|
||||
int runRepl()
|
||||
{
|
||||
initVM();
|
||||
|
||||
printf("\\\\/\"-\n");
|
||||
printf(" \\_/ wren v0.0.0\n");
|
||||
|
||||
char line[MAX_LINE_LENGTH];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
printf("> ");
|
||||
|
||||
if (!fgets(line, MAX_LINE_LENGTH, stdin))
|
||||
{
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Handle failure.
|
||||
wrenInterpret(vm, "Prompt", line);
|
||||
|
||||
// TODO: Automatically print the result of expressions.
|
||||
}
|
||||
|
||||
freeVM();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WrenVM* getVM()
|
||||
{
|
||||
return vm;
|
||||
}
|
||||
|
||||
uv_loop_t* getLoop()
|
||||
{
|
||||
return loop;
|
||||
}
|
||||
|
||||
+13
-5
@@ -1,14 +1,22 @@
|
||||
#ifndef vm_h
|
||||
#define vm_h
|
||||
|
||||
#include "uv.h"
|
||||
#include "wren.h"
|
||||
|
||||
// Creates a new Wren VM with the CLI's module loader and other configuration.
|
||||
WrenVM* createVM(WrenBindForeignMethodFn bindForeign);
|
||||
|
||||
// Executes the Wren script at [path] in a new VM.
|
||||
//
|
||||
// Exits if the script failed or could not be loaded.
|
||||
void runFile(WrenBindForeignMethodFn bindForeign, const char* path);
|
||||
// If [bindForeign] is not `NULL`, it will be called to register any foreign
|
||||
// methods that the CLI itself doesn't handle.
|
||||
void runFile(const char* path, WrenBindForeignMethodFn bindForeign);
|
||||
|
||||
// Runs the Wren interactive REPL.
|
||||
int runRepl();
|
||||
|
||||
// Gets the currently running VM.
|
||||
WrenVM* getVM();
|
||||
|
||||
// Gets the event loop the VM is using.
|
||||
uv_loop_t* getLoop();
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user