summaryrefslogtreecommitdiff
path: root/src/MoonP/moon_compiler.cpp
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2021-02-17 11:22:07 +0800
committerLi Jin <dragon-fly@qq.com>2021-02-17 11:22:07 +0800
commit7066392d1c974065181d95d93274136dcd625d43 (patch)
treecf51eafc2c52cbc12246a306bca172d799193d30 /src/MoonP/moon_compiler.cpp
parent90cd12ad9ef465f3e435e1bd034dcfbe4e19d016 (diff)
downloadyuescript-7066392d1c974065181d95d93274136dcd625d43.tar.gz
yuescript-7066392d1c974065181d95d93274136dcd625d43.tar.bz2
yuescript-7066392d1c974065181d95d93274136dcd625d43.zip
stop reusing variables, rename project.
Diffstat (limited to 'src/MoonP/moon_compiler.cpp')
-rw-r--r--src/MoonP/moon_compiler.cpp5622
1 files changed, 0 insertions, 5622 deletions
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp
deleted file mode 100644
index 24e4a97..0000000
--- a/src/MoonP/moon_compiler.cpp
+++ /dev/null
@@ -1,5622 +0,0 @@
1/* Copyright (c) 2021 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
9#include <string>
10#include <unordered_set>
11#include <unordered_map>
12#include <stack>
13#include <vector>
14#include <memory>
15#include <cassert>
16
17#include "MoonP/moon_parser.h"
18#include "MoonP/moon_compiler.h"
19
20#ifndef MOONP_NO_MACRO
21
22extern "C" {
23#include "lua.h"
24#include "lauxlib.h"
25#include "lualib.h"
26} // extern "C"
27
28// name of table stored in lua registry
29#define MOONP_MODULE "__moon_modules__"
30
31#if LUA_VERSION_NUM > 501
32 #ifndef LUA_COMPAT_5_1
33 #define lua_objlen lua_rawlen
34 #endif // LUA_COMPAT_5_1
35#endif // LUA_VERSION_NUM
36
37#endif // MOONP_NO_MACRO
38
39namespace MoonP {
40using namespace std::string_view_literals;
41using namespace parserlib;
42
43#define BLOCK_START do {
44#define BLOCK_END } while (false);
45#define BREAK_IF(cond) if (cond) break
46
47#define _DEFER(code,line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto){code;})
48#define DEFER(code) _DEFER(code,__LINE__)
49
50typedef std::list<std::string> str_list;
51
52inline std::string s(std::string_view sv) {
53 return std::string(sv);
54}
55
56const std::string_view version = "0.6.3"sv;
57const std::string_view extension = "mp"sv;
58
59class MoonCompilerImpl {
60public:
61#ifndef MOONP_NO_MACRO
62 MoonCompilerImpl(lua_State* sharedState,
63 const std::function<void(void*)>& luaOpen,
64 bool sameModule,
65 std::string_view moduleName = {}):
66 L(sharedState),
67 _luaOpen(luaOpen),
68 _moduleName(moduleName) {
69 BLOCK_START
70 BREAK_IF(!sameModule);
71 BREAK_IF(!L);
72 _sameModule = true;
73 int top = lua_gettop(L);
74 DEFER(lua_settop(L, top));
75 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
76 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
77 BREAK_IF(lua_istable(L, -1) == 0);
78 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
79 BREAK_IF(idx == 0);
80 _useModule = true;
81 BLOCK_END
82 }
83
84 ~MoonCompilerImpl() {
85 if (L && _stateOwner) {
86 lua_close(L);
87 L = nullptr;
88 }
89 }
90#endif // MOONP_NO_MACRO
91
92 CompileInfo compile(std::string_view codes, const MoonConfig& config) {
93 _config = config;
94#ifndef MOONP_NO_MACRO
95 if (L) passOptions();
96#endif // MOONP_NO_MACRO
97 _info = _parser.parse<File_t>(codes);
98 std::unique_ptr<GlobalVars> globals;
99 std::unique_ptr<Options> options;
100 if (!config.options.empty()) {
101 options = std::make_unique<Options>(config.options);
102 }
103 DEFER(clear());
104 if (_info.node) {
105 try {
106 str_list out;
107 pushScope();
108 _enableReturn.push(_info.moduleName.empty());
109 _varArgs.push(true);
110 transformBlock(_info.node.to<File_t>()->block, out,
111 config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common,
112 nullptr, true);
113 popScope();
114 if (config.lintGlobalVariable) {
115 globals = std::make_unique<GlobalVars>();
116 for (const auto& var : _globals) {
117 int line,col;
118 std::tie(line,col) = var.second;
119 globals->push_back({var.first, line, col});
120 }
121 }
122#ifndef MOONP_NO_MACRO
123 if (L) {
124 int top = lua_gettop(L);
125 DEFER(lua_settop(L, top));
126 if (!options) {
127 options = std::make_unique<Options>();
128 }
129 pushMoonp("options"sv);
130 lua_pushnil(L); // options startKey
131 while (lua_next(L, -2) != 0) { // options key value
132 size_t len = 0;
133 auto pstr = lua_tolstring(L, -2, &len);
134 std::string key{pstr, len};
135 pstr = lua_tolstring(L, -1, &len);
136 std::string value{pstr, len};
137 (*options)[key] = value;
138 lua_pop(L, 1); // options key
139 }
140 }
141#endif // MOONP_NO_MACRO
142 return {std::move(out.back()), Empty, std::move(globals), std::move(options)};
143 } catch (const std::logic_error& error) {
144 return {Empty, error.what(), std::move(globals), std::move(options)};
145 }
146 } else {
147 return {Empty, std::move(_info.error), std::move(globals), std::move(options)};
148 }
149 }
150
151 void clear() {
152 _indentOffset = 0;
153 _scopes.clear();
154 _codeCache.clear();
155 _buf.str("");
156 _buf.clear();
157 _joinBuf.str("");
158 _joinBuf.clear();
159 _globals.clear();
160 _info = {};
161 _varArgs = {};
162 _withVars = {};
163 _continueVars = {};
164 _enableReturn = {};
165#ifndef MOONP_NO_MACRO
166 if (_useModule) {
167 _useModule = false;
168 if (!_sameModule) {
169 int top = lua_gettop(L);
170 DEFER(lua_settop(L, top));
171 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
172 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
173 int idx = static_cast<int>(lua_objlen(L, -1));
174 lua_pushnil(L); // tb nil
175 lua_rawseti(L, -2, idx); // tb[idx] = nil, tb
176 }
177 }
178#endif // MOONP_NO_MACRO
179 }
180private:
181#ifndef MOONP_NO_MACRO
182 bool _stateOwner = false;
183 bool _useModule = false;
184 bool _sameModule = false;
185 lua_State* L = nullptr;
186 std::function<void(void*)> _luaOpen;
187#endif // MOONP_NO_MACRO
188 MoonConfig _config;
189 MoonParser _parser;
190 ParseInfo _info;
191 int _indentOffset = 0;
192 std::stack<bool> _varArgs;
193 std::stack<bool> _enableReturn;
194 std::stack<std::string> _withVars;
195 std::stack<std::string> _continueVars;
196 std::list<std::unique_ptr<input>> _codeCache;
197 std::unordered_map<std::string,std::pair<int,int>> _globals;
198 std::ostringstream _buf;
199 std::ostringstream _joinBuf;
200 const std::string _newLine = "\n";
201 std::string _moduleName;
202
203 enum class LocalMode {
204 None = 0,
205 Capital = 1,
206 Any = 2
207 };
208 enum class GlobalMode {
209 None = 0,
210 Capital = 1,
211 Any = 2
212 };
213 struct Scope {
214 GlobalMode mode = GlobalMode::None;
215 std::unique_ptr<std::unordered_set<std::string>> vars;
216 std::unique_ptr<std::unordered_set<std::string>> allows;
217 std::unique_ptr<std::unordered_set<std::string>> globals;
218 };
219 std::list<Scope> _scopes;
220 static const std::string Empty;
221
222 enum class MemType {
223 Builtin,
224 Common,
225 Property
226 };
227
228 struct ClassMember {
229 std::string item;
230 MemType type;
231 ast_node* node;
232 };
233
234 struct DestructItem {
235 bool isVariable = false;
236 std::string name;
237 std::string structure;
238 };
239
240 struct Destructure {
241 std::string value;
242 std::list<DestructItem> items;
243 };
244
245 enum class ExpUsage {
246 Return,
247 Assignment,
248 Common,
249 Closure
250 };
251
252 void pushScope() {
253 _scopes.emplace_back();
254 _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>();
255 }
256
257 void popScope() {
258 _scopes.pop_back();
259 }
260
261 bool isDefined(const std::string& name) const {
262 bool isDefined = false;
263 int mode = int(std::isupper(name[0]) ? GlobalMode::Capital : GlobalMode::Any);
264 const auto& current = _scopes.back();
265 if (int(current.mode) >= mode) {
266 if (current.globals) {
267 if (current.globals->find(name) != current.globals->end()) {
268 isDefined = true;
269 current.vars->insert(name);
270 }
271 } else {
272 isDefined = true;
273 current.vars->insert(name);
274 }
275 }
276 decltype(_scopes.back().allows.get()) allows = nullptr;
277 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
278 if (it->allows) allows = it->allows.get();
279 }
280 bool checkShadowScopeOnly = false;
281 if (allows) {
282 checkShadowScopeOnly = allows->find(name) == allows->end();
283 }
284 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
285 auto vars = it->vars.get();
286 if (vars->find(name) != vars->end()) {
287 isDefined = true;
288 break;
289 }
290 if (checkShadowScopeOnly && it->allows) break;
291 }
292 return isDefined;
293 }
294
295 bool isSolidDefined(const std::string& name) const {
296 bool isDefined = false;
297 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
298 auto vars = it->vars.get();
299 if (vars->find(name) != vars->end()) {
300 isDefined = true;
301 break;
302 }
303 }
304 return isDefined;
305 }
306
307 void markVarShadowed() {
308 auto& scope = _scopes.back();
309 scope.allows = std::make_unique<std::unordered_set<std::string>>();
310 }
311
312 void markVarGlobal(GlobalMode mode, bool specified) {
313 auto& scope = _scopes.back();
314 scope.mode = mode;
315 if (specified && !scope.globals) {
316 scope.globals = std::make_unique<std::unordered_set<std::string>>();
317 }
318 }
319
320 void addGlobalVar(const std::string& name) {
321 auto& scope = _scopes.back();
322 scope.globals->insert(name);
323 }
324
325 void addToAllowList(const std::string& name) {
326 auto& scope = _scopes.back();
327 scope.allows->insert(name);
328 }
329
330 void forceAddToScope(const std::string& name) {
331 auto& scope = _scopes.back();
332 scope.vars->insert(name);
333 }
334
335 Scope& currentScope() {
336 return _scopes.back();
337 }
338
339 bool addToScope(const std::string& name) {
340 bool defined = isDefined(name);
341 if (!defined) {
342 auto& scope = currentScope();
343 scope.vars->insert(name);
344 }
345 return !defined;
346 }
347
348 std::string getUnusedName(std::string_view name) const {
349 int index = 0;
350 std::string newName;
351 do {
352 newName = s(name) + std::to_string(index);
353 index++;
354 } while (isSolidDefined(newName));
355 return newName;
356 }
357
358 const std::string nll(ast_node* node) const {
359 if (_config.reserveLineNumber) {
360 return s(" -- "sv) + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
361 } else {
362 return _newLine;
363 }
364 }
365
366 const std::string nlr(ast_node* node) const {
367 if (_config.reserveLineNumber) {
368 return s(" -- "sv) + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
369 } else {
370 return _newLine;
371 }
372 }
373
374 void incIndentOffset() {
375 _indentOffset++;
376 }
377
378 void decIndentOffset() {
379 _indentOffset--;
380 }
381
382 std::string indent() const {
383 if (_config.useSpaceOverTab) {
384 return std::string((_scopes.size() - 1 + _indentOffset) * 2, ' ');
385 } else {
386 return std::string(_scopes.size() - 1 + _indentOffset, '\t');
387 }
388 }
389
390 std::string indent(int offset) const {
391 if (_config.useSpaceOverTab) {
392 return std::string((_scopes.size() - 1 + _indentOffset + offset) * 2, ' ');
393 } else {
394 return std::string(_scopes.size() - 1 + _indentOffset + offset, '\t');
395 }
396 }
397
398 std::string clearBuf() {
399 std::string str = _buf.str();
400 _buf.str("");
401 _buf.clear();
402 return str;
403 }
404
405 std::string join(const str_list& items) {
406 if (items.empty()) return Empty;
407 else if (items.size() == 1) return items.front();
408 for (const auto& item : items) {
409 _joinBuf << item;
410 }
411 auto result = _joinBuf.str();
412 _joinBuf.str("");
413 _joinBuf.clear();
414 return result;
415 }
416
417 std::string join(const str_list& items, std::string_view sep) {
418 if (items.empty()) return Empty;
419 else if (items.size() == 1) return items.front();
420 std::string sepStr = s(sep);
421 auto begin = ++items.begin();
422 _joinBuf << items.front();
423 for (auto it = begin; it != items.end(); ++it) {
424 _joinBuf << sepStr << *it;
425 }
426 auto result = _joinBuf.str();
427 _joinBuf.str("");
428 _joinBuf.clear();
429 return result;
430 }
431
432 unary_exp_t* singleUnaryExpFrom(ast_node* item) const {
433 Exp_t* exp = nullptr;
434 switch (item->getId()) {
435 case id<Exp_t>():
436 exp = static_cast<Exp_t*>(item);
437 break;
438 case id<ExpList_t>(): {
439 auto expList = static_cast<ExpList_t*>(item);
440 if (expList->exprs.size() == 1) {
441 exp = static_cast<Exp_t*>(expList->exprs.front());
442 }
443 break;
444 }
445 case id<ExpListLow_t>(): {
446 auto expList = static_cast<ExpListLow_t*>(item);
447 if (expList->exprs.size() == 1) {
448 exp = static_cast<Exp_t*>(expList->exprs.front());
449 }
450 break;
451 }
452 case id<unary_exp_t>(): {
453 auto unary = static_cast<unary_exp_t*>(item);
454 if (unary->expos.size() == 1) {
455 return unary;
456 }
457 return nullptr;
458 }
459 default: break;
460 }
461 if (!exp) return nullptr;
462 BLOCK_START
463 BREAK_IF(!exp->opValues.empty());
464 BREAK_IF(exp->backcalls.size() != 1);
465 auto unary = static_cast<unary_exp_t*>(exp->backcalls.back());
466 BREAK_IF(unary->expos.size() != 1);
467 return unary;
468 BLOCK_END
469 return nullptr;
470 }
471
472 Value_t* singleValueFrom(ast_node* item) const {
473 if (auto unary = singleUnaryExpFrom(item)) {
474 if (unary->ops.empty()) {
475 return static_cast<Value_t*>(unary->expos.back());
476 }
477 }
478 return nullptr;
479 }
480
481 ast_ptr<false, Exp_t> newExp(Value_t* value, ast_node* x) {
482 auto unary = x->new_ptr<unary_exp_t>();
483 unary->expos.push_back(value);
484 auto exp = x->new_ptr<Exp_t>();
485 exp->backcalls.push_back(unary);
486 return exp;
487 }
488
489 ast_ptr<false, Exp_t> newExp(Value_t* left, BinaryOperator_t* op, Value_t* right, ast_node* x) {
490 auto lunary = x->new_ptr<unary_exp_t>();
491 lunary->expos.push_back(left);
492 auto opValue = x->new_ptr<exp_op_value_t>();
493 {
494 auto runary = x->new_ptr<unary_exp_t>();
495 runary->expos.push_back(right);
496 opValue->op.set(op);
497 opValue->backcalls.push_back(runary);
498 }
499 auto exp = x->new_ptr<Exp_t>();
500 exp->backcalls.push_back(lunary);
501 exp->opValues.push_back(opValue);
502 return exp;
503 }
504
505 ast_ptr<false, Exp_t> newExp(unary_exp_t* unary, ast_node* x) {
506 auto exp = x->new_ptr<Exp_t>();
507 exp->backcalls.push_back(unary);
508 return exp;
509 }
510
511 SimpleValue_t* simpleSingleValueFrom(ast_node* expList) const {
512 auto value = singleValueFrom(expList);
513 if (value && value->item.is<SimpleValue_t>()) {
514 return static_cast<SimpleValue_t*>(value->item.get());
515 }
516 return nullptr;
517 }
518
519 Statement_t* lastStatementFrom(ast_node* body) const {
520 switch (body->getId()) {
521 case id<Block_t>():
522 return lastStatementFrom(static_cast<Block_t*>(body));
523 case id<Statement_t>(): {
524 return static_cast<Statement_t*>(body);
525 }
526 default: assert(false); break;
527 }
528 return nullptr;
529 }
530
531 Statement_t* lastStatementFrom(const node_container& stmts) const {
532 if (!stmts.empty()) {
533 auto it = stmts.end(); --it;
534 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) {
535 --it;
536 }
537 return static_cast<Statement_t*>(*it);
538 }
539 return nullptr;
540 }
541
542 Statement_t* lastStatementFrom(Body_t* body) const {
543 if (auto stmt = body->content.as<Statement_t>()) {
544 return stmt;
545 } else {
546 const auto& stmts = body->content.to<Block_t>()->statements.objects();
547 return lastStatementFrom(stmts);
548 }
549 }
550
551 Statement_t* lastStatementFrom(Block_t* block) const {
552 const auto& stmts = block->statements.objects();
553 return lastStatementFrom(stmts);
554 }
555
556 Exp_t* lastExpFromAssign(ast_node* action) {
557 switch (action->getId()) {
558 case id<Update_t>(): {
559 auto update = static_cast<Update_t*>(action);
560 return update->value;
561 }
562 case id<Assign_t>(): {
563 auto assign = static_cast<Assign_t*>(action);
564 return ast_cast<Exp_t>(assign->values.back());
565 }
566 }
567 return nullptr;
568 }
569
570 Exp_t* lastExpFromStatement(Statement_t* stmt) {
571 if (!stmt->content) return nullptr;
572 switch (stmt->content->getId()) {
573 case id<ExpListAssign_t>(): {
574 auto expListAssign = static_cast<ExpListAssign_t*>(stmt->content.get());
575 if (auto action = expListAssign->action.get()) {
576 return lastExpFromAssign(action);
577 } else {
578 return static_cast<Exp_t*>(expListAssign->expList->exprs.back());
579 }
580 }
581 case id<Export_t>(): {
582 auto exportNode = static_cast<Export_t*>(stmt->content.get());
583 if (auto action = exportNode->assign.get()) {
584 return lastExpFromAssign(action);
585 } else {
586 switch (exportNode->target->getId()) {
587 case id<Exp_t>(): return exportNode->target.to<Exp_t>();
588 case id<ExpList_t>(): return static_cast<Exp_t*>(exportNode->target.to<ExpList_t>()->exprs.back());
589 }
590 }
591 }
592 case id<Local_t>(): {
593 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<local_values_t>()) {
594 if (auto expList = localValues->valueList.as<ExpListLow_t>()) {
595 return static_cast<Exp_t*>(expList->exprs.back());
596 }
597 }
598 }
599 case id<Global_t>(): {
600 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<global_values_t>()) {
601 if (auto expList = globalValues->valueList.as<ExpListLow_t>()) {
602 return static_cast<Exp_t*>(expList->exprs.back());
603 }
604 }
605 }
606 }
607 return nullptr;
608 }
609
610 template <class T>
611 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
612 auto res = _parser.parse<T>(s(codes));
613 int line = parent->m_begin.m_line;
614 int col = parent->m_begin.m_line;
615 res.node->traverse([&](ast_node* node) {
616 node->m_begin.m_line = line;
617 node->m_end.m_line = line;
618 node->m_begin.m_col = col;
619 node->m_end.m_col = col;
620 return traversal::Continue;
621 });
622 _codeCache.push_back(std::move(res.codes));
623 return ast_ptr<false, T>(res.node.template to<T>());
624 }
625
626 bool isChainValueCall(ChainValue_t* chainValue) const {
627 return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back());
628 }
629
630 enum class ChainType {
631 Common,
632 EndWithColon,
633 EndWithEOP,
634 HasEOP,
635 HasKeyword,
636 Macro
637 };
638
639 ChainType specialChainValue(ChainValue_t* chainValue) const {
640 if (isMacroChain(chainValue)) {
641 return ChainType::Macro;
642 }
643 if (ast_is<ColonChainItem_t>(chainValue->items.back())) {
644 return ChainType::EndWithColon;
645 }
646 if (ast_is<existential_op_t>(chainValue->items.back())) {
647 return ChainType::EndWithEOP;
648 }
649 ChainType type = ChainType::Common;
650 for (auto item : chainValue->items.objects()) {
651 if (auto colonChain = ast_cast<ColonChainItem_t>(item)) {
652 if (ast_is<LuaKeyword_t>(colonChain->name)) {
653 type = ChainType::HasKeyword;
654 }
655 } else if (ast_is<existential_op_t>(item)) {
656 return ChainType::HasEOP;
657 }
658 }
659 return type;
660 }
661
662 std::string singleVariableFrom(ChainValue_t* chainValue) {
663 BLOCK_START
664 BREAK_IF(!chainValue);
665 BREAK_IF(chainValue->items.size() != 1);
666 auto callable = ast_cast<Callable_t>(chainValue->items.front());
667 BREAK_IF(!callable);
668 ast_node* var = callable->item.as<Variable_t>();
669 if (!var) {
670 if (auto self = callable->item.as<SelfName_t>()) {
671 var = self->name.as<self_t>();
672 }
673 }
674 BREAK_IF(!var);
675 str_list tmp;
676 transformCallable(callable, tmp);
677 return tmp.back();
678 BLOCK_END
679 return Empty;
680 }
681
682 std::string singleVariableFrom(ast_node* expList) {
683 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
684 BLOCK_START
685 auto value = singleValueFrom(expList);
686 BREAK_IF(!value);
687 auto chainValue = value->item.as<ChainValue_t>();
688 BREAK_IF(!chainValue);
689 BREAK_IF(chainValue->items.size() != 1);
690 auto callable = ast_cast<Callable_t>(chainValue->items.front());
691 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>()));
692 str_list tmp;
693 transformCallable(callable, tmp);
694 return tmp.back();
695 BLOCK_END
696 return Empty;
697 }
698
699 Variable_t* variableFrom(Exp_t* exp) {
700 BLOCK_START
701 auto value = singleValueFrom(exp);
702 BREAK_IF(!value);
703 auto chainValue = value->item.as<ChainValue_t>();
704 BREAK_IF(!chainValue);
705 BREAK_IF(chainValue->items.size() != 1);
706 auto callable = ast_cast<Callable_t>(chainValue->items.front());
707 BREAK_IF(!callable);
708 return callable->item.as<Variable_t>();
709 BLOCK_END
710 return nullptr;
711 }
712
713 bool isAssignable(const node_container& chainItems) const {
714 if (chainItems.size() == 1) {
715 auto firstItem = chainItems.back();
716 if (auto callable = ast_cast<Callable_t>(firstItem)) {
717 switch (callable->item->getId()) {
718 case id<Variable_t>():
719 case id<SelfName_t>():
720 return true;
721 }
722 } else if (firstItem->getId() == id<DotChainItem_t>()) {
723 return true;
724 }
725 } else {
726 auto lastItem = chainItems.back();
727 switch (lastItem->getId()) {
728 case id<DotChainItem_t>():
729 case id<Exp_t>():
730 return true;
731 }
732 }
733 return false;
734 }
735
736 bool isAssignable(Exp_t* exp) const {
737 if (auto value = singleValueFrom(exp)) {
738 auto item = value->item.get();
739 switch (item->getId()) {
740 case id<simple_table_t>():
741 return true;
742 case id<SimpleValue_t>(): {
743 auto simpleValue = static_cast<SimpleValue_t*>(item);
744 if (simpleValue->value.is<TableLit_t>()) {
745 return true;
746 }
747 return false;
748 }
749 case id<ChainValue_t>(): {
750 auto chainValue = static_cast<ChainValue_t*>(item);
751 return isAssignable(chainValue->items.objects());
752 }
753 }
754 }
755 return false;
756 }
757
758 bool isAssignable(Assignable_t* assignable) const {
759 if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) {
760 return isAssignable(assignableChain->items.objects());
761 }
762 return true;
763 }
764
765 void checkAssignable(ExpList_t* expList) const {
766 for (auto exp_ : expList->exprs.objects()) {
767 Exp_t* exp = static_cast<Exp_t*>(exp_);
768 if (!isAssignable(exp)) {
769 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
770 }
771 }
772 }
773
774 bool isPureBackcall(Exp_t* exp) const {
775 return exp->opValues.empty() && exp->backcalls.size() > 1;
776 }
777
778 bool isMacroChain(ChainValue_t* chainValue) const {
779 const auto& chainList = chainValue->items.objects();
780 BLOCK_START
781 auto callable = ast_cast<Callable_t>(chainList.front());
782 BREAK_IF(!callable);
783 BREAK_IF(!callable->item.is<MacroName_t>());
784 if (chainList.size() == 1 ||
785 !ast_is<Invoke_t,InvokeArgs_t>(*(++chainList.begin()))) {
786 throw std::logic_error(_info.errorMessage("macro expression must be followed by arguments list"sv, callable));
787 }
788 return true;
789 BLOCK_END
790 return false;
791 }
792
793 void transformStatement(Statement_t* statement, str_list& out) {
794 auto x = statement;
795 if (statement->appendix) {
796 if (auto assignment = assignmentFrom(statement)) {
797 auto preDefine = getPredefine(assignment);
798 if (!preDefine.empty()) out.push_back(preDefine + nll(statement));
799 } else if (auto local = statement->content.as<Local_t>()) {
800 if (!local->defined) {
801 local->defined = true;
802 transformLocalDef(local, out);
803 }
804 }
805 auto appendix = statement->appendix.get();
806 switch (appendix->item->getId()) {
807 case id<if_line_t>(): {
808 auto if_line = appendix->item.to<if_line_t>();
809 auto ifNode = x->new_ptr<If_t>();
810
811 auto ifCond = x->new_ptr<IfCond_t>();
812 ifCond->condition.set(if_line->condition);
813 ifCond->assign.set(if_line->assign);
814 ifNode->nodes.push_back(ifCond);
815
816 auto stmt = x->new_ptr<Statement_t>();
817 stmt->content.set(statement->content);
818 ifNode->nodes.push_back(stmt);
819
820 statement->appendix.set(nullptr);
821 auto simpleValue = x->new_ptr<SimpleValue_t>();
822 simpleValue->value.set(ifNode);
823 auto value = x->new_ptr<Value_t>();
824 value->item.set(simpleValue);
825 auto exp = newExp(value, x);
826 auto expList = x->new_ptr<ExpList_t>();
827 expList->exprs.push_back(exp);
828 auto expListAssign = x->new_ptr<ExpListAssign_t>();
829 expListAssign->expList.set(expList);
830 statement->content.set(expListAssign);
831 break;
832 }
833 case id<unless_line_t>(): {
834 auto unless_line = appendix->item.to<unless_line_t>();
835 auto unless = x->new_ptr<Unless_t>();
836
837 auto ifCond = x->new_ptr<IfCond_t>();
838 ifCond->condition.set(unless_line->condition);
839 unless->nodes.push_back(ifCond);
840
841 auto stmt = x->new_ptr<Statement_t>();
842 stmt->content.set(statement->content);
843 unless->nodes.push_back(stmt);
844
845 statement->appendix.set(nullptr);
846 auto simpleValue = x->new_ptr<SimpleValue_t>();
847 simpleValue->value.set(unless);
848 auto value = x->new_ptr<Value_t>();
849 value->item.set(simpleValue);
850 auto exp = newExp(value, x);
851 auto exprList = x->new_ptr<ExpList_t>();
852 exprList->exprs.push_back(exp);
853 auto expListAssign = x->new_ptr<ExpListAssign_t>();
854 expListAssign->expList.set(exprList);
855 statement->content.set(expListAssign);
856 break;
857 }
858 case id<CompInner_t>(): {
859 auto compInner = appendix->item.to<CompInner_t>();
860 auto comp = x->new_ptr<Comprehension_t>();
861 comp->forLoop.set(compInner);
862 auto stmt = x->new_ptr<Statement_t>();
863 stmt->content.set(statement->content);
864 comp->value.set(stmt);
865 auto simpleValue = x->new_ptr<SimpleValue_t>();
866 simpleValue->value.set(comp);
867 auto value = x->new_ptr<Value_t>();
868 value->item.set(simpleValue);
869 auto exp = newExp(value, x);
870 auto expList = x->new_ptr<ExpList_t>();
871 expList->exprs.push_back(exp);
872 auto expListAssign = x->new_ptr<ExpListAssign_t>();
873 expListAssign->expList.set(expList);
874 statement->content.set(expListAssign);
875 statement->appendix.set(nullptr);
876 break;
877 }
878 default: assert(false); break;
879 }
880 }
881 auto content = statement->content.get();
882 if (!content) {
883 out.push_back(Empty);
884 return;
885 }
886 switch (content->getId()) {
887 case id<Import_t>(): transformImport(static_cast<Import_t*>(content), out); break;
888 case id<While_t>(): transformWhile(static_cast<While_t*>(content), out); break;
889 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(content), out); break;
890 case id<For_t>(): transformFor(static_cast<For_t*>(content), out); break;
891 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(content), out); break;
892 case id<Return_t>(): transformReturn(static_cast<Return_t*>(content), out); break;
893 case id<Local_t>(): transformLocal(static_cast<Local_t*>(content), out); break;
894 case id<Global_t>(): transformGlobal(static_cast<Global_t*>(content), out); break;
895 case id<Export_t>(): transformExport(static_cast<Export_t*>(content), out); break;
896 case id<Macro_t>(): transformMacro(static_cast<Macro_t*>(content), out, false); break;
897 case id<BreakLoop_t>(): transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break;
898 case id<Label_t>(): transformLabel(static_cast<Label_t*>(content), out); break;
899 case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break;
900 case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break;
901 case id<BackcallBody_t>(): throw std::logic_error(_info.errorMessage("backcall chain must be following a value"sv, x)); break;
902 case id<ExpListAssign_t>(): {
903 auto expListAssign = static_cast<ExpListAssign_t*>(content);
904 if (expListAssign->action) {
905 transformAssignment(expListAssign, out);
906 } else {
907 auto expList = expListAssign->expList.get();
908 if (expList->exprs.objects().empty()) {
909 out.push_back(Empty);
910 break;
911 }
912 if (auto singleValue = singleValueFrom(expList)) {
913 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
914 auto value = simpleValue->value.get();
915 bool specialSingleValue = true;
916 switch (value->getId()) {
917 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Common); break;
918 case id<ClassDecl_t>(): transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Common); break;
919 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Common); break;
920 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Common); break;
921 case id<With_t>(): transformWith(static_cast<With_t*>(value), out); break;
922 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
923 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
924 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
925 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
926 case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break;
927 default: specialSingleValue = false; break;
928 }
929 if (specialSingleValue) {
930 break;
931 }
932 }
933 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
934 if (isChainValueCall(chainValue)) {
935 transformChainValue(chainValue, out, ExpUsage::Common);
936 break;
937 }
938 }
939 } else if (expList->exprs.size() == 1){
940 auto exp = static_cast<Exp_t*>(expList->exprs.back());
941 if (isPureBackcall(exp)) {
942 transformExp(exp, out, ExpUsage::Common);
943 break;
944 }
945 }
946 throw std::logic_error(_info.errorMessage("expression list is not supported here"sv, expList));
947 }
948 break;
949 }
950 default: assert(false); break;
951 }
952 if (statement->needSep && !out.back().empty()) {
953 auto index = std::string::npos;
954 if (_config.reserveLineNumber) {
955 index = out.back().rfind(" -- "sv);
956 } else {
957 index = out.back().find_last_not_of('\n');
958 if (index != std::string::npos) index++;
959 }
960 if (index != std::string::npos) {
961 auto ending = out.back().substr(0, index);
962 auto ind = ending.find_last_of(" \t\n"sv);
963 if (ind != std::string::npos) {
964 ending = ending.substr(ind + 1);
965 }
966 if (Keywords.find(ending) == Keywords.end()) {
967 out.back().insert(index, ";"sv);
968 }
969 }
970 }
971 }
972
973 str_list getAssignVars(ExpListAssign_t* assignment) {
974 str_list vars;
975 if (!assignment->action.is<Assign_t>()) return vars;
976 for (auto exp : assignment->expList->exprs.objects()) {
977 auto var = singleVariableFrom(exp);
978 vars.push_back(var.empty() ? Empty : var);
979 }
980 return vars;
981 }
982
983 str_list getAssignVars(With_t* with) {
984 str_list vars;
985 for (auto exp : with->valueList->exprs.objects()) {
986 auto var = singleVariableFrom(exp);
987 vars.push_back(var.empty() ? Empty : var);
988 }
989 return vars;
990 }
991
992 str_list getAssignDefs(ExpList_t* expList) {
993 str_list preDefs;
994 for (auto exp_ : expList->exprs.objects()) {
995 auto exp = static_cast<Exp_t*>(exp_);
996 if (auto value = singleValueFrom(exp)) {
997 if (auto chain = value->item.as<ChainValue_t>()) {
998 BLOCK_START
999 BREAK_IF(chain->items.size() != 1);
1000 auto callable = ast_cast<Callable_t>(chain->items.front());
1001 BREAK_IF(!callable);
1002 std::string name;
1003 if (auto var = callable->item.as<Variable_t>()) {
1004 name = _parser.toString(var);
1005 } else if (auto self = callable->item.as<SelfName_t>()) {
1006 if (self->name.is<self_t>()) name = "self"sv;
1007 }
1008 BREAK_IF(name.empty());
1009 if (!isDefined(name)) {
1010 preDefs.push_back(name);
1011 }
1012 BLOCK_END
1013 }
1014 } else {
1015 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
1016 }
1017 }
1018 return preDefs;
1019 }
1020
1021 str_list transformAssignDefs(ExpList_t* expList, bool markDefined = true) {
1022 str_list defs;
1023 for (auto exp_ : expList->exprs.objects()) {
1024 auto exp = static_cast<Exp_t*>(exp_);
1025 if (auto value = singleValueFrom(exp)) {
1026 if (auto chain = value->item.as<ChainValue_t>()) {
1027 BLOCK_START
1028 BREAK_IF(chain->items.size() != 1);
1029 auto callable = ast_cast<Callable_t>(chain->items.front());
1030 BREAK_IF(!callable);
1031 std::string name;
1032 if (auto var = callable->item.as<Variable_t>()) {
1033 name = _parser.toString(var);
1034 } else if (auto self = callable->item.as<SelfName_t>()) {
1035 if (self->name.is<self_t>()) name = "self"sv;
1036 }
1037 BREAK_IF(name.empty());
1038 if (!markDefined || addToScope(name)) {
1039 defs.push_back(name);
1040 }
1041 BLOCK_END
1042 }
1043 } else {
1044 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, exp));
1045 }
1046 }
1047 return defs;
1048 }
1049
1050 std::string getPredefine(const str_list& defs) {
1051 if (defs.empty()) return Empty;
1052 return indent() + s("local "sv) + join(defs, ", "sv);
1053 }
1054
1055 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1056 auto info = extractDestructureInfo(assignment, true);
1057 if (!info.first.empty()) {
1058 for (const auto& destruct : info.first) {
1059 str_list defs;
1060 for (const auto& item : destruct.items) {
1061 if (item.isVariable && addToScope(item.name)) {
1062 defs.push_back(item.name);
1063 }
1064 }
1065 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
1066 }
1067 }
1068 return clearBuf();
1069 }
1070
1071 std::string getPredefine(ExpListAssign_t* assignment) {
1072 auto preDefine = getDestrucureDefine(assignment);
1073 if (preDefine.empty()) {
1074 preDefine = getPredefine(transformAssignDefs(assignment->expList));
1075 }
1076 return preDefine;
1077 }
1078
1079 ExpList_t* expListFrom(Statement_t* statement) {
1080 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
1081 if (!expListAssign->action) {
1082 return expListAssign->expList.get();
1083 }
1084 }
1085 return nullptr;
1086 }
1087
1088 ExpListAssign_t* assignmentFrom(Statement_t* statement) {
1089 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
1090 if (expListAssign->action) {
1091 return expListAssign;
1092 }
1093 }
1094 return nullptr;
1095 }
1096
1097 void transformAssignment(ExpListAssign_t* assignment, str_list& out) {
1098 checkAssignable(assignment->expList);
1099 BLOCK_START
1100 auto assign = ast_cast<Assign_t>(assignment->action);
1101 BREAK_IF(!assign);
1102 BREAK_IF(assign->values.objects().size() != 1);
1103 auto value = assign->values.objects().back();
1104 if (ast_is<Exp_t>(value)) {
1105 if (auto val = simpleSingleValueFrom(value)) {
1106 value = val->value.get();
1107 }
1108 }
1109 switch (value->getId()) {
1110 case id<If_t>():
1111 case id<Unless_t>(): {
1112 auto expList = assignment->expList.get();
1113 str_list temp;
1114 auto defs = transformAssignDefs(expList);
1115 if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList));
1116 switch (value->getId()) {
1117 case id<If_t>(): transformIf(static_cast<If_t*>(value), temp, ExpUsage::Assignment, expList); break;
1118 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), temp, ExpUsage::Assignment, expList); break;
1119 }
1120 out.push_back(join(temp));
1121 return;
1122 }
1123 case id<Switch_t>(): {
1124 auto switchNode = static_cast<Switch_t*>(value);
1125 auto assignList = assignment->expList.get();
1126 std::string preDefine = getPredefine(assignment);
1127 transformSwitch(switchNode, out, ExpUsage::Assignment, assignList);
1128 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1129 return;
1130 }
1131 case id<With_t>(): {
1132 auto withNode = static_cast<With_t*>(value);
1133 auto expList = assignment->expList.get();
1134 std::string preDefine = getPredefine(assignment);
1135 transformWith(withNode, out, expList);
1136 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1137 return;
1138 }
1139 case id<Do_t>(): {
1140 auto expList = assignment->expList.get();
1141 auto doNode = static_cast<Do_t*>(value);
1142 std::string preDefine = getPredefine(assignment);
1143 transformDo(doNode, out, ExpUsage::Assignment, expList);
1144 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1145 return;
1146 }
1147 case id<Comprehension_t>(): {
1148 auto expList = assignment->expList.get();
1149 std::string preDefine = getPredefine(assignment);
1150 transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Assignment, expList);
1151 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1152 return;
1153 }
1154 case id<TblComprehension_t>(): {
1155 auto expList = assignment->expList.get();
1156 std::string preDefine = getPredefine(assignment);
1157 transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Assignment, expList);
1158 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1159 return;
1160 }
1161 case id<For_t>(): {
1162 auto expList = assignment->expList.get();
1163 std::string preDefine = getPredefine(assignment);
1164 transformForInPlace(static_cast<For_t*>(value), out, expList);
1165 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1166 return;
1167 }
1168 case id<ForEach_t>(): {
1169 auto expList = assignment->expList.get();
1170 std::string preDefine = getPredefine(assignment);
1171 transformForEachInPlace(static_cast<ForEach_t*>(value), out, expList);
1172 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1173 return;
1174 }
1175 case id<ClassDecl_t>(): {
1176 auto expList = assignment->expList.get();
1177 std::string preDefine = getPredefine(assignment);
1178 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Assignment, expList);
1179 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1180 return;
1181 }
1182 case id<While_t>(): {
1183 auto expList = assignment->expList.get();
1184 std::string preDefine = getPredefine(assignment);
1185 transformWhileInPlace(static_cast<While_t*>(value), out, expList);
1186 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1187 return;
1188 }
1189 }
1190 auto exp = ast_cast<Exp_t>(value);
1191 BREAK_IF(!exp);
1192 if (isPureBackcall(exp)) {
1193 auto expList = assignment->expList.get();
1194 transformExp(exp, out, ExpUsage::Assignment, expList);
1195 return;
1196 }
1197 auto singleVal = singleValueFrom(exp);
1198 BREAK_IF(!singleVal);
1199 if (auto chainValue = singleVal->item.as<ChainValue_t>()) {
1200 auto type = specialChainValue(chainValue);
1201 auto expList = assignment->expList.get();
1202 switch (type) {
1203 case ChainType::HasEOP:
1204 case ChainType::EndWithColon: {
1205 std::string preDefine = getPredefine(assignment);
1206 transformChainValue(chainValue, out, ExpUsage::Assignment, expList);
1207 out.back().insert(0, preDefine.empty() ? Empty : preDefine + nll(assignment));
1208 return;
1209 }
1210 case ChainType::HasKeyword:
1211 case ChainType::Macro:
1212 transformChainValue(chainValue, out, ExpUsage::Assignment, expList);
1213 return;
1214 case ChainType::Common:
1215 case ChainType::EndWithEOP:
1216 break;
1217 }
1218 }
1219 BLOCK_END
1220 auto info = extractDestructureInfo(assignment);
1221 if (info.first.empty()) {
1222 transformAssignmentCommon(assignment, out);
1223 } else {
1224 str_list temp;
1225 for (const auto& destruct : info.first) {
1226 if (destruct.items.size() == 1) {
1227 auto& pair = destruct.items.front();
1228 _buf << indent();
1229 if (pair.isVariable && !isDefined(pair.name)) {
1230 _buf << s("local "sv);
1231 }
1232 _buf << pair.name << " = "sv << info.first.front().value << pair.structure << nll(assignment);
1233 addToScope(pair.name);
1234 temp.push_back(clearBuf());
1235 } else if (_parser.match<Name_t>(destruct.value)) {
1236 str_list defs, names, values;
1237 for (const auto& item : destruct.items) {
1238 if (item.isVariable && addToScope(item.name)) {
1239 defs.push_back(item.name);
1240 }
1241 names.push_back(item.name);
1242 values.push_back(item.structure);
1243 }
1244 for (auto& v : values) v.insert(0, destruct.value);
1245 if (defs.empty()) {
1246 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1247 } else {
1248 _buf << indent() << "local "sv;
1249 if (defs.size() != names.size()) {
1250 _buf << join(defs,", "sv) << nll(assignment) << indent();
1251 }
1252 _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1253 }
1254 temp.push_back(clearBuf());
1255 } else {
1256 str_list defs, names, values;
1257 for (const auto& item : destruct.items) {
1258 if (item.isVariable && addToScope(item.name)) {
1259 defs.push_back(item.name);
1260 }
1261 names.push_back(item.name);
1262 values.push_back(item.structure);
1263 }
1264 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment);
1265 _buf << indent() << "do"sv << nll(assignment);
1266 pushScope();
1267 auto objVar = getUnusedName("_obj_"sv);
1268 for (auto& v : values) v.insert(0, objVar);
1269 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1270 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1271 popScope();
1272 _buf << indent() << "end"sv << nll(assignment);
1273 temp.push_back(clearBuf());
1274 }
1275 }
1276 if (info.second) {
1277 transformAssignmentCommon(info.second, temp);
1278 }
1279 out.push_back(join(temp));
1280 }
1281 }
1282
1283 void transformAssignItem(ast_node* value, str_list& out) {
1284 switch (value->getId()) {
1285 case id<With_t>(): transformWithClosure(static_cast<With_t*>(value), out); break;
1286 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1287 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
1288 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
1289 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
1290 default: assert(false); break;
1291 }
1292 }
1293
1294 std::list<DestructItem> destructFromExp(ast_node* node) {
1295 const node_container* tableItems = nullptr;
1296 if (ast_is<Exp_t>(node)) {
1297 auto item = singleValueFrom(node)->item.get();
1298 if (!item) throw std::logic_error(_info.errorMessage("invalid destructure value"sv, node));
1299 auto tbA = item->getByPath<TableLit_t>();
1300 if (tbA) {
1301 tableItems = &tbA->values.objects();
1302 } else {
1303 auto tbB = ast_cast<simple_table_t>(item);
1304 if (tbB) tableItems = &tbB->pairs.objects();
1305 }
1306 } else if (auto table = ast_cast<TableBlock_t>(node)) {
1307 tableItems = &table->values.objects();
1308 }
1309 std::list<DestructItem> pairs;
1310 int index = 0;
1311 for (auto pair : *tableItems) {
1312 switch (pair->getId()) {
1313 case id<Exp_t>(): {
1314 ++index;
1315 if (!isAssignable(static_cast<Exp_t*>(pair))) {
1316 throw std::logic_error(_info.errorMessage("can't destructure value"sv, pair));
1317 }
1318 auto value = singleValueFrom(pair);
1319 auto item = value->item.get();
1320 if (ast_is<simple_table_t>(item) ||
1321 item->getByPath<TableLit_t>()) {
1322 auto subPairs = destructFromExp(pair);
1323 for (auto& p : subPairs) {
1324 pairs.push_back({p.isVariable, p.name,
1325 s("["sv) + std::to_string(index) + s("]"sv) + p.structure});
1326 }
1327 } else {
1328 bool lintGlobal = _config.lintGlobalVariable;
1329 _config.lintGlobalVariable = false;
1330 auto exp = static_cast<Exp_t*>(pair);
1331 auto varName = singleVariableFrom(exp);
1332 bool isVariable = !varName.empty();
1333 if (!isVariable) {
1334 str_list temp;
1335 transformExp(exp, temp, ExpUsage::Closure);
1336 varName = std::move(temp.back());
1337 }
1338 _config.lintGlobalVariable = lintGlobal;
1339 pairs.push_back({
1340 isVariable,
1341 varName,
1342 s("["sv) + std::to_string(index) + s("]"sv)
1343 });
1344 }
1345 break;
1346 }
1347 case id<variable_pair_t>(): {
1348 auto vp = static_cast<variable_pair_t*>(pair);
1349 auto name = _parser.toString(vp->name);
1350 if (Keywords.find(name) != Keywords.end()) {
1351 pairs.push_back({true, name, s("[\""sv) + name + s("\"]"sv)});
1352 } else {
1353 pairs.push_back({true, name, s("."sv) + name});
1354 }
1355 break;
1356 }
1357 case id<normal_pair_t>(): {
1358 auto np = static_cast<normal_pair_t*>(pair);
1359 auto key = np->key->getByPath<Name_t>();
1360 if (!key) throw std::logic_error(_info.errorMessage("invalid key for destructure"sv, np));
1361 if (auto exp = np->value.as<Exp_t>()) {
1362 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp));
1363 auto item = singleValueFrom(exp)->item.get();
1364 if (ast_is<simple_table_t>(item) ||
1365 item->getByPath<TableLit_t>()) {
1366 auto subPairs = destructFromExp(exp);
1367 auto name = _parser.toString(key);
1368 for (auto& p : subPairs) {
1369 if (Keywords.find(name) != Keywords.end()) {
1370 pairs.push_back({p.isVariable, p.name,
1371 s("[\""sv) + name + s("\"]"sv) + p.structure});
1372 } else {
1373 pairs.push_back({p.isVariable, p.name,
1374 s("."sv) + name + p.structure});
1375 }
1376 }
1377 } else {
1378 bool lintGlobal = _config.lintGlobalVariable;
1379 _config.lintGlobalVariable = false;
1380 auto varName = singleVariableFrom(exp);
1381 bool isVariable = !varName.empty();
1382 if (!isVariable) {
1383 str_list temp;
1384 transformExp(exp, temp, ExpUsage::Closure);
1385 varName = std::move(temp.back());
1386 }
1387 _config.lintGlobalVariable = lintGlobal;
1388 auto name = _parser.toString(key);
1389 if (Keywords.find(name) != Keywords.end()) {
1390 pairs.push_back({
1391 isVariable,
1392 varName,
1393 s("[\""sv) + name + s("\"]"sv)
1394 });
1395 } else {
1396 pairs.push_back({
1397 isVariable,
1398 varName,
1399 s("."sv) + name
1400 });
1401 }
1402 }
1403 break;
1404 }
1405 if (np->value.is<TableBlock_t>()) {
1406 auto subPairs = destructFromExp(pair);
1407 for (auto& p : subPairs) {
1408 pairs.push_back({p.isVariable, p.name,
1409 s("."sv) + _parser.toString(key) + p.structure});
1410 }
1411 }
1412 break;
1413 }
1414 default: assert(false); break;
1415 }
1416 }
1417 return pairs;
1418 }
1419
1420 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1421 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) {
1422 auto x = assignment;
1423 std::list<Destructure> destructs;
1424 if (!assignment->action.is<Assign_t>()) return { destructs, nullptr };
1425 auto exprs = assignment->expList->exprs.objects();
1426 auto values = assignment->action.to<Assign_t>()->values.objects();
1427 size_t size = std::max(exprs.size(),values.size());
1428 ast_ptr<false, Exp_t> var;
1429 if (exprs.size() < size) {
1430 var = toAst<Exp_t>("_"sv, x);
1431 while (exprs.size() < size) exprs.emplace_back(var);
1432 }
1433 ast_ptr<false, Exp_t> nullNode;
1434 if (values.size() < size) {
1435 nullNode = toAst<Exp_t>("nil"sv, x);
1436 while (values.size() < size) values.emplace_back(nullNode);
1437 }
1438 using iter = node_container::iterator;
1439 std::vector<std::pair<iter,iter>> destructPairs;
1440 str_list temp;
1441 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
1442 auto expr = *i;
1443 auto value = singleValueFrom(expr);
1444 ast_node* destructNode = value->getByPath<SimpleValue_t, TableLit_t>();
1445 if (destructNode || (destructNode = value->item.as<simple_table_t>())) {
1446 destructPairs.push_back({i,j});
1447 auto& destruct = destructs.emplace_back();
1448 if (!varDefOnly) {
1449 pushScope();
1450 transformAssignItem(*j, temp);
1451 destruct.value = temp.back();
1452 temp.pop_back();
1453 popScope();
1454 }
1455 auto pairs = destructFromExp(expr);
1456 destruct.items = std::move(pairs);
1457 if (destruct.items.size() == 1 && !singleValueFrom(*j)) {
1458 destruct.value.insert(0, "("sv);
1459 destruct.value.append(")"sv);
1460 }
1461 }
1462 }
1463 for (const auto& p : destructPairs) {
1464 exprs.erase(p.first);
1465 values.erase(p.second);
1466 }
1467 ast_ptr<false, ExpListAssign_t> newAssignment;
1468 if (!destructPairs.empty() && !exprs.empty()) {
1469 auto x = assignment;
1470 auto expList = x->new_ptr<ExpList_t>();
1471 auto newAssign = x->new_ptr<ExpListAssign_t>();
1472 newAssign->expList.set(expList);
1473 for (auto expr : exprs) expList->exprs.push_back(expr);
1474 auto assign = x->new_ptr<Assign_t>();
1475 for (auto value : values) assign->values.push_back(value);
1476 newAssign->action.set(assign);
1477 newAssignment = newAssign;
1478 }
1479 return {std::move(destructs), newAssignment};
1480 }
1481
1482 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) {
1483 auto x = assignment;
1484 str_list temp;
1485 auto expList = assignment->expList.get();
1486 auto action = assignment->action.get();
1487 switch (action->getId()) {
1488 case id<Update_t>(): {
1489 if (expList->exprs.size() > 1) throw std::logic_error(_info.errorMessage("can not apply update to multiple values"sv, expList));
1490 auto update = static_cast<Update_t*>(action);
1491 auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front());
1492 auto leftValue = singleValueFrom(leftExp);
1493 if (!leftValue) throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, leftExp));
1494 if (auto chain = leftValue->item.as<ChainValue_t>()) {
1495 auto tmpChain = x->new_ptr<ChainValue_t>();
1496 for (auto item : chain->items.objects()) {
1497 bool itemAdded = false;
1498 BLOCK_START
1499 auto exp = ast_cast<Exp_t>(item);
1500 BREAK_IF(!exp);
1501 auto var = singleVariableFrom(exp);
1502 BREAK_IF(!var.empty());
1503 auto upVar = getUnusedName("_update_"sv);
1504 auto assignment = x->new_ptr<ExpListAssign_t>();
1505 assignment->expList.set(toAst<ExpList_t>(upVar, x));
1506 auto assign = x->new_ptr<Assign_t>();
1507 assign->values.push_back(exp);
1508 assignment->action.set(assign);
1509 transformAssignment(assignment, temp);
1510 tmpChain->items.push_back(toAst<Exp_t>(upVar, x));
1511 itemAdded = true;
1512 BLOCK_END
1513 if (!itemAdded) tmpChain->items.push_back(item);
1514 }
1515 chain->items.clear();
1516 chain->items.dup(tmpChain->items);
1517 }
1518 transformValue(leftValue, temp);
1519 auto left = std::move(temp.back());
1520 temp.pop_back();
1521 transformExp(update->value, temp, ExpUsage::Closure);
1522 auto right = std::move(temp.back());
1523 temp.pop_back();
1524 if (!singleValueFrom(update->value)) {
1525 right = s("("sv) + right + s(")"sv);
1526 }
1527 _buf << join(temp) << indent() << left << " = "sv << left <<
1528 " "sv << _parser.toString(update->op) << " "sv << right << nll(assignment);
1529 out.push_back(clearBuf());
1530 break;
1531 }
1532 case id<Assign_t>(): {
1533 bool oneLined = true;
1534 auto assign = static_cast<Assign_t*>(action);
1535 for (auto val : assign->values.objects()) {
1536 if (auto value = singleValueFrom(val)) {
1537 if (auto spValue = value->item.as<SimpleValue_t>()) {
1538 if (spValue->value.is<FunLit_t>()) {
1539 oneLined = false;
1540 break;
1541 }
1542 }
1543 }
1544 }
1545 auto defs = getAssignDefs(expList);
1546 if (oneLined && defs.size() == expList->exprs.objects().size()) {
1547 for (auto value : assign->values.objects()) {
1548 transformAssignItem(value, temp);
1549 }
1550 std::string preDefine = getPredefine(defs);
1551 for (const auto& def : defs) {
1552 addToScope(def);
1553 }
1554 if (preDefine.empty()) {
1555 transformExpList(expList, temp);
1556 std::string left = std::move(temp.back());
1557 temp.pop_back();
1558 out.push_back(indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1559 } else {
1560 out.push_back(preDefine + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1561 }
1562 } else {
1563 std::string preDefine = getPredefine(defs);
1564 for (const auto& def : defs) {
1565 addToScope(def);
1566 }
1567 transformExpList(expList, temp);
1568 std::string left = temp.back();
1569 temp.pop_back();
1570 for (auto value : assign->values.objects()) {
1571 transformAssignItem(value, temp);
1572 }
1573 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1574 }
1575 break;
1576 }
1577 default: assert(false); break;
1578 }
1579 }
1580
1581 void transformCond(const node_container& nodes, str_list& out, ExpUsage usage, bool unless, ExpList_t* assignList) {
1582 std::vector<ast_ptr<false, ast_node>> ns(false);
1583 for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
1584 ns.push_back(*it);
1585 if (auto cond = ast_cast<IfCond_t>(*it)) {
1586 if (*it != nodes.front() && cond->assign) {
1587 auto x = *it;
1588 auto newIf = x->new_ptr<If_t>();
1589 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1590 newIf->nodes.push_back(*j);
1591 }
1592 ns.clear();
1593 auto simpleValue = x->new_ptr<SimpleValue_t>();
1594 simpleValue->value.set(newIf);
1595 auto value = x->new_ptr<Value_t>();
1596 value->item.set(simpleValue);
1597 auto exp = newExp(value, x);
1598 auto expList = x->new_ptr<ExpList_t>();
1599 expList->exprs.push_back(exp);
1600 auto expListAssign = x->new_ptr<ExpListAssign_t>();
1601 expListAssign->expList.set(expList);
1602 auto stmt = x->new_ptr<Statement_t>();
1603 stmt->content.set(expListAssign);
1604 ns.push_back(stmt.get());
1605 }
1606 }
1607 }
1608 if (nodes.size() != ns.size()) {
1609 auto x = ns.back();
1610 auto newIf = x->new_ptr<If_t>();
1611 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1612 newIf->nodes.push_back(*j);
1613 }
1614 transformCond(newIf->nodes.objects(), out, usage, unless, assignList);
1615 return;
1616 }
1617 str_list temp;
1618 if (usage == ExpUsage::Closure) {
1619 temp.push_back(s("(function()"sv) + nll(nodes.front()));
1620 pushScope();
1621 _enableReturn.push(true);
1622 }
1623 std::list<std::pair<IfCond_t*, ast_node*>> ifCondPairs;
1624 ifCondPairs.emplace_back();
1625 for (auto node : nodes) {
1626 switch (node->getId()) {
1627 case id<IfCond_t>():
1628 ifCondPairs.back().first = static_cast<IfCond_t*>(node);
1629 break;
1630 case id<Block_t>():
1631 case id<Statement_t>():
1632 ifCondPairs.back().second = node;
1633 ifCondPairs.emplace_back();
1634 break;
1635 default: assert(false); break;
1636 }
1637 }
1638 auto assign = ifCondPairs.front().first->assign.get();
1639 bool storingValue = false;
1640 ast_ptr<false, ExpListAssign_t> extraAssignment;
1641 if (assign) {
1642 auto exp = ifCondPairs.front().first->condition.get();
1643 auto x = exp;
1644 bool lintGlobal = _config.lintGlobalVariable;
1645 _config.lintGlobalVariable = false;
1646 auto var = singleVariableFrom(exp);
1647 _config.lintGlobalVariable = lintGlobal;
1648 if (var.empty()) {
1649 storingValue = true;
1650 auto desVar = getUnusedName("_des_"sv);
1651 if (assign->values.objects().size() == 1) {
1652 auto var = singleVariableFrom(assign->values.objects().front());
1653 if (!var.empty()) {
1654 desVar = var;
1655 storingValue = false;
1656 }
1657 }
1658 if (storingValue) {
1659 if (usage != ExpUsage::Closure) {
1660 temp.push_back(indent() + s("do"sv) + nll(assign));
1661 pushScope();
1662 }
1663 auto expList = toAst<ExpList_t>(desVar, x);
1664 auto assignment = x->new_ptr<ExpListAssign_t>();
1665 assignment->expList.set(expList);
1666 assignment->action.set(assign);
1667 transformAssignment(assignment, temp);
1668 }
1669 {
1670 auto expList = x->new_ptr<ExpList_t>();
1671 expList->exprs.push_back(exp);
1672 auto assignOne = x->new_ptr<Assign_t>();
1673 auto valExp = toAst<Exp_t>(desVar, x);
1674 assignOne->values.push_back(valExp);
1675 auto assignment = x->new_ptr<ExpListAssign_t>();
1676 assignment->expList.set(expList);
1677 assignment->action.set(assignOne);
1678 extraAssignment.set(assignment);
1679 ifCondPairs.front().first->condition.set(valExp);
1680 }
1681 } else {
1682 if (!isDefined(var)) {
1683 storingValue = true;
1684 if (usage != ExpUsage::Closure) {
1685 temp.push_back(indent() + s("do"sv) + nll(assign));
1686 pushScope();
1687 }
1688 }
1689 auto expList = x->new_ptr<ExpList_t>();
1690 expList->exprs.push_back(exp);
1691 auto assignment = x->new_ptr<ExpListAssign_t>();
1692 assignment->expList.set(expList);
1693 assignment->action.set(assign);
1694 transformAssignment(assignment, temp);
1695 }
1696 }
1697 for (const auto& pair : ifCondPairs) {
1698 if (pair.first) {
1699 str_list tmp;
1700 auto condition = pair.first->condition.get();
1701 if (unless) {
1702 if (auto value = singleValueFrom(condition)) {
1703 transformValue(value, tmp);
1704 } else {
1705 transformExp(condition, tmp, ExpUsage::Closure);
1706 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
1707 }
1708 tmp.back().insert(0, s("not "sv));
1709 unless = false;
1710 } else {
1711 transformExp(condition, tmp, ExpUsage::Closure);
1712 }
1713 _buf << indent();
1714 if (pair != ifCondPairs.front()) {
1715 _buf << "else"sv;
1716 }
1717 _buf << "if "sv << tmp.back() << " then"sv << nll(condition);
1718 temp.push_back(clearBuf());
1719 }
1720 if (pair.second) {
1721 if (!pair.first) {
1722 temp.push_back(indent() + s("else"sv) + nll(pair.second));
1723 }
1724 pushScope();
1725 if (pair == ifCondPairs.front() && extraAssignment) {
1726 transformAssignment(extraAssignment, temp);
1727 }
1728 transform_plain_body(pair.second, temp, usage, assignList);
1729 popScope();
1730 }
1731 if (!pair.first) {
1732 temp.push_back(indent() + s("end"sv) + nll(nodes.front()));
1733 break;
1734 }
1735 }
1736 if (storingValue && usage != ExpUsage::Closure) {
1737 popScope();
1738 temp.push_back(indent() + s("end"sv) + nlr(nodes.front()));
1739 }
1740 if (usage == ExpUsage::Closure) {
1741 _enableReturn.pop();
1742 popScope();
1743 temp.push_back(indent() + s("end)()"sv));
1744 }
1745 out.push_back(join(temp));
1746 }
1747
1748 void transformIf(If_t* ifNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1749 transformCond(ifNode->nodes.objects(), out, usage, false, assignList);
1750 }
1751
1752 void transformUnless(Unless_t* unless, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1753 transformCond(unless->nodes.objects(), out, usage, true, assignList);
1754 }
1755
1756 void transformExpList(ExpList_t* expList, str_list& out) {
1757 str_list temp;
1758 for (auto exp : expList->exprs.objects()) {
1759 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
1760 }
1761 out.push_back(join(temp, ", "sv));
1762 }
1763
1764 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
1765 str_list temp;
1766 for (auto exp : expListLow->exprs.objects()) {
1767 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
1768 }
1769 out.push_back(join(temp, ", "sv));
1770 }
1771
1772 void transform_backcall_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1773 if (values.size() == 1 && usage == ExpUsage::Closure) {
1774 transform_unary_exp(static_cast<unary_exp_t*>(values.front()), out);
1775 } else {
1776 auto x = values.front();
1777 auto arg = newExp(static_cast<unary_exp_t*>(x), x);
1778 auto begin = values.begin(); begin++;
1779 for (auto it = begin; it != values.end(); ++it) {
1780 auto unary = static_cast<unary_exp_t*>(*it);
1781 auto value = static_cast<Value_t*>(singleUnaryExpFrom(unary) ? unary->expos.back() : nullptr);
1782 if (values.back() == *it && !unary->ops.empty() && usage == ExpUsage::Common) {
1783 throw std::logic_error(_info.errorMessage("expression list is not supported here"sv, x));
1784 }
1785 if (!value) throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, *it));
1786 if (auto chainValue = value->item.as<ChainValue_t>()) {
1787 if (isChainValueCall(chainValue)) {
1788 auto last = chainValue->items.back();
1789 _ast_list* args = nullptr;
1790 if (auto invoke = ast_cast<InvokeArgs_t>(last)) {
1791 args = &invoke->args;
1792 } else {
1793 args = &(ast_to<Invoke_t>(last)->args);
1794 }
1795 bool findPlaceHolder = false;
1796 for (auto a : args->objects()) {
1797 bool lintGlobal = _config.lintGlobalVariable;
1798 _config.lintGlobalVariable = false;
1799 auto name = singleVariableFrom(a);
1800 _config.lintGlobalVariable = lintGlobal;
1801 if (name == "_"sv) {
1802 if (!findPlaceHolder) {
1803 args->swap(a, arg);
1804 findPlaceHolder = true;
1805 } else {
1806 throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a));
1807 }
1808 }
1809 }
1810 if (!findPlaceHolder) {
1811 args->push_front(arg);
1812 }
1813 } else {
1814 auto invoke = x->new_ptr<Invoke_t>();
1815 invoke->args.push_front(arg);
1816 chainValue->items.push_back(invoke);
1817 }
1818 arg.set(newExp(unary, x));
1819 } else {
1820 throw std::logic_error(_info.errorMessage("backcall operator must be followed by chain value"sv, value));
1821 }
1822 }
1823 switch (usage) {
1824 case ExpUsage::Assignment: {
1825 auto assignment = x->new_ptr<ExpListAssign_t>();
1826 auto assign = x->new_ptr<Assign_t>();
1827 assign->values.push_back(arg);
1828 assignment->action.set(assign);
1829 assignment->expList.set(assignList);
1830 transformAssignment(assignment, out);
1831 return;
1832 }
1833 case ExpUsage::Common: {
1834 auto value = singleValueFrom(arg);
1835 if (value && value->item.is<ChainValue_t>()) {
1836 transformChainValue(value->item.to<ChainValue_t>(), out, ExpUsage::Common);
1837 } else {
1838 transformExp(arg, out, ExpUsage::Closure);
1839 out.back().insert(0, indent());
1840 out.back().append(nlr(x));
1841 }
1842 return;
1843 }
1844 case ExpUsage::Return: {
1845 auto ret = x->new_ptr<Return_t>();
1846 auto expListLow = x->new_ptr<ExpListLow_t>();
1847 expListLow->exprs.push_back(arg);
1848 ret->valueList.set(expListLow);
1849 transformReturn(ret, out);
1850 return;
1851 }
1852 case ExpUsage::Closure: {
1853 transformExp(arg, out, ExpUsage::Closure);
1854 return;
1855 }
1856 default: assert(false); return;
1857 }
1858 }
1859 }
1860
1861 void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
1862 if (exp->opValues.empty()) {
1863 transform_backcall_exp(exp->backcalls.objects(), out, usage, assignList);
1864 return;
1865 }
1866 assert(usage == ExpUsage::Closure);
1867 str_list temp;
1868 transform_backcall_exp(exp->backcalls.objects(), temp, ExpUsage::Closure);
1869 for (auto _opValue : exp->opValues.objects()) {
1870 auto opValue = static_cast<exp_op_value_t*>(_opValue);
1871 transformBinaryOperator(opValue->op, temp);
1872 transform_backcall_exp(opValue->backcalls.objects(), temp, ExpUsage::Closure);
1873 }
1874 out.push_back(join(temp, " "sv));
1875 }
1876
1877 void transformValue(Value_t* value, str_list& out) {
1878 auto item = value->item.get();
1879 switch (item->getId()) {
1880 case id<SimpleValue_t>(): transformSimpleValue(static_cast<SimpleValue_t*>(item), out); break;
1881 case id<simple_table_t>(): transform_simple_table(static_cast<simple_table_t*>(item), out); break;
1882 case id<ChainValue_t>(): transformChainValue(static_cast<ChainValue_t*>(item), out, ExpUsage::Closure); break;
1883 case id<String_t>(): transformString(static_cast<String_t*>(item), out); break;
1884 default: assert(false); break;
1885 }
1886 }
1887
1888 void transformCallable(Callable_t* callable, str_list& out, const ast_sel<false,Invoke_t,InvokeArgs_t>& invoke = {}) {
1889 auto item = callable->item.get();
1890 switch (item->getId()) {
1891 case id<Variable_t>(): {
1892 transformVariable(static_cast<Variable_t*>(item), out);
1893 if (_config.lintGlobalVariable && !isDefined(out.back())) {
1894 if (_globals.find(out.back()) == _globals.end()) {
1895 _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col};
1896 }
1897 }
1898 break;
1899 }
1900 case id<SelfName_t>(): {
1901 transformSelfName(static_cast<SelfName_t*>(item), out, invoke);
1902 if (_config.lintGlobalVariable) {
1903 std::string self("self"sv);
1904 if (!isDefined(self)) {
1905 if (_globals.find(self) == _globals.end()) {
1906 _globals[self] = {item->m_begin.m_line, item->m_begin.m_col};
1907 }
1908 }
1909 }
1910 break;
1911 }
1912 case id<VarArg_t>():
1913 if (_varArgs.empty() || !_varArgs.top()) {
1914 throw std::logic_error(_info.errorMessage("cannot use '...' outside a vararg function near '...'"sv, item));
1915 }
1916 out.push_back(s("..."sv));
1917 break;
1918 case id<Parens_t>(): transformParens(static_cast<Parens_t*>(item), out); break;
1919 default: assert(false); break;
1920 }
1921 }
1922
1923 void transformParens(Parens_t* parans, str_list& out) {
1924 str_list temp;
1925 transformExp(parans->expr, temp, ExpUsage::Closure);
1926 out.push_back(s("("sv) + temp.front() + s(")"sv));
1927 }
1928
1929 void transformSimpleValue(SimpleValue_t* simpleValue, str_list& out) {
1930 auto value = simpleValue->value.get();
1931 switch (value->getId()) {
1932 case id<const_value_t>(): transform_const_value(static_cast<const_value_t*>(value), out); break;
1933 case id<If_t>(): transformIf(static_cast<If_t*>(value), out, ExpUsage::Closure); break;
1934 case id<Unless_t>(): transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Closure); break;
1935 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
1936 case id<With_t>(): transformWithClosure(static_cast<With_t*>(value), out); break;
1937 case id<ClassDecl_t>(): transformClassDeclClosure(static_cast<ClassDecl_t*>(value), out); break;
1938 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
1939 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
1940 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
1941 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
1942 case id<unary_value_t>(): transform_unary_value(static_cast<unary_value_t*>(value), out); break;
1943 case id<TblComprehension_t>(): transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Closure); break;
1944 case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(value), out); break;
1945 case id<Comprehension_t>(): transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Closure); break;
1946 case id<FunLit_t>(): transformFunLit(static_cast<FunLit_t*>(value), out); break;
1947 case id<Num_t>(): transformNum(static_cast<Num_t*>(value), out); break;
1948 default: assert(false); break;
1949 }
1950 }
1951
1952 void transformFunLit(FunLit_t* funLit, str_list& out) {
1953 _enableReturn.push(true);
1954 _varArgs.push(false);
1955 str_list temp;
1956 bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv;
1957 pushScope();
1958 if (isFatArrow) {
1959 forceAddToScope(s("self"sv));
1960 }
1961 if (auto argsDef = funLit->argsDef.get()) {
1962 transformFnArgsDef(argsDef, temp);
1963 if (funLit->body) {
1964 transformBody(funLit->body, temp, ExpUsage::Return);
1965 } else {
1966 temp.push_back(Empty);
1967 }
1968 auto it = temp.begin();
1969 auto& args = *it;
1970 auto& initArgs = *(++it);
1971 auto& bodyCodes = *(++it);
1972 _buf << "function("sv;
1973 if (isFatArrow) {
1974 _buf << "self"sv;
1975 if (!args.empty()) _buf << ", "sv;
1976 }
1977 _buf << args << ')';
1978 if (!initArgs.empty() || !bodyCodes.empty()) {
1979 _buf << nlr(argsDef) << initArgs << bodyCodes;
1980 popScope();
1981 _buf << indent() << "end"sv;
1982 } else {
1983 popScope();
1984 _buf << " end"sv;
1985 }
1986 } else {
1987 if (funLit->body) {
1988 transformBody(funLit->body, temp, ExpUsage::Return);
1989 } else {
1990 temp.push_back(Empty);
1991 }
1992 auto& bodyCodes = temp.back();
1993 _buf << "function("sv <<
1994 (isFatArrow ? s("self"sv) : Empty) <<
1995 ')';
1996 if (!bodyCodes.empty()) {
1997 _buf << nll(funLit) << bodyCodes;
1998 popScope();
1999 _buf << indent() << "end"sv;
2000 } else {
2001 popScope();
2002 _buf << " end"sv;
2003 }
2004 }
2005 out.push_back(clearBuf());
2006 _enableReturn.pop();
2007 _varArgs.pop();
2008 }
2009
2010 void transformBody(Body_t* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
2011 auto x = body;
2012 if (auto stmt = body->content.as<Statement_t>()) {
2013 auto block = x->new_ptr<Block_t>();
2014 block->statements.push_back(stmt);
2015 transformBlock(block, out, usage, assignList);
2016 } else {
2017 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
2018 }
2019 }
2020
2021 void transformBlock(Block_t* block, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool isRoot = false) {
2022 const auto& nodes = block->statements.objects();
2023 LocalMode mode = LocalMode::None;
2024 Local_t* any = nullptr, *capital = nullptr;
2025 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
2026 auto node = *it;
2027 auto stmt = static_cast<Statement_t*>(node);
2028 if (auto backcallBody = stmt->content.as<BackcallBody_t>()) {
2029 auto x = stmt;
2030 bool cond = false;
2031 BLOCK_START
2032 BREAK_IF(it == nodes.begin());
2033 auto last = it; --last;
2034 auto lst = static_cast<Statement_t*>(*last);
2035 if (lst->appendix) {
2036 throw std::logic_error(_info.errorMessage("statement decorator must be placed at the end of backcall chain"sv, lst->appendix.get()));
2037 }
2038 lst->appendix.set(stmt->appendix);
2039 stmt->appendix.set(nullptr);
2040 lst->needSep.set(stmt->needSep);
2041 stmt->needSep.set(nullptr);
2042 auto exp = lastExpFromStatement(lst);
2043 BREAK_IF(!exp);
2044 for (auto val : backcallBody->values.objects()) {
2045 exp->backcalls.push_back(val);
2046 }
2047 cond = true;
2048 BLOCK_END
2049 if (!cond) throw std::logic_error(_info.errorMessage("backcall chain must be following a value"sv, x));
2050 stmt->content.set(nullptr);
2051 auto next = it; ++next;
2052 BLOCK_START
2053 BREAK_IF(next == nodes.end());
2054 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<BackcallBody_t>());
2055 throw std::logic_error(_info.errorMessage("indent mismatch in backcall chain"sv, *next));
2056 BLOCK_END
2057 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
2058 auto x = *nodes.begin();
2059 auto newBlock = x->new_ptr<Block_t>();
2060 if (it != nodes.begin()) {
2061 for (auto i = nodes.begin(); i != it; ++i) {
2062 newBlock->statements.push_back(*i);
2063 }
2064 }
2065 x = backcall;
2066 ast_ptr<false, Exp_t> arg;
2067 {
2068 auto block = x->new_ptr<Block_t>();
2069 auto next = it; ++next;
2070 if (next != nodes.end()) {
2071 for (auto i = next; i != nodes.end(); ++i) {
2072 block->statements.push_back(*i);
2073 }
2074 }
2075 auto body = x->new_ptr<Body_t>();
2076 body->content.set(block);
2077 auto funLit = x->new_ptr<FunLit_t>();
2078 funLit->argsDef.set(backcall->argsDef);
2079 auto arrow = _parser.toString(backcall->arrow);
2080 funLit->arrow.set(toAst<fn_arrow_t>(arrow == "<-"sv ? "->"sv : "=>"sv, x));
2081 funLit->body.set(body);
2082 auto simpleValue = x->new_ptr<SimpleValue_t>();
2083 simpleValue->value.set(funLit);
2084 auto value = x->new_ptr<Value_t>();
2085 value->item.set(simpleValue);
2086 arg = newExp(value, x);
2087 }
2088 if (isChainValueCall(backcall->value)) {
2089 auto last = backcall->value->items.back();
2090 _ast_list* args = nullptr;
2091 if (auto invoke = ast_cast<InvokeArgs_t>(last)) {
2092 args = &invoke->args;
2093 } else {
2094 args = &(ast_to<Invoke_t>(last)->args);
2095 }
2096 bool findPlaceHolder = false;
2097 for (auto a : args->objects()) {
2098 bool lintGlobal = _config.lintGlobalVariable;
2099 _config.lintGlobalVariable = false;
2100 auto name = singleVariableFrom(a);
2101 _config.lintGlobalVariable = lintGlobal;
2102 if (name == "_"sv) {
2103 if (!findPlaceHolder) {
2104 args->swap(a, arg);
2105 findPlaceHolder = true;
2106 } else {
2107 throw std::logic_error(_info.errorMessage("backcall placeholder can be used only in one place"sv, a));
2108 }
2109 }
2110 }
2111 if (!findPlaceHolder) {
2112 args->push_back(arg);
2113 }
2114 } else {
2115 auto invoke = x->new_ptr<Invoke_t>();
2116 invoke->args.push_back(arg);
2117 backcall->value->items.push_back(invoke);
2118 }
2119 auto newStmt = x->new_ptr<Statement_t>();
2120 {
2121 auto chainValue = backcall->value.get();
2122 auto value = x->new_ptr<Value_t>();
2123 value->item.set(chainValue);
2124 auto exp = newExp(value, x);
2125 auto expList = x->new_ptr<ExpList_t>();
2126 expList->exprs.push_back(exp);
2127 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2128 expListAssign->expList.set(expList);
2129 newStmt->content.set(expListAssign);
2130 newStmt->appendix.set(stmt->appendix);
2131 newBlock->statements.push_back(newStmt);
2132 }
2133 transformBlock(newBlock, out, usage, assignList, isRoot);
2134 return;
2135 }
2136 if (auto local = stmt->content.as<Local_t>()) {
2137 if (!local->collected) {
2138 local->collected = true;
2139 switch (local->item->getId()) {
2140 case id<local_flag_t>(): {
2141 auto flag = local->item.to<local_flag_t>();
2142 LocalMode newMode = _parser.toString(flag) == "*"sv ? LocalMode::Any : LocalMode::Capital;
2143 if (int(newMode) > int(mode)) {
2144 mode = newMode;
2145 }
2146 if (mode == LocalMode::Any) {
2147 if (!any) any = local;
2148 if (!capital) capital = local;
2149 } else {
2150 if (!capital) capital = local;
2151 }
2152 break;
2153 }
2154 case id<local_values_t>(): {
2155 auto values = local->item.to<local_values_t>();
2156 for (auto name : values->nameList->names.objects()) {
2157 local->forceDecls.push_back(_parser.toString(name));
2158 }
2159 break;
2160 }
2161 }
2162 }
2163 } else if (mode != LocalMode::None) {
2164 ClassDecl_t* classDecl = nullptr;
2165 if (auto assignment = assignmentFrom(stmt)) {
2166 auto vars = getAssignVars(assignment);
2167 for (const auto& var : vars) {
2168 if (var.empty()) continue;
2169 if (std::isupper(var[0]) && capital) {
2170 capital->decls.push_back(var);
2171 } else if (any) {
2172 any->decls.push_back(var);
2173 }
2174 }
2175 auto info = extractDestructureInfo(assignment, true);
2176 if (!info.first.empty()) {
2177 for (const auto& destruct : info.first)
2178 for (const auto& item : destruct.items)
2179 if (item.isVariable) {
2180 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name);
2181 } else if (any) {
2182 any->decls.push_back(item.name);
2183 }
2184 }
2185 }
2186 if (info.second) {
2187 auto defs = transformAssignDefs(info.second->expList, false);
2188 for (const auto& def : defs) {
2189 if (std::isupper(def[0]) && capital) { capital->decls.push_back(def);
2190 } else if (any) {
2191 any->decls.push_back(def);
2192 }
2193 }
2194 }
2195 BLOCK_START
2196 auto assign = assignment->action.as<Assign_t>();
2197 BREAK_IF(!assign);
2198 BREAK_IF(assign->values.objects().size() != 1);
2199 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
2200 BREAK_IF(!exp);
2201 auto value = singleValueFrom(exp);
2202 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2203 BLOCK_END
2204 } else if (auto expList = expListFrom(stmt)) {
2205 auto value = singleValueFrom(expList);
2206 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2207 }
2208 if (classDecl) {
2209 if (auto variable = classDecl->name->item.as<Variable_t>()) {
2210 auto className = _parser.toString(variable);
2211 if (!className.empty()) {
2212 if (std::isupper(className[0]) && capital) {
2213 capital->decls.push_back(className);
2214 } else if (any) {
2215 any->decls.push_back(className);
2216 }
2217 }
2218 }
2219 }
2220 }
2221 }
2222 if (isRoot && !_info.moduleName.empty()) {
2223 block->statements.push_front(toAst<Statement_t>(_info.moduleName + s(_info.exportDefault ? "=nil"sv : "={}"sv), block));
2224 }
2225 switch (usage) {
2226 case ExpUsage::Closure:
2227 case ExpUsage::Return: {
2228 BLOCK_START
2229 BREAK_IF(isRoot && !_info.moduleName.empty());
2230 auto last = lastStatementFrom(nodes);
2231 BREAK_IF(!last);
2232 auto x = last;
2233 auto expList = expListFrom(last);
2234 BREAK_IF(!expList ||
2235 (last->appendix &&
2236 last->appendix->item.is<CompInner_t>()));
2237 auto expListLow = x->new_ptr<ExpListLow_t>();
2238 expListLow->exprs.dup(expList->exprs);
2239 auto returnNode = x->new_ptr<Return_t>();
2240 returnNode->valueList.set(expListLow);
2241 returnNode->allowBlockMacroReturn = true;
2242 last->content.set(returnNode);
2243 last->needSep.set(nullptr);
2244 auto bLast = ++nodes.rbegin();
2245 if (bLast != nodes.rend()) {
2246 bool isMacro = false;
2247 BLOCK_START
2248 BREAK_IF(expListLow->exprs.size() != 1);
2249 auto exp = static_cast<Exp_t*>(expListLow->exprs.back());
2250 BREAK_IF(!exp->opValues.empty());
2251 auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>();
2252 BREAK_IF(!chainValue);
2253 isMacro = isMacroChain(chainValue);
2254 BLOCK_END
2255 if (!isMacro) {
2256 ast_to<Statement_t>(*bLast)->needSep.set(nullptr);
2257 }
2258 }
2259 BLOCK_END
2260 break;
2261 }
2262 case ExpUsage::Assignment: {
2263 auto last = lastStatementFrom(block);
2264 if (!last) return;
2265 bool lastAssignable = expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content);
2266 if (lastAssignable) {
2267 auto x = last;
2268 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2269 newAssignment->expList.set(assignList);
2270 auto assign = x->new_ptr<Assign_t>();
2271 if (auto valueList = last->content.as<ExpListAssign_t>()) {
2272 assign->values.dup(valueList->expList->exprs);
2273 } else {
2274 auto simpleValue = x->new_ptr<SimpleValue_t>();
2275 simpleValue->value.set(last->content);
2276 auto value = x->new_ptr<Value_t>();
2277 value->item.set(simpleValue);
2278 auto exp = newExp(value, x);
2279 assign->values.push_back(exp);
2280 }
2281 newAssignment->action.set(assign);
2282 last->content.set(newAssignment);
2283 last->needSep.set(nullptr);
2284 auto bLast = ++nodes.rbegin();
2285 if (bLast != nodes.rend()) {
2286 static_cast<Statement_t*>(*bLast)->needSep.set(nullptr);
2287 }
2288 }
2289 break;
2290 }
2291 default: break;
2292 }
2293 if (!nodes.empty()) {
2294 str_list temp;
2295 for (auto node : nodes) {
2296 transformStatement(static_cast<Statement_t*>(node), temp);
2297 }
2298 out.push_back(join(temp));
2299 } else {
2300 out.push_back(Empty);
2301 }
2302 if (isRoot && !_info.moduleName.empty()) {
2303 out.back().append(indent() + s("return "sv) + _info.moduleName + nlr(block));
2304 }
2305 }
2306
2307#ifndef MOONP_NO_MACRO
2308 void passOptions() {
2309 if (!_config.options.empty()) {
2310 pushMoonp("options"sv); // options
2311 for (const auto& option : _config.options) {
2312 lua_pushlstring(L, option.second.c_str(), option.second.size());
2313 lua_setfield(L, -2, option.first.c_str());
2314 }
2315 lua_pop(L, 1);
2316 }
2317 }
2318
2319 void pushCurrentModule() {
2320 if (_useModule) {
2321 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2322 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
2323 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
2324 lua_rawgeti(L, -1, idx); // tb[idx], tb cur
2325 lua_remove(L, -2); // cur
2326 return;
2327 }
2328 _useModule = true;
2329 if (!L) {
2330 L = luaL_newstate();
2331 if (_luaOpen) {
2332 _luaOpen(static_cast<void*>(L));
2333 }
2334 passOptions();
2335 _stateOwner = true;
2336 }
2337 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2338 lua_rawget(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE], tb
2339 if (lua_isnil(L, -1) != 0) { // tb == nil
2340 lua_pop(L, 1);
2341 lua_newtable(L); // tb
2342 lua_pushliteral(L, MOONP_MODULE); // tb MOONP_MODULE
2343 lua_pushvalue(L, -2); // tb MOONP_MODULE tb
2344 lua_rawset(L, LUA_REGISTRYINDEX); // reg[MOONP_MODULE] = tb, tb
2345 } // tb
2346 int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb
2347 lua_newtable(L); // tb cur
2348 lua_pushvalue(L, -1); // tb cur cur
2349 lua_rawseti(L, -3, idx + 1); // tb[idx + 1] = cur, tb cur
2350 lua_remove(L, -2); // cur
2351 }
2352
2353 void pushMoonp(std::string_view name) {
2354 lua_getglobal(L, "package"); // package
2355 lua_getfield(L, -1, "loaded"); // package loaded
2356 lua_getfield(L, -1, "moonp"); // package loaded moonp
2357 lua_pushlstring(L, &name.front(), name.size()); // package loaded moonp name
2358 lua_gettable(L, -2); // loaded[name], package loaded moonp item
2359 lua_insert(L, -4); // item package loaded moonp
2360 lua_pop(L, 3); // item
2361 }
2362
2363 bool isModuleLoaded(std::string_view name) {
2364 int top = lua_gettop(L);
2365 DEFER(lua_settop(L, top));
2366 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2367 lua_rawget(L, LUA_REGISTRYINDEX); // modules
2368 lua_pushlstring(L, &name.front(), name.size());
2369 lua_rawget(L, -2); // modules module
2370 if (lua_isnil(L, -1) != 0) {
2371 return false;
2372 }
2373 return true;
2374 }
2375
2376 void pushModuleTable(std::string_view name) {
2377 lua_pushliteral(L, MOONP_MODULE); // MOONP_MODULE
2378 lua_rawget(L, LUA_REGISTRYINDEX); // modules
2379 lua_pushlstring(L, &name.front(), name.size());
2380 lua_rawget(L, -2); // modules module
2381 if (lua_isnil(L, -1) != 0) {
2382 lua_pop(L, 1);
2383 lua_newtable(L); // modules module
2384 lua_pushlstring(L, &name.front(), name.size());
2385 lua_pushvalue(L, -2); // modules module name module
2386 lua_rawset(L, -4); // modules[name] = module, modules module
2387 }
2388 lua_remove(L, -2); // module
2389 }
2390
2391 void pushOptions(int lineOffset) {
2392 lua_newtable(L);
2393 lua_pushliteral(L, "lint_global");
2394 lua_pushboolean(L, 0);
2395 lua_rawset(L, -3);
2396 lua_pushliteral(L, "implicit_return_root");
2397 lua_pushboolean(L, 1);
2398 lua_rawset(L, -3);
2399 lua_pushliteral(L, "reserve_line_number");
2400 lua_pushboolean(L, 1);
2401 lua_rawset(L, -3);
2402 lua_pushliteral(L, "same_module");
2403 lua_pushboolean(L, 1);
2404 lua_rawset(L, -3);
2405 lua_pushliteral(L, "line_offset");
2406 lua_pushinteger(L, lineOffset);
2407 lua_rawset(L, -3);
2408 }
2409
2410 void transformMacro(Macro_t* macro, str_list& out, bool exporting) {
2411 if (_scopes.size() > 1) {
2412 throw std::logic_error(_info.errorMessage("can not define macro outside the root block"sv, macro));
2413 }
2414 auto macroName = _parser.toString(macro->name);
2415 auto argsDef = macro->macroLit->argsDef.get();
2416 str_list newArgs;
2417 if (argsDef) {
2418 for (auto def_ : argsDef->definitions.objects()) {
2419 auto def = static_cast<FnArgDef_t*>(def_);
2420 if (def->name.is<SelfName_t>()) {
2421 throw std::logic_error(_info.errorMessage("self name is not supported for macro function argument"sv, def->name));
2422 } else {
2423 std::string defVal;
2424 if (def->defaultValue) {
2425 defVal = _parser.toString(def->defaultValue);
2426 Utils::trim(defVal);
2427 defVal.insert(0, "=[==========["sv);
2428 defVal.append("]==========]"sv);
2429 }
2430 newArgs.emplace_back(_parser.toString(def->name) + defVal);
2431 }
2432 }
2433 if (argsDef->varArg) {
2434 newArgs.emplace_back(_parser.toString(argsDef->varArg));
2435 }
2436 }
2437 _buf << "("sv << join(newArgs, ","sv) << ")->"sv;
2438 _buf << _parser.toString(macro->macroLit->body);
2439 auto macroCodes = clearBuf();
2440 _buf << "=(macro "sv << macroName << ")";
2441 auto chunkName = clearBuf();
2442 pushCurrentModule(); // cur
2443 int top = lua_gettop(L) - 1;
2444 DEFER(lua_settop(L, top));
2445 pushMoonp("loadstring"sv); // cur loadstring
2446 lua_pushlstring(L, macroCodes.c_str(), macroCodes.size()); // cur loadstring codes
2447 lua_pushlstring(L, chunkName.c_str(), chunkName.size()); // cur loadstring codes chunk
2448 pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options
2449 if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err
2450 std::string err = lua_tostring(L, -1);
2451 throw std::logic_error(_info.errorMessage(s("failed to load macro codes\n"sv) + err, macro->macroLit));
2452 } // cur f err
2453 if (lua_isnil(L, -2) != 0) { // f == nil, cur f err
2454 std::string err = lua_tostring(L, -1);
2455 throw std::logic_error(_info.errorMessage(s("failed to load macro codes, at (macro "sv) + macroName + s("): "sv) + err, macro->macroLit));
2456 }
2457 lua_pop(L, 1); // cur f
2458 pushMoonp("pcall"sv); // cur f pcall
2459 lua_insert(L, -2); // cur pcall f
2460 if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro
2461 std::string err = lua_tostring(L, -1);
2462 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, macro->macroLit));
2463 } // cur success res
2464 if (lua_toboolean(L, -2) == 0) {
2465 std::string err = lua_tostring(L, -1);
2466 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, macro->macroLit));
2467 } // cur true macro
2468 lua_remove(L, -2); // cur macro
2469 if (exporting && !_moduleName.empty()) {
2470 pushModuleTable(_moduleName); // cur macro module
2471 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
2472 lua_pushvalue(L, -3); // cur macro module name macro
2473 lua_rawset(L, -3); // cur macro module
2474 lua_pop(L, 1);
2475 } // cur macro
2476 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro name
2477 lua_insert(L, -2); // cur name macro
2478 lua_rawset(L, -3); // cur[name] = macro, cur
2479 out.push_back(Empty);
2480 }
2481#else
2482 void transformMacro(Macro_t* macro, str_list&, bool) {
2483 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, macro));
2484 }
2485#endif // MOONP_NO_MACRO
2486
2487 void transformReturn(Return_t* returnNode, str_list& out) {
2488 if (!_enableReturn.top()) {
2489 ast_node* target = returnNode->valueList.get();
2490 if (!target) target = returnNode;
2491 throw std::logic_error(_info.errorMessage("illegal return statement here"sv, target));
2492 }
2493 if (auto valueList = returnNode->valueList.get()) {
2494 if (valueList->exprs.size() == 1) {
2495 auto exp = static_cast<Exp_t*>(valueList->exprs.back());
2496 if (isPureBackcall(exp)) {
2497 transformExp(exp, out, ExpUsage::Return);
2498 return;
2499 }
2500 }
2501 if (auto singleValue = singleValueFrom(valueList)) {
2502 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
2503 auto value = simpleValue->value.get();
2504 switch (value->getId()) {
2505 case id<Comprehension_t>():
2506 transformComprehension(static_cast<Comprehension_t*>(value), out, ExpUsage::Return);
2507 return;
2508 case id<TblComprehension_t>():
2509 transformTblComprehension(static_cast<TblComprehension_t*>(value), out, ExpUsage::Return);
2510 return;
2511 case id<With_t>():
2512 transformWith(static_cast<With_t*>(value), out, nullptr, true);
2513 return;
2514 case id<ClassDecl_t>():
2515 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Return);
2516 return;
2517 case id<Do_t>():
2518 transformDo(static_cast<Do_t*>(value), out, ExpUsage::Return);
2519 return;
2520 case id<Switch_t>():
2521 transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Return);
2522 return;
2523 case id<While_t>():
2524 transformWhileInPlace(static_cast<While_t*>(value), out);
2525 return;
2526 case id<For_t>():
2527 transformForInPlace(static_cast<For_t*>(value), out);
2528 return;
2529 case id<ForEach_t>():
2530 transformForEachInPlace(static_cast<ForEach_t*>(value), out);
2531 return;
2532 case id<If_t>():
2533 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
2534 return;
2535 case id<Unless_t>():
2536 transformUnless(static_cast<Unless_t*>(value), out, ExpUsage::Return);
2537 return;
2538 }
2539 } else if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
2540 if (specialChainValue(chainValue) != ChainType::Common) {
2541 transformChainValue(chainValue, out, ExpUsage::Return, nullptr, returnNode->allowBlockMacroReturn);
2542 return;
2543 }
2544 }
2545 transformValue(singleValue, out);
2546 out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode);
2547 return;
2548 } else {
2549 str_list temp;
2550 transformExpListLow(valueList, temp);
2551 out.push_back(indent() + s("return "sv) + temp.back() + nlr(returnNode));
2552 }
2553 } else {
2554 out.push_back(indent() + s("return"sv) + nll(returnNode));
2555 }
2556 }
2557
2558 void transformFnArgsDef(FnArgsDef_t* argsDef, str_list& out) {
2559 if (!argsDef->defList) {
2560 out.push_back(Empty);
2561 out.push_back(Empty);
2562 } else {
2563 transformFnArgDefList(argsDef->defList, out);
2564 }
2565 if (argsDef->shadowOption) {
2566 transform_outer_var_shadow(argsDef->shadowOption);
2567 }
2568 }
2569
2570 void transform_outer_var_shadow(outer_var_shadow_t* shadow) {
2571 markVarShadowed();
2572 if (shadow->varList) {
2573 for (auto name : shadow->varList->names.objects()) {
2574 addToAllowList(_parser.toString(name));
2575 }
2576 }
2577 }
2578
2579 void transformFnArgDefList(FnArgDefList_t* argDefList, str_list& out) {
2580 auto x = argDefList;
2581 struct ArgItem {
2582 std::string name;
2583 std::string assignSelf;
2584 };
2585 std::list<ArgItem> argItems;
2586 str_list temp;
2587 std::string varNames;
2588 bool assignSelf = false;
2589 for (auto _def : argDefList->definitions.objects()) {
2590 auto def = static_cast<FnArgDef_t*>(_def);
2591 auto& arg = argItems.emplace_back();
2592 switch (def->name->getId()) {
2593 case id<Variable_t>(): arg.name = _parser.toString(def->name); break;
2594 case id<SelfName_t>(): {
2595 assignSelf = true;
2596 auto selfName = static_cast<SelfName_t*>(def->name.get());
2597 switch (selfName->name->getId()) {
2598 case id<self_class_name_t>(): {
2599 auto clsName = static_cast<self_class_name_t*>(selfName->name.get());
2600 arg.name = _parser.toString(clsName->name);
2601 arg.assignSelf = s("self.__class."sv) + arg.name;
2602 break;
2603 }
2604 case id<self_class_t>():
2605 arg.name = "self.__class"sv;
2606 break;
2607 case id<self_name_t>(): {
2608 auto sfName = static_cast<self_name_t*>(selfName->name.get());
2609 arg.name = _parser.toString(sfName->name);
2610 arg.assignSelf = s("self."sv) + arg.name;
2611 break;
2612 }
2613 case id<self_t>():
2614 arg.name = "self"sv;
2615 break;
2616 default: assert(false); break;
2617 }
2618 break;
2619 }
2620 default: assert(false); break;
2621 }
2622 forceAddToScope(arg.name);
2623 if (def->defaultValue) {
2624 pushScope();
2625 auto expList = toAst<ExpList_t>(arg.name, x);
2626 auto assign = x->new_ptr<Assign_t>();
2627 assign->values.push_back(def->defaultValue.get());
2628 auto assignment = x->new_ptr<ExpListAssign_t>();
2629 assignment->expList.set(expList);
2630 assignment->action.set(assign);
2631 transformAssignment(assignment, temp);
2632 popScope();
2633 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def);
2634 _buf << temp.back();
2635 _buf << indent() << "end"sv << nll(def);
2636 temp.back() = clearBuf();
2637 }
2638 if (varNames.empty()) varNames = arg.name;
2639 else varNames.append(s(", "sv) + arg.name);
2640 }
2641 if (argDefList->varArg) {
2642 auto& arg = argItems.emplace_back();
2643 arg.name = "..."sv;
2644 if (varNames.empty()) varNames = arg.name;
2645 else varNames.append(s(", "sv) + arg.name);
2646 _varArgs.top() = true;
2647 }
2648 std::string initCodes = join(temp);
2649 if (assignSelf) {
2650 auto sjoin = [](const decltype(argItems)& items, int index) {
2651 std::string result;
2652 for (auto it = items.begin(); it != items.end(); ++it) {
2653 if (it->assignSelf.empty()) continue;
2654 if (result.empty()) result = (&it->name)[index];
2655 else result.append(s(", "sv) + (&it->name)[index]);
2656 }
2657 return result;
2658 };
2659 std::string sleft = sjoin(argItems, 1);
2660 std::string sright = sjoin(argItems, 0);
2661 initCodes.append(indent() + sleft + s(" = "sv) + sright + nll(argDefList));
2662 }
2663 out.push_back(varNames);
2664 out.push_back(initCodes);
2665 }
2666
2667 void transformSelfName(SelfName_t* selfName, str_list& out, const ast_sel<false,Invoke_t,InvokeArgs_t>& invoke = {}) {
2668 auto x = selfName;
2669 auto name = selfName->name.get();
2670 switch (name->getId()) {
2671 case id<self_class_name_t>(): {
2672 auto clsName = static_cast<self_class_name_t*>(name);
2673 auto nameStr = _parser.toString(clsName->name);
2674 if (LuaKeywords.find(nameStr) != LuaKeywords.end()) {
2675 out.push_back(s("self.__class[\""sv) + nameStr + s("\"]"sv));
2676 if (invoke) {
2677 if (auto invokePtr = invoke.as<Invoke_t>()) {
2678 invokePtr->args.push_front(toAst<Exp_t>("self.__class"sv, x));
2679 } else {
2680 auto invokeArgsPtr = invoke.as<InvokeArgs_t>();
2681 invokeArgsPtr->args.push_front(toAst<Exp_t>("self.__class"sv, x));
2682 }
2683 }
2684 } else {
2685 out.push_back(s("self.__class"sv) + s(invoke ? ":"sv : "."sv) + nameStr);
2686 }
2687 break;
2688 }
2689 case id<self_class_t>():
2690 out.push_back(s("self.__class"sv));
2691 break;
2692 case id<self_name_t>(): {
2693 auto sfName = static_cast<self_class_name_t*>(name);
2694 auto nameStr = _parser.toString(sfName->name);
2695 if (LuaKeywords.find(nameStr) != LuaKeywords.end()) {
2696 out.push_back(s("self[\""sv) + nameStr + s("\"]"sv));
2697 if (invoke) {
2698 if (auto invokePtr = invoke.as<Invoke_t>()) {
2699 invokePtr->args.push_front(toAst<Exp_t>("self"sv, x));
2700 } else {
2701 auto invokeArgsPtr = invoke.as<InvokeArgs_t>();
2702 invokeArgsPtr->args.push_front(toAst<Exp_t>("self"sv, x));
2703 }
2704 }
2705 } else {
2706 out.push_back(s("self"sv) + s(invoke ? ":"sv : "."sv) + nameStr);
2707 }
2708 break;
2709 }
2710 case id<self_t>():
2711 out.push_back(s("self"sv));
2712 break;
2713 default: assert(false); break;
2714 }
2715 }
2716
2717 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2718 auto x = chainList.front();
2719 if (ast_is<existential_op_t>(chainList.back())) {
2720 auto parens = x->new_ptr<Parens_t>();
2721 {
2722 auto chainValue = x->new_ptr<ChainValue_t>();
2723 for (auto item : chainList) {
2724 chainValue->items.push_back(item);
2725 }
2726 chainValue->items.pop_back();
2727 auto value = x->new_ptr<Value_t>();
2728 value->item.set(chainValue);
2729 auto exp = newExp(value, toAst<BinaryOperator_t>("!="sv, x), toAst<Value_t>("nil"sv, x), x);
2730 parens->expr.set(exp);
2731 }
2732 switch (usage) {
2733 case ExpUsage::Assignment: {
2734 auto callable = x->new_ptr<Callable_t>();
2735 callable->item.set(parens);
2736 auto chainValue = x->new_ptr<ChainValue_t>();
2737 chainValue->items.push_back(callable);
2738 auto value = x->new_ptr<Value_t>();
2739 value->item.set(chainValue);
2740 auto exp = newExp(value, x);
2741 auto assignment = x->new_ptr<ExpListAssign_t>();
2742 assignment->expList.set(assignList);
2743 auto assign = x->new_ptr<Assign_t>();
2744 assign->values.push_back(exp);
2745 assignment->action.set(assign);
2746 transformAssignment(assignment, out);
2747 break;
2748 }
2749 case ExpUsage::Return:
2750 transformParens(parens, out);
2751 out.back().insert(0, indent() + s("return "sv));
2752 out.back().append(nlr(x));
2753 break;
2754 default:
2755 transformParens(parens, out);
2756 break;
2757 }
2758 return true;
2759 }
2760 return false;
2761 }
2762
2763 bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2764 auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is<existential_op_t>(node); });
2765 if (opIt != chainList.end()) {
2766 auto x = chainList.front();
2767 str_list temp;
2768 if (usage == ExpUsage::Closure) {
2769 temp.push_back(s("(function()"sv) + nll(x));
2770 pushScope();
2771 _enableReturn.push(true);
2772 }
2773 auto partOne = x->new_ptr<ChainValue_t>();
2774 for (auto it = chainList.begin();it != opIt;++it) {
2775 partOne->items.push_back(*it);
2776 }
2777 BLOCK_START
2778 auto back = ast_cast<Callable_t>(partOne->items.back());
2779 BREAK_IF(!back);
2780 auto selfName = ast_cast<SelfName_t>(back->item);
2781 BREAK_IF(!selfName);
2782 if (auto sname = ast_cast<self_name_t>(selfName->name)) {
2783 auto colonItem = x->new_ptr<ColonChainItem_t>();
2784 colonItem->name.set(sname->name);
2785 partOne->items.pop_back();
2786 partOne->items.push_back(toAst<Callable_t>("@"sv, x));
2787 partOne->items.push_back(colonItem);
2788 break;
2789 }
2790 if (auto cname = ast_cast<self_class_name_t>(selfName->name)) {
2791 auto colonItem = x->new_ptr<ColonChainItem_t>();
2792 colonItem->name.set(cname->name);
2793 partOne->items.pop_back();
2794 partOne->items.push_back(toAst<Callable_t>("@@"sv, x));
2795 partOne->items.push_back(colonItem);
2796 break;
2797 }
2798 BLOCK_END
2799 auto objVar = singleVariableFrom(partOne);
2800 if (objVar.empty()) {
2801 objVar = getUnusedName("_obj_"sv);
2802 if (auto colonItem = ast_cast<ColonChainItem_t>(partOne->items.back())) {
2803 auto chainValue = x->new_ptr<ChainValue_t>();
2804 chainValue->items.dup(partOne->items);
2805 chainValue->items.pop_back();
2806 if (chainValue->items.empty()) {
2807 if (_withVars.empty()) {
2808 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x));
2809 }
2810 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x));
2811 }
2812 auto newObj = singleVariableFrom(chainValue);
2813 if (!newObj.empty()) {
2814 objVar = newObj;
2815 } else {
2816 auto value = x->new_ptr<Value_t>();
2817 value->item.set(chainValue);
2818 auto exp = newExp(value, x);
2819 auto assign = x->new_ptr<Assign_t>();
2820 assign->values.push_back(exp);
2821 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2822 expListAssign->expList.set(toAst<ExpList_t>(objVar, x));
2823 expListAssign->action.set(assign);
2824 transformAssignment(expListAssign, temp);
2825 }
2826 auto dotItem = x->new_ptr<DotChainItem_t>();
2827 auto name = colonItem->name.get();
2828 if (auto keyword = ast_cast<LuaKeyword_t>(name)) {
2829 name = keyword->name.get();
2830 }
2831 dotItem->name.set(name);
2832 partOne->items.clear();
2833 partOne->items.push_back(toAst<Callable_t>(objVar, x));
2834 partOne->items.push_back(dotItem);
2835 auto it = opIt; ++it;
2836 if (it != chainList.end() && ast_is<Invoke_t, InvokeArgs_t>(*it)) {
2837
2838 if (auto invoke = ast_cast<Invoke_t>(*it)) {
2839 invoke->args.push_front(toAst<Exp_t>(objVar, x));
2840 } else {
2841 auto invokeArgs = static_cast<InvokeArgs_t*>(*it);
2842 invokeArgs->args.push_front(toAst<Exp_t>(objVar, x));
2843 }
2844 }
2845 objVar = getUnusedName("_obj_"sv);
2846 }
2847 auto value = x->new_ptr<Value_t>();
2848 value->item.set(partOne);
2849 auto exp = newExp(value, x);
2850 auto assign = x->new_ptr<Assign_t>();
2851 assign->values.push_back(exp);
2852 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2853 expListAssign->expList.set(toAst<ExpList_t>(objVar, x));
2854 expListAssign->action.set(assign);
2855 transformAssignment(expListAssign, temp);
2856 }
2857 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x);
2858 temp.push_back(clearBuf());
2859 pushScope();
2860 auto partTwo = x->new_ptr<ChainValue_t>();
2861 partTwo->items.push_back(toAst<Callable_t>(objVar, x));
2862 for (auto it = ++opIt;it != chainList.end();++it) {
2863 partTwo->items.push_back(*it);
2864 }
2865 switch (usage) {
2866 case ExpUsage::Common:
2867 transformChainValue(partTwo, temp, ExpUsage::Common);
2868 break;
2869 case ExpUsage::Assignment: {
2870 auto value = x->new_ptr<Value_t>();
2871 value->item.set(partTwo);
2872 auto exp = newExp(value, x);
2873 auto assign = x->new_ptr<Assign_t>();
2874 assign->values.push_back(exp);
2875 auto assignment = x->new_ptr<ExpListAssign_t>();
2876 assignment->expList.set(assignList);
2877 assignment->action.set(assign);
2878 transformAssignment(assignment, temp);
2879 break;
2880 }
2881 case ExpUsage::Return:
2882 case ExpUsage::Closure: {
2883 auto value = x->new_ptr<Value_t>();
2884 value->item.set(partTwo);
2885 auto exp = newExp(value, x);
2886 auto ret = x->new_ptr<Return_t>();
2887 auto expListLow = x->new_ptr<ExpListLow_t>();
2888 expListLow->exprs.push_back(exp);
2889 ret->valueList.set(expListLow);
2890 transformReturn(ret, temp);
2891 break;
2892 }
2893 }
2894 popScope();
2895 temp.push_back(indent() + s("end"sv) + nlr(x));
2896 switch (usage) {
2897 case ExpUsage::Return:
2898 temp.push_back(indent() + s("return nil"sv) + nlr(x));
2899 break;
2900 case ExpUsage::Closure:
2901 temp.push_back(indent() + s("return nil"sv) + nlr(x));
2902 _enableReturn.pop();
2903 popScope();
2904 temp.push_back(indent() + s("end)()"sv));
2905 break;
2906 default:
2907 break;
2908 }
2909 out.push_back(join(temp));
2910 return true;
2911 }
2912 return false;
2913 }
2914
2915 bool transformChainEndWithColonItem(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
2916 if (ast_is<ColonChainItem_t>(chainList.back())) {
2917 auto x = chainList.front();
2918 str_list temp;
2919 switch (usage) {
2920 case ExpUsage::Assignment:
2921 temp.push_back(indent() + s("do"sv) + nll(x));
2922 pushScope();
2923 break;
2924 case ExpUsage::Closure:
2925 temp.push_back(s("(function()"sv) + nll(x));
2926 pushScope();
2927 _enableReturn.push(true);
2928 break;
2929 default:
2930 break;
2931 }
2932 auto baseChain = x->new_ptr<ChainValue_t>();
2933 switch (chainList.front()->getId()) {
2934 case id<DotChainItem_t>():
2935 case id<ColonChainItem_t>():
2936 if (_withVars.empty()) {
2937 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front()));
2938 } else {
2939 baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), x));
2940 }
2941 break;
2942 }
2943 auto end = --chainList.end();
2944 for (auto it = chainList.begin(); it != end; ++it) {
2945 baseChain->items.push_back(*it);
2946 }
2947 auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
2948 auto funcName = _parser.toString(colonChainItem->name);
2949 auto baseVar = getUnusedName("_base_"sv);
2950 auto fnVar = getUnusedName("_fn_"sv);
2951 {
2952 auto value = x->new_ptr<Value_t>();
2953 value->item.set(baseChain);
2954 auto exp = newExp(value, x);
2955 auto assign = x->new_ptr<Assign_t>();
2956 assign->values.push_back(exp);
2957 auto assignment = x->new_ptr<ExpListAssign_t>();
2958 assignment->expList.set(toAst<ExpList_t>(baseVar, x));
2959 assignment->action.set(assign);
2960 transformAssignment(assignment, temp);
2961 }
2962 {
2963 auto assign = x->new_ptr<Assign_t>();
2964 assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, x));
2965 auto assignment = x->new_ptr<ExpListAssign_t>();
2966 assignment->expList.set(toAst<ExpList_t>(fnVar, x));
2967 assignment->action.set(assign);
2968 transformAssignment(assignment, temp);
2969 }
2970 auto funLit = toAst<Exp_t>(fnVar + s(" and (...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), x);
2971 switch (usage) {
2972 case ExpUsage::Closure:
2973 case ExpUsage::Return: {
2974 auto returnNode = x->new_ptr<Return_t>();
2975 auto expListLow = x->new_ptr<ExpListLow_t>();
2976 expListLow->exprs.push_back(funLit);
2977 returnNode->valueList.set(expListLow);
2978 transformReturn(returnNode, temp);
2979 break;
2980 }
2981 case ExpUsage::Assignment: {
2982 auto assign = x->new_ptr<Assign_t>();
2983 assign->values.push_back(funLit);
2984 auto assignment = x->new_ptr<ExpListAssign_t>();
2985 assignment->expList.set(assignList);
2986 assignment->action.set(assign);
2987 transformAssignment(assignment, temp);
2988 break;
2989 }
2990 default:
2991 break;
2992 }
2993 switch (usage) {
2994 case ExpUsage::Assignment:
2995 popScope();
2996 temp.push_back(indent() + s("end"sv) + nlr(x));
2997 break;
2998 case ExpUsage::Closure:
2999 _enableReturn.pop();
3000 popScope();
3001 temp.push_back(indent() + s("end)()"sv));
3002 break;
3003 default:
3004 break;
3005 }
3006 out.push_back(join(temp));
3007 return true;
3008 }
3009 return false;
3010 }
3011
3012 void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3013 auto x = chainList.front();
3014 str_list temp;
3015 switch (x->getId()) {
3016 case id<DotChainItem_t>():
3017 case id<ColonChainItem_t>():
3018 if (_withVars.empty()) {
3019 throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x));
3020 } else {
3021 temp.push_back(_withVars.top());
3022 }
3023 break;
3024 }
3025 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
3026 auto item = *it;
3027 switch (item->getId()) {
3028 case id<Invoke_t>():
3029 transformInvoke(static_cast<Invoke_t*>(item), temp);
3030 break;
3031 case id<DotChainItem_t>():
3032 transformDotChainItem(static_cast<DotChainItem_t*>(item), temp);
3033 break;
3034 case id<ColonChainItem_t>(): {
3035 auto colonItem = static_cast<ColonChainItem_t*>(item);
3036 auto current = it;
3037 auto next = current; ++next;
3038 auto followItem = next != chainList.end() ? *next : nullptr;
3039 if (current != chainList.begin()) {
3040 --current;
3041 if (!ast_is<existential_op_t>(*current)) {
3042 ++current;
3043 }
3044 }
3045 if (ast_is<existential_op_t>(followItem)) {
3046 ++next;
3047 followItem = next != chainList.end() ? *next : nullptr;
3048 --next;
3049 }
3050 if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
3051 throw std::logic_error(_info.errorMessage("colon chain item must be followed by invoke arguments"sv, colonItem));
3052 }
3053 if (colonItem->name.is<LuaKeyword_t>()) {
3054 std::string callVar;
3055 auto block = x->new_ptr<Block_t>();
3056 {
3057 auto chainValue = x->new_ptr<ChainValue_t>();
3058 switch (chainList.front()->getId()) {
3059 case id<DotChainItem_t>():
3060 case id<ColonChainItem_t>():
3061 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x));
3062 break;
3063 }
3064 for (auto i = chainList.begin(); i != current; ++i) {
3065 chainValue->items.push_back(*i);
3066 }
3067 auto value = x->new_ptr<Value_t>();
3068 value->item.set(chainValue);
3069 auto exp = newExp(value, x);
3070 callVar = singleVariableFrom(exp);
3071 if (callVar.empty()) {
3072 callVar = getUnusedName(s("_call_"sv));
3073 auto assignment = x->new_ptr<ExpListAssign_t>();
3074 assignment->expList.set(toAst<ExpList_t>(callVar, x));
3075 auto assign = x->new_ptr<Assign_t>();
3076 assign->values.push_back(exp);
3077 assignment->action.set(assign);
3078 auto stmt = x->new_ptr<Statement_t>();
3079 stmt->content.set(assignment);
3080 block->statements.push_back(stmt);
3081 }
3082 }
3083 ast_ptr<false, Exp_t> nexp;
3084 {
3085 auto name = _parser.toString(colonItem->name);
3086 auto chainValue = x->new_ptr<ChainValue_t>();
3087 chainValue->items.push_back(toAst<Callable_t>(callVar, x));
3088 if (ast_is<existential_op_t>(*current)) {
3089 chainValue->items.push_back(x->new_ptr<existential_op_t>());
3090 }
3091 chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), x));
3092 if (auto invoke = ast_cast<Invoke_t>(followItem)) {
3093 invoke->args.push_front(toAst<Exp_t>(callVar, x));
3094 } else {
3095 auto invokeArgs = static_cast<InvokeArgs_t*>(followItem);
3096 invokeArgs->args.push_front(toAst<Exp_t>(callVar, x));
3097 }
3098 for (auto i = next; i != chainList.end(); ++i) {
3099 chainValue->items.push_back(*i);
3100 }
3101 auto value = x->new_ptr<Value_t>();
3102 value->item.set(chainValue);
3103 nexp = newExp(value, x);
3104 auto expList = x->new_ptr<ExpList_t>();
3105 expList->exprs.push_back(nexp);
3106 auto expListAssign = x->new_ptr<ExpListAssign_t>();
3107 expListAssign->expList.set(expList);
3108 auto stmt = x->new_ptr<Statement_t>();
3109 stmt->content.set(expListAssign);
3110 block->statements.push_back(stmt);
3111 }
3112 switch (usage) {
3113 case ExpUsage::Common:
3114 case ExpUsage::Return:
3115 transformBlock(block, out, usage);
3116 return;
3117 case ExpUsage::Assignment: {
3118 transformBlock(block, out, ExpUsage::Assignment, assignList);
3119 return;
3120 }
3121 default:
3122 break;
3123 }
3124 if (block->statements.size() == 1) {
3125 transformExp(nexp, out, usage, assignList);
3126 } else {
3127 auto body = x->new_ptr<Body_t>();
3128 body->content.set(block);
3129 auto funLit = toAst<FunLit_t>("->"sv, x);
3130 funLit->body.set(body);
3131 auto simpleValue = x->new_ptr<SimpleValue_t>();
3132 simpleValue->value.set(funLit);
3133 auto value = x->new_ptr<Value_t>();
3134 value->item.set(simpleValue);
3135 auto exp = newExp(value, x);
3136 auto paren = x->new_ptr<Parens_t>();
3137 paren->expr.set(exp);
3138 auto callable = x->new_ptr<Callable_t>();
3139 callable->item.set(paren);
3140 auto chainValue = x->new_ptr<ChainValue_t>();
3141 chainValue->items.push_back(callable);
3142 auto invoke = x->new_ptr<Invoke_t>();
3143 chainValue->items.push_back(invoke);
3144 transformChainValue(chainValue, out, ExpUsage::Closure);
3145 }
3146 return;
3147 }
3148 transformColonChainItem(colonItem, temp);
3149 break;
3150 }
3151 case id<Slice_t>():
3152 transformSlice(static_cast<Slice_t*>(item), temp);
3153 break;
3154 case id<Callable_t>(): {
3155 auto next = it; ++next;
3156 auto followItem = next != chainList.end() ? *next : nullptr;
3157 ast_sel<false, Invoke_t, InvokeArgs_t> invoke;
3158 if (ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
3159 invoke.set(followItem);
3160 }
3161 transformCallable(static_cast<Callable_t*>(item), temp, invoke);
3162 break;
3163 }
3164 case id<String_t>():
3165 transformString(static_cast<String_t*>(item), temp);
3166 temp.back() = s("("sv) + temp.back() + s(")"sv);
3167 break;
3168 case id<Exp_t>():
3169 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3170 temp.back() = s(temp.back().front() == '[' ? "[ "sv : "["sv) + temp.back() + s("]"sv);
3171 break;
3172 case id<InvokeArgs_t>(): transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break;
3173 default: assert(false); break;
3174 }
3175 }
3176 switch (usage) {
3177 case ExpUsage::Common:
3178 out.push_back(indent() + join(temp) + nll(chainList.front()));
3179 break;
3180 case ExpUsage::Return:
3181 out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front()));
3182 break;
3183 case ExpUsage::Assignment: assert(false); break;
3184 default:
3185 out.push_back(join(temp));
3186 break;
3187 }
3188 }
3189
3190#ifndef MOONP_NO_MACRO
3191 std::tuple<std::string,std::string,str_list> expandMacroStr(ChainValue_t* chainValue) {
3192 const auto& chainList = chainValue->items.objects();
3193 auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>();
3194 auto macroName = x->name ? _parser.toString(x->name) : Empty;
3195 if (!macroName.empty() && !_useModule) {
3196 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3197 }
3198 pushCurrentModule(); // cur
3199 int top = lua_gettop(L) - 1;
3200 DEFER(lua_settop(L, top));
3201 if (macroName.empty()) {
3202 lua_pop(L, 1); // empty
3203 auto item = *(++chainList.begin());
3204 const node_container* args = nullptr;
3205 if (auto invoke = ast_cast<Invoke_t>(item)) {
3206 args = &invoke->args.objects();
3207 } else {
3208 args = &ast_to<InvokeArgs_t>(item)->args.objects();
3209 }
3210 if (args->size() != 1) {
3211 throw std::logic_error(_info.errorMessage("in-place macro must be followed by a compile time function"sv, x));
3212 }
3213 auto fcodes = _parser.toString(args->back());
3214 Utils::trim(fcodes);
3215 pushMoonp("loadstring"sv); // loadstring
3216 lua_pushlstring(L, fcodes.c_str(), fcodes.size()); // loadstring codes
3217 lua_pushliteral(L, "=(macro in-place)"); // loadstring codes chunk
3218 pushOptions(args->back()->m_begin.m_line - 1); // loadstring codes chunk options
3219 if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), f err
3220 std::string err = lua_tostring(L, -1);
3221 throw std::logic_error(_info.errorMessage(s("failed to load macro codes\n"sv) + err, x));
3222 } // f err
3223 if (lua_isnil(L, -2) != 0) { // f == nil, f err
3224 std::string err = lua_tostring(L, -1);
3225 throw std::logic_error(_info.errorMessage(s("failed to load macro codes, at (macro in-place): "sv) + err, x));
3226 }
3227 lua_pop(L, 1); // f
3228 pushMoonp("pcall"sv); // f pcall
3229 lua_insert(L, -2); // pcall f
3230 if (lua_pcall(L, 1, 2, 0) != 0) { // f(), success macroFunc
3231 std::string err = lua_tostring(L, -1);
3232 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, x));
3233 } // success res
3234 if (lua_toboolean(L, -2) == 0) {
3235 std::string err = lua_tostring(L, -1);
3236 throw std::logic_error(_info.errorMessage(s("failed to generate macro function\n"sv) + err, x));
3237 } // true macroFunc
3238 lua_remove(L, -2); // macroFunc
3239 pushMoonp("pcall"sv); // macroFunc pcall
3240 lua_insert(L, -2); // pcall macroFunc
3241 bool success = lua_pcall(L, 1, 2, 0) == 0;
3242 if (!success) { // err
3243 std::string err = lua_tostring(L, -1);
3244 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3245 } // success err
3246 if (lua_toboolean(L, -2) == 0) {
3247 std::string err = lua_tostring(L, -1);
3248 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3249 }
3250 return {Empty, Empty, {}};
3251 }
3252 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName
3253 lua_rawget(L, -2); // cur[macroName], cur macroFunc
3254 if (lua_isfunction(L, -1) == 0) {
3255 throw std::logic_error(_info.errorMessage("can not resolve macro"sv, x));
3256 } // cur macroFunc
3257 pushMoonp("pcall"sv); // cur macroFunc pcall
3258 lua_insert(L, -2); // cur pcall macroFunc
3259 auto item = *(++chainList.begin());
3260 const node_container* args = nullptr;
3261 if (auto invoke = ast_cast<Invoke_t>(item)) {
3262 args = &invoke->args.objects();
3263 } else {
3264 args = &ast_to<InvokeArgs_t>(item)->args.objects();
3265 }
3266 for (auto arg : *args) {
3267 std::string str;
3268 // check whether arg is reassembled
3269 // do some workaround for backcall expression
3270 if (ast_is<Exp_t>(arg) && arg->m_begin.m_it == arg->m_end.m_it) {
3271 auto exp = static_cast<Exp_t*>(arg);
3272 BLOCK_START
3273 BREAK_IF(!exp->opValues.empty());
3274 auto chainValue = exp->getByPath<unary_exp_t, Value_t, ChainValue_t>();
3275 BREAK_IF(!chainValue);
3276 BREAK_IF(!isMacroChain(chainValue));
3277 BREAK_IF(chainValue->items.size() != 2);
3278 str = std::get<1>(expandMacroStr(chainValue));
3279 BLOCK_END
3280 if (str.empty()) {
3281 // exp is reassembled due to backcall expressions
3282 // in transform stage, toString(exp) won't be able
3283 // to convert its whole text content
3284 str = _parser.toString(exp->backcalls.front());
3285 }
3286 } else if (auto lstr = ast_cast<LuaString_t>(arg)) {
3287 str = _parser.toString(lstr->content);
3288 } else {
3289 bool multiLineStr = false;
3290 BLOCK_START
3291 auto exp = ast_cast<Exp_t>(arg);
3292 BREAK_IF(!exp);
3293 auto value = singleValueFrom(exp);
3294 BREAK_IF(!value);
3295 auto lstr = value->getByPath<String_t, LuaString_t>();
3296 BREAK_IF(!lstr);
3297 str = _parser.toString(lstr->content);
3298 multiLineStr = true;
3299 BLOCK_END
3300 if (!multiLineStr) {
3301 str = _parser.toString(arg);
3302 }
3303 }
3304 Utils::trim(str);
3305 Utils::replace(str, "\r\n"sv, "\n"sv);
3306 lua_pushlstring(L, str.c_str(), str.size());
3307 } // cur pcall macroFunc args...
3308 bool success = lua_pcall(L, static_cast<int>(args->size()) + 1, 2, 0) == 0;
3309 if (!success) { // cur err
3310 std::string err = lua_tostring(L, -1);
3311 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3312 } // cur success res
3313 if (lua_toboolean(L, -2) == 0) {
3314 std::string err = lua_tostring(L, -2);
3315 throw std::logic_error(_info.errorMessage(s("failed to expand macro: "sv) + err, x));
3316 }
3317 lua_remove(L, -2); // cur res
3318 if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) {
3319 throw std::logic_error(_info.errorMessage(s("macro function must return string or table"sv), x));
3320 } // cur res
3321 std::string codes;
3322 std::string type;
3323 str_list localVars;
3324 if (lua_istable(L, -1) != 0) {
3325 lua_getfield(L, -1, "codes"); // cur res codes
3326 if (lua_isstring(L, -1) != 0) {
3327 codes = lua_tostring(L, -1);
3328 } else {
3329 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"codes\" of string"sv), x));
3330 }
3331 lua_pop(L, 1); // cur res
3332 lua_getfield(L, -1, "type"); // cur res type
3333 if (lua_isstring(L, -1) != 0) {
3334 type = lua_tostring(L, -1);
3335 }
3336 if (type != "lua"sv && type != "text"sv) {
3337 throw std::logic_error(_info.errorMessage(s("macro table must contain field \"type\" of value \"lua\" or \"text\""sv), x));
3338 }
3339 lua_pop(L, 1); // cur res
3340 lua_getfield(L, -1, "locals"); // cur res locals
3341 if (lua_istable(L, -1) != 0) {
3342 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) {
3343 lua_rawgeti(L, -1, i + 1); // cur res locals item
3344 size_t len = 0;
3345 if (lua_isstring(L, -1) == 0) {
3346 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must be a table of strings"sv), x));
3347 }
3348 auto name = lua_tolstring(L, -1, &len);
3349 if (_parser.match<Variable_t>({name, len})) {
3350 localVars.push_back(std::string(name, len));
3351 } else {
3352 throw std::logic_error(_info.errorMessage(s("macro table field \"locals\" must contain names for local variables, got \""sv) + std::string(name, len) + '"', x));
3353 }
3354 lua_pop(L, 1);
3355 }
3356 }
3357 lua_pop(L, 1); // cur res
3358 } else {
3359 codes = lua_tostring(L, -1);
3360 }
3361 return {type, codes, std::move(localVars)};
3362 }
3363
3364 std::tuple<ast_ptr<false,ast_node>, std::unique_ptr<input>, std::string, str_list> expandMacro(ChainValue_t* chainValue, ExpUsage usage, bool allowBlockMacroReturn) {
3365 auto x = ast_to<Callable_t>(chainValue->items.front())->item.to<MacroName_t>();
3366 const auto& chainList = chainValue->items.objects();
3367 std::string type, codes;
3368 str_list localVars;
3369 std::tie(type, codes, localVars) = expandMacroStr(chainValue);
3370 bool isBlock = (usage == ExpUsage::Common) && (chainList.size() <= 2);
3371 ParseInfo info;
3372 if (type == "lua"sv) {
3373 if (!isBlock) {
3374 throw std::logic_error(_info.errorMessage("lua macro can only be placed where block macro is allowed"sv, x));
3375 }
3376 auto macroChunk = s("=(macro "sv) + _parser.toString(x->name) + ')';
3377 int top = lua_gettop(L);
3378 DEFER(lua_settop(L, top));
3379 if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) {
3380 std::string err = lua_tostring(L, -1);
3381 throw std::logic_error(_info.errorMessage(err, x));
3382 }
3383 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3384 } else if (type == "text"sv) {
3385 if (!isBlock) {
3386 throw std::logic_error(_info.errorMessage("text macro can only be placed where block macro is allowed"sv, x));
3387 }
3388 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
3389 } else {
3390 if (!codes.empty()) {
3391 if (isBlock) {
3392 info = _parser.parse<Block_t>(codes);
3393 if (!info.node) {
3394 info.error = info.error.substr(info.error.find(':') + 2);
3395 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as block: "sv) + info.error, x));
3396 }
3397 } else {
3398 info = _parser.parse<Exp_t>(codes);
3399 if (!info.node && allowBlockMacroReturn) {
3400 info = _parser.parse<Block_t>(codes);
3401 if (!info.node) {
3402 info.error = info.error.substr(info.error.find(':') + 2);
3403 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr or block: "sv) + info.error, x));
3404 }
3405 isBlock = true;
3406 } else if (!info.node) {
3407 info.error = info.error.substr(info.error.find(':') + 2);
3408 throw std::logic_error(_info.errorMessage(s("failed to expanded macro as expr: "sv) + info.error, x));
3409 }
3410 }
3411 int line = x->m_begin.m_line;
3412 int col = x->m_begin.m_col;
3413 info.node->traverse([&](ast_node* node) {
3414 node->m_begin.m_line = line;
3415 node->m_end.m_line = line;
3416 node->m_begin.m_col = col;
3417 node->m_end.m_col = col;
3418 return traversal::Continue;
3419 });
3420 if (!isBlock) {
3421 ast_ptr<false, Exp_t> exp;
3422 exp.set(info.node);
3423 if (!exp->opValues.empty() || chainList.size() > 2) {
3424 auto paren = x->new_ptr<Parens_t>();
3425 paren->expr.set(exp);
3426 auto callable = x->new_ptr<Callable_t>();
3427 callable->item.set(paren);
3428 auto newChain = x->new_ptr<ChainValue_t>();
3429 newChain->items.push_back(callable);
3430 auto it = chainList.begin();
3431 it++; it++;
3432 for (; it != chainList.end(); ++it) {
3433 newChain->items.push_back(*it);
3434 }
3435 auto value = x->new_ptr<Value_t>();
3436 value->item.set(newChain);
3437 exp = newExp(value, x);
3438 }
3439 if (usage == ExpUsage::Common) {
3440 auto expList = x->new_ptr<ExpList_t>();
3441 expList->exprs.push_back(exp);
3442 auto exps = x->new_ptr<ExpListAssign_t>();
3443 exps->expList.set(expList);
3444 auto stmt = x->new_ptr<Statement_t>();
3445 stmt->content.set(exps);
3446 auto block = x->new_ptr<Block_t>();
3447 block->statements.push_back(stmt);
3448 info.node.set(block);
3449 } else {
3450 info.node.set(exp);
3451 }
3452 }
3453 return {info.node, std::move(info.codes), Empty, std::move(localVars)};
3454 } else {
3455 if (!isBlock) throw std::logic_error(_info.errorMessage(s("failed to expanded empty macro as expr"sv), x));
3456 return {x->new_ptr<Block_t>().get(), std::move(info.codes), Empty, std::move(localVars)};
3457 }
3458 }
3459 }
3460#endif // MOONP_NO_MACRO
3461
3462 void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) {
3463 if (isMacroChain(chainValue)) {
3464#ifndef MOONP_NO_MACRO
3465 ast_ptr<false,ast_node> node;
3466 std::unique_ptr<input> codes;
3467 std::string luaCodes;
3468 str_list localVars;
3469 std::tie(node, codes, luaCodes, localVars) = expandMacro(chainValue, usage, allowBlockMacroReturn);
3470 Utils::replace(luaCodes, "\r\n"sv, "\n"sv);
3471 Utils::trim(luaCodes);
3472 if (!node) {
3473 if (!luaCodes.empty()) {
3474 if (_config.reserveLineNumber) {
3475 luaCodes.insert(0, nll(chainValue).substr(1));
3476 }
3477 luaCodes.append(nlr(chainValue));
3478 }
3479 out.push_back(luaCodes);
3480 if (!localVars.empty()) {
3481 for (const auto& var : localVars) {
3482 addToScope(var);
3483 }
3484 }
3485 return;
3486 }
3487 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
3488 transformBlock(node.to<Block_t>(), out, usage, assignList);
3489 } else {
3490 auto x = chainValue;
3491 switch (usage) {
3492 case ExpUsage::Assignment: {
3493 auto assign = x->new_ptr<Assign_t>();
3494 assign->values.push_back(node);
3495 auto assignment = x->new_ptr<ExpListAssign_t>();
3496 assignment->expList.set(assignList);
3497 assignment->action.set(assign);
3498 transformAssignment(assignment, out);
3499 break;
3500 }
3501 case ExpUsage::Return: {
3502 auto expListLow = x->new_ptr<ExpListLow_t>();
3503 expListLow->exprs.push_back(node);
3504 auto returnNode = x->new_ptr<Return_t>();
3505 returnNode->valueList.set(expListLow);
3506 transformReturn(returnNode, out);
3507 break;
3508 }
3509 default:
3510 transformExp(node.to<Exp_t>(), out, usage);
3511 break;
3512 }
3513 }
3514 return;
3515#else
3516 (void)allowBlockMacroReturn;
3517 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, chainValue));
3518#endif // MOONP_NO_MACRO
3519 }
3520 const auto& chainList = chainValue->items.objects();
3521 if (transformChainEndWithEOP(chainList, out, usage, assignList)) {
3522 return;
3523 }
3524 if (transformChainWithEOP(chainList, out, usage, assignList)) {
3525 return;
3526 }
3527 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
3528 return;
3529 }
3530 transformChainList(chainList, out, usage, assignList);
3531 }
3532
3533 void transformAssignableChain(AssignableChain_t* chain, str_list& out) {
3534 transformChainList(chain->items.objects(), out, ExpUsage::Closure);
3535 }
3536
3537 void transformDotChainItem(DotChainItem_t* dotChainItem, str_list& out) {
3538 auto name = _parser.toString(dotChainItem->name);
3539 if (Keywords.find(name) != Keywords.end()) {
3540 out.push_back(s("[\""sv) + name + s("\"]"sv));
3541 } else {
3542 out.push_back(s("."sv) + name);
3543 }
3544 }
3545
3546 void transformColonChainItem(ColonChainItem_t* colonChainItem, str_list& out) {
3547 auto name = _parser.toString(colonChainItem->name);
3548 out.push_back(s(colonChainItem->switchToDot ? "."sv : ":"sv) + name);
3549 }
3550
3551 void transformSlice(Slice_t* slice, str_list&) {
3552 throw std::logic_error(_info.errorMessage("slice syntax not supported here"sv, slice));
3553 }
3554
3555 void transformInvoke(Invoke_t* invoke, str_list& out) {
3556 str_list temp;
3557 for (auto arg : invoke->args.objects()) {
3558 switch (arg->getId()) {
3559 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(arg), temp, ExpUsage::Closure); break;
3560 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(arg), temp); break;
3561 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(arg), temp); break;
3562 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(arg), temp); break;
3563 case id<TableLit_t>(): transformTableLit(static_cast<TableLit_t*>(arg), temp); break;
3564 default: assert(false); break;
3565 }
3566 }
3567 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
3568 }
3569
3570 void transform_unary_value(unary_value_t* unary_value, str_list& out) {
3571 str_list temp;
3572 for (auto _op : unary_value->ops.objects()) {
3573 std::string op = _parser.toString(_op);
3574 temp.push_back(op + (op == "not"sv ? s(" "sv) : Empty));
3575 }
3576 transformValue(unary_value->value, temp);
3577 out.push_back(join(temp));
3578 }
3579
3580 void transform_unary_exp(unary_exp_t* unary_exp, str_list& out) {
3581 if (unary_exp->ops.empty() && unary_exp->expos.size() == 1) {
3582 transformValue(static_cast<Value_t*>(unary_exp->expos.back()), out);
3583 return;
3584 }
3585 std::string unary_op;
3586 for (auto _op : unary_exp->ops.objects()) {
3587 std::string op = _parser.toString(_op);
3588 unary_op.append(op + (op == "not"sv ? s(" "sv) : Empty));
3589 }
3590 str_list temp;
3591 for (auto _value : unary_exp->expos.objects()) {
3592 auto value = static_cast<Value_t*>(_value);
3593 transformValue(value, temp);
3594 }
3595 out.push_back(unary_op + join(temp, " ^ "sv));
3596 }
3597
3598 void transformVariable(Variable_t* name, str_list& out) {
3599 out.push_back(_parser.toString(name));
3600 }
3601
3602 void transformNum(Num_t* num, str_list& out) {
3603 out.push_back(_parser.toString(num));
3604 }
3605
3606 void transformTableLit(TableLit_t* table, str_list& out) {
3607 transformTable(table, table->values.objects(), out);
3608 }
3609
3610 void transformCompCommon(Comprehension_t* comp, str_list& out) {
3611 str_list temp;
3612 auto x = comp;
3613 auto compInner = comp->forLoop.get();
3614 for (auto item : compInner->items.objects()) {
3615 switch (item->getId()) {
3616 case id<CompForEach_t>():
3617 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3618 break;
3619 case id<CompFor_t>():
3620 transformCompFor(static_cast<CompFor_t*>(item), temp);
3621 break;
3622 case id<Exp_t>():
3623 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3624 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3625 pushScope();
3626 break;
3627 default: assert(false); break;
3628 }
3629 }
3630 if (auto stmt = comp->value.as<Statement_t>()) {
3631 transformStatement(stmt, temp);
3632 } else if (auto exp = comp->value.as<Exp_t>()) {
3633 auto expList = x->new_ptr<ExpList_t>();
3634 expList->exprs.push_back(exp);
3635 auto expListAssign = x->new_ptr<ExpListAssign_t>();
3636 expListAssign->expList.set(expList);
3637 auto statement = x->new_ptr<Statement_t>();
3638 statement->content.set(expListAssign);
3639 transformStatement(statement, temp);
3640 }
3641 auto value = temp.back();
3642 temp.pop_back();
3643 _buf << join(temp) << value;
3644 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3645 popScope();
3646 _buf << indent() << "end"sv << nll(comp);
3647 }
3648 out.push_back(clearBuf());
3649 }
3650
3651 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3652 auto x = comp;
3653 switch (usage) {
3654 case ExpUsage::Closure:
3655 _enableReturn.push(true);
3656 pushScope();
3657 break;
3658 case ExpUsage::Assignment:
3659 pushScope();
3660 break;
3661 default:
3662 break;
3663 }
3664 str_list temp;
3665 std::string accumVar = getUnusedName("_accum_"sv);
3666 std::string lenVar = getUnusedName("_len_"sv);
3667 addToScope(accumVar);
3668 addToScope(lenVar);
3669 auto compInner = comp->forLoop.get();
3670 for (auto item : compInner->items.objects()) {
3671 switch (item->getId()) {
3672 case id<CompForEach_t>():
3673 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3674 break;
3675 case id<CompFor_t>():
3676 transformCompFor(static_cast<CompFor_t*>(item), temp);
3677 break;
3678 case id<Exp_t>():
3679 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
3680 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3681 pushScope();
3682 break;
3683 default: assert(false); break;
3684 }
3685 }
3686 {
3687 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
3688 auto assign = x->new_ptr<Assign_t>();
3689 assign->values.push_back(comp->value);
3690 auto assignment = x->new_ptr<ExpListAssign_t>();
3691 assignment->expList.set(assignLeft);
3692 assignment->action.set(assign);
3693 transformAssignment(assignment, temp);
3694 }
3695 auto assignStr = temp.back();
3696 temp.pop_back();
3697 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3698 popScope();
3699 }
3700 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp);
3701 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp);
3702 _buf << join(temp);
3703 _buf << assignStr;
3704 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp);
3705 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
3706 _buf << indent(ind) << "end"sv << nll(comp);
3707 }
3708 switch (usage) {
3709 case ExpUsage::Common:
3710 break;
3711 case ExpUsage::Closure: {
3712 _enableReturn.pop();
3713 out.push_back(clearBuf());
3714 out.back().append(indent() + s("return "sv) + accumVar + nlr(comp));
3715 popScope();
3716 out.back().insert(0, s("(function()"sv) + nll(comp));
3717 out.back().append(indent() + s("end)()"sv));
3718 break;
3719 }
3720 case ExpUsage::Assignment: {
3721 out.push_back(clearBuf());
3722 auto assign = x->new_ptr<Assign_t>();
3723 assign->values.push_back(toAst<Exp_t>(accumVar, x));
3724 auto assignment = x->new_ptr<ExpListAssign_t>();
3725 assignment->expList.set(assignList);
3726 assignment->action.set(assign);
3727 transformAssignment(assignment, temp);
3728 popScope();
3729 out.back() = indent() + s("do"sv) + nll(comp) +
3730 out.back() + temp.back() +
3731 indent() + s("end"sv) + nlr(comp);
3732 break;
3733 }
3734 case ExpUsage::Return:
3735 out.push_back(clearBuf());
3736 out.back().append(indent() + s("return "sv) + accumVar + nlr(comp));
3737 break;
3738 default:
3739 break;
3740 }
3741 }
3742
3743 void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) {
3744 auto x = nameList;
3745 str_list temp;
3746 str_list vars;
3747 str_list varBefore, varAfter;
3748 std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs;
3749 for (auto _item : nameList->items.objects()) {
3750 auto item = static_cast<NameOrDestructure_t*>(_item)->item.get();
3751 switch (item->getId()) {
3752 case id<Variable_t>():
3753 transformVariable(static_cast<Variable_t*>(item), vars);
3754 varAfter.push_back(vars.back());
3755 break;
3756 case id<TableLit_t>(): {
3757 auto desVar = getUnusedName("_des_"sv);
3758 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
3759 vars.push_back(desVar);
3760 varAfter.push_back(desVar);
3761 break;
3762 }
3763 default: assert(false); break;
3764 }
3765 }
3766 switch (loopTarget->getId()) {
3767 case id<star_exp_t>(): {
3768 auto star_exp = static_cast<star_exp_t*>(loopTarget);
3769 auto listVar = singleVariableFrom(star_exp->value);
3770 auto indexVar = getUnusedName("_index_"sv);
3771 varAfter.push_back(indexVar);
3772 auto value = singleValueFrom(star_exp->value);
3773 if (!value) throw std::logic_error(_info.errorMessage("invalid star syntax"sv, star_exp));
3774 bool endWithSlice = false;
3775 BLOCK_START
3776 auto chainValue = value->item.as<ChainValue_t>();
3777 BREAK_IF(!chainValue);
3778 auto chainList = chainValue->items.objects();
3779 auto slice = ast_cast<Slice_t>(chainList.back());
3780 BREAK_IF(!slice);
3781 endWithSlice = true;
3782 if (listVar.empty() && chainList.size() == 2 &&
3783 ast_is<Callable_t>(chainList.front())) {
3784 transformCallable(static_cast<Callable_t*>(chainList.front()), temp);
3785 listVar = temp.back();
3786 temp.pop_back();
3787 }
3788 chainList.pop_back();
3789 auto chain = x->new_ptr<ChainValue_t>();
3790 for (auto item : chainList) {
3791 chain->items.push_back(item);
3792 }
3793 std::string startValue("1"sv);
3794 if (auto exp = slice->startValue.as<Exp_t>()) {
3795 transformExp(exp, temp, ExpUsage::Closure);
3796 startValue = temp.back();
3797 temp.pop_back();
3798 }
3799 std::string stopValue;
3800 if (auto exp = slice->stopValue.as<Exp_t>()) {
3801 transformExp(exp, temp, ExpUsage::Closure);
3802 stopValue = temp.back();
3803 temp.pop_back();
3804 }
3805 std::string stepValue;
3806 if (auto exp = slice->stepValue.as<Exp_t>()) {
3807 transformExp(exp, temp, ExpUsage::Closure);
3808 stepValue = temp.back();
3809 temp.pop_back();
3810 }
3811 if (listVar.empty()) {
3812 listVar = getUnusedName("_list_"sv);
3813 varBefore.push_back(listVar);
3814 transformChainValue(chain, temp, ExpUsage::Closure);
3815 _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
3816 }
3817 std::string maxVar;
3818 if (!stopValue.empty()) {
3819 maxVar = getUnusedName("_max_"sv);
3820 varBefore.push_back(maxVar);
3821 _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
3822 }
3823 _buf << indent() << "for "sv << indexVar << " = "sv;
3824 _buf << startValue << ", "sv;
3825 if (stopValue.empty()) {
3826 _buf << "#"sv << listVar;
3827 } else {
3828 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar;
3829 }
3830 if (!stepValue.empty()) {
3831 _buf << ", "sv << stepValue;
3832 }
3833 _buf << " do"sv << nlr(loopTarget);
3834 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
3835 out.push_back(clearBuf());
3836 BLOCK_END
3837 bool newListVal = false;
3838 if (listVar.empty()) {
3839 newListVal = true;
3840 listVar = getUnusedName("_list_"sv);
3841 varBefore.push_back(listVar);
3842 }
3843 if (!endWithSlice) {
3844 transformExp(star_exp->value, temp, ExpUsage::Closure);
3845 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
3846 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget);
3847 _buf << indent(1) << "local "sv << join(vars) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
3848 out.push_back(clearBuf());
3849 }
3850 break;
3851 }
3852 case id<Exp_t>():
3853 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
3854 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
3855 out.push_back(clearBuf());
3856 break;
3857 case id<ExpList_t>():
3858 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
3859 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
3860 out.push_back(clearBuf());
3861 break;
3862 default: assert(false); break;
3863 }
3864 for (auto& var : varBefore) addToScope(var);
3865 pushScope();
3866 for (auto& var : varAfter) addToScope(var);
3867 if (!destructPairs.empty()) {
3868 temp.clear();
3869 for (auto& pair : destructPairs) {
3870 auto sValue = x->new_ptr<SimpleValue_t>();
3871 sValue->value.set(pair.first);
3872 auto value = x->new_ptr<Value_t>();
3873 value->item.set(sValue);
3874 auto exp = newExp(value, x);
3875 auto expList = x->new_ptr<ExpList_t>();
3876 expList->exprs.push_back(exp);
3877 auto assign = x->new_ptr<Assign_t>();
3878 assign->values.push_back(pair.second);
3879 auto assignment = x->new_ptr<ExpListAssign_t>();
3880 assignment->expList.set(expList);
3881 assignment->action.set(assign);
3882 transformAssignment(assignment, temp);
3883 }
3884 out.back().append(join(temp));
3885 }
3886 }
3887
3888 void transformCompForEach(CompForEach_t* comp, str_list& out) {
3889 transformForEachHead(comp->nameList, comp->loopValue, out);
3890 }
3891
3892 void transformInvokeArgs(InvokeArgs_t* invokeArgs, str_list& out) {
3893 if (invokeArgs->args.size() > 1) {
3894 /* merge all the key-value pairs into one table
3895 from arguments in the end */
3896 auto lastArg = invokeArgs->args.back();
3897 _ast_list* lastTable = nullptr;
3898 if (auto tableBlock = ast_cast<TableBlock_t>(lastArg)) {
3899 lastTable = &tableBlock->values;
3900 } else if (auto value = singleValueFrom(lastArg)) {
3901 if (auto simpleTable = ast_cast<simple_table_t>(value->item)) {
3902 lastTable = &simpleTable->pairs;
3903 }
3904 }
3905 if (lastTable) {
3906 ast_ptr<false, ast_node> ref(lastArg);
3907 invokeArgs->args.pop_back();
3908 while (!invokeArgs->args.empty()) {
3909 if (Value_t* value = singleValueFrom(invokeArgs->args.back())) {
3910 if (auto tb = value->item.as<simple_table_t>()) {
3911 const auto& ps = tb->pairs.objects();
3912 for (auto it = ps.rbegin(); it != ps.rend(); ++it) {
3913 lastTable->push_front(*it);
3914 }
3915 invokeArgs->args.pop_back();
3916 continue;
3917 }
3918 }
3919 break;
3920 }
3921 invokeArgs->args.push_back(lastArg);
3922 }
3923 }
3924 str_list temp;
3925 for (auto arg : invokeArgs->args.objects()) {
3926 switch (arg->getId()) {
3927 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(arg), temp, ExpUsage::Closure); break;
3928 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(arg), temp); break;
3929 default: assert(false); break;
3930 }
3931 }
3932 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
3933 }
3934
3935 void transformForHead(For_t* forNode, str_list& out) {
3936 str_list temp;
3937 std::string varName = _parser.toString(forNode->varName);
3938 transformExp(forNode->startValue, temp, ExpUsage::Closure);
3939 transformExp(forNode->stopValue, temp, ExpUsage::Closure);
3940 if (forNode->stepValue) {
3941 transformExp(forNode->stepValue->value, temp, ExpUsage::Closure);
3942 } else {
3943 temp.emplace_back();
3944 }
3945 auto it = temp.begin();
3946 const auto& start = *it;
3947 const auto& stop = *(++it);
3948 const auto& step = *(++it);
3949 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(forNode);
3950 pushScope();
3951 addToScope(varName);
3952 out.push_back(clearBuf());
3953 }
3954
3955 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3956 switch (body->getId()) {
3957 case id<Block_t>():
3958 transformBlock(static_cast<Block_t*>(body), out, usage, assignList);
3959 break;
3960 case id<Statement_t>(): {
3961 auto newBlock = body->new_ptr<Block_t>();
3962 newBlock->statements.push_back(body);
3963 transformBlock(newBlock, out, usage, assignList);
3964 break;
3965 }
3966 default: assert(false); break;
3967 }
3968 }
3969
3970 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) {
3971 str_list temp;
3972 bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) {
3973 if (auto stmt = ast_cast<Statement_t>(node)) {
3974 if (stmt->content.is<BreakLoop_t>()) {
3975 return _parser.toString(stmt->content) == "continue"sv ?
3976 traversal::Stop : traversal::Return;
3977 } else if (expListFrom(stmt)) {
3978 return traversal::Continue;
3979 }
3980 return traversal::Return;
3981 }
3982 return traversal::Continue;
3983 });
3984 if (withContinue) {
3985 auto continueVar = getUnusedName("_continue_"sv);
3986 addToScope(continueVar);
3987 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body);
3988 _buf << indent() << "repeat"sv << nll(body);
3989 temp.push_back(clearBuf());
3990 _continueVars.push(continueVar);
3991 pushScope();
3992 }
3993 transform_plain_body(body, temp, usage, assignList);
3994 if (withContinue) {
3995 if (!appendContent.empty()) {
3996 _buf << indent() << appendContent;
3997 }
3998 _buf << indent() << _continueVars.top() << " = true"sv << nll(body);
3999 popScope();
4000 _buf << indent() << "until true"sv << nlr(body);
4001 _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body);
4002 _buf << indent(1) << "break"sv << nlr(body);
4003 _buf << indent() << "end"sv << nlr(body);
4004 temp.push_back(clearBuf());
4005 _continueVars.pop();
4006 } else if (!appendContent.empty()) {
4007 temp.back().append(indent() + appendContent);
4008 }
4009 out.push_back(join(temp));
4010 }
4011
4012 void transformFor(For_t* forNode, str_list& out) {
4013 str_list temp;
4014 transformForHead(forNode, temp);
4015 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common);
4016 popScope();
4017 out.push_back(join(temp) + indent() + s("end"sv) + nlr(forNode));
4018 }
4019
4020 std::string transformForInner(For_t* forNode, str_list& out) {
4021 auto x = forNode;
4022 std::string accum = getUnusedName("_accum_"sv);
4023 addToScope(accum);
4024 std::string len = getUnusedName("_len_"sv);
4025 addToScope(len);
4026 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode);
4027 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
4028 out.push_back(clearBuf());
4029 transformForHead(forNode, out);
4030 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), x);
4031 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forNode->body);
4032 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList);
4033 popScope();
4034 out.push_back(indent() + s("end"sv) + nlr(forNode));
4035 return accum;
4036 }
4037
4038 void transformForClosure(For_t* forNode, str_list& out) {
4039 str_list temp;
4040 _buf << "(function()"sv << nll(forNode);
4041 pushScope();
4042 _enableReturn.push(true);
4043 auto accum = transformForInner(forNode, temp);
4044 temp.push_back(indent() + s("return "sv) + accum + nlr(forNode));
4045 _enableReturn.pop();
4046 popScope();
4047 temp.push_back(indent() + s("end)()"sv));
4048 out.push_back(join(temp));
4049 }
4050
4051 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) {
4052 auto x = forNode;
4053 str_list temp;
4054 if (assignExpList) {
4055 _buf << indent() << "do"sv << nll(forNode);
4056 pushScope();
4057 auto accum = transformForInner(forNode, temp);
4058 auto assign = x->new_ptr<Assign_t>();
4059 assign->values.push_back(toAst<Exp_t>(accum, x));
4060 auto assignment = x->new_ptr<ExpListAssign_t>();
4061 assignment->expList.set(assignExpList);
4062 assignment->action.set(assign);
4063 transformAssignment(assignment, temp);
4064 popScope();
4065 temp.push_back(indent() + s("end"sv) + nlr(forNode));
4066 } else {
4067 auto accum = transformForInner(forNode, temp);
4068 auto returnNode = x->new_ptr<Return_t>();
4069 auto expListLow = toAst<ExpListLow_t>(accum, x);
4070 returnNode->valueList.set(expListLow);
4071 transformReturn(returnNode, temp);
4072 }
4073 out.push_back(join(temp));
4074 }
4075
4076 void transformBinaryOperator(BinaryOperator_t* node, str_list& out) {
4077 auto op = _parser.toString(node);
4078 out.push_back(op == "!="sv ? s("~="sv) : op);
4079 }
4080
4081 void transformForEach(ForEach_t* forEach, str_list& out) {
4082 str_list temp;
4083 transformForEachHead(forEach->nameList, forEach->loopValue, temp);
4084 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common);
4085 popScope();
4086 out.push_back(temp.front() + temp.back() + indent() + s("end"sv) + nlr(forEach));
4087 }
4088
4089 std::string transformForEachInner(ForEach_t* forEach, str_list& out) {
4090 auto x = forEach;
4091 std::string accum = getUnusedName("_accum_"sv);
4092 addToScope(accum);
4093 std::string len = getUnusedName("_len_"sv);
4094 addToScope(len);
4095 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach);
4096 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
4097 out.push_back(clearBuf());
4098 transformForEachHead(forEach->nameList, forEach->loopValue, out);
4099 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), x);
4100 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forEach->body);
4101 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList);
4102 popScope();
4103 out.push_back(indent() + s("end"sv) + nlr(forEach));
4104 return accum;
4105 }
4106
4107 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
4108 str_list temp;
4109 _buf << "(function()"sv << nll(forEach);
4110 pushScope();
4111 _enableReturn.push(true);
4112 auto accum = transformForEachInner(forEach, temp);
4113 temp.push_back(indent() + s("return "sv) + accum + nlr(forEach));
4114 _enableReturn.pop();
4115 popScope();
4116 temp.push_back(indent() + s("end)()"sv));
4117 out.push_back(join(temp));
4118 }
4119
4120 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) {
4121 auto x = forEach;
4122 str_list temp;
4123 if (assignExpList) {
4124 _buf << indent() << "do"sv << nll(forEach);
4125 pushScope();
4126 auto accum = transformForEachInner(forEach, temp);
4127 auto assign = x->new_ptr<Assign_t>();
4128 assign->values.push_back(toAst<Exp_t>(accum, x));
4129 auto assignment = x->new_ptr<ExpListAssign_t>();
4130 assignment->expList.set(assignExpList);
4131 assignment->action.set(assign);
4132 transformAssignment(assignment, temp);
4133 popScope();
4134 temp.push_back(indent() + s("end"sv) + nlr(forEach));
4135 } else {
4136 auto accum = transformForEachInner(forEach, temp);
4137 auto returnNode = x->new_ptr<Return_t>();
4138 auto expListLow = toAst<ExpListLow_t>(accum, x);
4139 returnNode->valueList.set(expListLow);
4140 transformReturn(returnNode, temp);
4141 }
4142 out.push_back(join(temp));
4143 }
4144
4145 void transform_variable_pair(variable_pair_t* pair, str_list& out) {
4146 auto name = _parser.toString(pair->name);
4147 out.push_back(name + s(" = "sv) + name);
4148 }
4149
4150 void transform_normal_pair(normal_pair_t* pair, str_list& out) {
4151 auto key = pair->key.get();
4152 str_list temp;
4153 switch (key->getId()) {
4154 case id<KeyName_t>(): {
4155 transformKeyName(static_cast<KeyName_t*>(key), temp);
4156 if (LuaKeywords.find(temp.back()) != LuaKeywords.end()) {
4157 temp.back() = s("[\""sv) + temp.back() + s("\"]");
4158 }
4159 break;
4160 }
4161 case id<Exp_t>():
4162 transformExp(static_cast<Exp_t*>(key), temp, ExpUsage::Closure);
4163 temp.back() = s(temp.back().front() == '[' ? "[ "sv : "["sv) + temp.back() + s("]"sv);
4164 break;
4165 case id<DoubleString_t>():
4166 transformDoubleString(static_cast<DoubleString_t*>(key), temp);
4167 temp.back() = s("["sv) + temp.back() + s("]"sv);
4168 break;
4169 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(key), temp);
4170 temp.back() = s("["sv) + temp.back() + s("]"sv);
4171 break;
4172 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(key), temp);
4173 temp.back() = s("[ "sv) + temp.back() + s("]"sv);
4174 break;
4175 default: assert(false); break;
4176 }
4177 auto value = pair->value.get();
4178 switch (value->getId()) {
4179 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), temp, ExpUsage::Closure); break;
4180 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), temp); break;
4181 default: assert(false); break;
4182 }
4183 out.push_back(temp.front() + s(" = "sv) + temp.back());
4184 }
4185
4186 void transformKeyName(KeyName_t* keyName, str_list& out) {
4187 auto name = keyName->name.get();
4188 switch (name->getId()) {
4189 case id<SelfName_t>(): transformSelfName(static_cast<SelfName_t*>(name), out); break;
4190 case id<Name_t>(): out.push_back(_parser.toString(name)); break;
4191 default: assert(false); break;
4192 }
4193 }
4194
4195 void transformLuaString(LuaString_t* luaString, str_list& out) {
4196 auto content = _parser.toString(luaString->content);
4197 Utils::replace(content, "\r\n"sv, "\n");
4198 if (content[0] == '\n') content.erase(content.begin());
4199 out.push_back(_parser.toString(luaString->open) + content + _parser.toString(luaString->close));
4200 }
4201
4202 void transformSingleString(SingleString_t* singleString, str_list& out) {
4203 auto str = _parser.toString(singleString);
4204 Utils::replace(str, "\r\n"sv, "\n");
4205 Utils::replace(str, "\n"sv, "\\n"sv);
4206 out.push_back(str);
4207 }
4208
4209 void transformDoubleString(DoubleString_t* doubleString, str_list& out) {
4210 str_list temp;
4211 for (auto _seg : doubleString->segments.objects()) {
4212 auto seg = static_cast<double_string_content_t*>(_seg);
4213 auto content = seg->content.get();
4214 switch (content->getId()) {
4215 case id<double_string_inner_t>(): {
4216 auto str = _parser.toString(content);
4217 Utils::replace(str, "\r\n"sv, "\n");
4218 Utils::replace(str, "\n"sv, "\\n"sv);
4219 temp.push_back(s("\""sv) + str + s("\""sv));
4220 break;
4221 }
4222 case id<Exp_t>(): {
4223 transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure);
4224 std::string tostr("tostring"sv);
4225 temp.back() = tostr + '(' + temp.back() + s(")"sv);
4226 if (_config.lintGlobalVariable) {
4227 if (!isDefined(tostr)) {
4228 if (_globals.find(tostr) == _globals.end()) {
4229 _globals[tostr] = {content->m_begin.m_line, content->m_begin.m_col};
4230 }
4231 }
4232 }
4233 break;
4234 }
4235 default: assert(false); break;
4236 }
4237 }
4238 out.push_back(temp.empty() ? s("\"\""sv) : join(temp, " .. "sv));
4239 }
4240
4241 void transformString(String_t* string, str_list& out) {
4242 auto str = string->str.get();
4243 switch (str->getId()) {
4244 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
4245 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
4246 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
4247 default: assert(false); break;
4248 }
4249 }
4250
4251 std::pair<std::string,bool> defineClassVariable(Assignable_t* assignable) {
4252 if (auto variable = assignable->item.as<Variable_t>()) {
4253 auto name = _parser.toString(variable);
4254 if (addToScope(name)) {
4255 return {name, true};
4256 } else {
4257 return {name, false};
4258 }
4259 }
4260 return {Empty, false};
4261 }
4262
4263 void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) {
4264 str_list temp;
4265 temp.push_back(s("(function()"sv) + nll(classDecl));
4266 pushScope();
4267 _enableReturn.push(true);
4268 transformClassDecl(classDecl, temp, ExpUsage::Return);
4269 _enableReturn.pop();
4270 popScope();
4271 temp.push_back(s("end)()"sv));
4272 out.push_back(join(temp));
4273 }
4274
4275 void transformClassDecl(ClassDecl_t* classDecl, str_list& out, ExpUsage usage, ExpList_t* expList = nullptr) {
4276 str_list temp;
4277 auto x = classDecl;
4278 auto body = classDecl->body.get();
4279 auto assignable = classDecl->name.get();
4280 auto extend = classDecl->extend.get();
4281 std::string className;
4282 std::string assignItem;
4283 if (assignable) {
4284 if (!isAssignable(assignable)) {
4285 throw std::logic_error(_info.errorMessage("left hand expression is not assignable"sv, assignable));
4286 }
4287 bool newDefined = false;
4288 std::tie(className, newDefined) = defineClassVariable(assignable);
4289 if (newDefined) {
4290 temp.push_back(indent() + s("local "sv) + className + nll(classDecl));
4291 }
4292 if (className.empty()) {
4293 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
4294 if (auto dotChain = ast_cast<DotChainItem_t>(chain->items.back())) {
4295 className = s("\""sv) + _parser.toString(dotChain->name) + s("\""sv);
4296 } else if (auto index = ast_cast<Exp_t>(chain->items.back())) {
4297 if (auto name = index->getByPath<unary_exp_t, Value_t, String_t>()) {
4298 transformString(name, temp);
4299 className = temp.back();
4300 temp.pop_back();
4301 }
4302 }
4303 }
4304 } else {
4305 className = s("\""sv) + className + s("\""sv);
4306 }
4307 pushScope();
4308 transformAssignable(assignable, temp);
4309 popScope();
4310 assignItem = temp.back();
4311 temp.pop_back();
4312 } else if (expList) {
4313 auto name = singleVariableFrom(expList);
4314 if (!name.empty()) {
4315 className = s("\""sv) + name + s("\""sv);
4316 }
4317 }
4318 temp.push_back(indent() + s("do"sv) + nll(classDecl));
4319 pushScope();
4320 auto classVar = getUnusedName("_class_"sv);
4321 addToScope(classVar);
4322 temp.push_back(indent() + s("local "sv) + classVar + nll(classDecl));
4323 if (body) {
4324 str_list varDefs;
4325 for (auto item : body->contents.objects()) {
4326 if (auto statement = ast_cast<Statement_t>(item)) {
4327 ClassDecl_t* clsDecl = nullptr;
4328 if (auto assignment = assignmentFrom(statement)) {
4329 auto names = transformAssignDefs(assignment->expList.get());
4330 varDefs.insert(varDefs.end(), names.begin(), names.end());
4331 auto info = extractDestructureInfo(assignment, true);
4332 if (!info.first.empty()) {
4333 for (const auto& destruct : info.first)
4334 for (const auto& item : destruct.items)
4335 if (item.isVariable && addToScope(item.name))
4336 varDefs.push_back(item.name);
4337 }
4338 BLOCK_START
4339 auto assign = assignment->action.as<Assign_t>();
4340 BREAK_IF(!assign);
4341 BREAK_IF(assign->values.objects().size() != 1);
4342 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
4343 BREAK_IF(!exp);
4344 auto value = singleValueFrom(exp);
4345 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4346 BLOCK_END
4347 } else if (auto expList = expListFrom(statement)) {
4348 auto value = singleValueFrom(expList);
4349 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4350 }
4351 if (clsDecl) {
4352 std::string clsName;
4353 bool newDefined = false;
4354 std::tie(clsName,newDefined) = defineClassVariable(clsDecl->name);
4355 if (newDefined) varDefs.push_back(clsName);
4356 }
4357 }
4358 }
4359 if (!varDefs.empty()) {
4360 temp.push_back(indent() + s("local "sv) + join(varDefs, ", "sv) + nll(body));
4361 }
4362 }
4363 std::string parent, parentVar;
4364 if (extend) {
4365 parentVar = getUnusedName("_parent_"sv);
4366 addToScope(parentVar);
4367 transformExp(extend, temp, ExpUsage::Closure);
4368 parent = temp.back();
4369 temp.pop_back();
4370 temp.push_back(indent() + s("local "sv) + parentVar + s(" = "sv) + parent + nll(classDecl));
4371 }
4372 auto baseVar = getUnusedName("_base_"sv);
4373 addToScope(baseVar);
4374 temp.push_back(indent() + s("local "sv) + baseVar + s(" = "sv));
4375 str_list builtins;
4376 str_list commons;
4377 str_list statements;
4378 if (body) {
4379 std::list<ClassMember> members;
4380 for (auto content : classDecl->body->contents.objects()) {
4381 switch (content->getId()) {
4382 case id<class_member_list_t>(): {
4383 size_t inc = transform_class_member_list(static_cast<class_member_list_t*>(content), members, classVar);
4384 auto it = members.end();
4385 for (size_t i = 0; i < inc; ++i, --it);
4386 for (; it != members.end(); ++it) {
4387 auto& member = *it;
4388 if (member.type == MemType::Property) {
4389 statements.push_back(indent() + member.item + nll(content));
4390 } else {
4391 member.item = indent(1) + member.item;
4392 }
4393 }
4394 break;
4395 }
4396 case id<Statement_t>():
4397 transformStatement(static_cast<Statement_t*>(content), statements);
4398 break;
4399 default: assert(false); break;
4400 }
4401 }
4402 for (auto& member : members) {
4403 switch (member.type) {
4404 case MemType::Common:
4405 commons.push_back((commons.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
4406 break;
4407 case MemType::Builtin:
4408 builtins.push_back((builtins.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
4409 break;
4410 default: break;
4411 }
4412 }
4413 if (!commons.empty()) {
4414 temp.back() += s("{"sv) + nll(body);
4415 temp.push_back(join(commons) + nll(body));
4416 temp.push_back(indent() + s("}"sv) + nll(body));
4417 } else {
4418 temp.back() += s("{ }"sv) + nll(body);
4419 }
4420 } else {
4421 temp.back() += s("{ }"sv) + nll(classDecl);
4422 }
4423 temp.push_back(indent() + baseVar + s(".__index = "sv) + baseVar + nll(classDecl));
4424 str_list tmp;
4425 if (usage == ExpUsage::Assignment) {
4426 auto assign = x->new_ptr<Assign_t>();
4427 assign->values.push_back(toAst<Exp_t>(classVar, x));
4428 auto assignment = x->new_ptr<ExpListAssign_t>();
4429 assignment->expList.set(expList);
4430 assignment->action.set(assign);
4431 transformAssignment(assignment, tmp);
4432 }
4433 if (extend) {
4434 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl);
4435 }
4436 _buf << indent() << classVar << " = setmetatable({"sv << nll(classDecl);
4437 if (!builtins.empty()) {
4438 _buf << join(builtins) << ","sv << nll(classDecl);
4439 } else {
4440 if (extend) {
4441 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl);
4442 _buf << indent(2) << "return _class_0.__parent.__init(self, ...)"sv << nll(classDecl);
4443 _buf << indent(1) << "end,"sv << nll(classDecl);
4444 } else {
4445 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl);
4446 }
4447 }
4448 _buf << indent(1) << "__base = "sv << baseVar;
4449 if (!className.empty()) {
4450 _buf << ","sv << nll(classDecl);
4451 _buf << indent(1) << "__name = "sv << className;
4452 }
4453 if (extend) {
4454 _buf << ","sv << nll(classDecl);
4455 _buf << indent(1) << "__parent = "sv << parentVar;
4456 }
4457 _buf << nll(classDecl);
4458 _buf << indent() << "}, {"sv << nll(classDecl);
4459 if (extend) {
4460 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl);
4461 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl);
4462 _buf << indent(2) << "if val == nil then"sv << nll(classDecl);
4463 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl);
4464 _buf << indent(3) << "if parent then"sv << nll(classDecl);
4465 _buf << indent(4) << "return parent[name]"sv << nll(classDecl);
4466 _buf << indent(3) << "end"sv << nll(classDecl);
4467 _buf << indent(2) << "else"sv << nll(classDecl);
4468 _buf << indent(3) << "return val"sv << nll(classDecl);
4469 _buf << indent(2) << "end"sv << nll(classDecl);
4470 _buf << indent(1) << "end,"sv << nll(classDecl);
4471 } else {
4472 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl);
4473 }
4474 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl);
4475 pushScope();
4476 auto selfVar = getUnusedName("_self_"sv);
4477 addToScope(selfVar);
4478 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({}, "sv << baseVar << ")"sv << nll(classDecl);
4479 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl);
4480 _buf << indent(1) << "return "sv << selfVar << nll(classDecl);
4481 popScope();
4482 _buf << indent(1) << "end"sv << nll(classDecl);
4483 _buf << indent() << "})"sv << nll(classDecl);
4484 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl);
4485 if (!statements.empty()) {
4486 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl);
4487 }
4488 _buf << join(statements);
4489 if (extend) {
4490 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl);
4491 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl);
4492 _buf << indent() << "end"sv << nll(classDecl);
4493 }
4494 if (!assignItem.empty()) {
4495 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl);
4496 }
4497 switch (usage) {
4498 case ExpUsage::Return: {
4499 _buf << indent() << "return "sv << classVar << nlr(classDecl);
4500 break;
4501 }
4502 case ExpUsage::Assignment: {
4503 _buf << tmp.back();
4504 break;
4505 }
4506 default: break;
4507 }
4508 temp.push_back(clearBuf());
4509 popScope();
4510 temp.push_back(indent() + s("end"sv) + nlr(classDecl));
4511 out.push_back(join(temp));
4512 }
4513
4514 size_t transform_class_member_list(class_member_list_t* class_member_list, std::list<ClassMember>& out, const std::string& classVar) {
4515 str_list temp;
4516 size_t count = 0;
4517 for (auto keyValue : class_member_list->values.objects()) {
4518 MemType type = MemType::Common;
4519 BLOCK_START
4520 auto normal_pair = ast_cast<normal_pair_t>(keyValue);
4521 BREAK_IF(!normal_pair);
4522 auto keyName = normal_pair->key.as<KeyName_t>();
4523 BREAK_IF(!keyName);
4524 std::string newSuperCall;
4525 auto selfName = keyName->name.as<SelfName_t>();
4526 if (selfName) {
4527 type = MemType::Property;
4528 auto name = ast_cast<self_name_t>(selfName->name);
4529 if (!name) throw std::logic_error(_info.errorMessage("invalid class poperty name"sv, selfName->name));
4530 newSuperCall = classVar + s(".__parent."sv) + _parser.toString(name->name);
4531 } else {
4532 auto x = keyName;
4533 auto nameNode = keyName->name.as<Name_t>();
4534 if (!nameNode) break;
4535 auto name = _parser.toString(nameNode);
4536 if (name == "new"sv) {
4537 type = MemType::Builtin;
4538 keyName->name.set(toAst<Name_t>("__init"sv, x));
4539 newSuperCall = classVar + s(".__parent.__init"sv);
4540 } else {
4541 newSuperCall = classVar + s(".__parent.__base."sv) + name;
4542 }
4543 }
4544 normal_pair->value->traverse([&](ast_node* node) {
4545 if (node->getId() == id<ClassDecl_t>()) return traversal::Return;
4546 if (auto chainValue = ast_cast<ChainValue_t>(node)) {
4547 if (auto callable = ast_cast<Callable_t>(chainValue->items.front())) {
4548 auto var = callable->item.get();
4549 if (_parser.toString(var) == "super"sv) {
4550 auto insertSelfToArguments = [&](ast_node* item) {
4551 auto x = item;
4552 switch (item->getId()) {
4553 case id<InvokeArgs_t>(): {
4554 auto invoke = static_cast<InvokeArgs_t*>(item);
4555 invoke->args.push_front(toAst<Exp_t>("self"sv, x));
4556 return true;
4557 }
4558 case id<Invoke_t>(): {
4559 auto invoke = static_cast<Invoke_t*>(item);
4560 invoke->args.push_front(toAst<Exp_t>("self"sv, x));
4561 return true;
4562 }
4563 default:
4564 return false;
4565 }
4566 };
4567 const auto& chainList = chainValue->items.objects();
4568 if (chainList.size() >= 2) {
4569 auto it = chainList.begin();
4570 auto secondItem = *(++it);
4571 if (!insertSelfToArguments(secondItem)) {
4572 if (auto colonChainItem = ast_cast<ColonChainItem_t>(secondItem)) {
4573 if (chainList.size() > 2 && insertSelfToArguments(*(++it))) {
4574 colonChainItem->switchToDot = true;
4575 }
4576 }
4577 newSuperCall = classVar + s(".__parent"sv);
4578 }
4579 } else {
4580 newSuperCall = classVar + s(".__parent"sv);
4581 }
4582 auto newChain = toAst<ChainValue_t>(newSuperCall, chainValue);
4583 chainValue->items.pop_front();
4584 const auto& items = newChain->items.objects();
4585 for (auto it = items.rbegin(); it != items.rend(); ++it) {
4586 chainValue->items.push_front(*it);
4587 }
4588 }
4589 }
4590 }
4591 return traversal::Continue;
4592 });
4593 BLOCK_END
4594 pushScope();
4595 if (type == MemType::Property) {
4596 decIndentOffset();
4597 }
4598 switch (keyValue->getId()) {
4599 case id<variable_pair_t>():
4600 transform_variable_pair(static_cast<variable_pair_t*>(keyValue), temp);
4601 break;
4602 case id<normal_pair_t>():
4603 transform_normal_pair(static_cast<normal_pair_t*>(keyValue), temp);
4604 break;
4605 default: assert(false); break;
4606 }
4607 if (type == MemType::Property) {
4608 incIndentOffset();
4609 }
4610 popScope();
4611 out.push_back({temp.back(), type, keyValue});
4612 temp.clear();
4613 ++count;
4614 }
4615 return count;
4616 }
4617
4618 void transformAssignable(Assignable_t* assignable, str_list& out) {
4619 auto item = assignable->item.get();
4620 switch (item->getId()) {
4621 case id<AssignableChain_t>(): transformAssignableChain(static_cast<AssignableChain_t*>(item), out); break;
4622 case id<Variable_t>(): transformVariable(static_cast<Variable_t*>(item), out); break;
4623 case id<SelfName_t>(): transformSelfName(static_cast<SelfName_t*>(item), out); break;
4624 default: assert(false); break;
4625 }
4626 }
4627
4628 void transformWithClosure(With_t* with, str_list& out) {
4629 str_list temp;
4630 temp.push_back(s("(function()"sv) + nll(with));
4631 pushScope();
4632 _enableReturn.push(true);
4633 transformWith(with, temp, nullptr, true);
4634 _enableReturn.pop();
4635 popScope();
4636 temp.push_back(indent() + s("end)()"sv));
4637 out.push_back(join(temp));
4638 }
4639
4640 void transformWith(With_t* with, str_list& out, ExpList_t* assignList = nullptr, bool returnValue = false) {
4641 auto x = with;
4642 str_list temp;
4643 std::string withVar;
4644 bool scoped = false;
4645 if (with->assigns) {
4646 checkAssignable(with->valueList);
4647 auto vars = getAssignVars(with);
4648 if (vars.front().empty()) {
4649 if (with->assigns->values.objects().size() == 1) {
4650 auto var = singleVariableFrom(with->assigns->values.objects().front());
4651 if (!var.empty()) {
4652 withVar = var;
4653 }
4654 }
4655 if (withVar.empty()) {
4656 withVar = getUnusedName("_with_"sv);
4657 auto assignment = x->new_ptr<ExpListAssign_t>();
4658 assignment->expList.set(toAst<ExpList_t>(withVar, x));
4659 auto assign = x->new_ptr<Assign_t>();
4660 assign->values.push_back(with->assigns->values.objects().front());
4661 assignment->action.set(assign);
4662 if (!returnValue) {
4663 scoped = true;
4664 temp.push_back(indent() + s("do"sv) + nll(with));
4665 pushScope();
4666 }
4667 transformAssignment(assignment, temp);
4668 }
4669 auto assignment = x->new_ptr<ExpListAssign_t>();
4670 assignment->expList.set(with->valueList);
4671 auto assign = x->new_ptr<Assign_t>();
4672 assign->values.push_back(toAst<Exp_t>(withVar, x));
4673 bool skipFirst = true;
4674 for (auto value : with->assigns->values.objects()) {
4675 if (skipFirst) {
4676 skipFirst = false;
4677 continue;
4678 }
4679 assign->values.push_back(value);
4680 }
4681 assignment->action.set(assign);
4682 transformAssignment(assignment, temp);
4683 } else {
4684 withVar = vars.front();
4685 auto assignment = x->new_ptr<ExpListAssign_t>();
4686 assignment->expList.set(with->valueList);
4687 assignment->action.set(with->assigns);
4688 if (!returnValue) {
4689 scoped = true;
4690 temp.push_back(indent() + s("do"sv) + nll(with));
4691 pushScope();
4692 }
4693 transformAssignment(assignment, temp);
4694 }
4695 } else {
4696 withVar = singleVariableFrom(with->valueList);
4697 if (withVar.empty()) {
4698 withVar = getUnusedName("_with_"sv);
4699 auto assignment = x->new_ptr<ExpListAssign_t>();
4700 assignment->expList.set(toAst<ExpList_t>(withVar, x));
4701 auto assign = x->new_ptr<Assign_t>();
4702 assign->values.dup(with->valueList->exprs);
4703 assignment->action.set(assign);
4704 if (!returnValue) {
4705 scoped = true;
4706 temp.push_back(indent() + s("do"sv) + nll(with));
4707 pushScope();
4708 }
4709 transformAssignment(assignment, temp);
4710 }
4711 }
4712 if (!with->eop && !scoped && !returnValue) {
4713 pushScope();
4714 scoped = traversal::Stop == with->body->traverse([&](ast_node* node) {
4715 if (auto statement = ast_cast<Statement_t>(node)) {
4716 ClassDecl_t* clsDecl = nullptr;
4717 if (auto assignment = assignmentFrom(statement)) {
4718 auto names = getAssignDefs(assignment->expList.get());
4719 if (!names.empty()) {
4720 return traversal::Stop;
4721 }
4722 auto info = extractDestructureInfo(assignment, true);
4723 if (!info.first.empty()) {
4724 for (const auto& destruct : info.first)
4725 for (const auto& item : destruct.items)
4726 if (item.isVariable && !isDefined(item.name))
4727 return traversal::Stop;
4728 }
4729 BLOCK_START
4730 auto assign = assignment->action.as<Assign_t>();
4731 BREAK_IF(!assign);
4732 BREAK_IF(assign->values.objects().size() != 1);
4733 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
4734 BREAK_IF(!exp);
4735 if (auto value = singleValueFrom(exp)) {
4736 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4737 }
4738 BLOCK_END
4739 } else if (auto expList = expListFrom(statement)) {
4740 auto value = singleValueFrom(expList);
4741 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
4742 }
4743 if (clsDecl) {
4744 auto variable = clsDecl->name.as<Variable_t>();
4745 if (!isDefined(_parser.toString(variable))) return traversal::Stop;
4746 }
4747 return traversal::Return;
4748 }
4749 return traversal::Continue;
4750 });
4751 popScope();
4752 if (scoped) {
4753 temp.push_back(indent() + s("do"sv) + nll(with));
4754 pushScope();
4755 }
4756 }
4757 _withVars.push(withVar);
4758 if (with->eop) {
4759 auto ifNode = x->new_ptr<If_t>();
4760 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + s("~=nil"sv), x));
4761 ifNode->nodes.push_back(with->body);
4762 transformIf(ifNode, temp, ExpUsage::Common);
4763 } else {
4764 transform_plain_body(with->body, temp, ExpUsage::Common);
4765 }
4766 _withVars.pop();
4767 if (assignList) {
4768 auto assignment = x->new_ptr<ExpListAssign_t>();
4769 assignment->expList.set(assignList);
4770 auto assign = x->new_ptr<Assign_t>();
4771 assign->values.push_back(toAst<Exp_t>(withVar, x));
4772 assignment->action.set(assign);
4773 transformAssignment(assignment, temp);
4774 }
4775 if (returnValue) {
4776 auto last = lastStatementFrom(with->body);
4777 if (last && !last->content.is<Return_t>()) {
4778 temp.push_back(indent() + s("return "sv) + withVar + nll(with));
4779 }
4780 }
4781 if (scoped) {
4782 popScope();
4783 temp.push_back(indent() + s("end"sv) + nll(with));
4784 }
4785 out.push_back(join(temp));
4786 }
4787
4788 void transform_const_value(const_value_t* const_value, str_list& out) {
4789 out.push_back(_parser.toString(const_value));
4790 }
4791
4792 void transformGlobal(Global_t* global, str_list& out) {
4793 auto x = global;
4794 auto item = global->item.get();
4795 switch (item->getId()) {
4796 case id<ClassDecl_t>(): {
4797 auto classDecl = static_cast<ClassDecl_t*>(item);
4798 if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) {
4799 markVarGlobal(GlobalMode::Any, true);
4800 addGlobalVar(_parser.toString(classDecl->name->item));
4801 }
4802 transformClassDecl(classDecl, out, ExpUsage::Common);
4803 break;
4804 }
4805 case id<global_op_t>():
4806 if (_parser.toString(item) == "*"sv) {
4807 markVarGlobal(GlobalMode::Any, false);
4808 } else {
4809 markVarGlobal(GlobalMode::Capital, false);
4810 }
4811 break;
4812 case id<global_values_t>(): {
4813 markVarGlobal(GlobalMode::Any, true);
4814 auto values = global->item.to<global_values_t>();
4815 if (values->valueList) {
4816 auto expList = x->new_ptr<ExpList_t>();
4817 for (auto name : values->nameList->names.objects()) {
4818 addGlobalVar(_parser.toString(name));
4819 auto callable = x->new_ptr<Callable_t>();
4820 callable->item.set(name);
4821 auto chainValue = x->new_ptr<ChainValue_t>();
4822 chainValue->items.push_back(callable);
4823 auto value = x->new_ptr<Value_t>();
4824 value->item.set(chainValue);
4825 auto exp = newExp(value, x);
4826 expList->exprs.push_back(exp);
4827 }
4828 auto assignment = x->new_ptr<ExpListAssign_t>();
4829 assignment->expList.set(expList);
4830 auto assign = x->new_ptr<Assign_t>();
4831 if (auto expListLow = values->valueList.as<ExpListLow_t>()) {
4832 assign->values.dup(expListLow->exprs);
4833 } else {
4834 auto tableBlock = values->valueList.to<TableBlock_t>();
4835 assign->values.push_back(tableBlock);
4836 }
4837 assignment->action.set(assign);
4838 transformAssignment(assignment, out);
4839 } else {
4840 for (auto name : values->nameList->names.objects()) {
4841 addGlobalVar(_parser.toString(name));
4842 }
4843 }
4844 break;
4845 }
4846 default: assert(false); break;
4847 }
4848 }
4849
4850 void transformExport(Export_t* exportNode, str_list& out) {
4851 auto x = exportNode;
4852 if (_scopes.size() > 1) {
4853 throw std::logic_error(_info.errorMessage("can not do module export outside the root block"sv, exportNode));
4854 }
4855 if (exportNode->assign) {
4856 auto expList = exportNode->target.to<ExpList_t>();
4857 if (expList->exprs.size() != exportNode->assign->values.size()) {
4858 throw std::logic_error(_info.errorMessage("left and right expressions must be matched in export statement"sv, x));
4859 }
4860 for (auto _exp : expList->exprs.objects()) {
4861 auto exp = static_cast<Exp_t*>(_exp);
4862 if (!variableFrom(exp) &&
4863 !exp->getByPath<unary_exp_t, Value_t, SimpleValue_t, TableLit_t>() &&
4864 !exp->getByPath<unary_exp_t, Value_t, simple_table_t>()) {
4865 throw std::logic_error(_info.errorMessage("left hand expressions must be variables in export statement"sv, x));
4866 }
4867 }
4868 auto assignment = x->new_ptr<ExpListAssign_t>();
4869 assignment->expList.set(expList);
4870 assignment->action.set(exportNode->assign);
4871 transformAssignment(assignment, out);
4872 str_list names = transformAssignDefs(expList, false);
4873 auto info = extractDestructureInfo(assignment, true);
4874 if (!info.first.empty()) {
4875 for (const auto& destruct : info.first)
4876 for (const auto& item : destruct.items)
4877 if (item.isVariable)
4878 names.push_back(item.name);
4879 }
4880 if (_info.exportDefault) {
4881 out.back().append(indent() + _info.moduleName + s(" = "sv) + names.back() + nlr(exportNode));
4882 } else {
4883 str_list lefts, rights;
4884 for (const auto& name : names) {
4885 lefts.push_back(_info.moduleName + s("[\""sv) + name + s("\"]"sv));
4886 rights.push_back(name);
4887 }
4888 out.back().append(indent() + join(lefts,", "sv) + s(" = "sv) + join(rights, ", "sv) + nlr(exportNode));
4889 }
4890 } else {
4891 if (auto macro = exportNode->target.as<Macro_t>()) {
4892 transformMacro(macro, out, true);
4893 } else if (_info.exportDefault) {
4894 auto exp = exportNode->target.to<Exp_t>();
4895 auto assignment = x->new_ptr<ExpListAssign_t>();
4896 assignment->expList.set(toAst<ExpList_t>(_info.moduleName, x));
4897 auto assign = x->new_ptr<Assign_t>();
4898 assign->values.push_back(exp);
4899 assignment->action.set(assign);
4900 transformAssignment(assignment, out);
4901 } else {
4902 str_list temp;
4903 auto expList = exportNode->target.to<ExpList_t>();
4904 auto assignment = x->new_ptr<ExpListAssign_t>();
4905 auto assignList = toAst<ExpList_t>(_info.moduleName + s("[#"sv) + _info.moduleName + s("+1]"sv), x);
4906 assignment->expList.set(assignList);
4907 for (auto exp : expList->exprs.objects()) {
4908 if (auto classDecl = exp->getByPath<unary_exp_t, Value_t, SimpleValue_t, ClassDecl_t>()) {
4909 if (classDecl->name && classDecl->name->item->getId() == id<Variable_t>()) {
4910 transformClassDecl(classDecl, temp, ExpUsage::Common);
4911 auto name = _parser.toString(classDecl->name->item);
4912 assignment->expList.set(toAst<ExpList_t>(_info.moduleName + s("[\""sv) + name + s("\"]"sv), x));
4913 auto assign = x->new_ptr<Assign_t>();
4914 assign->values.push_back(toAst<Exp_t>(name, x));
4915 assignment->action.set(assign);
4916 transformAssignment(assignment, temp);
4917 assignment->expList.set(assignList);
4918 continue;
4919 }
4920 }
4921 auto assign = x->new_ptr<Assign_t>();
4922 assign->values.push_back(exp);
4923 assignment->action.set(assign);
4924 transformAssignment(assignment, temp);
4925 }
4926 out.push_back(join(temp));
4927 }
4928 }
4929 }
4930
4931 void transformTable(ast_node* table, const node_container& pairs, str_list& out) {
4932 if (pairs.empty()) {
4933 out.push_back(s("{ }"sv));
4934 return;
4935 }
4936 str_list temp;
4937 incIndentOffset();
4938 for (auto pair : pairs) {
4939 switch (pair->getId()) {
4940 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(pair), temp, ExpUsage::Closure); break;
4941 case id<variable_pair_t>(): transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break;
4942 case id<normal_pair_t>(): transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break;
4943 case id<TableBlockIndent_t>(): transformTableBlockIndent(static_cast<TableBlockIndent_t*>(pair), temp); break;
4944 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(pair), temp); break;
4945 default: assert(false); break;
4946 }
4947 temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair);
4948 }
4949 out.push_back(s("{"sv) + nll(table) + join(temp));
4950 decIndentOffset();
4951 out.back() += (indent() + s("}"sv));
4952 }
4953
4954 void transform_simple_table(simple_table_t* table, str_list& out) {
4955 transformTable(table, table->pairs.objects(), out);
4956 }
4957
4958 void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
4959 switch (usage) {
4960 case ExpUsage::Closure:
4961 pushScope();
4962 _enableReturn.push(true);
4963 break;
4964 case ExpUsage::Assignment:
4965 pushScope();
4966 break;
4967 default:
4968 break;
4969 }
4970 auto x = comp;
4971 str_list kv;
4972 std::string tbl = getUnusedName("_tbl_"sv);
4973 addToScope(tbl);
4974 str_list temp;
4975 auto compInner = comp->forLoop.get();
4976 for (auto item : compInner->items.objects()) {
4977 switch (item->getId()) {
4978 case id<CompForEach_t>():
4979 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
4980 break;
4981 case id<CompFor_t>():
4982 transformCompFor(static_cast<CompFor_t*>(item), temp);
4983 break;
4984 case id<Exp_t>():
4985 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
4986 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
4987 pushScope();
4988 break;
4989 default: assert(false); break;
4990 }
4991 }
4992 transformExp(comp->key, kv, ExpUsage::Closure);
4993 if (comp->value) {
4994 transformExp(comp->value->value, kv, ExpUsage::Closure);
4995 }
4996 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
4997 popScope();
4998 }
4999 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp);
5000 _buf << join(temp);
5001 pushScope();
5002 if (!comp->value) {
5003 auto keyVar = getUnusedName("_key_"sv);
5004 auto valVar = getUnusedName("_val_"sv);
5005 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp);
5006 kv.front() = keyVar;
5007 kv.push_back(valVar);
5008 }
5009 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp);
5010 for (int ind = int(temp.size()) - 2; ind > -1 ; --ind) {
5011 _buf << indent(ind) << "end"sv << nll(comp);
5012 }
5013 popScope();
5014 _buf << indent() << "end"sv << nll(comp);
5015 switch (usage) {
5016 case ExpUsage::Closure:
5017 out.push_back(clearBuf() + indent() + s("return "sv) + tbl + nlr(comp));
5018 popScope();
5019 _enableReturn.pop();
5020 out.back().insert(0, s("(function()"sv) + nll(comp));
5021 out.back().append(indent() + s("end)()"sv));
5022 break;
5023 case ExpUsage::Assignment: {
5024 out.push_back(clearBuf());
5025 auto assign = x->new_ptr<Assign_t>();
5026 assign->values.push_back(toAst<Exp_t>(tbl, x));
5027 auto assignment = x->new_ptr<ExpListAssign_t>();
5028 assignment->expList.set(assignList);
5029 assignment->action.set(assign);
5030 transformAssignment(assignment, temp);
5031 out.back().append(temp.back());
5032 popScope();
5033 out.back().insert(0, indent() + s("do"sv) + nll(comp));
5034 out.back().append(indent() + s("end"sv) + nlr(comp));
5035 break;
5036 }
5037 case ExpUsage::Return:
5038 out.push_back(clearBuf() + indent() + s("return "sv) + tbl + nlr(comp));
5039 break;
5040 default:
5041 break;
5042 }
5043 }
5044
5045 void transformCompFor(CompFor_t* comp, str_list& out) {
5046 str_list temp;
5047 std::string varName = _parser.toString(comp->varName);
5048 transformExp(comp->startValue, temp, ExpUsage::Closure);
5049 transformExp(comp->stopValue, temp, ExpUsage::Closure);
5050 if (comp->stepValue) {
5051 transformExp(comp->stepValue->value, temp, ExpUsage::Closure);
5052 } else {
5053 temp.emplace_back();
5054 }
5055 auto it = temp.begin();
5056 const auto& start = *it;
5057 const auto& stop = *(++it);
5058 const auto& step = *(++it);
5059 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(comp);
5060 out.push_back(clearBuf());
5061 pushScope();
5062 addToScope(varName);
5063 }
5064
5065 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
5066 transformTable(table, table->values.objects(), out);
5067 }
5068
5069 void transformTableBlock(TableBlock_t* table, str_list& out) {
5070 transformTable(table, table->values.objects(), out);
5071 }
5072
5073 void transformDo(Do_t* doNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
5074 str_list temp;
5075 if (usage == ExpUsage::Closure) {
5076 temp.push_back(s("(function()"sv) + nll(doNode));
5077 _enableReturn.push(true);
5078 } else {
5079 temp.push_back(indent() + s("do"sv) + nll(doNode));
5080 }
5081 pushScope();
5082 transformBody(doNode->body, temp, usage, assignList);
5083 popScope();
5084 if (usage == ExpUsage::Closure) {
5085 _enableReturn.pop();
5086 temp.push_back(indent() + s("end)()"sv));
5087 } else {
5088 temp.push_back(indent() + s("end"sv) + nlr(doNode));
5089 }
5090 out.push_back(join(temp));
5091 }
5092
5093 void transformImportFrom(ImportFrom_t* import, str_list& out) {
5094 str_list temp;
5095 auto x = import;
5096 auto objVar = singleVariableFrom(import->exp);
5097 ast_ptr<false, ExpListAssign_t> objAssign;
5098 if (objVar.empty()) {
5099 objVar = getUnusedName("_obj_"sv);
5100 auto expList = toAst<ExpList_t>(objVar, x);
5101 auto assign = x->new_ptr<Assign_t>();
5102 assign->values.push_back(import->exp);
5103 auto assignment = x->new_ptr<ExpListAssign_t>();
5104 assignment->expList.set(expList);
5105 assignment->action.set(assign);
5106 objAssign.set(assignment);
5107 }
5108 auto expList = x->new_ptr<ExpList_t>();
5109 auto assign = x->new_ptr<Assign_t>();
5110 for (auto name : import->names.objects()) {
5111 switch (name->getId()) {
5112 case id<Variable_t>(): {
5113 auto var = ast_to<Variable_t>(name);
5114 {
5115 auto callable = toAst<Callable_t>(objVar, x);
5116 auto dotChainItem = x->new_ptr<DotChainItem_t>();
5117 dotChainItem->name.set(var->name);
5118 auto chainValue = x->new_ptr<ChainValue_t>();
5119 chainValue->items.push_back(callable);
5120 chainValue->items.push_back(dotChainItem);
5121 auto value = x->new_ptr<Value_t>();
5122 value->item.set(chainValue);
5123 auto exp = newExp(value, x);
5124 assign->values.push_back(exp);
5125 }
5126 auto callable = x->new_ptr<Callable_t>();
5127 callable->item.set(var);
5128 auto chainValue = x->new_ptr<ChainValue_t>();
5129 chainValue->items.push_back(callable);
5130 auto value = x->new_ptr<Value_t>();
5131 value->item.set(chainValue);
5132 auto exp = newExp(value, x);
5133 expList->exprs.push_back(exp);
5134 break;
5135 }
5136 case id<colon_import_name_t>(): {
5137 auto var = static_cast<colon_import_name_t*>(name)->name.get();
5138 {
5139 auto nameNode = var->name.get();
5140 auto callable = toAst<Callable_t>(objVar, x);
5141 auto colonChain = x->new_ptr<ColonChainItem_t>();
5142 colonChain->name.set(nameNode);
5143 auto chainValue = x->new_ptr<ChainValue_t>();
5144 chainValue->items.push_back(callable);
5145 chainValue->items.push_back(colonChain);
5146 auto value = x->new_ptr<Value_t>();
5147 value->item.set(chainValue);
5148 auto exp = newExp(value, x);
5149 assign->values.push_back(exp);
5150 }
5151 auto callable = x->new_ptr<Callable_t>();
5152 callable->item.set(var);
5153 auto chainValue = x->new_ptr<ChainValue_t>();
5154 chainValue->items.push_back(callable);
5155 auto value = x->new_ptr<Value_t>();
5156 value->item.set(chainValue);
5157 auto exp = newExp(value, x);
5158 expList->exprs.push_back(exp);
5159 break;
5160 }
5161 default: assert(false); break;
5162 }
5163 }
5164 if (objAssign) {
5165 auto preDef = getPredefine(transformAssignDefs(expList));
5166 if (!preDef.empty()) {
5167 temp.push_back(preDef + nll(import));
5168 }
5169 temp.push_back(indent() + s("do"sv) + nll(import));
5170 pushScope();
5171 transformAssignment(objAssign, temp);
5172 }
5173 auto assignment = x->new_ptr<ExpListAssign_t>();
5174 assignment->expList.set(expList);
5175 assignment->action.set(assign);
5176 transformAssignment(assignment, temp);
5177 if (objAssign) {
5178 popScope();
5179 temp.push_back(indent() + s("end"sv) + nlr(import));
5180 }
5181 out.push_back(join(temp));
5182 }
5183
5184 std::string moduleNameFrom(ImportLiteral_t* literal) {
5185 auto name = _parser.toString(literal->inners.back());
5186 Utils::replace(name, "-"sv, "_"sv);
5187 Utils::replace(name, " "sv, "_"sv);
5188 return name;
5189 }
5190
5191 void transformImportAs(ImportAs_t* import, str_list& out) {
5192 auto x = import;
5193 if (!import->target) {
5194 auto name = moduleNameFrom(import->literal);
5195 import->target.set(toAst<Variable_t>(name, x));
5196 }
5197 if (auto tabLit = import->target.as<ImportTabLit_t>()) {
5198 auto newTab = x->new_ptr<ImportTabLit_t>();
5199#ifndef MOONP_NO_MACRO
5200 bool importAllMacro = false;
5201 std::list<std::pair<std::string,std::string>> macroPairs;
5202 for (auto item : tabLit->items.objects()) {
5203 switch (item->getId()) {
5204 case id<MacroName_t>(): {
5205 auto macroName = static_cast<MacroName_t*>(item);
5206 auto name = _parser.toString(macroName->name);
5207 macroPairs.emplace_back(name, name);
5208 break;
5209 }
5210 case id<macro_name_pair_t>(): {
5211 auto pair = static_cast<macro_name_pair_t*>(item);
5212 macroPairs.emplace_back(_parser.toString(pair->key->name), _parser.toString(pair->value->name));
5213 break;
5214 }
5215 case id<import_all_macro_t>():
5216 if (importAllMacro) throw std::logic_error(_info.errorMessage(s("import all macro symbol duplicated"sv), item));
5217 importAllMacro = true;
5218 break;
5219 case id<variable_pair_t>():
5220 case id<normal_pair_t>():
5221 newTab->items.push_back(item);
5222 break;
5223 default: assert(false); break;
5224 }
5225 }
5226 if (importAllMacro || !macroPairs.empty()) {
5227 auto moduleName = _parser.toString(import->literal);
5228 Utils::replace(moduleName, "'"sv, ""sv);
5229 Utils::replace(moduleName, "\""sv, ""sv);
5230 Utils::trim(moduleName);
5231 pushCurrentModule(); // cur
5232 int top = lua_gettop(L) - 1; // Lua state may be setup by pushCurrentModule()
5233 DEFER(lua_settop(L, top));
5234 pushMoonp("find_modulepath"sv); // cur find_modulepath
5235 lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur find_modulepath moduleName
5236 if (lua_pcall(L, 1, 1, 0) != 0) {
5237 std::string err = lua_tostring(L, -1);
5238 throw std::logic_error(_info.errorMessage(s("failed to resolve module path\n"sv) + err, x));
5239 }
5240 if (lua_isnil(L, -1) != 0) {
5241 throw std::logic_error(_info.errorMessage(s("failed to find module '"sv) + moduleName + '\'', x));
5242 }
5243 std::string moduleFullName = lua_tostring(L, -1);
5244 lua_pop(L, 1); // cur
5245 if (!isModuleLoaded(moduleFullName)) {
5246 pushMoonp("read_file"sv); // cur read_file
5247 lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur load_text moduleFullName
5248 if (lua_pcall(L, 1, 1, 0) != 0) {
5249 std::string err = lua_tostring(L, -1);
5250 throw std::logic_error(_info.errorMessage(s("failed to read module file\n"sv) + err, x));
5251 } // cur text
5252 if (lua_isnil(L, -1) != 0) {
5253 throw std::logic_error(_info.errorMessage("failed to get module text"sv, x));
5254 } // cur text
5255 std::string text = lua_tostring(L, -1);
5256 auto compiler = MoonCompilerImpl(L, _luaOpen, false, moduleFullName);
5257 MoonConfig config;
5258 config.lineOffset = 0;
5259 config.lintGlobalVariable = false;
5260 config.reserveLineNumber = false;
5261 config.implicitReturnRoot = _config.implicitReturnRoot;
5262 auto result = compiler.compile(text, config);
5263 if (result.codes.empty() && !result.error.empty()) {
5264 throw std::logic_error(_info.errorMessage(s("failed to compile module '"sv) + moduleName + s("\': "sv) + result.error, x));
5265 }
5266 lua_pop(L, 1); // cur
5267 }
5268 pushModuleTable(moduleFullName); // cur mod
5269 if (importAllMacro) {
5270 lua_pushnil(L); // cur mod startKey
5271 while (lua_next(L, -2) != 0) { // cur mod key value
5272 lua_pushvalue(L, -2); // cur mod key value key
5273 lua_insert(L, -2); // cur mod key key value
5274 lua_rawset(L, -5); // cur[key] = value, cur mod key
5275 }
5276 }
5277 for (const auto& pair : macroPairs) {
5278 lua_getfield(L, -1, pair.first.c_str()); // mod[first], cur mod val
5279 lua_setfield(L, -3, pair.second.c_str()); // cur[second] = val, cur mod
5280 }
5281 }
5282#else // MOONP_NO_MACRO
5283 for (auto item : tabLit->items.objects()) {
5284 switch (item->getId()) {
5285 case id<MacroName_t>():
5286 case id<macro_name_pair_t>():
5287 case id<import_all_macro_t>(): {
5288 throw std::logic_error(_info.errorMessage("macro feature not supported"sv, item));
5289 break;
5290 }
5291 case id<variable_pair_t>():
5292 case id<normal_pair_t>():
5293 newTab->items.push_back(item);
5294 break;
5295 default: assert(false); break;
5296 }
5297 }
5298#endif // MOONP_NO_MACRO
5299 if (newTab->items.empty()) {
5300 out.push_back(Empty);
5301 return;
5302 } else {
5303 import->target.set(newTab);
5304 }
5305 }
5306 auto target = import->target.get();
5307 auto value = x->new_ptr<Value_t>();
5308 if (auto var = ast_cast<Variable_t>(target)) {
5309 auto callable = x->new_ptr<Callable_t>();
5310 callable->item.set(var);
5311 auto chainValue = x->new_ptr<ChainValue_t>();
5312 chainValue->items.push_back(callable);
5313 value->item.set(chainValue);
5314 } else {
5315 auto tabLit = ast_to<ImportTabLit_t>(target);
5316 auto simpleValue = x->new_ptr<SimpleValue_t>();
5317 auto tableLit = x->new_ptr<TableLit_t>();
5318 tableLit->values.dup(tabLit->items);
5319 simpleValue->value.set(tableLit);
5320 value->item.set(simpleValue);
5321 }
5322 auto exp = newExp(value, x);
5323 auto assignList = x->new_ptr<ExpList_t>();
5324 assignList->exprs.push_back(exp);
5325 auto assign = x->new_ptr<Assign_t>();
5326 assign->values.push_back(toAst<Exp_t>(s("require "sv) + _parser.toString(import->literal), x));
5327 auto assignment = x->new_ptr<ExpListAssign_t>();
5328 assignment->expList.set(assignList);
5329 assignment->action.set(assign);
5330 transformAssignment(assignment, out);
5331 }
5332
5333 void transformImport(Import_t* import, str_list& out) {
5334 auto content = import->content.get();
5335 switch (content->getId()) {
5336 case id<ImportAs_t>():
5337 transformImportAs(static_cast<ImportAs_t*>(content), out);
5338 break;
5339 case id<ImportFrom_t>():
5340 transformImportFrom(static_cast<ImportFrom_t*>(content), out);
5341 break;
5342 default: assert(false); break;
5343 }
5344 }
5345
5346 void transformWhileInPlace(While_t* whileNode, str_list& out, ExpList_t* expList = nullptr) {
5347 auto x = whileNode;
5348 str_list temp;
5349 if (expList) {
5350 temp.push_back(indent() + s("do"sv) + nll(whileNode));
5351 }
5352 pushScope();
5353 auto accumVar = getUnusedName("_accum_"sv);
5354 addToScope(accumVar);
5355 auto lenVar = getUnusedName("_len_"sv);
5356 addToScope(lenVar);
5357 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
5358 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
5359 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5360 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
5361 pushScope();
5362 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
5363 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
5364 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft);
5365 popScope();
5366 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5367 if (expList) {
5368 auto assign = x->new_ptr<Assign_t>();
5369 assign->values.push_back(toAst<Exp_t>(accumVar, x));
5370 auto assignment = x->new_ptr<ExpListAssign_t>();
5371 assignment->expList.set(expList);
5372 assignment->action.set(assign);
5373 transformAssignment(assignment, temp);
5374 } else {
5375 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
5376 }
5377 popScope();
5378 if (expList) {
5379 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5380 }
5381 out.push_back(join(temp));
5382 }
5383
5384 void transformWhileClosure(While_t* whileNode, str_list& out) {
5385 auto x = whileNode;
5386 str_list temp;
5387 temp.push_back(s("(function() "sv) + nll(whileNode));
5388 pushScope();
5389 _enableReturn.push(true);
5390 auto accumVar = getUnusedName("_accum_"sv);
5391 addToScope(accumVar);
5392 auto lenVar = getUnusedName("_len_"sv);
5393 addToScope(lenVar);
5394 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
5395 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
5396 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5397 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
5398 pushScope();
5399 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), x);
5400 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
5401 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft);
5402 popScope();
5403 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
5404 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
5405 _enableReturn.pop();
5406 popScope();
5407 temp.push_back(indent() + s("end)()"sv));
5408 out.push_back(join(temp));
5409 }
5410
5411 void transformWhile(While_t* whileNode, str_list& out) {
5412 str_list temp;
5413 pushScope();
5414 transformExp(whileNode->condition, temp, ExpUsage::Closure);
5415 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common);
5416 popScope();
5417 _buf << indent() << "while "sv << temp.front() << " do"sv << nll(whileNode);
5418 _buf << temp.back();
5419 _buf << indent() << "end"sv << nlr(whileNode);
5420 out.push_back(clearBuf());
5421 }
5422
5423 void transformRepeat(Repeat_t* repeat, str_list& out) {
5424 str_list temp;
5425 pushScope();
5426 transformLoopBody(repeat->body->content, temp, Empty, ExpUsage::Common);
5427 transformExp(repeat->condition, temp, ExpUsage::Closure);
5428 popScope();
5429 _buf << indent() << "repeat"sv << nll(repeat);
5430 _buf << temp.front();
5431 _buf << indent() << "until "sv << temp.back() << nlr(repeat);
5432 out.push_back(clearBuf());
5433 }
5434
5435 void transformSwitch(Switch_t* switchNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
5436 str_list temp;
5437 if (usage == ExpUsage::Closure) {
5438 temp.push_back(s("(function()"sv) + nll(switchNode));
5439 pushScope();
5440 _enableReturn.push(true);
5441 }
5442 auto objVar = singleVariableFrom(switchNode->target);
5443 if (objVar.empty()) {
5444 objVar = getUnusedName("_exp_"sv);
5445 addToScope(objVar);
5446 transformExp(switchNode->target, temp, ExpUsage::Closure);
5447 _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode);
5448 temp.back() = clearBuf();
5449 }
5450 const auto& branches = switchNode->branches.objects();
5451 for (auto branch_ : branches) {
5452 auto branch = static_cast<SwitchCase_t*>(branch_);
5453 temp.push_back(indent() + s(branches.front() == branch ? "if"sv : "elseif"sv));
5454 str_list tmp;
5455 const auto& exprs = branch->valueList->exprs.objects();
5456 for (auto exp_ : exprs) {
5457 auto exp = static_cast<Exp_t*>(exp_);
5458 transformExp(exp, tmp, ExpUsage::Closure);
5459 if (!singleValueFrom(exp)) {
5460 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
5461 }
5462 temp.back().append(s(" "sv) + tmp.back() + s(" == "sv) + objVar +
5463 s(exp == exprs.back() ? ""sv : " or"sv));
5464 }
5465 temp.back().append(s(" then"sv) + nll(branch));
5466 pushScope();
5467 transform_plain_body(branch->body, temp, usage, assignList);
5468 popScope();
5469 }
5470 if (switchNode->lastBranch) {
5471 temp.push_back(indent() + s("else"sv) + nll(switchNode->lastBranch));
5472 pushScope();
5473 transform_plain_body(switchNode->lastBranch, temp, usage, assignList);
5474 popScope();
5475 }
5476 temp.push_back(indent() + s("end"sv) + nlr(switchNode));
5477 if (usage == ExpUsage::Closure) {
5478 _enableReturn.pop();
5479 popScope();
5480 temp.push_back(indent() + s("end)()"sv));
5481 }
5482 out.push_back(join(temp));
5483 }
5484
5485 void transformLocalDef(Local_t* local, str_list& out) {
5486 if (!local->forceDecls.empty() || !local->decls.empty()) {
5487 str_list defs;
5488 for (const auto& decl : local->forceDecls) {
5489 forceAddToScope(decl);
5490 defs.push_back(decl);
5491 }
5492 for (const auto& decl : local->decls) {
5493 if (addToScope(decl)) {
5494 defs.push_back(decl);
5495 }
5496 }
5497 auto preDefine = getPredefine(defs);
5498 if (!preDefine.empty()) {
5499 out.push_back(preDefine + nll(local));
5500 }
5501 }
5502 }
5503
5504 void transformLocal(Local_t* local, str_list& out) {
5505 str_list temp;
5506 if (!local->defined) {
5507 local->defined = true;
5508 transformLocalDef(local, temp);
5509 }
5510 if (auto values = local->item.as<local_values_t>()) {
5511 if (values->valueList) {
5512 auto x = local;
5513 auto expList = x->new_ptr<ExpList_t>();
5514 for (auto name : values->nameList->names.objects()) {
5515 auto callable = x->new_ptr<Callable_t>();
5516 callable->item.set(name);
5517 auto chainValue = x->new_ptr<ChainValue_t>();
5518 chainValue->items.push_back(callable);
5519 auto value = x->new_ptr<Value_t>();
5520 value->item.set(chainValue);
5521 auto exp = newExp(value, x);
5522 expList->exprs.push_back(exp);
5523 }
5524 auto assignment = x->new_ptr<ExpListAssign_t>();
5525 assignment->expList.set(expList);
5526 auto assign = x->new_ptr<Assign_t>();
5527 if (auto expListLow = values->valueList.as<ExpListLow_t>()) {
5528 assign->values.dup(expListLow->exprs);
5529 } else {
5530 auto tableBlock = values->valueList.to<TableBlock_t>();
5531 assign->values.push_back(tableBlock);
5532 }
5533 assignment->action.set(assign);
5534 transformAssignment(assignment, temp);
5535 }
5536 }
5537 out.push_back(join(temp));
5538 }
5539
5540 void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) {
5541 auto x = localAttrib;
5542 auto attrib = _parser.toString(localAttrib->attrib);
5543 if (attrib != "close"sv && attrib != "const"sv) {
5544 throw std::logic_error(_info.errorMessage(s("unknown attribute '"sv) + attrib + '\'', localAttrib->attrib));
5545 }
5546 auto expList = x->new_ptr<ExpList_t>();
5547 str_list tmpVars;
5548 str_list vars;
5549 pushScope();
5550 for (auto name : localAttrib->nameList->names.objects()) {
5551 auto callable = x->new_ptr<Callable_t>();
5552 callable->item.set(name);
5553 auto chainValue = x->new_ptr<ChainValue_t>();
5554 chainValue->items.push_back(callable);
5555 auto value = x->new_ptr<Value_t>();
5556 value->item.set(chainValue);
5557 auto exp = newExp(value, x);
5558 expList->exprs.push_back(exp);
5559 tmpVars.push_back(getUnusedName("_var_"sv));
5560 addToScope(tmpVars.back());
5561 vars.push_back(_parser.toString(name));
5562 }
5563 popScope();
5564 auto tmpVarStr = join(tmpVars, ", "sv);
5565 auto tmpVarList = toAst<ExpList_t>(tmpVarStr, x);
5566 auto assignment = x->new_ptr<ExpListAssign_t>();
5567 assignment->expList.set(tmpVarList);
5568 assignment->action.set(localAttrib->assign);
5569 str_list temp;
5570 transformAssignment(assignment, temp);
5571 attrib = s(" <"sv) + attrib + '>';
5572 for (auto& var : vars) {
5573 forceAddToScope(var);
5574 var.append(attrib);
5575 }
5576 temp.push_back(indent() + s("local "sv) + join(vars, ", "sv) + s(" = "sv) + tmpVarStr + nll(x));
5577 out.push_back(join(temp));
5578 }
5579
5580 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
5581 auto keyword = _parser.toString(breakLoop);
5582 if (keyword == "break"sv) {
5583 out.push_back(indent() + keyword + nll(breakLoop));
5584 return;
5585 }
5586 if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop));
5587 _buf << indent() << _continueVars.top() << " = true"sv << nll(breakLoop);
5588 _buf << indent() << "break"sv << nll(breakLoop);
5589 out.push_back(clearBuf());
5590 }
5591
5592 void transformLabel(Label_t* label, str_list& out) {
5593 out.push_back(indent() + s("::"sv) + _parser.toString(label->label) + s("::"sv) + nll(label));
5594 }
5595
5596 void transformGoto(Goto_t* gotoNode, str_list& out) {
5597 out.push_back(indent() + s("goto "sv) + _parser.toString(gotoNode->label) + nll(gotoNode));
5598 }
5599};
5600
5601const std::string MoonCompilerImpl::Empty;
5602
5603MoonCompiler::MoonCompiler(void* sharedState,
5604 const std::function<void(void*)>& luaOpen,
5605 bool sameModule):
5606#ifndef MOONP_NO_MACRO
5607_compiler(std::make_unique<MoonCompilerImpl>(static_cast<lua_State*>(sharedState), luaOpen, sameModule)) {}
5608#else
5609_compiler(std::make_unique<MoonCompilerImpl>()) {
5610 (void)sharedState;
5611 (void)luaOpen;
5612 (void)sameModule;
5613}
5614#endif // MOONP_NO_MACRO
5615
5616MoonCompiler::~MoonCompiler() {}
5617
5618CompileInfo MoonCompiler::compile(std::string_view codes, const MoonConfig& config) {
5619 return _compiler->compile(codes, config);
5620}
5621
5622} // namespace MoonP