JSRequire.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #include <assert.h>
  2. #include <Atomic/IO/FileSystem.h>
  3. #include <Atomic/Resource/ResourceCache.h>
  4. #include "JSVM.h"
  5. #include "JSRequire.h"
  6. #include "JSPlugin.h"
  7. namespace Atomic
  8. {
  9. // see http://duktape.org/guide.html#modules
  10. static int js_module_search(duk_context* ctx)
  11. {
  12. JSVM* vm = JSVM::GetJSVM(ctx);
  13. FileSystem* fs = vm->GetSubsystem<FileSystem>();
  14. ResourceCache* cache = vm->GetSubsystem<ResourceCache>();
  15. int top = duk_get_top(ctx);
  16. assert(top == 4);
  17. String moduleID = duk_to_string(ctx, 0);
  18. if (top > 1)
  19. {
  20. // require function
  21. assert(duk_is_function(ctx, 1));
  22. }
  23. if (top > 2)
  24. {
  25. // exports
  26. assert(duk_is_object(ctx, 2));
  27. }
  28. if (top > 3)
  29. {
  30. // module (module.id == a resolved absolute identifier for the module being loaded)
  31. assert(duk_is_object(ctx, 3));
  32. }
  33. String pathName, fileName, extension;
  34. SplitPath(moduleID, pathName, fileName, extension);
  35. String path = moduleID;
  36. // Do we really want this? It is nice to not have to specify the Atomic path
  37. if (fileName.StartsWith("Atomic"))
  38. {
  39. path = "AtomicModules/" + path + ".js";
  40. }
  41. else
  42. {
  43. path += ".js";
  44. if (!cache->Exists(path))
  45. {
  46. const Vector<String>& searchPaths = vm->GetModuleSearchPaths();
  47. for (unsigned i = 0; i < searchPaths.Size(); i++)
  48. {
  49. String search = searchPaths[i] + path;
  50. if (cache->Exists(search))
  51. {
  52. path = search;
  53. break;
  54. }
  55. }
  56. }
  57. }
  58. if (cache->Exists(path))
  59. {
  60. SharedPtr<File> jsfile(cache->GetFile(path, false));
  61. vm->SetLastModuleSearchFile(jsfile->GetFullPath());
  62. String source;
  63. jsfile->ReadText(source);
  64. duk_push_string(ctx, source.CString());
  65. return 1;
  66. }
  67. else
  68. {
  69. // we're not a JS file, so check if we're a native module
  70. const Vector<String>& resourceDirs = cache->GetResourceDirs();
  71. for (unsigned i = 0; i < resourceDirs.Size(); i++)
  72. {
  73. String pluginLibrary;
  74. // TODO: proper platform folder detection
  75. #ifdef ATOMIC_PLATFORM_WINDOWS
  76. pluginLibrary = resourceDirs.At(i) + "Plugins/Windows/x64/" + moduleID + ".dll";
  77. #elif ATOMIC_PLATFORM_OSX
  78. pluginLibrary = resourceDirs.At(i) + "Plugins/Mac/x64/lib" + moduleID + ".dylib";
  79. #endif
  80. if (pluginLibrary.Length() && fs->FileExists(pluginLibrary))
  81. {
  82. // let duktape know we loaded a native module
  83. if (jsplugin_load(vm, pluginLibrary))
  84. {
  85. duk_push_undefined(ctx);
  86. return 1;
  87. }
  88. else
  89. {
  90. duk_push_sprintf(ctx, "Failed loading native plugins: %s", pluginLibrary.CString());
  91. duk_throw(ctx);
  92. }
  93. }
  94. }
  95. }
  96. duk_push_sprintf(ctx, "Failed loading module: %s", path.CString());
  97. duk_throw(ctx);
  98. }
  99. void js_init_require(JSVM* vm)
  100. {
  101. duk_context* ctx = vm->GetJSContext();
  102. duk_get_global_string(ctx, "Duktape");
  103. duk_push_c_function(ctx, js_module_search, 4);
  104. duk_put_prop_string(ctx, -2, "modSearch");
  105. duk_pop(ctx);
  106. }
  107. }