forked from Mirror/wren
Expose an API to let the host resolve relative import strings.
This is a breaking API change: wrenInterpret() now takes an additional parameter for the module name to interpret the code in.
This commit is contained in:
@ -228,7 +228,7 @@ void runFile(const char* path)
|
|||||||
|
|
||||||
initVM();
|
initVM();
|
||||||
|
|
||||||
WrenInterpretResult result = wrenInterpret(vm, source);
|
WrenInterpretResult result = wrenInterpret(vm, "main", source);
|
||||||
|
|
||||||
if (afterLoadFn != NULL) afterLoadFn(vm);
|
if (afterLoadFn != NULL) afterLoadFn(vm);
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ int runRepl()
|
|||||||
printf("\\\\/\"-\n");
|
printf("\\\\/\"-\n");
|
||||||
printf(" \\_/ wren v%s\n", WREN_VERSION_STRING);
|
printf(" \\_/ wren v%s\n", WREN_VERSION_STRING);
|
||||||
|
|
||||||
wrenInterpret(vm, "import \"repl\"\n");
|
wrenInterpret(vm, "main", "import \"repl\"\n");
|
||||||
|
|
||||||
uv_run(loop, UV_RUN_DEFAULT);
|
uv_run(loop, UV_RUN_DEFAULT);
|
||||||
|
|
||||||
|
|||||||
@ -58,16 +58,21 @@ typedef void (*WrenForeignMethodFn)(WrenVM* vm);
|
|||||||
// collection.
|
// collection.
|
||||||
typedef void (*WrenFinalizerFn)(void* data);
|
typedef void (*WrenFinalizerFn)(void* data);
|
||||||
|
|
||||||
|
// Gives the host a chance to canonicalize the imported module name,
|
||||||
|
// potentially taking into account the (previously resolved) name of the module
|
||||||
|
// that contains the import. Typically, this is used to implement relative
|
||||||
|
// imports.
|
||||||
|
typedef const char* (*WrenResolveModuleFn)(WrenVM* vm,
|
||||||
|
const char* importer, const char* name);
|
||||||
|
|
||||||
// Loads and returns the source code for the module [name].
|
// Loads and returns the source code for the module [name].
|
||||||
typedef char* (*WrenLoadModuleFn)(WrenVM* vm, const char* name);
|
typedef char* (*WrenLoadModuleFn)(WrenVM* vm, const char* name);
|
||||||
|
|
||||||
// Returns a pointer to a foreign method on [className] in [module] with
|
// Returns a pointer to a foreign method on [className] in [module] with
|
||||||
// [signature].
|
// [signature].
|
||||||
typedef WrenForeignMethodFn (*WrenBindForeignMethodFn)(WrenVM* vm,
|
typedef WrenForeignMethodFn (*WrenBindForeignMethodFn)(WrenVM* vm,
|
||||||
const char* module,
|
const char* module, const char* className, bool isStatic,
|
||||||
const char* className,
|
const char* signature);
|
||||||
bool isStatic,
|
|
||||||
const char* signature);
|
|
||||||
|
|
||||||
// Displays a string of text to the user.
|
// Displays a string of text to the user.
|
||||||
typedef void (*WrenWriteFn)(WrenVM* vm, const char* text);
|
typedef void (*WrenWriteFn)(WrenVM* vm, const char* text);
|
||||||
@ -126,6 +131,32 @@ typedef struct
|
|||||||
// If `NULL`, defaults to a built-in function that uses `realloc` and `free`.
|
// If `NULL`, defaults to a built-in function that uses `realloc` and `free`.
|
||||||
WrenReallocateFn reallocateFn;
|
WrenReallocateFn reallocateFn;
|
||||||
|
|
||||||
|
// The callback Wren uses to resolve a module name.
|
||||||
|
//
|
||||||
|
// Some host applications may wish to support "relative" imports, where the
|
||||||
|
// meaning of an import string depends on the module that contains it. To
|
||||||
|
// support that without baking any policy into Wren itself, the VM gives the
|
||||||
|
// host a chance to resolve an import string.
|
||||||
|
//
|
||||||
|
// Before an import is loaded, it calls this, passing in the name of the
|
||||||
|
// module that contains the import and the import string. The host app can
|
||||||
|
// look at both of those and produce a new "canonical" string that uniquely
|
||||||
|
// identifies the module. This string is then used as the name of the module
|
||||||
|
// going forward. It is what is passed to [loadModuleFn], how duplicate
|
||||||
|
// imports of the same module are detected, and how the module is reported in
|
||||||
|
// stack traces.
|
||||||
|
//
|
||||||
|
// If you leave this function NULL, then the original import string is
|
||||||
|
// treated as the resolved string.
|
||||||
|
//
|
||||||
|
// If an import cannot be resolved by the embedder, it should return NULL and
|
||||||
|
// Wren will report that as a runtime error.
|
||||||
|
//
|
||||||
|
// Wren will take ownership of the string you return and free it for you, so
|
||||||
|
// it should be allocated using the same allocation function you provide
|
||||||
|
// above.
|
||||||
|
WrenResolveModuleFn resolveModuleFn;
|
||||||
|
|
||||||
// The callback Wren uses to load a module.
|
// The callback Wren uses to load a module.
|
||||||
//
|
//
|
||||||
// Since Wren does not talk directly to the file system, it relies on the
|
// Since Wren does not talk directly to the file system, it relies on the
|
||||||
@ -200,7 +231,8 @@ typedef struct
|
|||||||
//
|
//
|
||||||
// For example, say that this is 50. After a garbage collection, when there
|
// For example, say that this is 50. After a garbage collection, when there
|
||||||
// are 400 bytes of memory still in use, the next collection will be triggered
|
// are 400 bytes of memory still in use, the next collection will be triggered
|
||||||
// after a total of 600 bytes are allocated (including the 400 already in use.)
|
// after a total of 600 bytes are allocated (including the 400 already in
|
||||||
|
// use.)
|
||||||
//
|
//
|
||||||
// Setting this to a smaller number wastes less memory, but triggers more
|
// Setting this to a smaller number wastes less memory, but triggers more
|
||||||
// frequent garbage collections.
|
// frequent garbage collections.
|
||||||
@ -256,7 +288,8 @@ void wrenFreeVM(WrenVM* vm);
|
|||||||
void wrenCollectGarbage(WrenVM* vm);
|
void wrenCollectGarbage(WrenVM* vm);
|
||||||
|
|
||||||
// Runs [source], a string of Wren source code in a new fiber in [vm].
|
// Runs [source], a string of Wren source code in a new fiber in [vm].
|
||||||
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source);
|
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* module,
|
||||||
|
const char* source);
|
||||||
|
|
||||||
// Creates a handle that can be used to invoke a method with [signature] on
|
// Creates a handle that can be used to invoke a method with [signature] on
|
||||||
// using a receiver and arguments that are set up on the stack.
|
// using a receiver and arguments that are set up on the stack.
|
||||||
|
|||||||
@ -14,9 +14,17 @@ void metaCompile(WrenVM* vm)
|
|||||||
bool printErrors = wrenGetSlotBool(vm, 3);
|
bool printErrors = wrenGetSlotBool(vm, 3);
|
||||||
|
|
||||||
// TODO: Allow passing in module?
|
// TODO: Allow passing in module?
|
||||||
ObjClosure* closure = wrenCompileSource(vm, "main", source,
|
// Look up the module surrounding the callsite. This is brittle. The -2 walks
|
||||||
isExpression, printErrors);
|
// up the callstack assuming that the meta module has one level of
|
||||||
|
// indirection before hitting the user's code. Any change to meta may require
|
||||||
|
// this constant to be tweaked.
|
||||||
|
ObjFiber* currentFiber = vm->fiber;
|
||||||
|
ObjFn* fn = currentFiber->frames[currentFiber->numFrames - 2].closure->fn;
|
||||||
|
ObjString* module = fn->module->name;
|
||||||
|
|
||||||
|
ObjClosure* closure = wrenCompileSource(vm, module->value, source,
|
||||||
|
isExpression, printErrors);
|
||||||
|
|
||||||
// Return the result. We can't use the public API for this since we have a
|
// Return the result. We can't use the public API for this since we have a
|
||||||
// bare ObjClosure*.
|
// bare ObjClosure*.
|
||||||
if (closure == NULL)
|
if (closure == NULL)
|
||||||
|
|||||||
@ -1181,7 +1181,7 @@ void wrenInitializeCore(WrenVM* vm)
|
|||||||
// '---------' '-------------------' -'
|
// '---------' '-------------------' -'
|
||||||
|
|
||||||
// The rest of the classes can now be defined normally.
|
// The rest of the classes can now be defined normally.
|
||||||
wrenInterpretInModule(vm, NULL, coreModuleSource);
|
wrenInterpret(vm, NULL, coreModuleSource);
|
||||||
|
|
||||||
vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool"));
|
vm->boolClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Bool"));
|
||||||
PRIMITIVE(vm->boolClass, "toString", bool_toString);
|
PRIMITIVE(vm->boolClass, "toString", bool_toString);
|
||||||
|
|||||||
@ -38,6 +38,7 @@ static void* defaultReallocate(void* ptr, size_t newSize)
|
|||||||
void wrenInitConfiguration(WrenConfiguration* config)
|
void wrenInitConfiguration(WrenConfiguration* config)
|
||||||
{
|
{
|
||||||
config->reallocateFn = defaultReallocate;
|
config->reallocateFn = defaultReallocate;
|
||||||
|
config->resolveModuleFn = NULL;
|
||||||
config->loadModuleFn = NULL;
|
config->loadModuleFn = NULL;
|
||||||
config->bindForeignMethodFn = NULL;
|
config->bindForeignMethodFn = NULL;
|
||||||
config->bindForeignClassFn = NULL;
|
config->bindForeignClassFn = NULL;
|
||||||
@ -693,8 +694,39 @@ void wrenFinalizeForeign(WrenVM* vm, ObjForeign* foreign)
|
|||||||
finalizer(foreign->data);
|
finalizer(foreign->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let the host resolve an imported module name if it wants to.
|
||||||
|
static Value resolveModule(WrenVM* vm, Value name)
|
||||||
|
{
|
||||||
|
// If the host doesn't care to resolve, leave the name alone.
|
||||||
|
if (vm->config.resolveModuleFn == NULL) return name;
|
||||||
|
|
||||||
|
ObjFiber* fiber = vm->fiber;
|
||||||
|
ObjFn* fn = fiber->frames[fiber->numFrames - 1].closure->fn;
|
||||||
|
ObjString* importer = fn->module->name;
|
||||||
|
|
||||||
|
const char* resolved = vm->config.resolveModuleFn(vm, importer->value,
|
||||||
|
AS_CSTRING(name));
|
||||||
|
if (resolved == NULL)
|
||||||
|
{
|
||||||
|
vm->fiber->error = wrenStringFormat(vm,
|
||||||
|
"Could not resolve module '@' imported from '@'.",
|
||||||
|
name, OBJ_VAL(importer));
|
||||||
|
return NULL_VAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If they resolved to the exact same string, we don't need to copy it.
|
||||||
|
if (resolved == AS_CSTRING(name)) return name;
|
||||||
|
|
||||||
|
// Copy the string into a Wren String object.
|
||||||
|
name = wrenNewString(vm, resolved);
|
||||||
|
DEALLOCATE(vm, (char*)resolved);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
Value wrenImportModule(WrenVM* vm, Value name)
|
Value wrenImportModule(WrenVM* vm, Value name)
|
||||||
{
|
{
|
||||||
|
name = resolveModule(vm, name);
|
||||||
|
|
||||||
// If the module is already loaded, we don't need to do anything.
|
// If the module is already loaded, we don't need to do anything.
|
||||||
Value existing = wrenMapGet(vm->modules, name);
|
Value existing = wrenMapGet(vm->modules, name);
|
||||||
if (!IS_UNDEFINED(existing)) return existing;
|
if (!IS_UNDEFINED(existing)) return existing;
|
||||||
@ -1436,13 +1468,8 @@ void wrenReleaseHandle(WrenVM* vm, WrenHandle* handle)
|
|||||||
DEALLOCATE(vm, handle);
|
DEALLOCATE(vm, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* source)
|
WrenInterpretResult wrenInterpret(WrenVM* vm, const char* module,
|
||||||
{
|
const char* source)
|
||||||
return wrenInterpretInModule(vm, "main", source);
|
|
||||||
}
|
|
||||||
|
|
||||||
WrenInterpretResult wrenInterpretInModule(WrenVM* vm, const char* module,
|
|
||||||
const char* source)
|
|
||||||
{
|
{
|
||||||
ObjClosure* closure = wrenCompileSource(vm, module, source, false, true);
|
ObjClosure* closure = wrenCompileSource(vm, module, source, false, true);
|
||||||
if (closure == NULL) return WREN_RESULT_COMPILE_ERROR;
|
if (closure == NULL) return WREN_RESULT_COMPILE_ERROR;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ static void call(WrenVM* vm)
|
|||||||
wrenInitConfiguration(&config);
|
wrenInitConfiguration(&config);
|
||||||
WrenVM* otherVM = wrenNewVM(&config);
|
WrenVM* otherVM = wrenNewVM(&config);
|
||||||
|
|
||||||
wrenInterpret(otherVM, testScript);
|
wrenInterpret(otherVM, "main", testScript);
|
||||||
|
|
||||||
WrenHandle* method = wrenMakeCallHandle(otherVM, "method(_,_,_,_)");
|
WrenHandle* method = wrenMakeCallHandle(otherVM, "method(_,_,_,_)");
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
#include "new_vm.h"
|
#include "new_vm.h"
|
||||||
#include "reset_stack_after_call_abort.h"
|
#include "reset_stack_after_call_abort.h"
|
||||||
#include "reset_stack_after_foreign_construct.h"
|
#include "reset_stack_after_foreign_construct.h"
|
||||||
|
#include "resolution.h"
|
||||||
#include "slots.h"
|
#include "slots.h"
|
||||||
#include "user_data.h"
|
#include "user_data.h"
|
||||||
|
|
||||||
@ -58,6 +59,9 @@ static WrenForeignMethodFn bindForeignMethod(
|
|||||||
method = newVMBindMethod(fullName);
|
method = newVMBindMethod(fullName);
|
||||||
if (method != NULL) return method;
|
if (method != NULL) return method;
|
||||||
|
|
||||||
|
method = resolutionBindMethod(fullName);
|
||||||
|
if (method != NULL) return method;
|
||||||
|
|
||||||
method = slotsBindMethod(fullName);
|
method = slotsBindMethod(fullName);
|
||||||
if (method != NULL) return method;
|
if (method != NULL) return method;
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ static void nullConfig(WrenVM* vm)
|
|||||||
WrenVM* otherVM = wrenNewVM(NULL);
|
WrenVM* otherVM = wrenNewVM(NULL);
|
||||||
|
|
||||||
// We should be able to execute code.
|
// We should be able to execute code.
|
||||||
WrenInterpretResult result = wrenInterpret(otherVM, "1 + 2");
|
WrenInterpretResult result = wrenInterpret(otherVM, "main", "1 + 2");
|
||||||
wrenSetSlotBool(vm, 0, result == WREN_RESULT_SUCCESS);
|
wrenSetSlotBool(vm, 0, result == WREN_RESULT_SUCCESS);
|
||||||
|
|
||||||
wrenFreeVM(otherVM);
|
wrenFreeVM(otherVM);
|
||||||
|
|||||||
149
test/api/resolution.c
Normal file
149
test/api/resolution.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "resolution.h"
|
||||||
|
|
||||||
|
static void write(WrenVM* vm, const char* text)
|
||||||
|
{
|
||||||
|
printf("%s", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reportError(WrenVM* vm, WrenErrorType type,
|
||||||
|
const char* module, int line, const char* message)
|
||||||
|
{
|
||||||
|
if (type == WREN_ERROR_RUNTIME) printf("%s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* loadModule(WrenVM* vm, const char* module)
|
||||||
|
{
|
||||||
|
printf("loading %s\n", module);
|
||||||
|
|
||||||
|
const char* source;
|
||||||
|
if (strcmp(module, "main/baz/bang") == 0)
|
||||||
|
{
|
||||||
|
source = "import \"foo|bar\"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source = "System.print(\"ok\")";
|
||||||
|
}
|
||||||
|
|
||||||
|
char* string = malloc(strlen(source) + 1);
|
||||||
|
strcpy(string, source);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runTestVM(WrenVM* vm, WrenConfiguration* configuration,
|
||||||
|
const char* source)
|
||||||
|
{
|
||||||
|
configuration->writeFn = write;
|
||||||
|
configuration->errorFn = reportError;
|
||||||
|
configuration->loadModuleFn = loadModule;
|
||||||
|
|
||||||
|
WrenVM* otherVM = wrenNewVM(configuration);
|
||||||
|
|
||||||
|
// We should be able to execute code.
|
||||||
|
WrenInterpretResult result = wrenInterpret(otherVM, "main", source);
|
||||||
|
if (result != WREN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
wrenSetSlotString(vm, 0, "error");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wrenSetSlotString(vm, 0, "success");
|
||||||
|
}
|
||||||
|
|
||||||
|
wrenFreeVM(otherVM);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void noResolver(WrenVM* vm)
|
||||||
|
{
|
||||||
|
WrenConfiguration configuration;
|
||||||
|
wrenInitConfiguration(&configuration);
|
||||||
|
|
||||||
|
// Should default to no resolution function.
|
||||||
|
if (configuration.resolveModuleFn != NULL)
|
||||||
|
{
|
||||||
|
wrenSetSlotString(vm, 0, "Did not have null resolve function.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runTestVM(vm, &configuration, "import \"foo/bar\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* resolveToNull(WrenVM* vm, const char* importer,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void returnsNull(WrenVM* vm)
|
||||||
|
{
|
||||||
|
WrenConfiguration configuration;
|
||||||
|
wrenInitConfiguration(&configuration);
|
||||||
|
|
||||||
|
configuration.resolveModuleFn = resolveToNull;
|
||||||
|
runTestVM(vm, &configuration, "import \"foo/bar\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* resolveChange(WrenVM* vm, const char* importer,
|
||||||
|
const char* name)
|
||||||
|
{
|
||||||
|
// Concatenate importer and name.
|
||||||
|
size_t length = strlen(importer) + 1 + strlen(name) + 1;
|
||||||
|
char* result = malloc(length);
|
||||||
|
strcpy(result, importer);
|
||||||
|
strcat(result, "/");
|
||||||
|
strcat(result, name);
|
||||||
|
|
||||||
|
// Replace "|" with "/".
|
||||||
|
for (size_t i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (result[i] == '|') result[i] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void changesString(WrenVM* vm)
|
||||||
|
{
|
||||||
|
WrenConfiguration configuration;
|
||||||
|
wrenInitConfiguration(&configuration);
|
||||||
|
|
||||||
|
configuration.resolveModuleFn = resolveChange;
|
||||||
|
runTestVM(vm, &configuration, "import \"foo|bar\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shared(WrenVM* vm)
|
||||||
|
{
|
||||||
|
WrenConfiguration configuration;
|
||||||
|
wrenInitConfiguration(&configuration);
|
||||||
|
|
||||||
|
configuration.resolveModuleFn = resolveChange;
|
||||||
|
runTestVM(vm, &configuration, "import \"foo|bar\"\nimport \"foo/bar\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void importer(WrenVM* vm)
|
||||||
|
{
|
||||||
|
WrenConfiguration configuration;
|
||||||
|
wrenInitConfiguration(&configuration);
|
||||||
|
|
||||||
|
configuration.resolveModuleFn = resolveChange;
|
||||||
|
runTestVM(vm, &configuration, "import \"baz|bang\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
WrenForeignMethodFn resolutionBindMethod(const char* signature)
|
||||||
|
{
|
||||||
|
if (strcmp(signature, "static Resolution.noResolver()") == 0) return noResolver;
|
||||||
|
if (strcmp(signature, "static Resolution.returnsNull()") == 0) return returnsNull;
|
||||||
|
if (strcmp(signature, "static Resolution.changesString()") == 0) return changesString;
|
||||||
|
if (strcmp(signature, "static Resolution.shared()") == 0) return shared;
|
||||||
|
if (strcmp(signature, "static Resolution.importer()") == 0) return importer;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolutionBindClass(const char* className, WrenForeignClassMethods* methods)
|
||||||
|
{
|
||||||
|
// methods->allocate = foreignClassAllocate;
|
||||||
|
}
|
||||||
4
test/api/resolution.h
Normal file
4
test/api/resolution.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "wren.h"
|
||||||
|
|
||||||
|
WrenForeignMethodFn resolutionBindMethod(const char* signature);
|
||||||
|
void resolutionBindClass(const char* className, WrenForeignClassMethods* methods);
|
||||||
39
test/api/resolution.wren
Normal file
39
test/api/resolution.wren
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
class Resolution {
|
||||||
|
foreign static noResolver()
|
||||||
|
foreign static returnsNull()
|
||||||
|
foreign static changesString()
|
||||||
|
foreign static shared()
|
||||||
|
foreign static importer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no resolver function is configured, the default resolver just passes
|
||||||
|
// along the import string unchanged.
|
||||||
|
System.print(Resolution.noResolver())
|
||||||
|
// expect: loading foo/bar
|
||||||
|
// expect: ok
|
||||||
|
// expect: success
|
||||||
|
|
||||||
|
// If the resolver returns NULL, it's reported as an error.
|
||||||
|
System.print(Resolution.returnsNull())
|
||||||
|
// expect: Could not resolve module 'foo/bar' imported from 'main'.
|
||||||
|
// expect: error
|
||||||
|
|
||||||
|
// The resolver function can change the string.
|
||||||
|
System.print(Resolution.changesString())
|
||||||
|
// expect: loading main/foo/bar
|
||||||
|
// expect: ok
|
||||||
|
// expect: success
|
||||||
|
|
||||||
|
// Imports both "foo/bar" and "foo|bar", but only loads the module once because
|
||||||
|
// they resolve to the same module.
|
||||||
|
System.print(Resolution.shared())
|
||||||
|
// expect: loading main/foo/bar
|
||||||
|
// expect: ok
|
||||||
|
// expect: success
|
||||||
|
|
||||||
|
// The string passed as importer is the resolver string of the importing module.
|
||||||
|
System.print(Resolution.importer())
|
||||||
|
// expect: loading main/baz/bang
|
||||||
|
// expect: loading main/baz/bang/foo/bar
|
||||||
|
// expect: ok
|
||||||
|
// expect: success
|
||||||
@ -23,6 +23,7 @@
|
|||||||
293B25591CEFD8C7005D9537 /* repl.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 293B25561CEFD8C7005D9537 /* repl.wren.inc */; };
|
293B25591CEFD8C7005D9537 /* repl.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 293B25561CEFD8C7005D9537 /* repl.wren.inc */; };
|
||||||
293B255A1CEFD8C7005D9537 /* repl.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 293B25561CEFD8C7005D9537 /* repl.wren.inc */; };
|
293B255A1CEFD8C7005D9537 /* repl.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 293B25561CEFD8C7005D9537 /* repl.wren.inc */; };
|
||||||
293D46961BB43F9900200083 /* call.c in Sources */ = {isa = PBXBuildFile; fileRef = 293D46941BB43F9900200083 /* call.c */; };
|
293D46961BB43F9900200083 /* call.c in Sources */ = {isa = PBXBuildFile; fileRef = 293D46941BB43F9900200083 /* call.c */; };
|
||||||
|
2940E98D2063EC030054503C /* resolution.c in Sources */ = {isa = PBXBuildFile; fileRef = 2940E98B2063EC020054503C /* resolution.c */; };
|
||||||
2949AA8D1C2F14F000B106BA /* get_variable.c in Sources */ = {isa = PBXBuildFile; fileRef = 2949AA8B1C2F14F000B106BA /* get_variable.c */; };
|
2949AA8D1C2F14F000B106BA /* get_variable.c in Sources */ = {isa = PBXBuildFile; fileRef = 2949AA8B1C2F14F000B106BA /* get_variable.c */; };
|
||||||
29512C811B91F8EB008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
29512C811B91F8EB008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
||||||
29512C821B91F901008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
29512C821B91F901008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
||||||
@ -115,6 +116,8 @@
|
|||||||
293B25561CEFD8C7005D9537 /* repl.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = repl.wren.inc; path = ../../src/module/repl.wren.inc; sourceTree = "<group>"; };
|
293B25561CEFD8C7005D9537 /* repl.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = repl.wren.inc; path = ../../src/module/repl.wren.inc; sourceTree = "<group>"; };
|
||||||
293D46941BB43F9900200083 /* call.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = call.c; path = ../../test/api/call.c; sourceTree = "<group>"; };
|
293D46941BB43F9900200083 /* call.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = call.c; path = ../../test/api/call.c; sourceTree = "<group>"; };
|
||||||
293D46951BB43F9900200083 /* call.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = call.h; path = ../../test/api/call.h; sourceTree = "<group>"; };
|
293D46951BB43F9900200083 /* call.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = call.h; path = ../../test/api/call.h; sourceTree = "<group>"; };
|
||||||
|
2940E98B2063EC020054503C /* resolution.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = resolution.c; path = ../../test/api/resolution.c; sourceTree = "<group>"; };
|
||||||
|
2940E98C2063EC020054503C /* resolution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = resolution.h; path = ../../test/api/resolution.h; sourceTree = "<group>"; };
|
||||||
2949AA8B1C2F14F000B106BA /* get_variable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = get_variable.c; path = ../../test/api/get_variable.c; sourceTree = "<group>"; };
|
2949AA8B1C2F14F000B106BA /* get_variable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = get_variable.c; path = ../../test/api/get_variable.c; sourceTree = "<group>"; };
|
||||||
2949AA8C1C2F14F000B106BA /* get_variable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = get_variable.h; path = ../../test/api/get_variable.h; sourceTree = "<group>"; };
|
2949AA8C1C2F14F000B106BA /* get_variable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = get_variable.h; path = ../../test/api/get_variable.h; sourceTree = "<group>"; };
|
||||||
29512C7F1B91F86E008C10E6 /* api_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = api_test; sourceTree = BUILT_PRODUCTS_DIR; };
|
29512C7F1B91F86E008C10E6 /* api_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = api_test; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -304,6 +307,8 @@
|
|||||||
29D880651DC8ECF600025364 /* reset_stack_after_call_abort.h */,
|
29D880651DC8ECF600025364 /* reset_stack_after_call_abort.h */,
|
||||||
29C80D581D73332A00493837 /* reset_stack_after_foreign_construct.c */,
|
29C80D581D73332A00493837 /* reset_stack_after_foreign_construct.c */,
|
||||||
29C80D591D73332A00493837 /* reset_stack_after_foreign_construct.h */,
|
29C80D591D73332A00493837 /* reset_stack_after_foreign_construct.h */,
|
||||||
|
2940E98B2063EC020054503C /* resolution.c */,
|
||||||
|
2940E98C2063EC020054503C /* resolution.h */,
|
||||||
29D009AA1B7E39A8000CE58C /* slots.c */,
|
29D009AA1B7E39A8000CE58C /* slots.c */,
|
||||||
29D009AB1B7E39A8000CE58C /* slots.h */,
|
29D009AB1B7E39A8000CE58C /* slots.h */,
|
||||||
29D24DB01E82C0A2006618CC /* user_data.c */,
|
29D24DB01E82C0A2006618CC /* user_data.c */,
|
||||||
@ -394,6 +399,7 @@
|
|||||||
29205C9A1AB4E6430073018D /* wren_core.c in Sources */,
|
29205C9A1AB4E6430073018D /* wren_core.c in Sources */,
|
||||||
2901D7641B74F4050083A2C8 /* timer.c in Sources */,
|
2901D7641B74F4050083A2C8 /* timer.c in Sources */,
|
||||||
29729F331BA70A620099CA20 /* io.wren.inc in Sources */,
|
29729F331BA70A620099CA20 /* io.wren.inc in Sources */,
|
||||||
|
2940E98D2063EC030054503C /* resolution.c in Sources */,
|
||||||
29C8A9331AB71FFF00DEC81D /* vm.c in Sources */,
|
29C8A9331AB71FFF00DEC81D /* vm.c in Sources */,
|
||||||
291647C41BA5EA45006142EE /* scheduler.c in Sources */,
|
291647C41BA5EA45006142EE /* scheduler.c in Sources */,
|
||||||
29A427341BDBE435001E6E22 /* wren_opt_meta.c in Sources */,
|
29A427341BDBE435001E6E22 /* wren_opt_meta.c in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user