forked from Mirror/wren
Move Meta to a separate module.
Also cleaned up some of the code around loading the core module.
This commit is contained in:
@ -1 +1,13 @@
|
||||
class Meta {}
|
||||
class Meta {
|
||||
static eval(source) {
|
||||
if (!(source is String)) Fiber.abort("Source code must be a string.")
|
||||
|
||||
var fn = compile_(source)
|
||||
// TODO: Include compile errors.
|
||||
if (fn == null) Fiber.abort("Could not compile source code.")
|
||||
|
||||
Fiber.new(fn).call()
|
||||
}
|
||||
|
||||
foreign static compile_(source)
|
||||
}
|
||||
|
||||
@ -44,11 +44,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// If true, loads the "Meta" class in the standard library.
|
||||
// If true, loads the "meta" built in module.
|
||||
//
|
||||
// Defaults to on.
|
||||
#ifndef WREN_USE_LIB_META
|
||||
#define WREN_USE_LIB_META 1
|
||||
#ifndef WREN_USE_META_MODULE
|
||||
#define WREN_USE_META_MODULE 1
|
||||
#endif
|
||||
|
||||
// These flags are useful for debugging and hacking on Wren itself. They are not
|
||||
|
||||
@ -1047,7 +1047,16 @@ static void fnCall(WrenVM* vm, const char* signature)
|
||||
|
||||
void wrenInitializeCore(WrenVM* vm)
|
||||
{
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
ObjString* name = AS_STRING(CONST_STRING(vm, "core"));
|
||||
wrenPushRoot(vm, (Obj*)name);
|
||||
|
||||
ObjModule* coreModule = wrenNewModule(vm, name, NULL);
|
||||
wrenPopRoot(vm); // name.
|
||||
wrenPushRoot(vm, (Obj*)coreModule);
|
||||
|
||||
// The core module's key is null in the module map.
|
||||
wrenMapSet(vm, vm->modules, NULL_VAL, OBJ_VAL(coreModule));
|
||||
wrenPopRoot(vm); // coreModule.
|
||||
|
||||
// Define the root Object class. This has to be done a little specially
|
||||
// because it has no superclass.
|
||||
@ -1103,7 +1112,7 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
// '---------' '-------------------' -'
|
||||
|
||||
// The rest of the classes can now be defined normally.
|
||||
wrenInterpret(vm, "", coreModuleSource);
|
||||
wrenInterpretInModule(vm, NULL, "", coreModuleSource);
|
||||
|
||||
vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool"));
|
||||
PRIMITIVE(vm->boolClass, "toString", bool_toString);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "wren_meta.h"
|
||||
|
||||
#if WREN_USE_LIB_META
|
||||
#if WREN_USE_META_MODULE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -8,46 +8,49 @@
|
||||
|
||||
#include "wren_meta.wren.inc"
|
||||
|
||||
DEF_PRIMITIVE(meta_eval)
|
||||
void metaCompile(WrenVM* vm)
|
||||
{
|
||||
if (!validateString(vm, args[1], "Source code")) return false;
|
||||
|
||||
// Eval the code in the module where the calling function was defined.
|
||||
Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 1].fn);
|
||||
// Evaluate the code in the module where the calling function was defined.
|
||||
// That's one stack frame back from the top since the top-most frame is the
|
||||
// helper eval() method in Meta itself.
|
||||
Value callingFn = OBJ_VAL(vm->fiber->frames[vm->fiber->numFrames - 2].fn);
|
||||
ObjModule* module = IS_FN(callingFn)
|
||||
? AS_FN(callingFn)->module
|
||||
: AS_CLOSURE(callingFn)->fn->module;
|
||||
|
||||
// Compile it.
|
||||
ObjFn* fn = wrenCompile(vm, module, AS_CSTRING(args[1]), false);
|
||||
if (fn == NULL) RETURN_ERROR("Could not compile source code.");
|
||||
|
||||
// TODO: Include the compile errors in the runtime error message.
|
||||
|
||||
wrenPushRoot(vm, (Obj*)fn);
|
||||
|
||||
// Create a fiber to run the code in.
|
||||
ObjFiber* evalFiber = wrenNewFiber(vm, (Obj*)fn);
|
||||
|
||||
// Remember what fiber to return to.
|
||||
evalFiber->caller = vm->fiber;
|
||||
|
||||
// Switch to the fiber.
|
||||
vm->fiber = evalFiber;
|
||||
|
||||
wrenPopRoot(vm);
|
||||
return false;
|
||||
// Compile it.
|
||||
ObjFn* fn = wrenCompile(vm, module, wrenGetArgumentString(vm, 1), false);
|
||||
if (fn == NULL) return;
|
||||
|
||||
// Return the result. We can't use the public API for this since we have a
|
||||
// bare ObjFn.
|
||||
*vm->foreignCallSlot = OBJ_VAL(fn);
|
||||
vm->foreignCallSlot = NULL;
|
||||
}
|
||||
|
||||
void wrenLoadMetaLibrary(WrenVM* vm)
|
||||
static WrenForeignMethodFn bindMetaForeignMethods(WrenVM* vm,
|
||||
const char* module,
|
||||
const char* className,
|
||||
bool isStatic,
|
||||
const char* signature)
|
||||
{
|
||||
wrenInterpret(vm, "", metaModuleSource);
|
||||
// There is only one foreign method in the meta module.
|
||||
ASSERT(strcmp(module, "meta") == 0, "Should be in meta module.");
|
||||
ASSERT(strcmp(className, "Meta") == 0, "Should be in Meta class.");
|
||||
ASSERT(isStatic, "Should be static.");
|
||||
ASSERT(strcmp(signature, "compile_(_)") == 0, "Should be compile method.");
|
||||
|
||||
return metaCompile;
|
||||
}
|
||||
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
void wrenLoadMetaModule(WrenVM* vm)
|
||||
{
|
||||
WrenBindForeignMethodFn previousBindFn = vm->config.bindForeignMethodFn;
|
||||
vm->config.bindForeignMethodFn = bindMetaForeignMethods;
|
||||
|
||||
wrenInterpretInModule(vm, "meta", "meta", metaModuleSource);
|
||||
|
||||
// The methods on "Meta" are static, so get the metaclass for the Meta class.
|
||||
ObjClass* meta = AS_CLASS(wrenFindVariable(vm, coreModule, "Meta"));
|
||||
PRIMITIVE(meta->obj.classObj, "eval(_)", meta_eval);
|
||||
vm->config.bindForeignMethodFn = previousBindFn;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,9 +6,9 @@
|
||||
#include "wren.h"
|
||||
|
||||
// This module defines the Meta class and its associated methods.
|
||||
#if WREN_USE_LIB_META
|
||||
#if WREN_USE_META_MODULE
|
||||
|
||||
void wrenLoadMetaLibrary(WrenVM* vm);
|
||||
void wrenLoadMetaModule(WrenVM* vm);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,3 +1,15 @@
|
||||
// Generated automatically from builtin/meta.wren. Do not edit.
|
||||
static const char* metaModuleSource =
|
||||
"class Meta {}\n";
|
||||
"class Meta {\n"
|
||||
" static eval(source) {\n"
|
||||
" if (!(source is String)) Fiber.abort(\"Source code must be a string.\")\n"
|
||||
"\n"
|
||||
" var fn = compile_(source)\n"
|
||||
" // TODO: Include compile errors.\n"
|
||||
" if (fn == null) Fiber.abort(\"Could not compile source code.\")\n"
|
||||
"\n"
|
||||
" Fiber.new(fn).call()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static compile_(source)\n"
|
||||
"}\n";
|
||||
|
||||
@ -8,11 +8,7 @@
|
||||
#include "wren_debug.h"
|
||||
#include "wren_vm.h"
|
||||
|
||||
#if WREN_USE_LIB_IO
|
||||
#include "wren_io.h"
|
||||
#endif
|
||||
|
||||
#if WREN_USE_LIB_META
|
||||
#if WREN_USE_META_MODULE
|
||||
#include "wren_meta.h"
|
||||
#endif
|
||||
|
||||
@ -57,22 +53,12 @@ WrenVM* wrenNewVM(WrenConfiguration* config)
|
||||
|
||||
wrenSymbolTableInit(&vm->methodNames);
|
||||
|
||||
ObjString* name = AS_STRING(CONST_STRING(vm, "core"));
|
||||
wrenPushRoot(vm, (Obj*)name);
|
||||
|
||||
// Implicitly create a "core" module for the built in libraries.
|
||||
ObjModule* coreModule = wrenNewModule(vm, name, NULL);
|
||||
wrenPushRoot(vm, (Obj*)coreModule);
|
||||
|
||||
vm->modules = wrenNewMap(vm);
|
||||
wrenMapSet(vm, vm->modules, NULL_VAL, OBJ_VAL(coreModule));
|
||||
|
||||
wrenPopRoot(vm); // mainModule.
|
||||
wrenPopRoot(vm); // name.
|
||||
|
||||
wrenInitializeCore(vm);
|
||||
#if WREN_USE_LIB_META
|
||||
wrenLoadMetaLibrary(vm);
|
||||
|
||||
#if WREN_USE_META_MODULE
|
||||
wrenLoadMetaModule(vm);
|
||||
#endif
|
||||
|
||||
return vm;
|
||||
@ -463,14 +449,17 @@ static ObjFiber* loadModule(WrenVM* vm, Value name, const char* source)
|
||||
// multiple times.
|
||||
wrenMapSet(vm, vm->modules, name, OBJ_VAL(module));
|
||||
|
||||
// Implicitly import the core module.
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
for (int i = 0; i < coreModule->variables.count; i++)
|
||||
// Implicitly import the core module (unless we *are* core).
|
||||
if (!IS_NULL(name))
|
||||
{
|
||||
wrenDefineVariable(vm, module,
|
||||
coreModule->variableNames.data[i].buffer,
|
||||
coreModule->variableNames.data[i].length,
|
||||
coreModule->variables.data[i]);
|
||||
ObjModule* coreModule = getModule(vm, NULL_VAL);
|
||||
for (int i = 0; i < coreModule->variables.count; i++)
|
||||
{
|
||||
wrenDefineVariable(vm, module,
|
||||
coreModule->variableNames.data[i].buffer,
|
||||
coreModule->variableNames.data[i].length,
|
||||
coreModule->variables.data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1457,49 +1446,36 @@ void* wrenAllocateForeign(WrenVM* vm, size_t size)
|
||||
return (void*)foreign->data;
|
||||
}
|
||||
|
||||
// Execute [source] in the context of the core module.
|
||||
static WrenInterpretResult loadIntoCore(WrenVM* vm, const char* source)
|
||||
{
|
||||
ObjModule* coreModule = wrenGetCoreModule(vm);
|
||||
|
||||
ObjFn* fn = wrenCompile(vm, coreModule, source, true);
|
||||
if (fn == NULL) return WREN_RESULT_COMPILE_ERROR;
|
||||
|
||||
wrenPushRoot(vm, (Obj*)fn);
|
||||
ObjFiber* fiber = wrenNewFiber(vm, (Obj*)fn);
|
||||
wrenPopRoot(vm);
|
||||
|
||||
return runInterpreter(vm, fiber);
|
||||
}
|
||||
|
||||
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* sourcePath,
|
||||
const char* source)
|
||||
{
|
||||
if (strlen(sourcePath) == 0) return loadIntoCore(vm, source);
|
||||
return wrenInterpretInModule(vm, "main", sourcePath, source);
|
||||
}
|
||||
|
||||
// TODO: Better module name.
|
||||
Value name = CONST_STRING(vm, "main");
|
||||
wrenPushRoot(vm, AS_OBJ(name));
|
||||
|
||||
ObjFiber* fiber = loadModule(vm, name, source);
|
||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
||||
const char* sourcePath,
|
||||
const char* source)
|
||||
{
|
||||
Value nameValue = NULL_VAL;
|
||||
if (module != NULL)
|
||||
{
|
||||
nameValue = wrenStringFormat(vm, "$", module);
|
||||
wrenPushRoot(vm, AS_OBJ(nameValue));
|
||||
}
|
||||
|
||||
ObjFiber* fiber = loadModule(vm, nameValue, source);
|
||||
if (fiber == NULL)
|
||||
{
|
||||
wrenPopRoot(vm);
|
||||
return WREN_RESULT_COMPILE_ERROR;
|
||||
}
|
||||
|
||||
wrenPopRoot(vm); // name.
|
||||
if (module != NULL)
|
||||
{
|
||||
wrenPopRoot(vm); // nameValue.
|
||||
}
|
||||
|
||||
WrenInterpretResult result = runInterpreter(vm, fiber);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ObjModule* wrenGetCoreModule(WrenVM* vm)
|
||||
{
|
||||
ObjModule* module = getModule(vm, NULL_VAL);
|
||||
ASSERT(module != NULL, "Could not find core module.");
|
||||
return module;
|
||||
return runInterpreter(vm, fiber);
|
||||
}
|
||||
|
||||
Value wrenImportModule(WrenVM* vm, const char* name)
|
||||
|
||||
@ -131,8 +131,10 @@ void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign);
|
||||
// Creates a new [WrenValue] for [value].
|
||||
WrenValue* wrenCaptureValue(WrenVM* vm, Value value);
|
||||
|
||||
// Looks up the core module in the module map.
|
||||
ObjModule* wrenGetCoreModule(WrenVM* vm);
|
||||
// Executes [source] in the context of [module].
|
||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
||||
const char* sourcePath,
|
||||
const char* source);
|
||||
|
||||
// Imports the module with [name].
|
||||
//
|
||||
|
||||
@ -1 +1,3 @@
|
||||
import "meta" for Meta
|
||||
|
||||
Meta.eval("!!") // expect runtime error: Could not compile source code.
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import "meta" for Meta
|
||||
|
||||
var y
|
||||
|
||||
Meta.eval("y = 2")
|
||||
|
||||
@ -1 +1,3 @@
|
||||
import "meta" for Meta
|
||||
|
||||
Meta.eval(123) // expect runtime error: Source code must be a string.
|
||||
|
||||
Reference in New Issue
Block a user