jswrap_modules.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. /*
  2. * This file is part of Espruino, a JavaScript interpreter for Microcontrollers
  3. *
  4. * Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. *
  10. * ----------------------------------------------------------------------------
  11. * This file is designed to be parsed during the build process
  12. *
  13. * JavaScript Functions for handling Modules
  14. * ----------------------------------------------------------------------------
  15. */
  16. #include "jswrap_functions.h"
  17. #include "jslex.h"
  18. #include "jsvar.h"
  19. #include "jsparse.h"
  20. #include "jsinteractive.h"
  21. #include "jswrapper.h"
  22. #ifdef USE_FILESYSTEM
  23. #include "../libs/jswrap_fat.h"
  24. #endif
  25. static JsVar *jswrap_modules_getModuleList() {
  26. JsVar *moduleListName = jsvFindChildFromString(jsiGetParser()->root, JSPARSE_MODULE_CACHE_NAME, true);
  27. if (!moduleListName) return 0; // out of memory
  28. JsVar *moduleList = jsvSkipName(moduleListName);
  29. if (!moduleList) {
  30. moduleList = jsvNewWithFlags(JSV_OBJECT);
  31. if (!moduleList) { jsvUnLock(moduleListName); return 0; } // out of memory
  32. jsvSetValueOfName(moduleListName, moduleList); // no need to unlock
  33. }
  34. jsvUnLock(moduleListName);
  35. return moduleList;
  36. }
  37. /*JSON{ "type":"function", "name" : "require",
  38. "description" : "Load the given module, and return the exported functions",
  39. "generate" : "jswrap_require",
  40. "params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ],
  41. "return" : ["JsVar", "The result of evaluating the string"]
  42. }*/
  43. JsVar *jswrap_require(JsVar *moduleName) {
  44. if (!jsvIsString(moduleName)) {
  45. jsWarn("Expecting a module name as a string, but got %t", moduleName);
  46. return 0;
  47. }
  48. // Search to see if we have already loaded this module
  49. JsVar *moduleList = jswrap_modules_getModuleList();
  50. if (!moduleList) return 0; // out of memory
  51. JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true);
  52. jsvUnLock(moduleList);
  53. if (!moduleExportName) return 0; // out of memory
  54. JsVar *moduleExport = jsvSkipName(moduleExportName);
  55. if (moduleExport) {
  56. // Found the module!
  57. jsvUnLock(moduleExportName);
  58. return moduleExport;
  59. }
  60. // Now check if it is built-in
  61. char moduleNameBuf[32];
  62. jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf));
  63. if (jswIsBuiltInLibrary(moduleNameBuf)) {
  64. // create a 'fake' module that Espruino can use to map its built-in functions against
  65. moduleExport = jspNewBuiltin(moduleNameBuf);
  66. } else {
  67. // Now try and load it
  68. JsVar *fileContents = 0;
  69. //if (jsvIsStringEqual(moduleName,"http")) {}
  70. //if (jsvIsStringEqual(moduleName,"fs")) {}
  71. #ifdef USE_FILESYSTEM
  72. JsVar *modulePath = jsvNewFromString(
  73. #ifdef LINUX
  74. "node_modules/"
  75. #else
  76. "NODE_M~1/"
  77. #endif
  78. );
  79. if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory
  80. jsvAppendStringVarComplete(modulePath, moduleName);
  81. jsvAppendString(modulePath,".js");
  82. fileContents = wrap_fat_readFile(modulePath);
  83. jsvUnLock(modulePath);
  84. #endif
  85. if (!fileContents || jsvIsStringEqual(fileContents,"")) {
  86. jsvUnLock(moduleExportName);
  87. jsvUnLock(fileContents);
  88. jsWarn("Module not found");
  89. return 0;
  90. }
  91. moduleExport = jspEvaluateModule(jsiGetParser(), fileContents);
  92. jsvUnLock(fileContents);
  93. }
  94. assert(moduleExport);
  95. jsvSetValueOfName(moduleExportName, moduleExport); // save in cache
  96. jsvUnLock(moduleExportName);
  97. return moduleExport;
  98. }
  99. /*JSON{ "type":"staticmethod",
  100. "class" : "Modules", "name" : "getCached",
  101. "description" : "Return an array of module names that have been cached",
  102. "generate" : "jswrap_modules_getCached",
  103. "return" : ["JsVar", "An array of module names"]
  104. }*/
  105. JsVar *jswrap_modules_getCached() {
  106. JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
  107. if (!arr) return 0; // out of memory
  108. JsVar *moduleList = jswrap_modules_getModuleList();
  109. if (!moduleList) return arr; // out of memory
  110. JsObjectIterator it;
  111. jsvObjectIteratorNew(&it, moduleList);
  112. while (jsvObjectIteratorHasElement(&it)) {
  113. JsVar *idx = jsvObjectIteratorGetKey(&it);
  114. JsVar *idxCopy = jsvCopyNameOnly(idx, false, false);
  115. jsvArrayPushAndUnLock(arr, idxCopy);
  116. jsvUnLock(idx);
  117. jsvObjectIteratorNext(&it);
  118. }
  119. jsvObjectIteratorFree(&it);
  120. jsvUnLock(moduleList);
  121. return arr;
  122. }
  123. /*JSON{ "type":"staticmethod",
  124. "class" : "Modules", "name" : "removeCached",
  125. "description" : "Remove the given module from the list of cached modules",
  126. "generate" : "jswrap_modules_removeCached",
  127. "params" : [ [ "id", "JsVar", "The module name to remove"] ]
  128. }*/
  129. void jswrap_modules_removeCached(JsVar *id) {
  130. if (!jsvIsString(id)) {
  131. jsError("The argument to removeCached must be a string");
  132. return;
  133. }
  134. JsVar *moduleList = jswrap_modules_getModuleList();
  135. if (!moduleList) return; // out of memory
  136. JsVar *moduleExportName = jsvFindChildFromVar(moduleList, id, false);
  137. if (!moduleExportName) {
  138. jsWarn("Module not found");
  139. } else {
  140. jsvRemoveChild(moduleList, moduleExportName);
  141. jsvUnLock(moduleExportName);
  142. }
  143. jsvUnLock(moduleList);
  144. }
  145. /*JSON{ "type":"staticmethod",
  146. "class" : "Modules", "name" : "removeAllCached",
  147. "description" : "Remove all cached modules",
  148. "generate" : "jswrap_modules_removeAllCached"
  149. }*/
  150. void jswrap_modules_removeAllCached() {
  151. JsVar *moduleList = jswrap_modules_getModuleList();
  152. if (!moduleList) return; // out of memory
  153. jsvRemoveAllChildren(moduleList);
  154. jsvUnLock(moduleList);
  155. }
  156. /*JSON{ "type":"staticmethod",
  157. "class" : "Modules", "name" : "addCached",
  158. "description" : "Add the given module to the cache",
  159. "generate" : "jswrap_modules_addCached",
  160. "params" : [ [ "id", "JsVar", "The module name to add" ],
  161. [ "sourcecode", "JsVar", "The module's sourcecode" ] ]
  162. }*/
  163. void jswrap_modules_addCached(JsVar *id, JsVar *sourceCode) {
  164. if (!jsvIsString(id) || !jsvIsString(sourceCode)) {
  165. jsError("Both arguments to addCached must be strings");
  166. return;
  167. }
  168. JsVar *moduleList = jswrap_modules_getModuleList();
  169. if (!moduleList) return; // out of memory
  170. JsVar *moduleExport = jspEvaluateModule(jsiGetParser(), sourceCode);
  171. if (!moduleExport) {
  172. jsWarn("Unable to load module");
  173. } else {
  174. JsVar *moduleName = jsvFindChildFromVar(moduleList, id, true);
  175. if (moduleName) jsvSetValueOfName(moduleName, moduleExport);
  176. jsvUnLock(moduleExport);
  177. }
  178. jsvUnLock(moduleList);
  179. }