@@ -33,6 +33,38 @@ namespace std {
3333 * @ingroup wrenbind17
3434 */
3535namespace wrenbind17 {
36+
37+ namespace detail {
38+ inline std::string defaultLoadFileFn (const std::string& name) {
39+
40+ if (auto t = std::ifstream (name)) {
41+ std::string source ((std::istreambuf_iterator<char >(t)), std::istreambuf_iterator<char >());
42+ return source;
43+ }
44+
45+ throw NotFound ();
46+ }
47+
48+ inline void defaultPrintFn (const char * text) {
49+ std::cout << text;
50+ }
51+
52+ inline std::string defaultPathResolveFn (const std::vector<std::string>& paths, const std::string& importer,
53+ const std::string& name) {
54+ for (const auto & path : paths) {
55+ const auto test = path + " /" + std::string (name) + " .wren" ;
56+
57+ std::ifstream t (test);
58+ if (!t)
59+ continue ;
60+
61+ return test;
62+ }
63+
64+ return name;
65+ }
66+ } // namespace detail
67+
3668 /* *
3769 * @ingroup wrenbind17
3870 */
@@ -41,7 +73,14 @@ namespace wrenbind17 {
4173 /* *
4274 * @ingroup wrenbind17
4375 */
44- typedef std::function<std::string(const std::vector<std::string>& paths, const std::string& name)> LoadFileFn;
76+ typedef std::function<std::string(const std::string& name)> LoadFileFn;
77+
78+ /* *
79+ * @ingroup wrenbind17
80+ */
81+ typedef std::function<std::string(const std::vector<std::string>& paths, const std::string& importer,
82+ const std::string& name)>
83+ PathResolveFn;
4584
4685 /* *
4786 * @ingroup wrenbind17
@@ -61,27 +100,18 @@ namespace wrenbind17 {
61100 : data(std::make_unique<Data>()) {
62101
63102 data->paths = std::move (paths);
64- data->printFn = [](const char * text) -> void { std::cout << text; };
65- data->loadFileFn = [](const std::vector<std::string>& paths, const std::string& name) -> std::string {
66- for (const auto & path : paths) {
67- const auto test = path + " /" + std::string (name) + " .wren" ;
68103
69- std::ifstream t (test);
70- if (!t)
71- continue ;
72-
73- std::string source ((std::istreambuf_iterator<char >(t)), std::istreambuf_iterator<char >());
74- return source;
75- }
76-
77- throw NotFound ();
78- };
104+ data->printFn = detail::defaultPrintFn;
105+ data->loadFileFn = detail::defaultLoadFileFn;
106+ data->pathResolveFn = detail::defaultPathResolveFn;
79107
80108 wrenInitConfiguration (&data->config );
109+
81110 data->config .initialHeapSize = initHeap;
82111 data->config .minHeapSize = minHeap;
83112 data->config .heapGrowthPercent = heapGrowth;
84113 data->config .userData = data.get ();
114+
85115#if WREN_VERSION_NUMBER >= 4000 // >= 0.4.0
86116 data->config .reallocateFn = [](void * memory, size_t newSize, void * userData) -> void * {
87117 return std::realloc (memory, newSize);
@@ -103,7 +133,7 @@ namespace wrenbind17 {
103133 }
104134
105135 try {
106- auto source = self.loadFileFn (self. paths , std::string (name));
136+ auto source = self.loadFileFn (std::string (name));
107137 auto buffer = new char [source.size () + 1 ];
108138 std::memcpy (buffer, &source[0 ], source.size () + 1 );
109139 res.source = buffer;
@@ -115,6 +145,14 @@ namespace wrenbind17 {
115145 }
116146 return res;
117147 };
148+ data->config .resolveModuleFn = [](WrenVM* vm, const char * importer, const char * name) -> const char * {
149+ auto & self = *reinterpret_cast <VM::Data*>(wrenGetUserData (vm));
150+ const auto resolved = self.pathResolveFn (self.paths , std::string (importer), std::string (name));
151+ auto buffer = new char [resolved.size () + 1 ];
152+ std::memcpy (buffer, &resolved[0 ], resolved.size () + 1 );
153+
154+ return buffer;
155+ };
118156#else // < 0.4.0
119157 data->config .reallocateFn = std::realloc;
120158 data->config .loadModuleFn = [](WrenVM* vm, const char * name) -> char * {
@@ -256,8 +294,9 @@ namespace wrenbind17 {
256294 * @throws CompileError if the compilation has failed
257295 */
258296 inline void runFromModule (const std::string& name) {
259- const auto source = data->loadFileFn (data->paths , name);
260- runFromSource (name, source);
297+ const auto resolved = data->pathResolveFn (data->paths , " " , name);
298+ const auto source = data->loadFileFn (resolved);
299+ runFromSource (resolved, source);
261300 }
262301
263302 /* !
@@ -338,6 +377,20 @@ namespace wrenbind17 {
338377 data->loadFileFn = fn;
339378 }
340379
380+ /* !
381+ * @brief Set a custom path resolver for imports
382+ * @see PathResolveFn
383+ * @details This must be a function that accepts a std::vector of strings
384+ * (which are the lookup paths from the constructor), the name of the importer as
385+ * the second parameter and the name of the import as the third.
386+ * Used for implementing relative paths. If the module is loaded through runFromModule
387+ * the importer parameter will be empty.
388+ * If you want to cancel the import, simply throw an exception.
389+ */
390+ inline void setPathResolveFunc (const PathResolveFn& fn) {
391+ data->pathResolveFn = fn;
392+ }
393+
341394 /* !
342395 * @brief Runs the garbage collector
343396 */
@@ -358,6 +411,7 @@ namespace wrenbind17 {
358411 std::string nextError;
359412 PrintFn printFn;
360413 LoadFileFn loadFileFn;
414+ PathResolveFn pathResolveFn;
361415
362416 inline void addClassType (const std::string& module , const std::string& name, const size_t hash) {
363417 classToModule.insert (std::make_pair (hash, module ));
0 commit comments