From d04b23b9a47c2ec6631aec16dc79f5b803fe07f3 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 24 Mar 2020 18:09:45 +0800 Subject: add command line option "-e" to moonp to eval file or string. --- makefile | 2 +- src/moonp.cpp | 209 +++++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 157 insertions(+), 54 deletions(-) diff --git a/makefile b/makefile index 68f35be..a285842 100644 --- a/makefile +++ b/makefile @@ -210,7 +210,7 @@ clean: test: release @echo "Compiling Moonscript codes..." @$(START_TIME) - @./$(BIN_NAME) $(TEST_INPUT)/*.moon -t $(TEST_OUTPUT) + @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) @echo -en "Compile time: " @$(END_TIME) diff --git a/src/moonp.cpp b/src/moonp.cpp index a43f11c..4128f10 100644 --- a/src/moonp.cpp +++ b/src/moonp.cpp @@ -5,6 +5,10 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "MoonP/moon_compiler.h" +#include "MoonP/moon_parser.h" + #include #include #include @@ -12,8 +16,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include "MoonP/moon_compiler.h" -#include "MoonP/moon_parser.h" +#include +#include +using namespace std::string_view_literals; +#include +namespace fs = std::filesystem; + +#define _DEFER(code,line) std::shared_ptr _defer_##line(nullptr, [&](auto){code;}) +#define DEFER(code) _DEFER(code,__LINE__) extern "C" { @@ -30,16 +40,29 @@ static void openlibs(void* state) { luaopen_moonp(L); } +void pushMoonp(lua_State* L, std::string_view name) { + lua_getglobal(L, "package"); // package + lua_getfield(L, -1, "loaded"); // package loaded + lua_getfield(L, -1, "moonp"); // package loaded moonp + lua_pushlstring(L, &name.front(), name.size()); // package loaded moonp name + lua_gettable(L, -2); // loaded[name], package loaded moonp item + lua_insert(L, -4); // item package loaded moonp + lua_pop(L, 3); // item +} + int main(int narg, const char** args) { const char* help = -"Usage: moonp [options|files] ...\n\n" -" -h Print this message\n" -" -t path Specify where to place compiled files\n" -" -o file Write output to file\n" -" -p Write output to standard out\n" -" -b Dump compile time (doesn't write output)\n" -" -l Write line numbers from source codes\n" -" -v Print version\n"; +"Usage: moonp [options|files|directories] ...\n\n" +" -h Print this message\n" +" -e str Execute a file or raw codes\n" +" -t path Specify where to place compiled files\n" +" -o file Write output to file\n" +" -p Write output to standard out\n" +" -b Dump compile time (doesn't write output)\n" +" -l Write line numbers from source codes\n" +" -v Print version\n" +" -- Read from standard in, print to standard out\n" +" (Must be first and only argument)\n"; if (narg == 0) { std::cout << help; return 0; @@ -50,14 +73,88 @@ int main(int narg, const char** args) { bool dumpCompileTime = false; std::string targetPath; std::string resultFile; - std::list files; + std::list> files; for (int i = 1; i < narg; ++i) { std::string arg = args[i]; - if (arg == "-l") { + if (arg == "--"sv) { + if (i != 1) { + std::cout << help; + return 1; + } + char ch; + std::string s; + while ((ch = std::cin.get()) != EOF) { + s += ch; + } + MoonP::MoonConfig conf; + conf.implicitReturnRoot = true; + conf.lintGlobalVariable = false; + conf.reserveLineNumber = false; + auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, conf); + if (std::get<1>(result).empty()) { + std::cout << std::get<0>(result); + return 0; + } else { + std::ostringstream buf; + std::cout << std::get<1>(result) << '\n'; + return 1; + } + } else if (arg == "-e"sv) { + ++i; + if (i < narg) { + lua_State* L = luaL_newstate(); + openlibs(L); + DEFER(lua_close(L)); + pushMoonp(L, "insert_loader"sv); + if (lua_pcall(L, 0, 0, 0) != 0) { + std::cout << lua_tostring(L, -1) << '\n'; + return 1; + } + std::string evalStr = args[i]; + std::ifstream input(evalStr, std::ios::in); + if (input) { + auto ext = fs::path(evalStr).extension().string(); + for (auto& ch : ext) ch = std::tolower(ch); + if (ext == ".lua") { + lua_getglobal(L, "load"); + } else { + pushMoonp(L, "loadstring"sv); + } + std::string s( + (std::istreambuf_iterator(input)), + std::istreambuf_iterator()); + lua_pushlstring(L, s.c_str(), s.size()); + lua_pushlstring(L, evalStr.c_str(), evalStr.size()); + } else { + pushMoonp(L, "loadstring"sv); + lua_pushlstring(L, evalStr.c_str(), evalStr.size()); + lua_pushliteral(L, "=(eval str)"); + } + if (lua_pcall(L, 2, 1, 0) != 0) { + std::cout << lua_tostring(L, -1) << '\n'; + return 1; + } + pushMoonp(L, "pcall"sv); + lua_insert(L, -2); + if (lua_pcall(L, 1, 2, 0) != 0) { + std::cout << lua_tostring(L, -1) << '\n'; + return 1; + } + bool success = lua_toboolean(L, -2) != 0; + if (!success) { + std::cout << lua_tostring(L, -1) << '\n'; + return 1; + } + return 0; + } else { + std::cout << help; + return 1; + } + } else if (arg == "-l"sv) { config.reserveLineNumber = true; - } else if (arg == "-p") { + } else if (arg == "-p"sv) { writeToFile = false; - } else if (arg == "-t") { + } else if (arg == "-t"sv) { ++i; if (i < narg) { targetPath = args[i]; @@ -65,15 +162,15 @@ int main(int narg, const char** args) { std::cout << help; return 1; } - } else if (arg == "-b") { + } else if (arg == "-b"sv) { dumpCompileTime = true; - } else if (arg == "-h") { + } else if (arg == "-h"sv) { std::cout << help; return 0; - } else if (arg == "-v") { - std::cout << "Moonscript version: " << MoonP::moonScriptVersion() << '\n'; + } else if (arg == "-v"sv) { + std::cout << "Moonscript version: "sv << MoonP::moonScriptVersion() << '\n'; return 0; - } else if (arg == "-o") { + } else if (arg == "-o"sv) { ++i; if (i < narg) { resultFile = args[i]; @@ -82,7 +179,19 @@ int main(int narg, const char** args) { return 1; } } else { - files.push_back(arg); + if (fs::is_directory(arg)) { + for (auto item : fs::recursive_directory_iterator(arg)) { + if (!item.is_directory()) { + auto ext = item.path().extension().string(); + for (char& ch : ext) ch = std::tolower(ch); + if (ext == ".moon"sv) { + files.emplace_back(item.path().string(), item.path().lexically_relative(arg).string()); + } + } + } + } else { + files.emplace_back(arg, arg); + } } } if (files.empty()) { @@ -90,23 +199,20 @@ int main(int narg, const char** args) { return 0; } if (!resultFile.empty() && files.size() > 1) { - std::cout << "Error: -o can not be used with multiple input files.\n"; + std::cout << "Error: -o can not be used with multiple input files.\n"sv; std::cout << help; } - if (!targetPath.empty() && targetPath.back() != '/' && targetPath.back() != '\\') { - targetPath.append("/"); - } std::list>> results; for (const auto& file : files) { auto task = std::async(std::launch::async, [=]() { - std::ifstream input(file, std::ios::in); + std::ifstream input(file.first, std::ios::in); if (input) { std::string s( (std::istreambuf_iterator(input)), std::istreambuf_iterator()); if (dumpCompileTime) { auto start = std::chrono::high_resolution_clock::now(); - auto result = MoonP::MoonCompiler{nullptr,openlibs}.compile(s, config); + auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, config); auto end = std::chrono::high_resolution_clock::now(); if (!std::get<0>(result).empty()) { std::chrono::duration diff = end - start; @@ -115,59 +221,57 @@ int main(int narg, const char** args) { end = std::chrono::high_resolution_clock::now(); std::chrono::duration parseDiff = end - start; std::ostringstream buf; - buf << file << " \n"; - buf << "Parse time: " << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n"; - buf << "Compile time: " << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n"; + buf << file.first << " \n"sv; + buf << "Parse time: "sv << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n"; + buf << "Compile time: "sv << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n"; return std::pair{0, buf.str()}; } else { std::ostringstream buf; - buf << "Fail to compile: " << file << ".\n"; + buf << "Fail to compile: "sv << file.first << ".\n"sv; buf << std::get<1>(result) << '\n'; return std::pair{1, buf.str()}; } } - auto result = MoonP::MoonCompiler{nullptr,openlibs}.compile(s, config); + auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, config); if (!std::get<0>(result).empty()) { if (!writeToFile) { return std::pair{1, std::get<0>(result) + '\n'}; } else { - std::string targetFile; - if (resultFile.empty()) { - targetFile = file; - size_t pos = file.rfind('.'); - if (pos != std::string::npos) { - targetFile = file.substr(0, pos) + ".lua"; - } + fs::path targetFile; + if (!resultFile.empty()) { + targetFile = resultFile; + } else { if (!targetPath.empty()) { - std::string name; - pos = targetFile.find_last_of("/\\"); - if (pos == std::string::npos) { - name = targetFile; - } else { - name = targetFile.substr(pos + 1); - } - targetFile = targetPath + name; + targetFile = fs::path(targetPath) / file.second; + } else { + targetFile = file.first; } - } else { - targetFile = resultFile; + targetFile.replace_extension(".lua"sv); + } + if (!targetPath.empty()) { + fs::create_directories(targetFile.parent_path()); } std::ofstream output(targetFile, std::ios::trunc | std::ios::out); if (output) { const auto& codes = std::get<0>(result); + if (config.reserveLineNumber) { + auto head = std::string("-- [moon]: "sv) + file.first + '\n'; + output.write(head.c_str(), head.size()); + } output.write(codes.c_str(), codes.size()); - return std::pair{0, std::string("Built ") + file + '\n'}; + return std::pair{0, std::string("Built "sv) + file.first + '\n'}; } else { - return std::pair{1, std::string("Fail to write file: ") + targetFile + '\n'}; + return std::pair{1, std::string("Fail to write file: "sv) + targetFile.string() + '\n'}; } } } else { std::ostringstream buf; - buf << "Fail to compile: " << file << ".\n"; + buf << "Fail to compile: "sv << file.first << ".\n"; buf << std::get<1>(result) << '\n'; return std::pair{1, buf.str()}; } } else { - return std::pair{1, std::string("Fail to read file: ") + file + ".\n"}; + return std::pair{1, std::string("Fail to read file: "sv) + file.first + ".\n"}; } }); results.push_back(std::move(task)); @@ -184,4 +288,3 @@ int main(int narg, const char** args) { } return ret; } - -- cgit v1.2.3-55-g6feb