JSRequire.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include <assert.h>
  23. #include <Atomic/IO/FileSystem.h>
  24. #include <Atomic/Resource/ResourceCache.h>
  25. /*
  26. // subsystem requires
  27. #include <Atomic/Engine/Engine.h>
  28. #include <Atomic/Graphics/Graphics.h>
  29. #include <Atomic/Graphics/Renderer.h>
  30. #include <Atomic/Input/Input.h>
  31. #include <Atomic/Resource/ResourceCache.h>
  32. */
  33. #include "JSVM.h"
  34. #include "JSRequire.h"
  35. #include "JSPlugin.h"
  36. namespace Atomic
  37. {
  38. /*
  39. static bool js_require_subsystem(const String& name, JSVM* vm)
  40. {
  41. duk_context* ctx = vm->GetJSContext();
  42. String lowername = name.ToLower();
  43. if (lowername.ToLower() == "input")
  44. {
  45. js_push_class_object_instance(ctx, vm->GetSubsystem<Input>());
  46. return true;
  47. }
  48. if (lowername.ToLower() == "resourcecache")
  49. {
  50. js_push_class_object_instance(ctx, vm->GetSubsystem<ResourceCache>());
  51. return true;
  52. }
  53. if (lowername.ToLower() == "engine")
  54. {
  55. js_push_class_object_instance(ctx, vm->GetSubsystem<Engine>());
  56. return true;
  57. }
  58. if (lowername.ToLower() == "renderer")
  59. {
  60. js_push_class_object_instance(ctx, vm->GetSubsystem<Renderer>());
  61. return true;
  62. }
  63. if (lowername == "graphics")
  64. {
  65. js_push_class_object_instance(ctx, vm->GetSubsystem<Graphics>());
  66. return true;
  67. }
  68. if (lowername.ToLower() == "vm")
  69. {
  70. js_push_class_object_instance(ctx, vm);
  71. return true;
  72. }
  73. return false;
  74. }
  75. */
  76. // see http://duktape.org/guide.html#modules
  77. static int js_module_search(duk_context* ctx)
  78. {
  79. JSVM* vm = JSVM::GetJSVM(ctx);
  80. FileSystem* fs = vm->GetSubsystem<FileSystem>();
  81. ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
  82. int top = duk_get_top(ctx);
  83. assert(top == 4);
  84. String moduleID = duk_to_string(ctx, 0);
  85. if (top > 1)
  86. {
  87. // require function
  88. assert(duk_is_function(ctx, 1));
  89. }
  90. if (top > 2)
  91. {
  92. // exports
  93. assert(duk_is_object(ctx, 2));
  94. }
  95. if (top > 3)
  96. {
  97. // module (module.id == a resolved absolute identifier for the module being loaded)
  98. assert(duk_is_object(ctx, 3));
  99. }
  100. String pathName, fileName, extension;
  101. SplitPath(moduleID, pathName, fileName, extension);
  102. String path = moduleID;
  103. // It is nice to not have to specify the Atomic path, but verify that the module exists first since it could be user provided
  104. if (fileName.StartsWith("Atomic") && cache->Exists("AtomicModules/" + path + ".js"))
  105. {
  106. path = "AtomicModules/" + path + ".js";
  107. }
  108. else
  109. {
  110. path += ".js";
  111. if (!cache->Exists(path))
  112. {
  113. const Vector<String>& searchPaths = vm->GetModuleSearchPaths();
  114. for (unsigned i = 0; i < searchPaths.Size(); i++)
  115. {
  116. String search = searchPaths[i] + path;
  117. if (cache->Exists(search))
  118. {
  119. path = search;
  120. break;
  121. }
  122. }
  123. }
  124. }
  125. if (cache->Exists(path))
  126. {
  127. // We're a module w/o an associated filename, so we need
  128. // to provide the fully qualified filename path so the debugger
  129. // can resolve to a file correctly
  130. if (duk_is_object(ctx, 3) &&
  131. !duk_has_prop_string(ctx, 3, "filename"))
  132. {
  133. duk_push_string(ctx, path.CString());
  134. duk_put_prop_string(ctx, 3, "filename");
  135. }
  136. SharedPtr<File> jsfile(cache->GetFile(path, false));
  137. vm->SetLastModuleSearchFile(jsfile->GetFullPath());
  138. String source;
  139. jsfile->ReadText(source);
  140. source.Append('\n');
  141. duk_push_string(ctx, source.CString());
  142. return 1;
  143. }
  144. else
  145. {
  146. // we're not a JS file, so check if we're a native module
  147. const Vector<String>& resourceDirs = cache->GetResourceDirs();
  148. for (unsigned i = 0; i < resourceDirs.Size(); i++)
  149. {
  150. String pluginLibrary;
  151. // TODO: proper platform folder detection
  152. #ifdef ATOMIC_PLATFORM_WINDOWS
  153. pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
  154. #elif ATOMIC_PLATFORM_OSX
  155. pluginLibrary = resourceDirs.At(i) + "Plugins/Mac/x64/lib" + moduleID + ".dylib";
  156. #endif
  157. if (pluginLibrary.Length() && fs->FileExists(pluginLibrary))
  158. {
  159. // let duktape know we loaded a native module
  160. if (jsplugin_load(vm, pluginLibrary))
  161. {
  162. duk_push_undefined(ctx);
  163. return 1;
  164. }
  165. else
  166. {
  167. duk_push_sprintf(ctx, "Failed loading native plugins: %s", pluginLibrary.CString());
  168. duk_throw(ctx);
  169. }
  170. }
  171. }
  172. }
  173. duk_push_sprintf(ctx, "Failed loading module: %s", path.CString());
  174. duk_throw(ctx);
  175. }
  176. void js_init_require(JSVM* vm)
  177. {
  178. duk_context* ctx = vm->GetJSContext();
  179. duk_get_global_string(ctx, "Duktape");
  180. duk_push_c_function(ctx, js_module_search, 4);
  181. duk_put_prop_string(ctx, -2, "modSearch");
  182. duk_pop(ctx);
  183. }
  184. }