diff options
author | Li Jin <dragon-fly@qq.com> | 2020-03-24 18:09:45 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2020-03-24 18:09:45 +0800 |
commit | d04b23b9a47c2ec6631aec16dc79f5b803fe07f3 (patch) | |
tree | dd851ebf0499b6acca5b6962207094f48eb6c414 | |
parent | 2447d158241aeaaf9c0b1ab21a08db7a40e5cef3 (diff) | |
download | yuescript-d04b23b9a47c2ec6631aec16dc79f5b803fe07f3.tar.gz yuescript-d04b23b9a47c2ec6631aec16dc79f5b803fe07f3.tar.bz2 yuescript-d04b23b9a47c2ec6631aec16dc79f5b803fe07f3.zip |
add command line option "-e" to moonp to eval file or string.
-rw-r--r-- | makefile | 2 | ||||
-rw-r--r-- | src/moonp.cpp | 209 |
2 files changed, 157 insertions, 54 deletions
@@ -210,7 +210,7 @@ clean: | |||
210 | test: release | 210 | test: release |
211 | @echo "Compiling Moonscript codes..." | 211 | @echo "Compiling Moonscript codes..." |
212 | @$(START_TIME) | 212 | @$(START_TIME) |
213 | @./$(BIN_NAME) $(TEST_INPUT)/*.moon -t $(TEST_OUTPUT) | 213 | @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) |
214 | @echo -en "Compile time: " | 214 | @echo -en "Compile time: " |
215 | @$(END_TIME) | 215 | @$(END_TIME) |
216 | 216 | ||
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 | |||
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
6 | 6 | ||
7 | 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. */ | 7 | 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. */ |
8 | |||
9 | #include "MoonP/moon_compiler.h" | ||
10 | #include "MoonP/moon_parser.h" | ||
11 | |||
8 | #include <iostream> | 12 | #include <iostream> |
9 | #include <iomanip> | 13 | #include <iomanip> |
10 | #include <fstream> | 14 | #include <fstream> |
@@ -12,8 +16,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
12 | #include <future> | 16 | #include <future> |
13 | #include <sstream> | 17 | #include <sstream> |
14 | #include <tuple> | 18 | #include <tuple> |
15 | #include "MoonP/moon_compiler.h" | 19 | #include <string_view> |
16 | #include "MoonP/moon_parser.h" | 20 | #include <memory> |
21 | using namespace std::string_view_literals; | ||
22 | #include <filesystem> | ||
23 | namespace fs = std::filesystem; | ||
24 | |||
25 | #define _DEFER(code,line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto){code;}) | ||
26 | #define DEFER(code) _DEFER(code,__LINE__) | ||
17 | 27 | ||
18 | extern "C" { | 28 | extern "C" { |
19 | 29 | ||
@@ -30,16 +40,29 @@ static void openlibs(void* state) { | |||
30 | luaopen_moonp(L); | 40 | luaopen_moonp(L); |
31 | } | 41 | } |
32 | 42 | ||
43 | void pushMoonp(lua_State* L, std::string_view name) { | ||
44 | lua_getglobal(L, "package"); // package | ||
45 | lua_getfield(L, -1, "loaded"); // package loaded | ||
46 | lua_getfield(L, -1, "moonp"); // package loaded moonp | ||
47 | lua_pushlstring(L, &name.front(), name.size()); // package loaded moonp name | ||
48 | lua_gettable(L, -2); // loaded[name], package loaded moonp item | ||
49 | lua_insert(L, -4); // item package loaded moonp | ||
50 | lua_pop(L, 3); // item | ||
51 | } | ||
52 | |||
33 | int main(int narg, const char** args) { | 53 | int main(int narg, const char** args) { |
34 | const char* help = | 54 | const char* help = |
35 | "Usage: moonp [options|files] ...\n\n" | 55 | "Usage: moonp [options|files|directories] ...\n\n" |
36 | " -h Print this message\n" | 56 | " -h Print this message\n" |
37 | " -t path Specify where to place compiled files\n" | 57 | " -e str Execute a file or raw codes\n" |
38 | " -o file Write output to file\n" | 58 | " -t path Specify where to place compiled files\n" |
39 | " -p Write output to standard out\n" | 59 | " -o file Write output to file\n" |
40 | " -b Dump compile time (doesn't write output)\n" | 60 | " -p Write output to standard out\n" |
41 | " -l Write line numbers from source codes\n" | 61 | " -b Dump compile time (doesn't write output)\n" |
42 | " -v Print version\n"; | 62 | " -l Write line numbers from source codes\n" |
63 | " -v Print version\n" | ||
64 | " -- Read from standard in, print to standard out\n" | ||
65 | " (Must be first and only argument)\n"; | ||
43 | if (narg == 0) { | 66 | if (narg == 0) { |
44 | std::cout << help; | 67 | std::cout << help; |
45 | return 0; | 68 | return 0; |
@@ -50,14 +73,88 @@ int main(int narg, const char** args) { | |||
50 | bool dumpCompileTime = false; | 73 | bool dumpCompileTime = false; |
51 | std::string targetPath; | 74 | std::string targetPath; |
52 | std::string resultFile; | 75 | std::string resultFile; |
53 | std::list<std::string> files; | 76 | std::list<std::pair<std::string,std::string>> files; |
54 | for (int i = 1; i < narg; ++i) { | 77 | for (int i = 1; i < narg; ++i) { |
55 | std::string arg = args[i]; | 78 | std::string arg = args[i]; |
56 | if (arg == "-l") { | 79 | if (arg == "--"sv) { |
80 | if (i != 1) { | ||
81 | std::cout << help; | ||
82 | return 1; | ||
83 | } | ||
84 | char ch; | ||
85 | std::string s; | ||
86 | while ((ch = std::cin.get()) != EOF) { | ||
87 | s += ch; | ||
88 | } | ||
89 | MoonP::MoonConfig conf; | ||
90 | conf.implicitReturnRoot = true; | ||
91 | conf.lintGlobalVariable = false; | ||
92 | conf.reserveLineNumber = false; | ||
93 | auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, conf); | ||
94 | if (std::get<1>(result).empty()) { | ||
95 | std::cout << std::get<0>(result); | ||
96 | return 0; | ||
97 | } else { | ||
98 | std::ostringstream buf; | ||
99 | std::cout << std::get<1>(result) << '\n'; | ||
100 | return 1; | ||
101 | } | ||
102 | } else if (arg == "-e"sv) { | ||
103 | ++i; | ||
104 | if (i < narg) { | ||
105 | lua_State* L = luaL_newstate(); | ||
106 | openlibs(L); | ||
107 | DEFER(lua_close(L)); | ||
108 | pushMoonp(L, "insert_loader"sv); | ||
109 | if (lua_pcall(L, 0, 0, 0) != 0) { | ||
110 | std::cout << lua_tostring(L, -1) << '\n'; | ||
111 | return 1; | ||
112 | } | ||
113 | std::string evalStr = args[i]; | ||
114 | std::ifstream input(evalStr, std::ios::in); | ||
115 | if (input) { | ||
116 | auto ext = fs::path(evalStr).extension().string(); | ||
117 | for (auto& ch : ext) ch = std::tolower(ch); | ||
118 | if (ext == ".lua") { | ||
119 | lua_getglobal(L, "load"); | ||
120 | } else { | ||
121 | pushMoonp(L, "loadstring"sv); | ||
122 | } | ||
123 | std::string s( | ||
124 | (std::istreambuf_iterator<char>(input)), | ||
125 | std::istreambuf_iterator<char>()); | ||
126 | lua_pushlstring(L, s.c_str(), s.size()); | ||
127 | lua_pushlstring(L, evalStr.c_str(), evalStr.size()); | ||
128 | } else { | ||
129 | pushMoonp(L, "loadstring"sv); | ||
130 | lua_pushlstring(L, evalStr.c_str(), evalStr.size()); | ||
131 | lua_pushliteral(L, "=(eval str)"); | ||
132 | } | ||
133 | if (lua_pcall(L, 2, 1, 0) != 0) { | ||
134 | std::cout << lua_tostring(L, -1) << '\n'; | ||
135 | return 1; | ||
136 | } | ||
137 | pushMoonp(L, "pcall"sv); | ||
138 | lua_insert(L, -2); | ||
139 | if (lua_pcall(L, 1, 2, 0) != 0) { | ||
140 | std::cout << lua_tostring(L, -1) << '\n'; | ||
141 | return 1; | ||
142 | } | ||
143 | bool success = lua_toboolean(L, -2) != 0; | ||
144 | if (!success) { | ||
145 | std::cout << lua_tostring(L, -1) << '\n'; | ||
146 | return 1; | ||
147 | } | ||
148 | return 0; | ||
149 | } else { | ||
150 | std::cout << help; | ||
151 | return 1; | ||
152 | } | ||
153 | } else if (arg == "-l"sv) { | ||
57 | config.reserveLineNumber = true; | 154 | config.reserveLineNumber = true; |
58 | } else if (arg == "-p") { | 155 | } else if (arg == "-p"sv) { |
59 | writeToFile = false; | 156 | writeToFile = false; |
60 | } else if (arg == "-t") { | 157 | } else if (arg == "-t"sv) { |
61 | ++i; | 158 | ++i; |
62 | if (i < narg) { | 159 | if (i < narg) { |
63 | targetPath = args[i]; | 160 | targetPath = args[i]; |
@@ -65,15 +162,15 @@ int main(int narg, const char** args) { | |||
65 | std::cout << help; | 162 | std::cout << help; |
66 | return 1; | 163 | return 1; |
67 | } | 164 | } |
68 | } else if (arg == "-b") { | 165 | } else if (arg == "-b"sv) { |
69 | dumpCompileTime = true; | 166 | dumpCompileTime = true; |
70 | } else if (arg == "-h") { | 167 | } else if (arg == "-h"sv) { |
71 | std::cout << help; | 168 | std::cout << help; |
72 | return 0; | 169 | return 0; |
73 | } else if (arg == "-v") { | 170 | } else if (arg == "-v"sv) { |
74 | std::cout << "Moonscript version: " << MoonP::moonScriptVersion() << '\n'; | 171 | std::cout << "Moonscript version: "sv << MoonP::moonScriptVersion() << '\n'; |
75 | return 0; | 172 | return 0; |
76 | } else if (arg == "-o") { | 173 | } else if (arg == "-o"sv) { |
77 | ++i; | 174 | ++i; |
78 | if (i < narg) { | 175 | if (i < narg) { |
79 | resultFile = args[i]; | 176 | resultFile = args[i]; |
@@ -82,7 +179,19 @@ int main(int narg, const char** args) { | |||
82 | return 1; | 179 | return 1; |
83 | } | 180 | } |
84 | } else { | 181 | } else { |
85 | files.push_back(arg); | 182 | if (fs::is_directory(arg)) { |
183 | for (auto item : fs::recursive_directory_iterator(arg)) { | ||
184 | if (!item.is_directory()) { | ||
185 | auto ext = item.path().extension().string(); | ||
186 | for (char& ch : ext) ch = std::tolower(ch); | ||
187 | if (ext == ".moon"sv) { | ||
188 | files.emplace_back(item.path().string(), item.path().lexically_relative(arg).string()); | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | } else { | ||
193 | files.emplace_back(arg, arg); | ||
194 | } | ||
86 | } | 195 | } |
87 | } | 196 | } |
88 | if (files.empty()) { | 197 | if (files.empty()) { |
@@ -90,23 +199,20 @@ int main(int narg, const char** args) { | |||
90 | return 0; | 199 | return 0; |
91 | } | 200 | } |
92 | if (!resultFile.empty() && files.size() > 1) { | 201 | if (!resultFile.empty() && files.size() > 1) { |
93 | std::cout << "Error: -o can not be used with multiple input files.\n"; | 202 | std::cout << "Error: -o can not be used with multiple input files.\n"sv; |
94 | std::cout << help; | 203 | std::cout << help; |
95 | } | 204 | } |
96 | if (!targetPath.empty() && targetPath.back() != '/' && targetPath.back() != '\\') { | ||
97 | targetPath.append("/"); | ||
98 | } | ||
99 | std::list<std::future<std::pair<int,std::string>>> results; | 205 | std::list<std::future<std::pair<int,std::string>>> results; |
100 | for (const auto& file : files) { | 206 | for (const auto& file : files) { |
101 | auto task = std::async(std::launch::async, [=]() { | 207 | auto task = std::async(std::launch::async, [=]() { |
102 | std::ifstream input(file, std::ios::in); | 208 | std::ifstream input(file.first, std::ios::in); |
103 | if (input) { | 209 | if (input) { |
104 | std::string s( | 210 | std::string s( |
105 | (std::istreambuf_iterator<char>(input)), | 211 | (std::istreambuf_iterator<char>(input)), |
106 | std::istreambuf_iterator<char>()); | 212 | std::istreambuf_iterator<char>()); |
107 | if (dumpCompileTime) { | 213 | if (dumpCompileTime) { |
108 | auto start = std::chrono::high_resolution_clock::now(); | 214 | auto start = std::chrono::high_resolution_clock::now(); |
109 | auto result = MoonP::MoonCompiler{nullptr,openlibs}.compile(s, config); | 215 | auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, config); |
110 | auto end = std::chrono::high_resolution_clock::now(); | 216 | auto end = std::chrono::high_resolution_clock::now(); |
111 | if (!std::get<0>(result).empty()) { | 217 | if (!std::get<0>(result).empty()) { |
112 | std::chrono::duration<double> diff = end - start; | 218 | std::chrono::duration<double> diff = end - start; |
@@ -115,59 +221,57 @@ int main(int narg, const char** args) { | |||
115 | end = std::chrono::high_resolution_clock::now(); | 221 | end = std::chrono::high_resolution_clock::now(); |
116 | std::chrono::duration<double> parseDiff = end - start; | 222 | std::chrono::duration<double> parseDiff = end - start; |
117 | std::ostringstream buf; | 223 | std::ostringstream buf; |
118 | buf << file << " \n"; | 224 | buf << file.first << " \n"sv; |
119 | buf << "Parse time: " << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n"; | 225 | buf << "Parse time: "sv << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n"; |
120 | buf << "Compile time: " << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n"; | 226 | buf << "Compile time: "sv << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n"; |
121 | return std::pair{0, buf.str()}; | 227 | return std::pair{0, buf.str()}; |
122 | } else { | 228 | } else { |
123 | std::ostringstream buf; | 229 | std::ostringstream buf; |
124 | buf << "Fail to compile: " << file << ".\n"; | 230 | buf << "Fail to compile: "sv << file.first << ".\n"sv; |
125 | buf << std::get<1>(result) << '\n'; | 231 | buf << std::get<1>(result) << '\n'; |
126 | return std::pair{1, buf.str()}; | 232 | return std::pair{1, buf.str()}; |
127 | } | 233 | } |
128 | } | 234 | } |
129 | auto result = MoonP::MoonCompiler{nullptr,openlibs}.compile(s, config); | 235 | auto result = MoonP::MoonCompiler{nullptr, openlibs}.compile(s, config); |
130 | if (!std::get<0>(result).empty()) { | 236 | if (!std::get<0>(result).empty()) { |
131 | if (!writeToFile) { | 237 | if (!writeToFile) { |
132 | return std::pair{1, std::get<0>(result) + '\n'}; | 238 | return std::pair{1, std::get<0>(result) + '\n'}; |
133 | } else { | 239 | } else { |
134 | std::string targetFile; | 240 | fs::path targetFile; |
135 | if (resultFile.empty()) { | 241 | if (!resultFile.empty()) { |
136 | targetFile = file; | 242 | targetFile = resultFile; |
137 | size_t pos = file.rfind('.'); | 243 | } else { |
138 | if (pos != std::string::npos) { | ||
139 | targetFile = file.substr(0, pos) + ".lua"; | ||
140 | } | ||
141 | if (!targetPath.empty()) { | 244 | if (!targetPath.empty()) { |
142 | std::string name; | 245 | targetFile = fs::path(targetPath) / file.second; |
143 | pos = targetFile.find_last_of("/\\"); | 246 | } else { |
144 | if (pos == std::string::npos) { | 247 | targetFile = file.first; |
145 | name = targetFile; | ||
146 | } else { | ||
147 | name = targetFile.substr(pos + 1); | ||
148 | } | ||
149 | targetFile = targetPath + name; | ||
150 | } | 248 | } |
151 | } else { | 249 | targetFile.replace_extension(".lua"sv); |
152 | targetFile = resultFile; | 250 | } |
251 | if (!targetPath.empty()) { | ||
252 | fs::create_directories(targetFile.parent_path()); | ||
153 | } | 253 | } |
154 | std::ofstream output(targetFile, std::ios::trunc | std::ios::out); | 254 | std::ofstream output(targetFile, std::ios::trunc | std::ios::out); |
155 | if (output) { | 255 | if (output) { |
156 | const auto& codes = std::get<0>(result); | 256 | const auto& codes = std::get<0>(result); |
257 | if (config.reserveLineNumber) { | ||
258 | auto head = std::string("-- [moon]: "sv) + file.first + '\n'; | ||
259 | output.write(head.c_str(), head.size()); | ||
260 | } | ||
157 | output.write(codes.c_str(), codes.size()); | 261 | output.write(codes.c_str(), codes.size()); |
158 | return std::pair{0, std::string("Built ") + file + '\n'}; | 262 | return std::pair{0, std::string("Built "sv) + file.first + '\n'}; |
159 | } else { | 263 | } else { |
160 | return std::pair{1, std::string("Fail to write file: ") + targetFile + '\n'}; | 264 | return std::pair{1, std::string("Fail to write file: "sv) + targetFile.string() + '\n'}; |
161 | } | 265 | } |
162 | } | 266 | } |
163 | } else { | 267 | } else { |
164 | std::ostringstream buf; | 268 | std::ostringstream buf; |
165 | buf << "Fail to compile: " << file << ".\n"; | 269 | buf << "Fail to compile: "sv << file.first << ".\n"; |
166 | buf << std::get<1>(result) << '\n'; | 270 | buf << std::get<1>(result) << '\n'; |
167 | return std::pair{1, buf.str()}; | 271 | return std::pair{1, buf.str()}; |
168 | } | 272 | } |
169 | } else { | 273 | } else { |
170 | return std::pair{1, std::string("Fail to read file: ") + file + ".\n"}; | 274 | return std::pair{1, std::string("Fail to read file: "sv) + file.first + ".\n"}; |
171 | } | 275 | } |
172 | }); | 276 | }); |
173 | results.push_back(std::move(task)); | 277 | results.push_back(std::move(task)); |
@@ -184,4 +288,3 @@ int main(int narg, const char** args) { | |||
184 | } | 288 | } |
185 | return ret; | 289 | return ret; |
186 | } | 290 | } |
187 | |||