rtt-f030/components/external/espruino/src/jswrap_modules.c

196 lines
6.6 KiB
C

/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* ----------------------------------------------------------------------------
* This file is designed to be parsed during the build process
*
* JavaScript Functions for handling Modules
* ----------------------------------------------------------------------------
*/
#include "jswrap_functions.h"
#include "jslex.h"
#include "jsvar.h"
#include "jsparse.h"
#include "jsinteractive.h"
#include "jswrapper.h"
#ifdef USE_FILESYSTEM
#include "../libs/jswrap_fat.h"
#endif
static JsVar *jswrap_modules_getModuleList() {
JsVar *moduleListName = jsvFindChildFromString(jsiGetParser()->root, JSPARSE_MODULE_CACHE_NAME, true);
if (!moduleListName) return 0; // out of memory
JsVar *moduleList = jsvSkipName(moduleListName);
if (!moduleList) {
moduleList = jsvNewWithFlags(JSV_OBJECT);
if (!moduleList) { jsvUnLock(moduleListName); return 0; } // out of memory
jsvSetValueOfName(moduleListName, moduleList); // no need to unlock
}
jsvUnLock(moduleListName);
return moduleList;
}
/*JSON{ "type":"function", "name" : "require",
"description" : "Load the given module, and return the exported functions",
"generate" : "jswrap_require",
"params" : [ [ "moduleName", "JsVar", "A String containing the name of the given module"] ],
"return" : ["JsVar", "The result of evaluating the string"]
}*/
JsVar *jswrap_require(JsVar *moduleName) {
if (!jsvIsString(moduleName)) {
jsWarn("Expecting a module name as a string, but got %t", moduleName);
return 0;
}
// Search to see if we have already loaded this module
JsVar *moduleList = jswrap_modules_getModuleList();
if (!moduleList) return 0; // out of memory
JsVar *moduleExportName = jsvFindChildFromVar(moduleList, moduleName, true);
jsvUnLock(moduleList);
if (!moduleExportName) return 0; // out of memory
JsVar *moduleExport = jsvSkipName(moduleExportName);
if (moduleExport) {
// Found the module!
jsvUnLock(moduleExportName);
return moduleExport;
}
// Now check if it is built-in
char moduleNameBuf[32];
jsvGetString(moduleName, moduleNameBuf, sizeof(moduleNameBuf));
if (jswIsBuiltInLibrary(moduleNameBuf)) {
// create a 'fake' module that Espruino can use to map its built-in functions against
moduleExport = jspNewBuiltin(moduleNameBuf);
} else {
// Now try and load it
JsVar *fileContents = 0;
//if (jsvIsStringEqual(moduleName,"http")) {}
//if (jsvIsStringEqual(moduleName,"fs")) {}
#ifdef USE_FILESYSTEM
JsVar *modulePath = jsvNewFromString(
#ifdef LINUX
"node_modules/"
#else
"NODE_M~1/"
#endif
);
if (!modulePath) { jsvUnLock(moduleExportName); return 0; } // out of memory
jsvAppendStringVarComplete(modulePath, moduleName);
jsvAppendString(modulePath,".js");
fileContents = wrap_fat_readFile(modulePath);
jsvUnLock(modulePath);
#endif
if (!fileContents || jsvIsStringEqual(fileContents,"")) {
jsvUnLock(moduleExportName);
jsvUnLock(fileContents);
jsWarn("Module not found");
return 0;
}
moduleExport = jspEvaluateModule(jsiGetParser(), fileContents);
jsvUnLock(fileContents);
}
assert(moduleExport);
jsvSetValueOfName(moduleExportName, moduleExport); // save in cache
jsvUnLock(moduleExportName);
return moduleExport;
}
/*JSON{ "type":"staticmethod",
"class" : "Modules", "name" : "getCached",
"description" : "Return an array of module names that have been cached",
"generate" : "jswrap_modules_getCached",
"return" : ["JsVar", "An array of module names"]
}*/
JsVar *jswrap_modules_getCached() {
JsVar *arr = jsvNewWithFlags(JSV_ARRAY);
if (!arr) return 0; // out of memory
JsVar *moduleList = jswrap_modules_getModuleList();
if (!moduleList) return arr; // out of memory
JsObjectIterator it;
jsvObjectIteratorNew(&it, moduleList);
while (jsvObjectIteratorHasElement(&it)) {
JsVar *idx = jsvObjectIteratorGetKey(&it);
JsVar *idxCopy = jsvCopyNameOnly(idx, false, false);
jsvArrayPushAndUnLock(arr, idxCopy);
jsvUnLock(idx);
jsvObjectIteratorNext(&it);
}
jsvObjectIteratorFree(&it);
jsvUnLock(moduleList);
return arr;
}
/*JSON{ "type":"staticmethod",
"class" : "Modules", "name" : "removeCached",
"description" : "Remove the given module from the list of cached modules",
"generate" : "jswrap_modules_removeCached",
"params" : [ [ "id", "JsVar", "The module name to remove"] ]
}*/
void jswrap_modules_removeCached(JsVar *id) {
if (!jsvIsString(id)) {
jsError("The argument to removeCached must be a string");
return;
}
JsVar *moduleList = jswrap_modules_getModuleList();
if (!moduleList) return; // out of memory
JsVar *moduleExportName = jsvFindChildFromVar(moduleList, id, false);
if (!moduleExportName) {
jsWarn("Module not found");
} else {
jsvRemoveChild(moduleList, moduleExportName);
jsvUnLock(moduleExportName);
}
jsvUnLock(moduleList);
}
/*JSON{ "type":"staticmethod",
"class" : "Modules", "name" : "removeAllCached",
"description" : "Remove all cached modules",
"generate" : "jswrap_modules_removeAllCached"
}*/
void jswrap_modules_removeAllCached() {
JsVar *moduleList = jswrap_modules_getModuleList();
if (!moduleList) return; // out of memory
jsvRemoveAllChildren(moduleList);
jsvUnLock(moduleList);
}
/*JSON{ "type":"staticmethod",
"class" : "Modules", "name" : "addCached",
"description" : "Add the given module to the cache",
"generate" : "jswrap_modules_addCached",
"params" : [ [ "id", "JsVar", "The module name to add" ],
[ "sourcecode", "JsVar", "The module's sourcecode" ] ]
}*/
void jswrap_modules_addCached(JsVar *id, JsVar *sourceCode) {
if (!jsvIsString(id) || !jsvIsString(sourceCode)) {
jsError("Both arguments to addCached must be strings");
return;
}
JsVar *moduleList = jswrap_modules_getModuleList();
if (!moduleList) return; // out of memory
JsVar *moduleExport = jspEvaluateModule(jsiGetParser(), sourceCode);
if (!moduleExport) {
jsWarn("Unable to load module");
} else {
JsVar *moduleName = jsvFindChildFromVar(moduleList, id, true);
if (moduleName) jsvSetValueOfName(moduleName, moduleExport);
jsvUnLock(moduleExport);
}
jsvUnLock(moduleList);
}