aboutsummaryrefslogtreecommitdiff
path: root/src/moonp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/moonp.cpp')
-rw-r--r--src/moonp.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/moonp.cpp b/src/moonp.cpp
new file mode 100644
index 0000000..a6c99df
--- /dev/null
+++ b/src/moonp.cpp
@@ -0,0 +1,293 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE 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#include <iostream>
9#include <iomanip>
10#include <fstream>
11#include <chrono>
12#include <future>
13#include "MoonP/moon_compiler.h"
14#include "MoonP/moon_parser.h"
15
16#ifndef LIBMOONP
17
18int main(int narg, const char** args) {
19 const char* help =
20"Usage: moonp [options|files] ...\n\n"
21" -h Print this message\n"
22" -t path Specify where to place compiled files\n"
23" -o file Write output to file\n"
24" -p Write output to standard out\n"
25" -b Dump compile time (doesn't write output)\n"
26" -l Write line numbers from source codes\n"
27" -v Print version\n";
28 if (narg == 0) {
29 std::cout << help;
30 return 0;
31 }
32 MoonP::MoonConfig config;
33 config.reserveLineNumber = false;
34 bool writeToFile = true;
35 bool dumpCompileTime = false;
36 std::string targetPath;
37 std::string resultFile;
38 std::list<std::string> files;
39 for (int i = 1; i < narg; ++i) {
40 switch (hash(args[i])) {
41 case "-l"_id:
42 config.reserveLineNumber = true;
43 break;
44 case "-p"_id:
45 writeToFile = false;
46 break;
47 case "-t"_id:
48 ++i;
49 if (i < narg) {
50 targetPath = args[i];
51 } else {
52 std::cout << help;
53 return 1;
54 }
55 break;
56 case "-b"_id:
57 dumpCompileTime = true;
58 break;
59 case "-h"_id:
60 std::cout << help;
61 return 0;
62 case "-v"_id:
63 std::cout << "Moonscript version: " << MoonP::moonScriptVersion() << '\n';
64 return 0;
65 case "-o"_id:
66 ++i;
67 if (i < narg) {
68 resultFile = args[i];
69 } else {
70 std::cout << help;
71 return 1;
72 }
73 break;
74 default:
75 files.push_back(args[i]);
76 break;
77 }
78 }
79 if (files.empty()) {
80 std::cout << help;
81 return 0;
82 }
83 if (!resultFile.empty() && files.size() > 1) {
84 std::cout << "Error: -o can not be used with multiple input files.\n";
85 std::cout << help;
86 }
87 if (!targetPath.empty() && targetPath.back() != '/' && targetPath.back() != '\\') {
88 targetPath.append("/");
89 }
90 std::list<std::future<std::result_of_t<std::decay_t<int()>()>>> results;
91 for (const auto& file : files) {
92 auto task = std::async(std::launch::async, [=]() {
93 std::ifstream input(file, input.in);
94 if (input) {
95 std::string s(
96 (std::istreambuf_iterator<char>(input)),
97 std::istreambuf_iterator<char>());
98 if (dumpCompileTime) {
99 auto start = std::chrono::high_resolution_clock::now();
100 auto result = MoonP::moonCompile(s, config);
101 auto end = std::chrono::high_resolution_clock::now();
102 if (!std::get<0>(result).empty()) {
103 std::chrono::duration<double> diff = end - start;
104 start = std::chrono::high_resolution_clock::now();
105 MoonP::MoonParser{}.parse<MoonP::File_t>(s);
106 end = std::chrono::high_resolution_clock::now();
107 std::chrono::duration<double> parseDiff = end - start;
108 std::cout << file << " \n";
109 std::cout << "Parse time: " << std::setprecision(5) << parseDiff.count() * 1000 << " ms\n";
110 std::cout << "Compile time: " << std::setprecision(5) << (diff.count() - parseDiff.count()) * 1000 << " ms\n\n";
111 return 0;
112 } else {
113 std::cout << "Fail to compile: " << file << ".\n";
114 std::cout << std::get<1>(result) << '\n';
115 return 1;
116 }
117 }
118 auto result = MoonP::moonCompile(s, config);
119 if (!std::get<0>(result).empty()) {
120 if (!writeToFile) {
121 std::cout << std::get<0>(result) << '\n';
122 return 1;
123 } else {
124 std::string targetFile;
125 if (resultFile.empty()) {
126 targetFile = file;
127 size_t pos = file.rfind('.');
128 if (pos != std::string::npos) {
129 targetFile = file.substr(0, pos) + ".lua";
130 }
131 if (!targetPath.empty()) {
132 std::string name;
133 pos = targetFile.find_last_of("/\\");
134 if (pos == std::string::npos) {
135 name = targetFile;
136 } else {
137 name = targetFile.substr(pos + 1);
138 }
139 targetFile = targetPath + name;
140 }
141 } else {
142 targetFile = resultFile;
143 }
144 std::ofstream output(targetFile, output.trunc | output.out);
145 if (output) {
146 const auto& codes = std::get<0>(result);
147 output.write(codes.c_str(), codes.size());
148 std::cout << "Built " << file << '\n';
149 return 0;
150 } else {
151 std::cout << "Fail to write file: " << targetFile << ".\n";
152 return 1;
153 }
154 }
155 } else {
156 std::cout << "Fail to compile: " << file << ".\n";
157 std::cout << std::get<1>(result) << '\n';
158 return 1;
159 }
160 } else {
161 std::cout << "Fail to read file: " << file << ".\n";
162 return 1;
163 }
164 });
165 results.push_back(std::move(task));
166 }
167 int ret = 0;
168 for (auto& result : results) {
169 int val = result.get();
170 if (val != 0) {
171 ret = val;
172 }
173 }
174 return ret;
175}
176
177#else
178
179extern "C" {
180
181#include "lua.h"
182#include "lauxlib.h"
183
184static const char moonplusCodes[] =
185#include "MoonPlus.h"
186
187static int init_moonplus(lua_State* L) {
188 MoonP::MoonConfig config;
189 std::string s(moonplusCodes, sizeof(moonplusCodes) / sizeof(moonplusCodes[0]) - 1);
190 std::string codes, err;
191 MoonP::GlobalVars globals;
192 std::tie(codes, err, globals) = MoonP::moonCompile(s, config);
193 if (codes.empty()) {
194 luaL_error(L, "fail to compile moonplus init codes.\n%s", err.c_str());
195 }
196 int top = lua_gettop(L);
197 if (luaL_loadbuffer(L, codes.c_str(), codes.size(), "=(moonplus)") != 0) {
198 luaL_error(L, "fail to init moonplus module.");
199 } else {
200 lua_call(L, 0, 0);
201 }
202 lua_settop(L, top);
203 return 0;
204}
205
206static const char stpCodes[] =
207#include "StackTracePlus.h"
208
209static int init_stacktraceplus(lua_State* L) {
210 if (luaL_loadbuffer(L, stpCodes, sizeof(stpCodes) / sizeof(stpCodes[0]) - 1, "=(stacktraceplus)") != 0) {
211 luaL_error(L, "fail to init stacktraceplus module.");
212 } else {
213 lua_call(L, 0, 1);
214 }
215 return 1;
216}
217
218static int moontolua(lua_State* L) {
219 size_t size = 0;
220 const char* input = luaL_checklstring(L, 1, &size);
221 MoonP::MoonConfig config;
222 if (lua_gettop(L) == 2) {
223 lua_pushstring(L, "lint_global");
224 lua_gettable(L, -2);
225 if (!lua_isnil(L, -1)) {
226 config.lintGlobalVariable = lua_toboolean(L, -1) != 0;
227 }
228 lua_pop(L, 1);
229 lua_pushstring(L, "implicit_return_root");
230 lua_gettable(L, -2);
231 if (!lua_isnil(L, -1)) {
232 config.implicitReturnRoot = lua_toboolean(L, -1) != 0;
233 }
234 lua_pop(L, 1);
235 lua_pushstring(L, "reserve_line_number");
236 lua_gettable(L, -2);
237 if (!lua_isnil(L, -1)) {
238 config.reserveLineNumber = lua_toboolean(L, -1) != 0;
239 }
240 lua_pop(L, 1);
241 }
242 std::string s(input, size);
243 std::string codes, err;
244 MoonP::GlobalVars globals;
245 std::tie(codes, err, globals) = MoonP::moonCompile(s, config);
246 if (codes.empty()) {
247 lua_pushnil(L);
248 } else {
249 lua_pushlstring(L, codes.c_str(), codes.size());
250 }
251 if (err.empty()) {
252 lua_pushnil(L);
253 } else {
254 lua_pushlstring(L, err.c_str(), err.size());
255 }
256 if (globals && !globals->empty()) {
257 lua_createtable(L, static_cast<int>(globals->size()), 0);
258 int i = 1;
259 for (const auto& var : *globals) {
260 lua_createtable(L, 3, 0);
261 lua_pushlstring(L, var.name.c_str(), var.name.size());
262 lua_rawseti(L, -2, 1);
263 lua_pushinteger(L, var.line);
264 lua_rawseti(L, -2, 2);
265 lua_pushinteger(L, var.col);
266 lua_rawseti(L, -2, 3);
267 lua_rawseti(L, -2, i);
268 i++;
269 }
270 } else {
271 lua_pushnil(L);
272 }
273 return 3;
274}
275
276int luaopen_moonp(lua_State* L) {
277 lua_getglobal(L, "package");
278 lua_getfield(L, -1, "loaded");
279 lua_createtable(L, 0, 0);
280 lua_pushcfunction(L, moontolua);
281 lua_setfield(L, -2, "to_lua");
282 lua_pushcfunction(L, init_stacktraceplus);
283 lua_setfield(L, -2, "load_stacktraceplus");
284 lua_setfield(L, -2, "moonp");
285 lua_pop(L, 2);
286 init_moonplus(L);
287 return 0;
288}
289
290} // extern "C"
291
292#endif // LIBMOONP
293