diff --git a/backend/JavaScriptCore/JscEngine.cc b/backend/JavaScriptCore/JscEngine.cc index 9ead88ae..cec728fa 100644 --- a/backend/JavaScriptCore/JscEngine.cc +++ b/backend/JavaScriptCore/JscEngine.cc @@ -19,6 +19,7 @@ #include "../../src/Native.hpp" #include "JscEngine.hpp" #include "JscHelper.h" +#include "../../src/utils/Helper.hpp" namespace script::jsc_backend { @@ -177,6 +178,27 @@ script::Local JscEngine::eval(const script::Local return eval(script, {}); } +Local JscEngine::loadFile(const Local& scriptFile) { + if(scriptFile.toString().empty()) + throw Exception("script file no found"); + Local content = internal::readAllFileContent(scriptFile); + if(content.isNull()) + throw Exception("can't load script file"); + + std::string sourceFilePath = scriptFile.toString(); + std::size_t pathSymbol = sourceFilePath.rfind("/"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + else + { + pathSymbol = sourceFilePath.rfind("\\"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + } + Local sourceFileName = String::newString(sourceFilePath); + return eval(content.asString(), sourceFileName); +} + std::shared_ptr JscEngine::messageQueue() { return messageQueue_; } void JscEngine::gc() { diff --git a/backend/JavaScriptCore/JscEngine.h b/backend/JavaScriptCore/JscEngine.h index aedd71ed..0b8f5817 100644 --- a/backend/JavaScriptCore/JscEngine.h +++ b/backend/JavaScriptCore/JscEngine.h @@ -86,6 +86,8 @@ class JscEngine : public ::script::ScriptEngine { Local eval(const Local& script) override; using ScriptEngine::eval; + Local loadFile(const Local& scriptFile) override; + std::shared_ptr messageQueue() override; void gc() override; diff --git a/backend/Lua/LuaEngine.cc b/backend/Lua/LuaEngine.cc index ff86d299..9ce5715e 100644 --- a/backend/Lua/LuaEngine.cc +++ b/backend/Lua/LuaEngine.cc @@ -28,6 +28,7 @@ #include "LuaHelper.hpp" #include "LuaReference.hpp" #include "LuaScope.hpp" +#include "../../src/utils/Helper.hpp" // ref https://www.lua.org/manual/5.1/manual.html // https://www.lua.org/wshop14/Zykov.pdf @@ -259,6 +260,27 @@ Local LuaEngine::eval(const Local& script, const Local& so return lua_backend::callFunction({}, {}, 0, nullptr); } +Local LuaEngine::loadFile(const Local& scriptFile) { + if(scriptFile.toString().empty()) + throw Exception("script file no found"); + Local content = internal::readAllFileContent(scriptFile); + if(content.isNull()) + throw Exception("can't load script file"); + + std::string sourceFilePath = scriptFile.toString(); + std::size_t pathSymbol = sourceFilePath.rfind("/"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + else + { + pathSymbol = sourceFilePath.rfind("\\"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + } + Local sourceFileName = String::newString(sourceFilePath); + return eval(content.asString(), sourceFileName); +} + Arguments LuaEngine::makeArguments(LuaEngine* engine, int stackBase, size_t paramCount, bool isInstanceFunc) { lua_backend::ArgumentsData argumentsData{engine, stackBase, paramCount, isInstanceFunc}; diff --git a/backend/Lua/LuaEngine.h b/backend/Lua/LuaEngine.h index 4a1ec3c7..c2cd0135 100644 --- a/backend/Lua/LuaEngine.h +++ b/backend/Lua/LuaEngine.h @@ -77,6 +77,8 @@ class LuaEngine : public ScriptEngine { Local eval(const Local& script) override; using ScriptEngine::eval; + Local loadFile(const Local& scriptFile) override; + std::shared_ptr messageQueue() override; void gc() override; diff --git a/backend/QuickJs/QjsEngine.cc b/backend/QuickJs/QjsEngine.cc index e71a6e7d..3b043a62 100644 --- a/backend/QuickJs/QjsEngine.cc +++ b/backend/QuickJs/QjsEngine.cc @@ -17,6 +17,7 @@ #include "QjsEngine.h" #include +#include "../../src/utils/Helper.hpp" namespace script::qjs_backend { @@ -94,6 +95,9 @@ QjsEngine::QjsEngine(std::shared_ptr queue, const QjsFactor } initEngineResource(); + + /* set default loader for ES6 modules */ + JS_SetModuleLoaderFunc(runtime_, NULL, js_module_loader, NULL); } void QjsEngine::initEngineResource() { @@ -268,6 +272,39 @@ Local QjsEngine::eval(const Local& script, const Local& so return Local(ret); } +Local QjsEngine::loadFile(const Local& scriptFile) { + Tracer trace(this, "QjsEngine::loadFile"); + + if(scriptFile.toString().empty()) + throw Exception("script file no found"); + Local content = internal::readAllFileContent(scriptFile); + if(content.isNull()) + throw Exception("can't load script file"); + + // get source file name + std::string sourceFilePath = scriptFile.toString(); + std::size_t pathSymbol = sourceFilePath.rfind("/"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + else + { + pathSymbol = sourceFilePath.rfind("\\"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + } + Local sourceFileName = String::newString(sourceFilePath); + + StringHolder contentStr(content.asString()); + StringHolder fileNameStr(sourceFileName); + JSValue ret = JS_Eval(context_, contentStr.c_str(), contentStr.length(), fileNameStr.c_str(), + JS_EVAL_TYPE_MODULE); + + qjs_backend::checkException(ret); + scheduleTick(); + + return Local(ret); +} + std::shared_ptr QjsEngine::messageQueue() { return queue_; } void QjsEngine::gc() { diff --git a/backend/QuickJs/QjsEngine.h b/backend/QuickJs/QjsEngine.h index 6ea4966a..b810323d 100644 --- a/backend/QuickJs/QjsEngine.h +++ b/backend/QuickJs/QjsEngine.h @@ -94,6 +94,8 @@ class QjsEngine : public ScriptEngine { Local eval(const Local& script) override; using ScriptEngine::eval; + Local loadFile(const Local& scriptFile) override; + std::shared_ptr messageQueue() override; void gc() override; diff --git a/backend/QuickJs/QjsHelper.h b/backend/QuickJs/QjsHelper.h index a9a55775..4c0d4dae 100644 --- a/backend/QuickJs/QjsHelper.h +++ b/backend/QuickJs/QjsHelper.h @@ -21,6 +21,7 @@ SCRIPTX_BEGIN_INCLUDE_LIBRARY #include +#include SCRIPTX_END_INCLUDE_LIBRARY namespace script::qjs_backend { diff --git a/backend/V8/V8Engine.cc b/backend/V8/V8Engine.cc index 23686521..a208ac06 100644 --- a/backend/V8/V8Engine.cc +++ b/backend/V8/V8Engine.cc @@ -19,6 +19,7 @@ #include #include #include +#include "../../src/utils/Helper.hpp" namespace script::v8_backend { @@ -174,6 +175,27 @@ Local V8Engine::eval(const Local& script, const Local& so Local V8Engine::eval(const Local& script) { return eval(script, {}); } +Local V8Engine::loadFile(const Local& scriptFile) { + if(scriptFile.toString().empty()) + throw Exception("script file no found"); + Local content = internal::readAllFileContent(scriptFile); + if(content.isNull()) + throw Exception("can't load script file"); + + std::string sourceFilePath = scriptFile.toString(); + std::size_t pathSymbol = sourceFilePath.rfind("/"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + else + { + pathSymbol = sourceFilePath.rfind("\\"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + } + Local sourceFileName = String::newString(sourceFilePath); + return eval(content.asString(), sourceFileName); +} + void V8Engine::registerNativeClassStatic(v8::Local funcT, const internal::StaticDefine* staticDefine) { for (auto& prop : staticDefine->properties) { diff --git a/backend/V8/V8Engine.h b/backend/V8/V8Engine.h index 8942ecfa..ad9b1375 100644 --- a/backend/V8/V8Engine.h +++ b/backend/V8/V8Engine.h @@ -115,6 +115,8 @@ class V8Engine : public ::script::ScriptEngine { Local eval(const Local& script) override; using ScriptEngine::eval; + Local loadFile(const Local& scriptFile) override; + /** * Create a new V8 Engine that share the same isolate, but with different context. * Caller own the returned pointer, and the returned instance diff --git a/backend/WebAssembly/WasmEngine.cc b/backend/WebAssembly/WasmEngine.cc index c52d446b..727323da 100644 --- a/backend/WebAssembly/WasmEngine.cc +++ b/backend/WebAssembly/WasmEngine.cc @@ -23,6 +23,7 @@ #include "WasmNative.hpp" #include "WasmReference.hpp" #include "WasmScope.hpp" +#include "../../src/utils/Helper.hpp" namespace script::wasm_backend { @@ -76,6 +77,27 @@ Local WasmEngine::eval(const Local& script, const Local& s return Local(retIndex); } +Local WasmEngine::loadFile(const Local& scriptFile) { + if(scriptFile.toString().empty()) + throw Exception("script file no found"); + Local content = internal::readAllFileContent(scriptFile); + if(content.isNull()) + throw Exception("can't load script file"); + + std::string sourceFilePath = scriptFile.toString(); + std::size_t pathSymbol = sourceFilePath.rfind("/"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + else + { + pathSymbol = sourceFilePath.rfind("\\"); + if(pathSymbol != -1) + sourceFilePath = sourceFilePath.substr(pathSymbol + 1); + } + Local sourceFileName = String::newString(sourceFilePath); + return eval(content.asString(), sourceFileName); +} + std::shared_ptr WasmEngine::messageQueue() { return messageQueue_; } void WasmEngine::gc() {} diff --git a/backend/WebAssembly/WasmEngine.h b/backend/WebAssembly/WasmEngine.h index b8d629f2..9384dcba 100644 --- a/backend/WebAssembly/WasmEngine.h +++ b/backend/WebAssembly/WasmEngine.h @@ -74,6 +74,8 @@ class WasmEngine : public ScriptEngine { Local eval(const Local& script) override; using ScriptEngine::eval; + Local loadFile(const Local& scriptFile) override; + std::shared_ptr messageQueue() override; void gc() override; diff --git a/src/Engine.h b/src/Engine.h index 6697efb6..6cf7b665 100644 --- a/src/Engine.h +++ b/src/Engine.h @@ -120,6 +120,17 @@ class ScriptEngine { String::newString(std::forward(sourceFileStringLike))); } + /** + * @param scriptFile path of script file to load + * @return evaluate result + */ + virtual Local loadFile(const Local& scriptFile) = 0; + + template + Local loadFile(T&& scriptFileStringLike) { + return loadFile(String::newString(std::forward(scriptFileStringLike))); + } + /** * register a native class definition (constructor & property & function) to script. * @tparam T a subclass of the NativeClass, which implements all the Script-Native method in cpp. diff --git a/src/utils/Helper.cc b/src/utils/Helper.cc index 18eb70c4..37040f03 100644 --- a/src/utils/Helper.cc +++ b/src/utils/Helper.cc @@ -18,6 +18,7 @@ #include #include +#include namespace script::internal { @@ -56,4 +57,17 @@ Local getNamespaceObject(ScriptEngine* engine, const std::string_view& na return nameSpaceObj; } +Local readAllFileContent(const Local& scriptFile) +{ + std::ifstream fRead; + fRead.open(scriptFile.toString(), std::ios_base::in); + if (!fRead.is_open()) { + return Local(); + } + std::string data((std::istreambuf_iterator(fRead)), + std::istreambuf_iterator()); + fRead.close(); + return String::newString(std::move(data)).asValue(); +} + } // namespace script::internal \ No newline at end of file diff --git a/src/utils/Helper.hpp b/src/utils/Helper.hpp index 6790ccb3..541791dd 100644 --- a/src/utils/Helper.hpp +++ b/src/utils/Helper.hpp @@ -55,4 +55,6 @@ void withNArray(size_t N, FN&& fn) { Local getNamespaceObject(ScriptEngine* engine, const std::string_view& nameSpace, Local rootNs = {}); + +Local readAllFileContent(const Local& scriptFile); } // namespace script::internal \ No newline at end of file