Move Meta to a separate module.

Also cleaned up some of the code around loading the core module.
This commit is contained in:
Bob Nystrom
2015-10-15 18:08:56 -07:00
parent 06a4e00f31
commit d5b9f0096c
11 changed files with 119 additions and 99 deletions

View File

@ -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)
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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";

View File

@ -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)

View File

@ -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].
//

View File

@ -1 +1,3 @@
import "meta" for Meta
Meta.eval("!!") // expect runtime error: Could not compile source code.

View File

@ -1,3 +1,5 @@
import "meta" for Meta
var y
Meta.eval("y = 2")

View File

@ -1 +1,3 @@
import "meta" for Meta
Meta.eval(123) // expect runtime error: Source code must be a string.