aboutsummaryrefslogtreecommitdiff
path: root/MoonParser/moon_compiler.cpp
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2019-10-29 11:25:27 +0800
committerLi Jin <dragon-fly@qq.com>2019-10-29 11:25:27 +0800
commit975167856ed0b11c2ede03c6eb750ca4e4a6a7fc (patch)
treefa4369fe7e7d49c63cae93d6c5b52b78116f58cd /MoonParser/moon_compiler.cpp
parent726fee3152c81fdac7e3ad5f663bfbea8f99ddd8 (diff)
downloadyuescript-975167856ed0b11c2ede03c6eb750ca4e4a6a7fc.tar.gz
yuescript-975167856ed0b11c2ede03c6eb750ca4e4a6a7fc.tar.bz2
yuescript-975167856ed0b11c2ede03c6eb750ca4e4a6a7fc.zip
complete moon compiler in C++.
Diffstat (limited to 'MoonParser/moon_compiler.cpp')
-rw-r--r--MoonParser/moon_compiler.cpp3851
1 files changed, 3851 insertions, 0 deletions
diff --git a/MoonParser/moon_compiler.cpp b/MoonParser/moon_compiler.cpp
new file mode 100644
index 0000000..85b19ff
--- /dev/null
+++ b/MoonParser/moon_compiler.cpp
@@ -0,0 +1,3851 @@
1#include <string>
2#include <unordered_set>
3#include <unordered_map>
4#include <stack>
5#include <vector>
6#include <numeric>
7#include <memory>
8#include <sstream>
9#include <string_view>
10using namespace std::string_view_literals;
11#include "parser.hpp"
12#include "moon_ast.h"
13#include "moon_compiler.h"
14
15namespace MoonP {
16
17#define BLOCK_START do {
18#define BLOCK_END } while (false);
19#define BREAK_IF(cond) if (cond) break
20
21typedef std::list<std::string> str_list;
22
23inline std::string s(std::string_view sv) {
24 return std::string(sv);
25}
26
27class MoonCompliler {
28public:
29 std::pair<std::string,std::string> complile(const std::string& codes, bool lintGlobalVar, bool implicitReturnRoot, bool lineNumber) {
30 _lintGlobalVar = lintGlobalVar;
31 _lineNumber = lineNumber;
32 _input = _converter.from_bytes(codes);
33 error_list el;
34 State st;
35 ast_ptr<false, File_t> root;
36 try {
37 root = parse<File_t>(_input, File, el, &st);
38 } catch (const std::logic_error& error) {
39 clear();
40 return {Empty, error.what()};
41 }
42 if (root) {
43 try {
44 str_list out;
45 pushScope();
46 transformBlock(root->block, out, implicitReturnRoot);
47 popScope();
48 return {std::move(out.back()), Empty};
49 } catch (const std::logic_error& error) {
50 clear();
51 return {Empty, error.what()};
52 }
53 } else {
54 clearBuf();
55 for (error_list::iterator it = el.begin(); it != el.end(); ++it) {
56 const error& err = *it;
57 _buf << debugInfo("Syntax error."sv, &err);
58 }
59 std::pair<std::string,std::string> result{Empty, clearBuf()};
60 clear();
61 return result;
62 }
63 }
64
65 const std::unordered_map<std::string,std::pair<int,int>>& getGlobals() const {
66 return _globals;
67 }
68
69 void clear() {
70 _indentOffset = 0;
71 _scopes.clear();
72 _codeCache.clear();
73 std::stack<std::string> emptyWith;
74 _withVars.swap(emptyWith);
75 std::stack<std::string> emptyContinue;
76 _continueVars.swap(emptyContinue);
77 _buf.str("");
78 _buf.clear();
79 _joinBuf.str("");
80 _joinBuf.clear();
81 _globals.clear();
82 _input.clear();
83 }
84private:
85 bool _lintGlobalVar = false;
86 bool _lineNumber = false;
87 int _indentOffset = 0;
88 Converter _converter;
89 input _input;
90 std::list<input> _codeCache;
91 std::stack<std::string> _withVars;
92 std::stack<std::string> _continueVars;
93 std::unordered_map<std::string,std::pair<int,int>> _globals;
94 std::ostringstream _buf;
95 std::ostringstream _joinBuf;
96 std::string _newLine = "\n";
97 enum class LocalMode {
98 None = 0,
99 Capital = 1,
100 Any = 2
101 };
102 enum class ExportMode {
103 None = 0,
104 Capital = 1,
105 Any = 2
106 };
107 struct Scope {
108 ExportMode mode = ExportMode::None;
109 std::unique_ptr<std::unordered_set<std::string>> vars;
110 std::unique_ptr<std::unordered_set<std::string>> allows;
111 std::unique_ptr<std::unordered_set<std::string>> exports;
112 };
113 std::list<Scope> _scopes;
114 static const std::string Empty;
115
116 enum class MemType {
117 Builtin,
118 Common,
119 Property
120 };
121
122 struct ClassMember {
123 std::string item;
124 MemType type;
125 ast_node* node;
126 };
127
128 struct DestructItem {
129 bool isVariable = false;
130 std::string name;
131 std::string structure;
132 };
133
134 struct Destructure {
135 std::string value;
136 std::list<DestructItem> items;
137 };
138
139 enum class ExpUsage {
140 Return,
141 Assignment,
142 Common,
143 Closure
144 };
145
146 enum class IfUsage {
147 Return,
148 Closure,
149 Common
150 };
151
152 void pushScope() {
153 _scopes.emplace_back();
154 _scopes.back().vars = std::make_unique<std::unordered_set<std::string>>();
155 }
156
157 void popScope() {
158 _scopes.pop_back();
159 }
160
161 bool isDefined(const std::string& name) {
162 bool isDefined = false;
163 int mode = int(std::isupper(name[0]) ? ExportMode::Capital : ExportMode::Any);
164 const auto& current = _scopes.back();
165 if (int(current.mode) >= mode) {
166 if (current.exports) {
167 if (current.exports->find(name) != current.exports->end()) {
168 isDefined = true;
169 current.vars->insert(name);
170 }
171 } else {
172 isDefined = true;
173 current.vars->insert(name);
174 }
175 }
176 decltype(_scopes.back().allows.get()) allows = nullptr;
177 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
178 if (it->allows) allows = it->allows.get();
179 }
180 bool checkShadowScopeOnly = false;
181 if (allows) {
182 checkShadowScopeOnly = allows->find(name) == allows->end();
183 }
184 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
185 auto vars = it->vars.get();
186 if (vars->find(name) != vars->end()) {
187 isDefined = true;
188 break;
189 }
190 if (checkShadowScopeOnly && it->allows) break;
191 }
192 return isDefined;
193 }
194
195 bool isSolidDefined(const std::string& name) {
196 bool isDefined = false;
197 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
198 auto vars = it->vars.get();
199 if (vars->find(name) != vars->end()) {
200 isDefined = true;
201 break;
202 }
203 }
204 return isDefined;
205 }
206
207 void markVarShadowed() {
208 auto& scope = _scopes.back();
209 scope.allows = std::make_unique<std::unordered_set<std::string>>();
210 }
211
212 void markVarExported(ExportMode mode, bool specified) {
213 auto& scope = _scopes.back();
214 scope.mode = mode;
215 if (specified && !scope.exports) {
216 scope.exports = std::make_unique<std::unordered_set<std::string>>();
217 }
218 }
219
220 void addExportedVar(const std::string& name) {
221 auto& scope = _scopes.back();
222 scope.exports->insert(name);
223 }
224
225 void addToAllowList(const std::string& name) {
226 auto& scope = _scopes.back();
227 scope.allows->insert(name);
228 }
229
230 void forceAddToScope(const std::string& name) {
231 auto& scope = _scopes.back();
232 scope.vars->insert(name);
233 }
234
235 Scope& currentScope() {
236 return _scopes.back();
237 }
238
239 bool addToScope(const std::string& name) {
240 bool defined = isDefined(name);
241 if (!defined) {
242 auto& scope = currentScope();
243 scope.vars->insert(name);
244 }
245 return !defined;
246 }
247
248 std::string getUnusedName(std::string_view name) {
249 int index = 0;
250 std::string newName;
251 do {
252 newName = s(name) + std::to_string(index);
253 index++;
254 } while (isSolidDefined(newName));
255 return newName;
256 }
257
258 const std::string nll(ast_node* node) {
259 if (_lineNumber) {
260 return s(" -- "sv) + std::to_string(node->m_begin.m_line) + _newLine;
261 } else {
262 return _newLine;
263 }
264 }
265
266 const std::string nlr(ast_node* node) {
267 if (_lineNumber) {
268 return s(" -- "sv) + std::to_string(node->m_end.m_line) + _newLine;
269 } else {
270 return _newLine;
271 }
272 }
273
274 void incIndentOffset() {
275 _indentOffset++;
276 }
277
278 void decIndentOffset() {
279 _indentOffset--;
280 }
281
282 std::string indent() {
283 return std::string((_scopes.size() - 1 + _indentOffset) * 2, ' ');
284 }
285
286 std::string indent(int offset) {
287 return std::string((_scopes.size() - 1 + _indentOffset + offset) * 2, ' ');
288 }
289
290 std::string clearBuf() {
291 std::string str = _buf.str();
292 _buf.str("");
293 _buf.clear();
294 return str;
295 }
296
297 std::string join(const str_list& items) {
298 if (items.empty()) return Empty;
299 else if (items.size() == 1) return items.front();
300 for (const auto& item : items) {
301 _joinBuf << item;
302 }
303 auto result = _joinBuf.str();
304 _joinBuf.str("");
305 _joinBuf.clear();
306 return result;
307 }
308
309 std::string join(const str_list& items, std::string_view sep) {
310 if (items.empty()) return Empty;
311 else if (items.size() == 1) return items.front();
312 std::string sepStr = s(sep);
313 auto begin = ++items.begin();
314 _joinBuf << items.front();
315 for (auto it = begin; it != items.end(); ++it) {
316 _joinBuf << sepStr << *it;
317 }
318 auto result = _joinBuf.str();
319 _joinBuf.str("");
320 _joinBuf.clear();
321 return result;
322 }
323
324 std::string toString(ast_node* node) {
325 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it));
326 }
327
328 std::string toString(input::iterator begin, input::iterator end) {
329 return _converter.to_bytes(std::wstring(begin, end));
330 }
331
332 Value_t* singleValueFrom(ast_node* item) {
333 Exp_t* exp = nullptr;
334 switch (item->getId()) {
335 case "Exp"_id:
336 exp = static_cast<Exp_t*>(item);
337 break;
338 case "ExpList"_id: {
339 auto expList = static_cast<ExpList_t*>(item);
340 if (expList->exprs.size() == 1) {
341 exp = static_cast<Exp_t*>(expList->exprs.front());
342 }
343 break;
344 }
345 case "ExpListLow"_id: {
346 auto expList = static_cast<ExpListLow_t*>(item);
347 if (expList->exprs.size() == 1) {
348 exp = static_cast<Exp_t*>(expList->exprs.front());
349 }
350 break;
351 }
352 }
353 if (!exp) return nullptr;
354 if (exp->opValues.empty()) {
355 return exp->value.get();
356 }
357 return nullptr;
358 }
359
360 SimpleValue_t* simpleSingleValueFrom(ast_node* expList) {
361 auto value = singleValueFrom(expList);
362 if (value && value->item.is<SimpleValue_t>()) {
363 return static_cast<SimpleValue_t*>(value->item.get());
364 }
365 return nullptr;
366 }
367
368 Value_t* firstValueFrom(ast_node* item) {
369 Exp_t* exp = nullptr;
370 if (auto expList = ast_cast<ExpList_t>(item)) {
371 if (!expList->exprs.empty()) {
372 exp = static_cast<Exp_t*>(expList->exprs.front());
373 }
374 } else {
375 exp = ast_cast<Exp_t>(item);
376 }
377 return exp->value.get();
378 }
379
380 Statement_t* lastStatementFrom(Body_t* body) {
381 if (auto stmt = body->content.as<Statement_t>()) {
382 return stmt;
383 } else {
384 auto node = body->content.to<Block_t>()->statements.objects().back();
385 return static_cast<Statement_t*>(node);
386 }
387 }
388
389 Statement_t* lastStatementFrom(Block_t* block) {
390 auto node = block->statements.objects().back();
391 return static_cast<Statement_t*>(node);
392 }
393
394 template <class T>
395 ast_ptr<false, T> toAst(std::string_view codes, rule& r, ast_node* parent) {
396 _codeCache.push_back(_converter.from_bytes(s(codes)));
397 error_list el;
398 State st;
399 auto ptr = parse<T>(_codeCache.back(), r, el, &st);
400 ptr->traverse([&](ast_node* node) {
401 node->m_begin.m_line = parent->m_begin.m_line;
402 node->m_end.m_line = parent->m_begin.m_line;
403 return traversal::Continue;
404 });
405 return ptr;
406 }
407
408 bool matchAst(rule& r, std::string_view codes) {
409 error_list el;
410 State st;
411 input i = _converter.from_bytes(s(codes));
412 auto rEnd = rule(r >> eof());
413 ast_ptr<false, ast_node> result(_parse(i, rEnd, el, &st));
414 return result;
415 }
416
417 bool isChainValueCall(ChainValue_t* chainValue) {
418 return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back());
419 }
420
421 std::string singleVariableFrom(ast_node* expList) {
422 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
423 BLOCK_START
424 auto value = singleValueFrom(expList);
425 BREAK_IF(!value);
426 auto chainValue = value->getByPath<ChainValue_t>();
427 BREAK_IF(!chainValue);
428 BREAK_IF(chainValue->items.size() != 1);
429 auto callable = ast_cast<Callable_t>(chainValue->items.front());
430 BREAK_IF(!callable || !callable->item.is<Variable_t>());
431 str_list tmp;
432 transformCallable(callable, tmp, false);
433 return tmp.back();
434 BLOCK_END
435 return Empty;
436 }
437
438 bool isColonChain(ChainValue_t* chainValue) {
439 return ast_is<ColonChainItem_t>(chainValue->items.back());
440 }
441
442 bool hasKeywordColonChainItem(ChainValue_t* chainValue) {
443 const auto& chainList = chainValue->items.objects();
444 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
445 if (auto colonItem = ast_cast<ColonChainItem_t>(*it)) {
446 if (colonItem->name.is<LuaKeyword_t>()) {
447 return true;
448 }
449 }
450 }
451 return false;
452 }
453
454 bool isAssignable(const node_container& chainItems) {
455 if (chainItems.size() == 1) {
456 auto firstItem = chainItems.back();
457 if (auto callable = ast_cast<Callable_t>(firstItem)) {
458 switch (callable->item->getId()) {
459 case "Variable"_id:
460 case "SelfName"_id:
461 return true;
462 }
463 } else if (firstItem->getId() == "DotChainItem"_id) {
464 return true;
465 }
466 } else {
467 auto lastItem = chainItems.back();
468 switch (lastItem->getId()) {
469 case "DotChainItem"_id:
470 case "Exp"_id:
471 return true;
472 }
473 }
474 return false;
475 }
476
477 bool isAssignable(Exp_t* exp) {
478 if (auto value = singleValueFrom(exp)) {
479 auto item = value->item.get();
480 switch (item->getId()) {
481 case "simple_table"_id:
482 return true;
483 case "SimpleValue"_id: {
484 auto simpleValue = static_cast<SimpleValue_t*>(item);
485 if (simpleValue->value.is<TableLit_t>()) {
486 return true;
487 }
488 return false;
489 }
490 case "ChainValue"_id: {
491 auto chainValue = static_cast<ChainValue_t*>(item);
492 return isAssignable(chainValue->items.objects());
493 }
494 }
495 }
496 return false;
497 }
498
499 bool isAssignable(Assignable_t* assignable) {
500 if (auto assignableChain = ast_cast<AssignableChain_t>(assignable->item)) {
501 return isAssignable(assignableChain->items.objects());
502 }
503 return true;
504 }
505
506 void checkAssignable(ExpList_t* expList) {
507 for (auto exp_ : expList->exprs.objects()) {
508 Exp_t* exp = static_cast<Exp_t*>(exp_);
509 if (!isAssignable(exp)) {
510 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
511 }
512 }
513 }
514
515 std::string debugInfo(std::string_view msg, const input_range* loc) {
516 const int ASCII = 255;
517 int length = loc->m_begin.m_line;
518 auto begin = _input.begin();
519 auto end = _input.end();
520 int count = 0;
521 for (auto it = _input.begin(); it != _input.end(); ++it) {
522 if (*it == '\n') {
523 if (count + 1 == length) {
524 end = it;
525 break;
526 } else {
527 begin = it + 1;
528 }
529 count++;
530 }
531 }
532 auto line = _converter.to_bytes(std::wstring(begin, end));
533 int oldCol = loc->m_begin.m_col;
534 int col = loc->m_begin.m_col - 1;
535 auto it = begin;
536 for (int i = 0; i < oldCol; ++i) {
537 if (*it > ASCII) {
538 ++col;
539 }
540 ++it;
541 }
542 replace(line, "\t"sv, " "sv);
543 std::ostringstream buf;
544 buf << loc->m_begin.m_line << ": "sv << msg <<
545 '\n' << line << '\n' << std::string(col, ' ') << "^"sv;
546 return buf.str();
547 }
548
549 void transformStatement(Statement_t* statement, str_list& out) {
550 auto x = statement;
551 if (statement->appendix) {
552 if (auto assignment = assignmentFrom(statement)) {
553 auto preDefine = getPredefine(transformAssignDefs(assignment->expList));
554 if (!preDefine.empty()) out.push_back(preDefine + nll(statement));
555 }
556 auto appendix = statement->appendix.get();
557 switch (appendix->item->getId()) {
558 case "if_else_line"_id: {
559 auto if_else_line = appendix->item.to<if_else_line_t>();
560 auto ifNode = x->new_ptr<If_t>();
561
562 auto ifCond = x->new_ptr<IfCond_t>();
563 ifCond->condition.set(if_else_line->condition);
564 ifNode->nodes.push_back(ifCond);
565
566 auto stmt = x->new_ptr<Statement_t>();
567 stmt->content.set(statement->content);
568 auto body = x->new_ptr<Body_t>();
569 body->content.set(stmt);
570 ifNode->nodes.push_back(body);
571
572 if (!ast_is<default_value_t>(if_else_line->elseExpr)) {
573 auto expList = x->new_ptr<ExpList_t>();
574 expList->exprs.push_back(if_else_line->elseExpr);
575 auto expListAssign = x->new_ptr<ExpListAssign_t>();
576 expListAssign->expList.set(expList);
577 auto stmt = x->new_ptr<Statement_t>();
578 stmt->content.set(expListAssign);
579 auto body = x->new_ptr<Body_t>();
580 body->content.set(stmt);
581 ifNode->nodes.push_back(body);
582 }
583
584 statement->appendix.set(nullptr);
585 auto simpleValue = x->new_ptr<SimpleValue_t>();
586 simpleValue->value.set(ifNode);
587 auto value = x->new_ptr<Value_t>();
588 value->item.set(simpleValue);
589 auto exp = x->new_ptr<Exp_t>();
590 exp->value.set(value);
591 auto expList = x->new_ptr<ExpList_t>();
592 expList->exprs.push_back(exp);
593 auto expListAssign = x->new_ptr<ExpListAssign_t>();
594 expListAssign->expList.set(expList);
595 statement->content.set(expListAssign);
596 break;
597 }
598 case "unless_line"_id: {
599 auto unless_line = appendix->item.to<unless_line_t>();
600 auto unless = x->new_ptr<Unless_t>();
601
602 auto ifCond = x->new_ptr<IfCond_t>();
603 ifCond->condition.set(unless_line->condition);
604 unless->nodes.push_back(ifCond);
605
606 auto stmt = x->new_ptr<Statement_t>();
607 stmt->content.set(statement->content);
608 auto body = x->new_ptr<Body_t>();
609 body->content.set(stmt);
610 unless->nodes.push_back(body);
611
612 statement->appendix.set(nullptr);
613 auto simpleValue = x->new_ptr<SimpleValue_t>();
614 simpleValue->value.set(unless);
615 auto value = x->new_ptr<Value_t>();
616 value->item.set(simpleValue);
617 auto exp = x->new_ptr<Exp_t>();
618 exp->value.set(value);
619 auto exprList = x->new_ptr<ExpList_t>();
620 exprList->exprs.push_back(exp);
621 auto expListAssign = x->new_ptr<ExpListAssign_t>();
622 expListAssign->expList.set(exprList);
623 statement->content.set(expListAssign);
624 break;
625 }
626 case "CompInner"_id: {
627 auto compInner = appendix->item.to<CompInner_t>();
628 auto comp = x->new_ptr<Comprehension_t>();
629 comp->forLoop.set(compInner);
630 auto stmt = x->new_ptr<Statement_t>();
631 stmt->content.set(statement->content);
632 comp->value.set(stmt);
633 auto simpleValue = x->new_ptr<SimpleValue_t>();
634 simpleValue->value.set(comp);
635 auto value = x->new_ptr<Value_t>();
636 value->item.set(simpleValue);
637 auto exp = x->new_ptr<Exp_t>();
638 exp->value.set(value);
639 auto expList = x->new_ptr<ExpList_t>();
640 expList->exprs.push_back(exp);
641 auto expListAssign = x->new_ptr<ExpListAssign_t>();
642 expListAssign->expList.set(expList);
643 statement->content.set(expListAssign);
644 statement->appendix.set(nullptr);
645 break;
646 }
647 default: break;
648 }
649 }
650 auto content = statement->content.get();
651 if (!content) {
652 out.push_back(Empty);
653 return;
654 }
655 switch (content->getId()) {
656 case "Import"_id: transformImport(static_cast<Import_t*>(content), out); break;
657 case "While"_id: transformWhile(static_cast<While_t*>(content), out); break;
658 case "For"_id: transformFor(static_cast<For_t*>(content), out); break;
659 case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(content), out); break;
660 case "Return"_id: transformReturn(static_cast<Return_t*>(content), out); break;
661 case "Local"_id: transformLocal(static_cast<Local_t*>(content), out); break;
662 case "Export"_id: transformExport(static_cast<Export_t*>(content), out); break;
663 case "BreakLoop"_id: transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break;
664 case "ExpListAssign"_id: {
665 auto expListAssign = static_cast<ExpListAssign_t*>(content);
666 if (expListAssign->action) {
667 transformAssignment(expListAssign, out);
668 } else {
669 auto expList = expListAssign->expList.get();
670 if (expList->exprs.objects().empty()) {
671 out.push_back(Empty);
672 break;
673 }
674 if (auto singleValue = singleValueFrom(expList)) {
675 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
676 auto value = simpleValue->value.get();
677 bool specialSingleValue = true;
678 switch (value->getId()) {
679 case "If"_id: transformIf(static_cast<If_t*>(value), out); break;
680 case "ClassDecl"_id: transformClassDecl(static_cast<ClassDecl_t*>(value), out); break;
681 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out); break;
682 case "Switch"_id: transformSwitch(static_cast<Switch_t*>(value), out); break;
683 case "With"_id: transformWith(static_cast<With_t*>(value), out); break;
684 case "ForEach"_id: transformForEach(static_cast<ForEach_t*>(value), out); break;
685 case "For"_id: transformFor(static_cast<For_t*>(value), out); break;
686 case "While"_id: transformWhile(static_cast<While_t*>(value), out); break;
687 case "Do"_id: transformDo(static_cast<Do_t*>(value), out); break;
688 case "Comprehension"_id: transformCompCommon(static_cast<Comprehension_t*>(value), out); break;
689 default: specialSingleValue = false; break;
690 }
691 if (specialSingleValue) {
692 break;
693 }
694 }
695 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
696 if (isChainValueCall(chainValue)) {
697 transformChainValue(chainValue, out, ExpUsage::Common);
698 break;
699 }
700 }
701 }
702 auto assign = x->new_ptr<Assign_t>();
703 assign->values.dup(expList->exprs);
704 auto assignment = x->new_ptr<ExpListAssign_t>();
705 assignment->expList.set(toAst<ExpList_t>("_", ExpList, x));
706 assignment->action.set(assign);
707 transformAssignment(assignment, out);
708 }
709 break;
710 }
711 default: break;
712 }
713 }
714
715 str_list getAssignVars(ExpListAssign_t* assignment) {
716 str_list vars;
717 if (!assignment->action.is<Assign_t>()) return vars;
718 for (auto exp : assignment->expList->exprs.objects()) {
719 auto var = singleVariableFrom(exp);
720 vars.push_back(var.empty() ? Empty : var);
721 }
722 return vars;
723 }
724
725 str_list getAssignVars(With_t* with) {
726 str_list vars;
727 for (auto exp : with->valueList->exprs.objects()) {
728 auto var = singleVariableFrom(exp);
729 vars.push_back(var.empty() ? Empty : var);
730 }
731 return vars;
732 }
733
734 str_list getAssignDefs(ExpList_t* expList) {
735 str_list preDefs;
736 for (auto exp_ : expList->exprs.objects()) {
737 auto exp = static_cast<Exp_t*>(exp_);
738 if (auto value = singleValueFrom(exp)) {
739 if (auto chain = value->item.as<ChainValue_t>()) {
740 BLOCK_START
741 BREAK_IF(chain->items.size() != 1);
742 auto callable = ast_cast<Callable_t>(chain->items.front());
743 BREAK_IF(!callable);
744 auto var = callable->item.as<Variable_t>();
745 BREAK_IF(!var);
746 auto name = toString(var);
747 if (!isDefined(name)) {
748 preDefs.push_back(name);
749 }
750 BLOCK_END
751 }
752 } else {
753 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
754 }
755 }
756 return preDefs;
757 }
758
759 str_list transformAssignDefs(ExpList_t* expList) {
760 str_list preDefs;
761 for (auto exp_ : expList->exprs.objects()) {
762 auto exp = static_cast<Exp_t*>(exp_);
763 if (auto value = singleValueFrom(exp)) {
764 if (auto chain = value->item.as<ChainValue_t>()) {
765 BLOCK_START
766 BREAK_IF(chain->items.size() != 1);
767 auto callable = ast_cast<Callable_t>(chain->items.front());
768 BREAK_IF(!callable);
769 auto var = callable->item.as<Variable_t>();
770 BREAK_IF(!var);
771 auto name = toString(var);
772 if (addToScope(name)) {
773 preDefs.push_back(name);
774 }
775 BLOCK_END
776 }
777 } else {
778 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, exp));
779 }
780 }
781 return preDefs;
782 }
783
784 std::string getPredefine(const str_list& defs) {
785 if (defs.empty()) return Empty;
786 return indent() + s("local "sv) + join(defs, ", "sv);
787 }
788
789 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
790 auto info = extractDestructureInfo(assignment);
791 if (!info.first.empty()) {
792 for (const auto& destruct : info.first) {
793 str_list defs;
794 for (const auto& item : destruct.items) {
795 if (item.isVariable && addToScope(item.name)) {
796 defs.push_back(item.name);
797 }
798 }
799 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
800 }
801 }
802 return clearBuf();
803 }
804
805 std::string getPredefine(ExpListAssign_t* assignment) {
806 auto preDefine = getDestrucureDefine(assignment);
807 if (preDefine.empty()) {
808 preDefine = getPredefine(transformAssignDefs(assignment->expList));
809 }
810 return preDefine.empty() ? preDefine : preDefine + nll(assignment);
811 }
812
813 ExpList_t* expListFrom(Statement_t* statement) {
814 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
815 if (!expListAssign->action) {
816 return expListAssign->expList.get();
817 }
818 }
819 return nullptr;
820 }
821
822 ExpListAssign_t* assignmentFrom(Statement_t* statement) {
823 if (auto expListAssign = statement->content.as<ExpListAssign_t>()) {
824 if (expListAssign->action) {
825 return expListAssign;
826 }
827 }
828 return nullptr;
829 }
830
831 void assignLastExplist(ExpList_t* expList, Body_t* body) {
832 auto last = lastStatementFrom(body);
833 if (!last) return;
834 bool lastAssignable = expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content);
835 if (lastAssignable) {
836 auto x = last;
837 auto newAssignment = x->new_ptr<ExpListAssign_t>();
838 newAssignment->expList.set(expList);
839 auto assign = x->new_ptr<Assign_t>();
840 if (auto valueList = last->content.as<ExpListAssign_t>()) {
841 assign->values.dup(valueList->expList->exprs);
842 } else {
843 auto simpleValue = x->new_ptr<SimpleValue_t>();
844 simpleValue->value.set(last->content);
845 auto value = x->new_ptr<Value_t>();
846 value->item.set(simpleValue);
847 auto exp = x->new_ptr<Exp_t>();
848 exp->value.set(value);
849 assign->values.push_back(exp);
850 }
851 newAssignment->action.set(assign);
852 last->content.set(newAssignment);
853 }
854 }
855
856 void transformAssignment(ExpListAssign_t* assignment, str_list& out) {
857 checkAssignable(assignment->expList);
858 BLOCK_START
859 auto assign = ast_cast<Assign_t>(assignment->action);
860 BREAK_IF(!assign || assign->values.objects().size() != 1);
861 auto value = assign->values.objects().front();
862 if (ast_is<Exp_t>(value)) {
863 if (auto val = simpleSingleValueFrom(value)) {
864 value = val->value.get();
865 }
866 }
867 switch (value->getId()) {
868 case "If"_id:
869 case "Unless"_id: {
870 auto expList = assignment->expList.get();
871 str_list temp;
872 auto defs = transformAssignDefs(expList);
873 if (!defs.empty()) temp.push_back(getPredefine(defs) + nll(expList));
874 value->traverse([&](ast_node* node) {
875 switch (node->getId()) {
876 case "IfCond"_id: return traversal::Return;
877 case "Body"_id: {
878 auto body = static_cast<Body_t*>(node);
879 assignLastExplist(expList, body);
880 return traversal::Return;
881 }
882 default: return traversal::Continue;
883 }
884 });
885 switch (value->getId()) {
886 case "If"_id: transformIf(static_cast<If_t*>(value), temp); break;
887 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), temp); break;
888 }
889 out.push_back(join(temp));
890 return;
891 }
892 case "Switch"_id: {
893 auto switchNode = static_cast<Switch_t*>(value);
894 auto expList = assignment->expList.get();
895 for (auto branch_ : switchNode->branches.objects()) {
896 auto branch = static_cast<SwitchCase_t*>(branch_);
897 assignLastExplist(expList, branch->body);
898 }
899 if (switchNode->lastBranch) {
900 assignLastExplist(expList, switchNode->lastBranch);
901 }
902 std::string preDefine = getPredefine(assignment);
903 transformSwitch(switchNode, out);
904 out.back() = preDefine + out.back();
905 return;
906 }
907 case "With"_id: {
908 auto withNode = static_cast<With_t*>(value);
909 str_list temp;
910 auto expList = assignment->expList.get();
911 std::string preDefine = getPredefine(assignment);
912 transformWith(withNode, temp, expList);
913 out.push_back(preDefine + temp.back());
914 return;
915 }
916 case "Do"_id: {
917 auto doNode = static_cast<Do_t*>(value);
918 auto expList = assignment->expList.get();
919 assignLastExplist(expList, doNode->body);
920 std::string preDefine = getPredefine(assignment);
921 transformDo(doNode, out);
922 out.back() = preDefine + out.back();
923 return;
924 }
925 case "Comprehension"_id: {
926 auto expList = assignment->expList.get();
927 std::string preDefine = getPredefine(assignment);
928 transformCompInPlace(static_cast<Comprehension_t*>(value), expList, out);
929 out.back() = preDefine + out.back();
930 return;
931 }
932 case "TblComprehension"_id: {
933 auto expList = assignment->expList.get();
934 std::string preDefine = getPredefine(assignment);
935 transformTblCompInPlace(static_cast<TblComprehension_t*>(value), expList, out);
936 out.back() = preDefine + out.back();
937 return;
938 }
939 case "For"_id: {
940 str_list temp;
941 auto expList = assignment->expList.get();
942 std::string preDefine = getPredefine(assignment);
943 transformForInPlace(static_cast<For_t*>(value), temp, expList);
944 out.push_back(preDefine + temp.back());
945 return;
946 }
947 case "ForEach"_id: {
948 str_list temp;
949 auto expList = assignment->expList.get();
950 std::string preDefine = getPredefine(assignment);
951 transformForEachInPlace(static_cast<ForEach_t*>(value), temp, expList);
952 out.push_back(preDefine + temp.back());
953 return;
954 }
955 case "ClassDecl"_id: {
956 str_list temp;
957 auto expList = assignment->expList.get();
958 std::string preDefine = getPredefine(assignment);
959 transformClassDecl(static_cast<ClassDecl_t*>(value), temp, ExpUsage::Assignment, expList);
960 out.push_back(preDefine + temp.back());
961 return;
962 }
963 case "While"_id: {
964 str_list temp;
965 auto expList = assignment->expList.get();
966 std::string preDefine = getPredefine(assignment);
967 transformWhileInPlace(static_cast<While_t*>(value), temp, expList);
968 out.push_back(preDefine + temp.back());
969 return;
970 }
971 }
972 auto exp = ast_cast<Exp_t>(value);
973 BREAK_IF(!exp);
974 if (auto chainValue = exp->value->item.as<ChainValue_t>()) {
975 if (isColonChain(chainValue)) {
976 auto assignable = assignment->expList.get();
977 std::string preDefine = getPredefine(transformAssignDefs(assignable));
978 transformColonChain(chainValue, out, ExpUsage::Assignment, assignable);
979 auto nl = preDefine.empty() ? Empty : nll(chainValue);
980 if (!preDefine.empty()) out.back() = preDefine + nl + out.back();
981 return;
982 } else if (hasKeywordColonChainItem(chainValue)) {
983 transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList);
984 return;
985 }
986 }
987 BLOCK_END
988 auto info = extractDestructureInfo(assignment);
989 if (info.first.empty()) {
990 transformAssignmentCommon(assignment, out);
991 } else {
992 str_list temp;
993 for (const auto& destruct : info.first) {
994 if (destruct.items.size() == 1) {
995 auto& pair = destruct.items.front();
996 _buf << indent();
997 if (pair.isVariable && !isDefined(pair.name)) {
998 _buf << s("local "sv);
999 }
1000 _buf << pair.name << " = "sv << info.first.front().value << pair.structure << nll(assignment);
1001 addToScope(pair.name);
1002 temp.push_back(clearBuf());
1003 } else if (matchAst(Name, destruct.value)) {
1004 str_list defs, names, values;
1005 for (const auto& item : destruct.items) {
1006 if (item.isVariable && addToScope(item.name)) {
1007 defs.push_back(item.name);
1008 }
1009 names.push_back(item.name);
1010 values.push_back(item.structure);
1011 }
1012 for (auto& v : values) v.insert(0, destruct.value);
1013 if (defs.empty()) {
1014 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1015 } else {
1016 _buf << indent() << "local "sv;
1017 if (defs.size() != names.size()) {
1018 _buf << join(defs,", "sv) << nll(assignment) << indent();
1019 }
1020 _buf << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1021 }
1022 temp.push_back(clearBuf());
1023 } else {
1024 str_list defs, names, values;
1025 for (const auto& item : destruct.items) {
1026 if (item.isVariable && addToScope(item.name)) {
1027 defs.push_back(item.name);
1028 }
1029 names.push_back(item.name);
1030 values.push_back(item.structure);
1031 }
1032 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment);
1033 _buf << indent() << "do"sv << nll(assignment);
1034 pushScope();
1035 auto objVar = getUnusedName("_obj_");
1036 for (auto& v : values) v.insert(0, objVar);
1037 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1038 _buf << indent() << join(names, ", "sv) << " = "sv << join(values, ", "sv) << nll(assignment);
1039 popScope();
1040 _buf << indent() << "end"sv << nll(assignment);
1041 temp.push_back(clearBuf());
1042 }
1043 }
1044 if (info.second) {
1045 transformAssignmentCommon(info.second, temp);
1046 }
1047 out.push_back(join(temp));
1048 }
1049 }
1050
1051 void transformAssignItem(ast_node* value, str_list& out) {
1052 switch (value->getId()) {
1053 case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break;
1054 case "If"_id: transformIf(static_cast<If_t*>(value), out, IfUsage::Closure); break;
1055 case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break;
1056 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
1057 case "Exp"_id: transformExp(static_cast<Exp_t*>(value), out); break;
1058 default: break;
1059 }
1060 }
1061
1062 std::list<DestructItem> destructFromExp(ast_node* node) {
1063 const node_container* tableItems = nullptr;
1064 if (ast_cast<Exp_t>(node)) {
1065 auto item = singleValueFrom(node)->item.get();
1066 if (!item) throw std::logic_error(debugInfo("Invalid destructure value."sv, node));
1067 auto tbA = item->getByPath<TableLit_t>();
1068 if (tbA) {
1069 tableItems = &tbA->values.objects();
1070 } else {
1071 auto tbB = ast_cast<simple_table_t>(item);
1072 if (tbB) tableItems = &tbB->pairs.objects();
1073 }
1074 } else if (auto table = ast_cast<TableBlock_t>(node)) {
1075 tableItems = &table->values.objects();
1076 }
1077 std::list<DestructItem> pairs;
1078 int index = 0;
1079 for (auto pair : *tableItems) {
1080 switch (pair->getId()) {
1081 case "Exp"_id: {
1082 ++index;
1083 if (!isAssignable(static_cast<Exp_t*>(pair))) {
1084 throw std::logic_error(debugInfo("Can't destructure value."sv, pair));
1085 }
1086 auto value = singleValueFrom(pair);
1087 auto item = value->item.get();
1088 if (ast_cast<simple_table_t>(item) ||
1089 item->getByPath<TableLit_t>()) {
1090 auto subPairs = destructFromExp(pair);
1091 for (auto& p : subPairs) {
1092 pairs.push_back({p.isVariable, p.name,
1093 s("["sv) + std::to_string(index) + s("]"sv) + p.structure});
1094 }
1095 } else {
1096 bool checkGlobal = _lintGlobalVar;
1097 _lintGlobalVar = false;
1098 auto exp = static_cast<Exp_t*>(pair);
1099 auto varName = singleVariableFrom(exp);
1100 bool isVariable = !varName.empty();
1101 if (!isVariable) {
1102 str_list temp;
1103 transformExp(exp, temp);
1104 varName = std::move(temp.back());
1105 }
1106 _lintGlobalVar = checkGlobal;
1107 pairs.push_back({
1108 isVariable,
1109 varName,
1110 s("["sv) + std::to_string(index) + s("]"sv)
1111 });
1112 }
1113 break;
1114 }
1115 case "variable_pair"_id: {
1116 auto vp = static_cast<variable_pair_t*>(pair);
1117 auto name = toString(vp->name);
1118 pairs.push_back({true, name, s("."sv) + name});
1119 break;
1120 }
1121 case "normal_pair"_id: {
1122 auto np = static_cast<normal_pair_t*>(pair);
1123 auto key = np->key->getByPath<Name_t>();
1124 if (!key) throw std::logic_error(debugInfo("Invalid key for destructure."sv, np));
1125 if (auto exp = np->value.as<Exp_t>()) {
1126 if (!isAssignable(exp)) throw std::logic_error(debugInfo("Can't destructure value."sv, exp));
1127 auto item = singleValueFrom(exp)->item.get();
1128 if (ast_cast<simple_table_t>(item) ||
1129 item->getByPath<TableLit_t>()) {
1130 auto subPairs = destructFromExp(exp);
1131 for (auto& p : subPairs) {
1132 pairs.push_back({p.isVariable, p.name,
1133 s("."sv) + toString(key) + p.structure});
1134 }
1135 } else {
1136 bool checkGlobal = _lintGlobalVar;
1137 _lintGlobalVar = false;
1138 auto varName = singleVariableFrom(exp);
1139 bool isVariable = !varName.empty();
1140 if (!isVariable) {
1141 str_list temp;
1142 transformExp(exp, temp);
1143 varName = std::move(temp.back());
1144 }
1145 _lintGlobalVar = checkGlobal;
1146 pairs.push_back({
1147 isVariable,
1148 varName,
1149 s("."sv) + toString(key)
1150 });
1151 }
1152 break;
1153 }
1154 if (np->value.as<TableBlock_t>()) {
1155 auto subPairs = destructFromExp(pair);
1156 for (auto& p : subPairs) {
1157 pairs.push_back({p.isVariable, p.name,
1158 s("."sv) + toString(key) + p.structure});
1159 }
1160 }
1161 break;
1162 }
1163 }
1164 }
1165 return pairs;
1166 }
1167
1168 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1169 extractDestructureInfo(ExpListAssign_t* assignment) {
1170 auto x = assignment;
1171 std::list<Destructure> destructs;
1172 if (!assignment->action.is<Assign_t>()) return { destructs, nullptr };
1173 auto exprs = assignment->expList->exprs.objects();
1174 auto values = assignment->action.to<Assign_t>()->values.objects();
1175 size_t size = std::max(exprs.size(),values.size());
1176 ast_ptr<false, Exp_t> var;
1177 if (exprs.size() < size) {
1178 var = toAst<Exp_t>("_"sv, Exp, x);
1179 while (exprs.size() < size) exprs.emplace_back(var);
1180 }
1181 ast_ptr<false, Exp_t> nullNode;
1182 if (values.size() < size) {
1183 nullNode = toAst<Exp_t>("nil"sv, Exp, x);
1184 while (values.size() < size) values.emplace_back(nullNode);
1185 }
1186 using iter = node_container::iterator;
1187 std::vector<std::pair<iter, iter>> destructPairs;
1188 str_list temp;
1189 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
1190 auto expr = *i;
1191 ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>();
1192 if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) {
1193 destructPairs.push_back({i,j});
1194 pushScope();
1195 transformAssignItem(*j, temp);
1196 popScope();
1197 auto& destruct = destructs.emplace_back();
1198 destruct.value = temp.back();
1199 temp.pop_back();
1200 auto pairs = destructFromExp(expr);
1201 destruct.items = std::move(pairs);
1202 }
1203 }
1204 for (const auto& p : destructPairs) {
1205 exprs.erase(p.first);
1206 values.erase(p.second);
1207 }
1208 ast_ptr<false, ExpListAssign_t> newAssignment;
1209 if (!destructPairs.empty() && !exprs.empty()) {
1210 auto x = assignment;
1211 auto expList = x->new_ptr<ExpList_t>();
1212 auto newAssign = x->new_ptr<ExpListAssign_t>();
1213 newAssign->expList.set(expList);
1214 for (auto expr : exprs) expList->exprs.push_back(expr);
1215 auto assign = x->new_ptr<Assign_t>();
1216 for (auto value : values) assign->values.push_back(value);
1217 newAssign->action.set(assign);
1218 newAssignment = newAssign;
1219 }
1220 return {std::move(destructs), newAssignment};
1221 }
1222
1223 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) {
1224 auto x = assignment;
1225 str_list temp;
1226 auto expList = assignment->expList.get();
1227 auto action = assignment->action.get();
1228 switch (action->getId()) {
1229 case "Update"_id: {
1230 auto update = static_cast<Update_t*>(action);
1231 auto leftExp = static_cast<Exp_t*>(expList->exprs.objects().front());
1232 auto leftValue = singleValueFrom(leftExp);
1233 if (!leftValue) throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, leftExp));
1234 if (auto chain = leftValue->getByPath<ChainValue_t>()) {
1235 auto tmpChain = x->new_ptr<ChainValue_t>();
1236 for (auto item : chain->items.objects()) {
1237 bool itemAdded = false;
1238 BLOCK_START
1239 auto exp = ast_cast<Exp_t>(item);
1240 BREAK_IF(!exp);
1241 auto var = singleVariableFrom(exp);
1242 BREAK_IF(!var.empty());
1243 auto upVar = getUnusedName("_update_");
1244 auto assignment = x->new_ptr<ExpListAssign_t>();
1245 assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x));
1246 auto assign = x->new_ptr<Assign_t>();
1247 assign->values.push_back(exp);
1248 assignment->action.set(assign);
1249 transformAssignment(assignment, temp);
1250 tmpChain->items.push_back(toAst<Exp_t>(upVar, Exp, x));
1251 itemAdded = true;
1252 BLOCK_END
1253 if (!itemAdded) tmpChain->items.push_back(item);
1254 }
1255 chain->items.clear();
1256 chain->items.dup(tmpChain->items);
1257 }
1258 transformValue(leftValue, temp);
1259 auto left = std::move(temp.back());
1260 temp.pop_back();
1261 transformExp(update->value, temp);
1262 auto right = std::move(temp.back());
1263 temp.pop_back();
1264 if (!singleValueFrom(update->value)) {
1265 right = s("("sv) + right + s(")"sv);
1266 }
1267 _buf << join(temp) << indent() << left << " = "sv << left <<
1268 " "sv << toString(update->op) << " "sv << right << nll(assignment);
1269 out.push_back(clearBuf());
1270 break;
1271 }
1272 case "Assign"_id: {
1273 auto defs = getAssignDefs(expList);
1274 bool oneLined = defs.size() == expList->exprs.objects().size() &&
1275 traversal::Stop != action->traverse([&](ast_node* n) {
1276 if (n->getId() == "Callable"_id) {
1277 if (auto name = n->getByPath<Variable_t>()) {
1278 for (const auto& def : defs) {
1279 if (def == toString(name)) {
1280 return traversal::Stop;
1281 }
1282 }
1283 }
1284 }
1285 return traversal::Continue;
1286 });
1287 if (oneLined) {
1288 auto assign = static_cast<Assign_t*>(action);
1289 for (auto value : assign->values.objects()) {
1290 transformAssignItem(value, temp);
1291 }
1292 std::string preDefine = getPredefine(defs);
1293 for (const auto& def : defs) {
1294 addToScope(def);
1295 }
1296 if (preDefine.empty()) {
1297 transformExpList(expList, temp);
1298 std::string left = std::move(temp.back());
1299 temp.pop_back();
1300 out.push_back(indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1301 } else {
1302 out.push_back(preDefine + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1303 }
1304 }
1305 else {
1306 std::string preDefine = getPredefine(defs);
1307 for (const auto& def : defs) {
1308 addToScope(def);
1309 }
1310 transformExpList(expList, temp);
1311 std::string left = temp.back();
1312 temp.pop_back();
1313 auto assign = static_cast<Assign_t*>(action);
1314 for (auto value : assign->values.objects()) {
1315 transformAssignItem(value, temp);
1316 }
1317 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + s(" = "sv) + join(temp, ", "sv) + nll(assignment));
1318 }
1319 break;
1320 }
1321 default: break;
1322 }
1323 }
1324
1325 void transformCond(const node_container& nodes, str_list& out, IfUsage usage = IfUsage::Common, bool unless = false) {
1326 std::vector<ast_ptr<false, ast_node>> ns(false);
1327 for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) {
1328 ns.push_back(*it);
1329 if (auto cond = ast_cast<IfCond_t>(*it)) {
1330 if (*it != nodes.front() && cond->assign) {
1331 auto x = *it;
1332 auto newIf = x->new_ptr<If_t>();
1333 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1334 newIf->nodes.push_back(*j);
1335 }
1336 ns.clear();
1337 auto simpleValue = x->new_ptr<SimpleValue_t>();
1338 simpleValue->value.set(newIf);
1339 auto value = x->new_ptr<Value_t>();
1340 value->item.set(simpleValue);
1341 auto exp = x->new_ptr<Exp_t>();
1342 exp->value.set(value);
1343 auto expList = x->new_ptr<ExpList_t>();
1344 expList->exprs.push_back(exp);
1345 auto expListAssign = x->new_ptr<ExpListAssign_t>();
1346 expListAssign->expList.set(expList);
1347 auto stmt = x->new_ptr<Statement_t>();
1348 stmt->content.set(expListAssign);
1349 auto body = x->new_ptr<Body_t>();
1350 body->content.set(stmt);
1351 ns.push_back(body.get());
1352 }
1353 }
1354 }
1355 if (nodes.size() != ns.size()) {
1356 auto x = ns.back();
1357 auto newIf = x->new_ptr<If_t>();
1358 for (auto j = ns.rbegin(); j != ns.rend(); ++j) {
1359 newIf->nodes.push_back(*j);
1360 }
1361 transformCond(newIf->nodes.objects(), out, usage, unless);
1362 return;
1363 }
1364 str_list temp;
1365 if (usage == IfUsage::Closure) {
1366 temp.push_back(s("(function()"sv) + nll(nodes.front()));
1367 pushScope();
1368 }
1369 std::list<std::pair<IfCond_t*, Body_t*>> ifCondPairs;
1370 ifCondPairs.emplace_back();
1371 for (auto node : nodes) {
1372 switch (node->getId()) {
1373 case "IfCond"_id:
1374 ifCondPairs.back().first = static_cast<IfCond_t*>(node);
1375 break;
1376 case "Body"_id:
1377 ifCondPairs.back().second = static_cast<Body_t*>(node);
1378 ifCondPairs.emplace_back();
1379 break;
1380 default: break;
1381 }
1382 }
1383 auto assign = ifCondPairs.front().first->assign.get();
1384 bool storingValue = false;
1385 ast_ptr<false, ExpListAssign_t> extraAssignment;
1386 if (assign) {
1387 auto exp = ifCondPairs.front().first->condition.get();
1388 auto x = exp;
1389 auto var = singleVariableFrom(exp);
1390 if (var.empty()) {
1391 storingValue = true;
1392 std::string desVar = getUnusedName("_des_");
1393 if (assign->values.objects().size() == 1) {
1394 auto var = singleVariableFrom(assign->values.objects().front());
1395 if (!var.empty()) {
1396 desVar = var;
1397 storingValue = false;
1398 }
1399 }
1400 if (storingValue) {
1401 if (usage != IfUsage::Closure) {
1402 temp.push_back(indent() + s("do"sv) + nll(assign));
1403 pushScope();
1404 }
1405 auto expList = toAst<ExpList_t>(desVar, ExpList, x);
1406 auto assignment = x->new_ptr<ExpListAssign_t>();
1407 assignment->expList.set(expList);
1408 assignment->action.set(assign);
1409 transformAssignment(assignment, temp);
1410 }
1411 {
1412 auto expList = x->new_ptr<ExpList_t>();
1413 expList->exprs.push_back(exp);
1414 auto assignOne = x->new_ptr<Assign_t>();
1415 auto valExp = toAst<Exp_t>(desVar, Exp, x);
1416 assignOne->values.push_back(valExp);
1417 auto assignment = x->new_ptr<ExpListAssign_t>();
1418 assignment->expList.set(expList);
1419 assignment->action.set(assignOne);
1420 extraAssignment.set(assignment);
1421 ifCondPairs.front().first->condition.set(valExp);
1422 }
1423 } else {
1424 if (!isDefined(var)) {
1425 storingValue = true;
1426 if (usage != IfUsage::Closure) {
1427 temp.push_back(indent() + s("do"sv) + nll(assign));
1428 pushScope();
1429 }
1430 }
1431 auto expList = x->new_ptr<ExpList_t>();
1432 expList->exprs.push_back(exp);
1433 auto assignment = x->new_ptr<ExpListAssign_t>();
1434 assignment->expList.set(expList);
1435 assignment->action.set(assign);
1436 transformAssignment(assignment, temp);
1437 }
1438 }
1439 for (const auto& pair : ifCondPairs) {
1440 if (pair.first) {
1441 str_list tmp;
1442 auto condition = pair.first->condition.get();
1443 if (unless) {
1444 if (auto value = singleValueFrom(condition)) {
1445 transformValue(value, tmp);
1446 } else {
1447 transformExp(condition, tmp);
1448 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
1449 }
1450 tmp.back().insert(0, s("not "sv));
1451 unless = false;
1452 } else {
1453 transformExp(condition, tmp);
1454 }
1455 _buf << indent();
1456 if (pair != ifCondPairs.front()) {
1457 _buf << "else"sv;
1458 }
1459 _buf << "if "sv << tmp.back() << " then"sv << nll(condition);
1460 temp.push_back(clearBuf());
1461 }
1462 if (pair.second) {
1463 if (!pair.first) {
1464 temp.push_back(indent() + s("else"sv) + nll(pair.second));
1465 }
1466 pushScope();
1467 if (pair == ifCondPairs.front() && extraAssignment) {
1468 transformAssignment(extraAssignment, temp);
1469 }
1470 transformBody(pair.second, temp, usage != IfUsage::Common);
1471 popScope();
1472 }
1473 if (!pair.first) {
1474 temp.push_back(indent() + s("end"sv) + nll(nodes.front()));
1475 break;
1476 }
1477 }
1478 if (storingValue && usage != IfUsage::Closure) {
1479 popScope();
1480 temp.push_back(indent() + s("end"sv) + nlr(nodes.front()));
1481 }
1482 if (usage == IfUsage::Closure) {
1483 popScope();
1484 temp.push_back(indent() + s("end)()"sv));
1485 }
1486 out.push_back(join(temp));
1487 }
1488
1489 void transformIf(If_t* ifNode, str_list& out, IfUsage usage = IfUsage::Common) {
1490 transformCond(ifNode->nodes.objects(), out, usage);
1491 }
1492
1493 void transformUnless(Unless_t* unless, str_list& out, IfUsage usage = IfUsage::Common) {
1494 transformCond(unless->nodes.objects(), out, usage, true);
1495 }
1496
1497 void transformExpList(ExpList_t* expList, str_list& out) {
1498 str_list temp;
1499 for (auto exp : expList->exprs.objects()) {
1500 transformExp(static_cast<Exp_t*>(exp), temp);
1501 }
1502 out.push_back(join(temp, ", "sv));
1503 }
1504
1505 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
1506 str_list temp;
1507 for (auto exp : expListLow->exprs.objects()) {
1508 transformExp(static_cast<Exp_t*>(exp), temp);
1509 }
1510 out.push_back(join(temp, ", "sv));
1511 }
1512
1513 void transformExp(Exp_t* exp, str_list& out) {
1514 str_list temp;
1515 transformValue(exp->value, temp);
1516 for (auto _opValue : exp->opValues.objects()) {
1517 auto opValue = static_cast<exp_op_value_t*>(_opValue);
1518 transformBinaryOperator(opValue->op, temp);
1519 transformValue(opValue->value, temp);
1520 }
1521 out.push_back(join(temp, " "sv));
1522 }
1523
1524 void transformValue(Value_t* value, str_list& out) {
1525 auto item = value->item.get();
1526 switch (item->getId()) {
1527 case "SimpleValue"_id: transformSimpleValue(static_cast<SimpleValue_t*>(item), out); break;
1528 case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break;
1529 case "ChainValue"_id: {
1530 auto chainValue = static_cast<ChainValue_t*>(item);
1531 if (isColonChain(chainValue)) {
1532 transformColonChainClosure(chainValue, out);
1533 } else {
1534 transformChainValue(chainValue, out);
1535 }
1536 break;
1537 }
1538 case "String"_id: transformString(static_cast<String_t*>(item), out); break;
1539 default: break;
1540 }
1541 }
1542
1543 void transformCallable(Callable_t* callable, str_list& out, bool invoke) {
1544 auto item = callable->item.get();
1545 switch (item->getId()) {
1546 case "Variable"_id: {
1547 transformVariable(static_cast<Variable_t*>(item), out);
1548 if (_lintGlobalVar && !isDefined(out.back())) {
1549 if (_globals.find(out.back()) == _globals.end()) {
1550 _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col};
1551 }
1552 }
1553 break;
1554 }
1555 case "SelfName"_id: { transformSelfName(static_cast<SelfName_t*>(item), out, invoke);
1556 if (_lintGlobalVar) {
1557 std::string self("self"sv);
1558 if (!isDefined(self)) {
1559 if (_globals.find(self) == _globals.end()) {
1560 _globals[self] = {item->m_begin.m_line, item->m_begin.m_col};
1561 }
1562 }
1563 }
1564 break;
1565 }
1566 case "VarArg"_id: out.push_back(s("..."sv)); break;
1567 case "Parens"_id: transformParens(static_cast<Parens_t*>(item), out); break;
1568 default: break;
1569 }
1570 }
1571
1572 void transformParens(Parens_t* parans, str_list& out) {
1573 str_list temp;
1574 transformExp(parans->expr, temp);
1575 out.push_back(s("("sv) + temp.front() + s(")"sv));
1576 }
1577
1578 void transformSimpleValue(SimpleValue_t* simpleValue, str_list& out) {
1579 auto value = simpleValue->value.get();
1580 switch (value->getId()) {
1581 case "const_value"_id: transform_const_value(static_cast<const_value_t*>(value), out); break;
1582 case "If"_id: transformIf(static_cast<If_t*>(value), out, IfUsage::Closure); break;
1583 case "Unless"_id: transformUnless(static_cast<Unless_t*>(value), out, IfUsage::Closure); break;
1584 case "Switch"_id: transformSwitchClosure(static_cast<Switch_t*>(value), out); break;
1585 case "With"_id: transformWithClosure(static_cast<With_t*>(value), out); break;
1586 case "ClassDecl"_id: transformClassDeclClosure(static_cast<ClassDecl_t*>(value), out); break;
1587 case "ForEach"_id: transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
1588 case "For"_id: transformForClosure(static_cast<For_t*>(value), out); break;
1589 case "While"_id: transformWhileClosure(static_cast<While_t*>(value), out); break;
1590 case "Do"_id: transformDoClosure(static_cast<Do_t*>(value), out); break;
1591 case "unary_exp"_id: transform_unary_exp(static_cast<unary_exp_t*>(value), out); break;
1592 case "TblComprehension"_id: transformTblCompClosure(static_cast<TblComprehension_t*>(value), out); break;
1593 case "TableLit"_id: transformTableLit(static_cast<TableLit_t*>(value), out); break;
1594 case "Comprehension"_id: transformCompClosure(static_cast<Comprehension_t*>(value), out); break;
1595 case "FunLit"_id: transformFunLit(static_cast<FunLit_t*>(value), out); break;
1596 case "Num"_id: transformNum(static_cast<Num_t*>(value), out); break;
1597 default: break;
1598 }
1599 }
1600
1601 void transformFunLit(FunLit_t* funLit, str_list& out) {
1602 str_list temp;
1603 bool isFatArrow = toString(funLit->arrow) == "=>"sv;
1604 pushScope();
1605 if (isFatArrow) {
1606 forceAddToScope(s("self"sv));
1607 }
1608 if (auto argsDef = funLit->argsDef.get()) {
1609 transformFnArgsDef(argsDef, temp);
1610 if (funLit->body) {
1611 transformBody(funLit->body, temp, true);
1612 } else {
1613 temp.push_back(Empty);
1614 }
1615 auto it = temp.begin();
1616 auto& args = *it;
1617 auto& initArgs = *(++it);
1618 auto& bodyCodes = *(++it);
1619 _buf << "function("sv <<
1620 (isFatArrow ? s("self, "sv) : Empty) <<
1621 args << ')';
1622 if (!initArgs.empty() || !bodyCodes.empty()) {
1623 _buf << nlr(argsDef) << initArgs << bodyCodes;
1624 popScope();
1625 _buf << indent() << "end"sv;
1626 } else {
1627 popScope();
1628 _buf << " end"sv;
1629 }
1630 } else {
1631 if (funLit->body) {
1632 transformBody(funLit->body, temp, true);
1633 } else {
1634 temp.push_back(Empty);
1635 }
1636 auto& bodyCodes = temp.back();
1637 _buf << "function("sv <<
1638 (isFatArrow ? s("self"sv) : Empty) <<
1639 ')';
1640 if (!bodyCodes.empty()) {
1641 _buf << nll(funLit) << bodyCodes;
1642 popScope();
1643 _buf << indent() << "end"sv;
1644 } else {
1645 popScope();
1646 _buf << " end"sv;
1647 }
1648 }
1649 out.push_back(clearBuf());
1650 }
1651
1652 void transformCodes(const node_container& nodes, str_list& out, bool implicitReturn) {
1653 LocalMode mode = LocalMode::None;
1654 Local_t* any = nullptr, *capital = nullptr;
1655 for (auto node : nodes) {
1656 auto stmt = static_cast<Statement_t*>(node);
1657 if (auto local = stmt->content.as<Local_t>()) {
1658 if (auto flag = local->name.as<local_flag_t>()) {
1659 LocalMode newMode = toString(flag) == "*"sv ? LocalMode::Any : LocalMode::Capital;
1660 if (int(newMode) > int(mode)) {
1661 mode = newMode;
1662 }
1663 if (mode == LocalMode::Any) {
1664 if (!any) any = local;
1665 if (!capital) capital = local;
1666 } else {
1667 if (!capital) capital = local;
1668 }
1669 } else {
1670 auto names = local->name.to<NameList_t>();
1671 for (auto name : names->names.objects()) {
1672 local->forceDecls.push_back(toString(name));
1673 }
1674 }
1675 } else if (mode != LocalMode::None) {
1676 ClassDecl_t* classDecl = nullptr;
1677 if (auto assignment = assignmentFrom(stmt)) {
1678 auto vars = getAssignVars(assignment);
1679 for (const auto& var : vars) {
1680 if (var.empty()) continue;
1681 if (std::isupper(var[0]) && capital) {
1682 capital->decls.push_back(var);
1683 } else if (any) {
1684 any->decls.push_back(var);
1685 }
1686 }
1687 auto info = extractDestructureInfo(assignment);
1688 if (!info.first.empty()) {
1689 for (const auto& destruct : info.first)
1690 for (const auto& item : destruct.items)
1691 if (item.isVariable) {
1692 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name);
1693 } else if (any) {
1694 any->decls.push_back(item.name);
1695 }
1696 }
1697 }
1698 BLOCK_START
1699 auto assign = assignment->action.as<Assign_t>();
1700 BREAK_IF(!assign);
1701 BREAK_IF(assign->values.objects().size() != 1);
1702 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
1703 BREAK_IF(!exp);
1704 auto value = singleValueFrom(exp);
1705 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
1706 BLOCK_END
1707 } else if (auto expList = expListFrom(stmt)) {
1708 auto value = singleValueFrom(expList);
1709 classDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
1710 }
1711 if (classDecl) {
1712 if (auto variable = classDecl->name->item.as<Variable_t>()) {
1713 auto className = toString(variable);
1714 if (!className.empty()) {
1715 if (std::isupper(className[0]) && capital) {
1716 capital->decls.push_back(className);
1717 } else if (any) {
1718 any->decls.push_back(className);
1719 }
1720 }
1721 }
1722 }
1723 }
1724 }
1725 if (implicitReturn) {
1726 auto last = static_cast<Statement_t*>(nodes.back());
1727 auto x = last;
1728 BLOCK_START
1729 auto expList = expListFrom(last);
1730 BREAK_IF(!expList ||
1731 (last->appendix &&
1732 last->appendix->item.is<CompInner_t>()));
1733 auto expListLow = x->new_ptr<ExpListLow_t>();
1734 expListLow->exprs.dup(expList->exprs);
1735 auto returnNode = x->new_ptr<Return_t>();
1736 returnNode->valueList.set(expListLow);
1737 last->content.set(returnNode);
1738 BLOCK_END
1739 }
1740 str_list temp;
1741 for (auto node : nodes) {
1742 transformStatement(static_cast<Statement_t*>(node), temp);
1743 }
1744 out.push_back(join(temp));
1745 }
1746
1747 void transformBody(Body_t* body, str_list& out, bool implicitReturn = false) {
1748 if (auto stmt = body->content.as<Statement_t>()) {
1749 transformCodes(node_container{stmt}, out, implicitReturn);
1750 } else {
1751 transformCodes(body->content.to<Block_t>()->statements.objects(), out, implicitReturn);
1752 }
1753 }
1754
1755 void transformBlock(Block_t* block, str_list& out, bool implicitReturn = true) {
1756 transformCodes(block->statements.objects(), out, implicitReturn);
1757 }
1758
1759 void transformReturn(Return_t* returnNode, str_list& out) {
1760 if (auto valueList = returnNode->valueList.get()) {
1761 if (auto singleValue = singleValueFrom(valueList)) {
1762 if (auto simpleValue = singleValue->item.as<SimpleValue_t>()) {
1763 auto value = simpleValue->value.get();
1764 switch (value->getId()) {
1765 case "Comprehension"_id:
1766 transformCompReturn(static_cast<Comprehension_t*>(value), out);
1767 return;
1768 case "TblComprehension"_id:
1769 transformTblCompReturn(static_cast<TblComprehension_t*>(value), out);
1770 return;
1771 case "With"_id:
1772 transformWith(static_cast<With_t*>(value), out, nullptr, true);
1773 return;
1774 case "ClassDecl"_id:
1775 transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Return);
1776 return;
1777 case "Do"_id:
1778 transformDo(static_cast<Do_t*>(value), out, true);
1779 return;
1780 case "Switch"_id:
1781 transformSwitch(static_cast<Switch_t*>(value), out, true);
1782 return;
1783 case "While"_id:
1784 transformWhileInPlace(static_cast<While_t*>(value), out);
1785 return;
1786 case "For"_id:
1787 transformForInPlace(static_cast<For_t*>(value), out);
1788 return;
1789 case "ForEach"_id:
1790 transformForEachInPlace(static_cast<ForEach_t*>(value), out);
1791 return;
1792 case "If"_id:
1793 transformIf(static_cast<If_t*>(value), out, IfUsage::Return);
1794 return;
1795 case "Unless"_id:
1796 transformUnless(static_cast<Unless_t*>(value), out, IfUsage::Return);
1797 return;
1798 }
1799 }
1800 if (auto chainValue = singleValue->item.as<ChainValue_t>()) {
1801 if (isColonChain(chainValue)) {
1802 transformColonChain(chainValue, out, ExpUsage::Return);
1803 } else {
1804 transformChainValue(chainValue, out, ExpUsage::Return);
1805 }
1806 return;
1807 }
1808 transformValue(singleValue, out);
1809 out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode);
1810 return;
1811 } else {
1812 str_list temp;
1813 transformExpListLow(valueList, temp);
1814 out.push_back(indent() + s("return "sv) + temp.back() + nlr(returnNode));
1815 }
1816 } else {
1817 out.push_back(indent() + s("return"sv) + nll(returnNode));
1818 }
1819 }
1820
1821 void transformFnArgsDef(FnArgsDef_t* argsDef, str_list& out) {
1822 if (!argsDef->defList) {
1823 out.push_back(Empty);
1824 out.push_back(Empty);
1825 } else {
1826 transformFnArgDefList(argsDef->defList, out);
1827 }
1828 if (argsDef->shadowOption) {
1829 transform_outer_var_shadow(argsDef->shadowOption);
1830 }
1831 }
1832
1833 void transform_outer_var_shadow(outer_var_shadow_t* shadow) {
1834 markVarShadowed();
1835 if (shadow->varList) {
1836 for (auto name : shadow->varList->names.objects()) {
1837 addToAllowList(toString(name));
1838 }
1839 }
1840 }
1841
1842 void transformFnArgDefList(FnArgDefList_t* argDefList, str_list& out) {
1843 auto x = argDefList;
1844 struct ArgItem {
1845 std::string name;
1846 std::string assignSelf;
1847 };
1848 std::list<ArgItem> argItems;
1849 str_list temp;
1850 std::string varNames;
1851 bool assignSelf = false;
1852 for (auto _def : argDefList->definitions.objects()) {
1853 auto def = static_cast<FnArgDef_t*>(_def);
1854 auto& arg = argItems.emplace_back();
1855 switch (def->name->getId()) {
1856 case "Variable"_id: arg.name = toString(def->name); break;
1857 case "SelfName"_id: {
1858 assignSelf = true;
1859 auto selfName = static_cast<SelfName_t*>(def->name.get());
1860 switch (selfName->name->getId()) {
1861 case "self_class_name"_id: {
1862 auto clsName = static_cast<self_class_name_t*>(selfName->name.get());
1863 arg.name = toString(clsName->name);
1864 arg.assignSelf = s("self.__class."sv) + arg.name;
1865 break;
1866 }
1867 case "self_class"_id:
1868 arg.name = "self.__class"sv;
1869 break;
1870 case "self_name"_id: {
1871
1872 auto sfName = static_cast<self_name_t*>(selfName->name.get());
1873 arg.name = toString(sfName->name);
1874 arg.assignSelf = s("self."sv) + arg.name;
1875 break;
1876 }
1877 case "self"_id:
1878 arg.name = "self"sv;
1879 break;
1880 default: break;
1881 }
1882 break;
1883 }
1884 }
1885 forceAddToScope(arg.name);
1886 if (def->defaultValue) {
1887 pushScope();
1888 auto expList = toAst<ExpList_t>(arg.name, ExpList, x);
1889 auto assign = x->new_ptr<Assign_t>();
1890 assign->values.push_back(def->defaultValue.get());
1891 auto assignment = x->new_ptr<ExpListAssign_t>();
1892 assignment->expList.set(expList);
1893 assignment->action.set(assign);
1894 transformAssignment(assignment, temp);
1895 popScope();
1896 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def);
1897 _buf << temp.back();
1898 _buf << indent() << "end"sv << nll(def);
1899 temp.back() = clearBuf();
1900 }
1901 if (varNames.empty()) varNames = arg.name;
1902 else varNames.append(s(", "sv) + arg.name);
1903 }
1904 if (argDefList->varArg) {
1905 auto& arg = argItems.emplace_back();
1906 arg.name = "..."sv;
1907 if (varNames.empty()) varNames = arg.name;
1908 else varNames.append(s(", "sv) + arg.name);
1909 }
1910 std::string initCodes = join(temp);
1911 if (assignSelf) {
1912 auto sjoin = [](const decltype(argItems)& items, int index) {
1913 std::string result;
1914 for (auto it = items.begin(); it != items.end(); ++it) {
1915 if (it->assignSelf.empty()) continue;
1916 if (result.empty()) result = (&it->name)[index];
1917 else result.append(s(", "sv) + (&it->name)[index]);
1918 }
1919 return result;
1920 };
1921 std::string sleft = sjoin(argItems, 1);
1922 std::string sright = sjoin(argItems, 0);
1923 initCodes.append(indent() + sleft + s(" = "sv) + sright + nll(argDefList));
1924 }
1925 out.push_back(varNames);
1926 out.push_back(initCodes);
1927 }
1928
1929 void transformSelfName(SelfName_t* selfName, str_list& out, bool invoke) {
1930 auto name = selfName->name.get();
1931 switch (name->getId()) {
1932 case "self_class_name"_id: {
1933 auto clsName = static_cast<self_class_name_t*>(name);
1934 out.push_back(s("self.__class"sv) + s(invoke ? ":"sv : "."sv) + toString(clsName->name));
1935 break;
1936 }
1937 case "self_class"_id:
1938 out.push_back(s("self.__class"sv));
1939 break;
1940 case "self_name"_id: {
1941 auto sfName = static_cast<self_class_name_t*>(name);
1942 out.push_back(s("self"sv) + s(invoke ? ":"sv : "."sv) + toString(sfName->name));
1943 break;
1944 }
1945 case "self"_id:
1946 out.push_back(s("self"sv));
1947 break;
1948 }
1949 }
1950
1951 void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) {
1952 str_list temp;
1953 temp.push_back(s("(function()"sv) + nll(chainValue));
1954 pushScope();
1955 transformColonChain(chainValue, temp, ExpUsage::Return);
1956 popScope();
1957 temp.push_back(indent() + s("end)()"sv));
1958 out.push_back(join(temp));
1959 }
1960
1961 void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) {
1962 auto x = chainValue;
1963 const auto& chainList = chainValue->items.objects();
1964 auto baseChain = x->new_ptr<ChainValue_t>();
1965 switch (chainList.front()->getId()) {
1966 case "DotChainItem"_id:
1967 case "ColonChainItem"_id:
1968 if (_withVars.empty()) {
1969 throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
1970 } else {
1971 baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
1972 }
1973 break;
1974 }
1975 auto end = --chainList.end();
1976 for (auto it = chainList.begin(); it != end; ++it) {
1977 baseChain->items.push_back(*it);
1978 }
1979 auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back());
1980 auto funcName = toString(colonChainItem->name);
1981 if (usage != ExpUsage::Return) pushScope();
1982 auto baseVar = getUnusedName("_base_"sv);
1983 auto fnVar = getUnusedName("_fn_"sv);
1984 str_list temp;
1985 {
1986 auto value = x->new_ptr<Value_t>();
1987 value->item.set(baseChain);
1988 auto exp = x->new_ptr<Exp_t>();
1989 exp->value.set(value);
1990 auto assign = x->new_ptr<Assign_t>();
1991 assign->values.push_back(exp);
1992 auto assignment = x->new_ptr<ExpListAssign_t>();
1993 assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x));
1994 assignment->action.set(assign);
1995 transformAssignment(assignment, temp);
1996 }
1997 {
1998 auto assign = x->new_ptr<Assign_t>();
1999 assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x));
2000 auto assignment = x->new_ptr<ExpListAssign_t>();
2001 assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x));
2002 assignment->action.set(assign);
2003 transformAssignment(assignment, temp);
2004 }
2005 auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x);
2006 switch (usage) {
2007 case ExpUsage::Return:
2008 transformExp(funLit, temp);
2009 _buf << temp.front();
2010 _buf << *(++temp.begin());
2011 _buf << indent() << "return " << temp.back() << nll(chainValue);
2012 break;
2013 case ExpUsage::Assignment: {
2014 auto assign = x->new_ptr<Assign_t>();
2015 assign->values.push_back(funLit);
2016 auto assignment = x->new_ptr<ExpListAssign_t>();
2017 assignment->expList.set(expList);
2018 assignment->action.set(assign);
2019 transformAssignment(assignment, temp);
2020 _buf << indent(-1) << "do"sv << nll(chainValue);
2021 _buf << temp.front();
2022 _buf << *(++temp.begin());
2023 _buf << temp.back();
2024 popScope();
2025 _buf << indent() << "end"sv << nll(chainValue);
2026 break;
2027 }
2028 case ExpUsage::Common: {
2029 auto assign = x->new_ptr<Assign_t>();
2030 assign->values.push_back(funLit);
2031 auto assignment = x->new_ptr<ExpListAssign_t>();
2032 assignment->expList.set(toAst<ExpList_t>("_"sv, ExpList, x));
2033 assignment->action.set(assign);
2034 transformAssignment(assignment, temp);
2035 _buf << indent(-1) << "do"sv << nll(chainValue);
2036 _buf << temp.front();
2037 _buf << *(++temp.begin());
2038 _buf << temp.back();
2039 popScope();
2040 _buf << indent() << "end"sv << nll(chainValue);
2041 break;
2042 }
2043 default: break;
2044 }
2045 out.push_back(clearBuf());
2046 }
2047
2048 void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
2049 auto x = chainList.front();
2050 str_list temp;
2051 switch (chainList.front()->getId()) {
2052 case "DotChainItem"_id:
2053 case "ColonChainItem"_id:
2054 if (_withVars.empty()) {
2055 throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front()));
2056 } else {
2057 temp.push_back(_withVars.top());
2058 }
2059 break;
2060 }
2061 for (auto it = chainList.begin(); it != chainList.end(); ++it) {
2062 auto item = *it;
2063 switch (item->getId()) {
2064 case "Invoke"_id:
2065 transformInvoke(static_cast<Invoke_t*>(item), temp);
2066 break;
2067 case "DotChainItem"_id:
2068 transformDotChainItem(static_cast<DotChainItem_t*>(item), temp);
2069 break;
2070 case "ColonChainItem"_id: {
2071 auto colonItem = static_cast<ColonChainItem_t*>(item);
2072 auto next = it; ++next;
2073 auto followItem = next != chainList.end() ? *next : nullptr;
2074 if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) {
2075 throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem));
2076 }
2077 if (colonItem->name.is<LuaKeyword_t>()) {
2078 auto callVar = getUnusedName(s("_call_"sv));
2079 auto block = x->new_ptr<Block_t>();
2080 {
2081 auto chainValue = x->new_ptr<ChainValue_t>();
2082 switch (chainList.front()->getId()) {
2083 case "DotChainItem"_id:
2084 case "ColonChainItem"_id:
2085 chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x));
2086 break;
2087 }
2088 for (auto i = chainList.begin(); i != it; ++i) {
2089 chainValue->items.push_back(*i);
2090 }
2091 auto value = x->new_ptr<Value_t>();
2092 value->item.set(chainValue);
2093 auto exp = x->new_ptr<Exp_t>();
2094 exp->value.set(value);
2095 auto assignment = x->new_ptr<ExpListAssign_t>();
2096 assignment->expList.set(toAst<ExpList_t>(callVar, ExpList, x));
2097 auto assign = x->new_ptr<Assign_t>();
2098 assign->values.push_back(exp);
2099 assignment->action.set(assign);
2100 auto stmt = x->new_ptr<Statement_t>();
2101 stmt->content.set(assignment);
2102 block->statements.push_back(stmt);
2103 }
2104 {
2105 auto name = toString(colonItem->name);
2106 auto chainValue = x->new_ptr<ChainValue_t>();
2107 chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x));
2108 chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x));
2109 if (auto invoke = ast_cast<Invoke_t>(followItem)) {
2110 invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x));
2111 } else {
2112 auto invokeArgs = static_cast<InvokeArgs_t*>(followItem);
2113 invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x));
2114 }
2115 chainValue->items.push_back(followItem);
2116 for (auto i = ++next; i != chainList.end(); ++i) {
2117 chainValue->items.push_back(*i);
2118 }
2119 auto value = x->new_ptr<Value_t>();
2120 value->item.set(chainValue);
2121 auto exp = x->new_ptr<Exp_t>();
2122 exp->value.set(value);
2123 auto expList = x->new_ptr<ExpList_t>();
2124 expList->exprs.push_back(exp);
2125 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2126 expListAssign->expList.set(expList);
2127 auto stmt = x->new_ptr<Statement_t>();
2128 stmt->content.set(expListAssign);
2129 block->statements.push_back(stmt);
2130 }
2131 switch (usage) {
2132 case ExpUsage::Common:
2133 transformBlock(block, out, false);
2134 return;
2135 case ExpUsage::Return:
2136 transformBlock(block, out, true);
2137 return;
2138 case ExpUsage::Assignment: {
2139 auto body = x->new_ptr<Body_t>();
2140 body->content.set(block);
2141 assignLastExplist(assignList, body);
2142 transformBlock(block, out);
2143 return;
2144 }
2145 default:
2146 break;
2147 }
2148 auto body = x->new_ptr<Body_t>();
2149 body->content.set(block);
2150 auto funLit = toAst<FunLit_t>("->"sv, FunLit, x);
2151 funLit->body.set(body);
2152 auto simpleValue = x->new_ptr<SimpleValue_t>();
2153 simpleValue->value.set(funLit);
2154 auto value = x->new_ptr<Value_t>();
2155 value->item.set(simpleValue);
2156 auto exp = x->new_ptr<Exp_t>();
2157 exp->value.set(value);
2158 auto paren = x->new_ptr<Parens_t>();
2159 paren->expr.set(exp);
2160 auto callable = x->new_ptr<Callable_t>();
2161 callable->item.set(paren);
2162 auto chainValue = x->new_ptr<ChainValue_t>();
2163 chainValue->items.push_back(callable);
2164 auto invoke = x->new_ptr<Invoke_t>();
2165 chainValue->items.push_back(invoke);
2166 transformChainValue(chainValue, out);
2167 return;
2168 }
2169 transformColonChainItem(colonItem, temp);
2170 break;
2171 }
2172 case "Slice"_id:
2173 transformSlice(static_cast<Slice_t*>(item), temp);
2174 break;
2175 case "Callable"_id: {
2176 auto next = it; ++next;
2177 auto followItem = next != chainList.end() ? *next : nullptr;
2178 transformCallable(static_cast<Callable_t*>(item), temp,
2179 followItem && ast_is<Invoke_t, InvokeArgs_t>(followItem));
2180 break;
2181 }
2182 case "String"_id:
2183 transformString(static_cast<String_t*>(item), temp);
2184 temp.back() = s("("sv) + temp.back() + s(")"sv);
2185 break;
2186 case "Exp"_id:
2187 transformExp(static_cast<Exp_t*>(item), temp);
2188 temp.back() = s("["sv) + temp.back() + s("]"sv);
2189 break;
2190 case "InvokeArgs"_id: transformInvokeArgs(static_cast<InvokeArgs_t*>(item), temp); break;
2191 default: break;
2192 }
2193 }
2194 switch (usage) {
2195 case ExpUsage::Common:
2196 out.push_back(indent() + join(temp) + nll(chainList.front()));
2197 break;
2198 case ExpUsage::Return:
2199 out.push_back(indent() + s("return "sv) + join(temp) + nll(chainList.front()));
2200 break;
2201 default:
2202 out.push_back(join(temp));
2203 break;
2204 }
2205 }
2206
2207 void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) {
2208 transformChainList(chainValue->items.objects(), out, usage, assignList);
2209 }
2210
2211 void transformAssignableChain(AssignableChain_t* chain, str_list& out) {
2212 transformChainList(chain->items.objects(), out, ExpUsage::Closure);
2213 }
2214
2215 void transformDotChainItem(DotChainItem_t* dotChainItem, str_list& out) {
2216 auto name = toString(dotChainItem->name);
2217 if (State::keywords.find(name) != State::keywords.end()) {
2218 out.push_back(s("[\""sv) + name + s("\"]"sv));
2219 } else {
2220 out.push_back(s("."sv) + name);
2221 }
2222 }
2223
2224 void transformColonChainItem(ColonChainItem_t* colonChainItem, str_list& out) {
2225 auto name = toString(colonChainItem->name);
2226 out.push_back(s(colonChainItem->switchToDot ? "."sv : ":"sv) + name);
2227 }
2228
2229 void transformSlice(Slice_t* slice, str_list& out) {
2230 throw std::logic_error(debugInfo("Slice syntax not supported here."sv, slice));
2231 }
2232
2233 void transformInvoke(Invoke_t* invoke, str_list& out) {
2234 str_list temp;
2235 for (auto arg : invoke->args.objects()) {
2236 switch (arg->getId()) {
2237 case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break;
2238 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(arg), temp); break;
2239 case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(arg), temp); break;
2240 case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(arg), temp); break;
2241 default: break;
2242 }
2243 }
2244 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
2245 }
2246
2247 void transform_unary_exp(unary_exp_t* unary_exp, str_list& out) {
2248 std::string op = toString(unary_exp->m_begin.m_it, unary_exp->item->m_begin.m_it);
2249 str_list temp{op + (op == "not"sv ? s(" "sv) : Empty)};
2250 transformExp(unary_exp->item, temp);
2251 out.push_back(join(temp));
2252 }
2253
2254 void transformVariable(Variable_t* name, str_list& out) {
2255 out.push_back(toString(name));
2256 }
2257
2258 void transformNum(Num_t* num, str_list& out) {
2259 out.push_back(toString(num));
2260 }
2261
2262 void transformTableLit(TableLit_t* table, str_list& out) {
2263 transformTable(table, table->values.objects(), out);
2264 }
2265
2266 void transformCompCommon(Comprehension_t* comp, str_list& out) {
2267 str_list temp;
2268 auto x = comp;
2269 auto compInner = comp->forLoop.get();
2270 for (auto item : compInner->items.objects()) {
2271 switch (item->getId()) {
2272 case "CompForEach"_id:
2273 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
2274 break;
2275 case "CompFor"_id:
2276 transformCompFor(static_cast<CompFor_t*>(item), temp);
2277 break;
2278 case "Exp"_id:
2279 transformExp(static_cast<Exp_t*>(item), temp);
2280 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
2281 pushScope();
2282 break;
2283 }
2284 }
2285 if (auto stmt = comp->value.as<Statement_t>()) {
2286 transformStatement(stmt, temp);
2287 } else if (auto exp = comp->value.as<Exp_t>()) {
2288 auto expList = x->new_ptr<ExpList_t>();
2289 expList->exprs.push_back(exp);
2290 auto expListAssign = x->new_ptr<ExpListAssign_t>();
2291 expListAssign->expList.set(expList);
2292 auto statement = x->new_ptr<Statement_t>();
2293 statement->content.set(expListAssign);
2294 transformStatement(statement, temp);
2295 }
2296 auto value = temp.back();
2297 temp.pop_back();
2298 _buf << join(temp) << value;
2299 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
2300 popScope();
2301 _buf << indent() << "end"sv << nll(comp);
2302 }
2303 out.push_back(clearBuf());
2304 }
2305
2306 void transformComprehension(Comprehension_t* comp, str_list& out) {
2307 str_list temp;
2308 std::string accum = getUnusedName("_accum_");
2309 std::string len = getUnusedName("_len_");
2310 addToScope(accum);
2311 addToScope(len);
2312 auto compInner = comp->forLoop.get();
2313 for (auto item : compInner->items.objects()) {
2314 switch (item->getId()) {
2315 case "CompForEach"_id:
2316 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
2317 break;
2318 case "CompFor"_id:
2319 transformCompFor(static_cast<CompFor_t*>(item), temp);
2320 break;
2321 case "Exp"_id:
2322 transformExp(static_cast<Exp_t*>(item), temp);
2323 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
2324 pushScope();
2325 break;
2326 }
2327 }
2328 transformExp(comp->value.to<Exp_t>(), temp);
2329 auto value = temp.back();
2330 temp.pop_back();
2331 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
2332 popScope();
2333 }
2334 _buf << indent() << "local "sv << accum << " = { }"sv << nll(comp);
2335 _buf << indent() << "local "sv << len << " = 1"sv << nll(comp);
2336 _buf << join(temp);
2337 _buf << indent(int(temp.size())) << accum << "["sv << len << "] = "sv << value << nll(comp);
2338 _buf << indent(int(temp.size())) << len << " = "sv << len << " + 1"sv << nll(comp);
2339 for (int ind = int(temp.size()) - 1; ind > -1 ; --ind) {
2340 _buf << indent(ind) << "end"sv << nll(comp);
2341 }
2342 out.push_back(accum);
2343 out.push_back(clearBuf());
2344 }
2345
2346 void transformCompInPlace(Comprehension_t* comp, ExpList_t* expList, str_list& out) {
2347 auto x = comp;
2348 str_list temp;
2349 auto ind = indent();
2350 pushScope();
2351 transformComprehension(comp, temp);
2352 auto assign = x->new_ptr<Assign_t>();
2353 assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x));
2354 auto assignment = x->new_ptr<ExpListAssign_t>();
2355 assignment->expList.set(expList);
2356 assignment->action.set(assign);
2357 transformAssignment(assignment, temp);
2358 out.push_back(
2359 ind + s("do"sv) + nll(comp) +
2360 *(++temp.begin()) +
2361 temp.back());
2362 popScope();
2363 out.back() = out.back() + indent() + s("end"sv) + nlr(comp);
2364 }
2365
2366 void transformCompReturn(Comprehension_t* comp, str_list& out) {
2367 str_list temp;
2368 transformComprehension(comp, temp);
2369 out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp));
2370 }
2371
2372 void transformCompClosure(Comprehension_t* comp, str_list& out) {
2373 str_list temp;
2374 std::string before = s("(function()"sv) + nll(comp);
2375 pushScope();
2376 transformComprehension(comp, temp);
2377 out.push_back(
2378 before +
2379 temp.back() +
2380 indent() + s("return "sv) + temp.front() + nlr(comp));
2381 popScope();
2382 out.back() = out.back() + indent() + s("end)()"sv);
2383 }
2384
2385 void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) {
2386 auto x = nameList;
2387 str_list temp;
2388 str_list vars;
2389 str_list varBefore, varAfter;
2390 std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs;
2391 for (auto _item : nameList->items.objects()) {
2392 auto item = static_cast<NameOrDestructure_t*>(_item)->item.get();
2393 switch (item->getId()) {
2394 case "Variable"_id:
2395 transformVariable(static_cast<Variable_t*>(item), vars);
2396 varAfter.push_back(vars.back());
2397 break;
2398 case "TableLit"_id: {
2399 auto desVar = getUnusedName("_des_"sv);
2400 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, Exp, x));
2401 vars.push_back(desVar);
2402 varAfter.push_back(desVar);
2403 break;
2404 }
2405 default: break;
2406 }
2407 }
2408 switch (loopTarget->getId()) {
2409 case "star_exp"_id: {
2410 auto star_exp = static_cast<star_exp_t*>(loopTarget);
2411 auto listVar = singleVariableFrom(star_exp->value);
2412 auto indexVar = getUnusedName("_index_");
2413 varAfter.push_back(indexVar);
2414 auto value = singleValueFrom(star_exp->value);
2415 if (!value) throw std::logic_error(debugInfo("Invalid star syntax."sv, star_exp));
2416 bool endWithSlice = false;
2417 BLOCK_START
2418 auto chainValue = value->item.as<ChainValue_t>();
2419 BREAK_IF(!chainValue);
2420 auto chainList = chainValue->items.objects();
2421 auto slice = ast_cast<Slice_t>(chainList.back());
2422 BREAK_IF(!slice);
2423 endWithSlice = true;
2424 if (listVar.empty() && chainList.size() == 2 &&
2425 ast_is<Callable_t>(chainList.front())) {
2426 transformCallable(static_cast<Callable_t*>(chainList.front()), temp, false);
2427 listVar = temp.back();
2428 temp.pop_back();
2429 }
2430 chainList.pop_back();
2431 auto chain = x->new_ptr<ChainValue_t>();
2432 for (auto item : chainList) {
2433 chain->items.push_back(item);
2434 }
2435 std::string startValue("1"sv);
2436 if (auto exp = slice->startValue.as<Exp_t>()) {
2437 transformExp(exp, temp);
2438 startValue = temp.back();
2439 temp.pop_back();
2440 }
2441 std::string stopValue;
2442 if (auto exp = slice->stopValue.as<Exp_t>()) {
2443 transformExp(exp, temp);
2444 stopValue = temp.back();
2445 temp.pop_back();
2446 }
2447 std::string stepValue;
2448 if (auto exp = slice->stepValue.as<Exp_t>()) {
2449 transformExp(exp, temp);
2450 stepValue = temp.back();
2451 temp.pop_back();
2452 }
2453 if (listVar.empty()) {
2454 listVar = getUnusedName("_list_");
2455 varBefore.push_back(listVar);
2456 transformChainValue(chain, temp);
2457 _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
2458 }
2459 std::string maxVar;
2460 if (!stopValue.empty()) {
2461 maxVar = getUnusedName("_max_");
2462 varBefore.push_back(maxVar);
2463 _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
2464 }
2465 _buf << indent() << "for "sv << indexVar << " = "sv;
2466 _buf << startValue << ", "sv;
2467 if (stopValue.empty()) {
2468 _buf << "#"sv << listVar;
2469 } else {
2470 _buf << maxVar << " < 0 and #"sv << listVar <<" + " << maxVar << " or "sv << maxVar;
2471 }
2472 if (!stepValue.empty()) {
2473 _buf << ", "sv << stepValue;
2474 }
2475 _buf << " do"sv << nlr(loopTarget);
2476 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
2477 out.push_back(clearBuf());
2478 BLOCK_END
2479 bool newListVal = false;
2480 if (listVar.empty()) {
2481 newListVal = true;
2482 listVar = getUnusedName("_list_");
2483 varBefore.push_back(listVar);
2484 }
2485 if (!endWithSlice) {
2486 transformExp(star_exp->value, temp);
2487 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
2488 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget);
2489 _buf << indent(1) << "local "sv << join(vars) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList);
2490 out.push_back(clearBuf());
2491 }
2492 break;
2493 }
2494 case "Exp"_id:
2495 transformExp(static_cast<Exp_t*>(loopTarget), temp);
2496 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
2497 out.push_back(clearBuf());
2498 break;
2499 case "ExpList"_id:
2500 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
2501 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget);
2502 out.push_back(clearBuf());
2503 break;
2504 default: break;
2505 }
2506 for (auto& var : varBefore) addToScope(var);
2507 pushScope();
2508 for (auto& var : varAfter) addToScope(var);
2509 if (!destructPairs.empty()) {
2510 temp.clear();
2511 for (auto& pair : destructPairs) {
2512 auto sValue = x->new_ptr<SimpleValue_t>();
2513 sValue->value.set(pair.first);
2514 auto value = x->new_ptr<Value_t>();
2515 value->item.set(sValue);
2516 auto exp = x->new_ptr<Exp_t>();
2517 exp->value.set(value);
2518 auto expList = x->new_ptr<ExpList_t>();
2519 expList->exprs.push_back(exp);
2520 auto assign = x->new_ptr<Assign_t>();
2521 assign->values.push_back(pair.second);
2522 auto assignment = x->new_ptr<ExpListAssign_t>();
2523 assignment->expList.set(expList);
2524 assignment->action.set(assign);
2525 transformAssignment(assignment, temp);
2526 }
2527 out.back().append(join(temp));
2528 }
2529 }
2530
2531 void transformCompForEach(CompForEach_t* comp, str_list& out) {
2532 transformForEachHead(comp->nameList, comp->loopValue, out);
2533 }
2534
2535 void transformInvokeArgs(InvokeArgs_t* invokeArgs, str_list& out) {
2536 str_list temp;
2537 for (auto arg : invokeArgs->args.objects()) {
2538 switch (arg->getId()) {
2539 case "Exp"_id: transformExp(static_cast<Exp_t*>(arg), temp); break;
2540 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(arg), temp); break;
2541 default: break;
2542 }
2543 }
2544 out.push_back(s("("sv) + join(temp, ", "sv) + s(")"sv));
2545 }
2546
2547 void transformForHead(For_t* forNode, str_list& out) {
2548 str_list temp;
2549 std::string varName = toString(forNode->varName);
2550 transformExp(forNode->startValue, temp);
2551 transformExp(forNode->stopValue, temp);
2552 if (forNode->stepValue) {
2553 transformExp(forNode->stepValue->value, temp);
2554 } else {
2555 temp.emplace_back();
2556 }
2557 auto it = temp.begin();
2558 const auto& start = *it;
2559 const auto& stop = *(++it);
2560 const auto& step = *(++it);
2561 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(forNode);
2562 pushScope();
2563 addToScope(varName);
2564 out.push_back(clearBuf());
2565 }
2566
2567 void transformLoopBody(Body_t* body, str_list& out, const std::string& appendContent) {
2568 str_list temp;
2569 bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) {
2570 switch (node->getId()) {
2571 case "For"_id:
2572 case "ForEach"_id:
2573 return traversal::Return;
2574 case "BreakLoop"_id: {
2575 return toString(node) == "continue"sv ?
2576 traversal::Stop : traversal::Return;
2577 }
2578 default:
2579 return traversal::Continue;
2580 }
2581 });
2582 if (withContinue) {
2583 auto continueVar = getUnusedName("_continue_"sv);
2584 addToScope(continueVar);
2585 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body);
2586 _buf << indent() << "repeat"sv << nll(body);
2587 temp.push_back(clearBuf());
2588 _continueVars.push(continueVar);
2589 pushScope();
2590 }
2591 transformBody(body, temp);
2592 if (withContinue) {
2593 if (!appendContent.empty()) {
2594 _buf << indent() << appendContent;
2595 }
2596 _buf << indent() << _continueVars.top() << " = true"sv << nll(body);
2597 popScope();
2598 _buf << indent() << "until true"sv << nlr(body);
2599 _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body);
2600 _buf << indent(1) << "break"sv << nlr(body);
2601 _buf << indent() << "end"sv << nlr(body);
2602 temp.push_back(clearBuf());
2603 _continueVars.pop();
2604 } else if (!appendContent.empty()) {
2605 temp.back().append(indent() + appendContent);
2606 }
2607 out.push_back(join(temp));
2608 }
2609
2610 void transformFor(For_t* forNode, str_list& out) {
2611 str_list temp;
2612 transformForHead(forNode, temp);
2613 transformLoopBody(forNode->body, temp, Empty);
2614 popScope();
2615 out.push_back(join(temp) + indent() + s("end"sv) + nlr(forNode));
2616 }
2617
2618 std::string transformForInner(For_t* forNode, str_list& out) {
2619 auto x = forNode;
2620 std::string accum = getUnusedName("_accum_");
2621 addToScope(accum);
2622 std::string len = getUnusedName("_len_");
2623 addToScope(len);
2624 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode);
2625 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
2626 out.push_back(clearBuf());
2627 transformForHead(forNode, out);
2628 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x);
2629 assignLastExplist(expList, forNode->body);
2630 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forNode->body);
2631 transformLoopBody(forNode->body, out, lenLine);
2632 popScope();
2633 out.push_back(indent() + s("end"sv) + nlr(forNode));
2634 return accum;
2635 }
2636
2637 void transformForClosure(For_t* forNode, str_list& out) {
2638 str_list temp;
2639 _buf << "(function()"sv << nll(forNode);
2640 pushScope();
2641 auto accum = transformForInner(forNode, temp);
2642 temp.push_back(indent() + s("return "sv) + accum + nlr(forNode));
2643 popScope();
2644 temp.push_back(indent() + s("end)()"sv));
2645 out.push_back(join(temp));
2646 }
2647
2648 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) {
2649 auto x = forNode;
2650 str_list temp;
2651 if (assignExpList) {
2652 _buf << indent() << "do"sv << nll(forNode);
2653 pushScope();
2654 auto accum = transformForInner(forNode, temp);
2655 auto assign = x->new_ptr<Assign_t>();
2656 assign->values.push_back(toAst<Exp_t>(accum, Exp, x));
2657 auto assignment = x->new_ptr<ExpListAssign_t>();
2658 assignment->expList.set(assignExpList);
2659 assignment->action.set(assign);
2660 transformAssignment(assignment, temp);
2661 popScope();
2662 temp.push_back(indent() + s("end"sv) + nlr(forNode));
2663 } else {
2664 auto accum = transformForInner(forNode, temp);
2665 auto returnNode = x->new_ptr<Return_t>();
2666 auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x);
2667 returnNode->valueList.set(expListLow);
2668 transformReturn(returnNode, temp);
2669 }
2670 out.push_back(join(temp));
2671 }
2672
2673 void transformBinaryOperator(BinaryOperator_t* node, str_list& out) {
2674 auto op = toString(node);
2675 out.push_back(op == "!="sv ? s("~="sv) : op);
2676 }
2677
2678 void transformForEach(ForEach_t* forEach, str_list& out) {
2679 str_list temp;
2680 transformForEachHead(forEach->nameList, forEach->loopValue, temp);
2681 transformLoopBody(forEach->body, temp, Empty);
2682 popScope();
2683 out.push_back(temp.front() + temp.back() + indent() + s("end"sv) + nlr(forEach));
2684 }
2685
2686 std::string transformForEachInner(ForEach_t* forEach, str_list& out) {
2687 auto x = forEach;
2688 std::string accum = getUnusedName("_accum_");
2689 addToScope(accum);
2690 std::string len = getUnusedName("_len_");
2691 addToScope(len);
2692 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach);
2693 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
2694 out.push_back(clearBuf());
2695 transformForEachHead(forEach->nameList, forEach->loopValue, out);
2696 auto expList = toAst<ExpList_t>(accum + s("["sv) + len + s("]"sv), ExpList, x);
2697 assignLastExplist(expList, forEach->body);
2698 auto lenLine = len + s(" = "sv) + len + s(" + 1"sv) + nlr(forEach->body);
2699 transformLoopBody(forEach->body, out, lenLine);
2700 popScope();
2701 out.push_back(indent() + s("end"sv) + nlr(forEach));
2702 return accum;
2703 }
2704
2705 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
2706 str_list temp;
2707 _buf << "(function()"sv << nll(forEach);
2708 pushScope();
2709 auto accum = transformForEachInner(forEach, temp);
2710 temp.push_back(indent() + s("return "sv) + accum + nlr(forEach));
2711 popScope();
2712 temp.push_back(indent() + s("end)()"sv));
2713 out.push_back(join(temp));
2714 }
2715
2716 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) {
2717 auto x = forEach;
2718 str_list temp;
2719 if (assignExpList) {
2720 _buf << indent() << "do"sv << nll(forEach);
2721 pushScope();
2722 auto accum = transformForEachInner(forEach, temp);
2723 auto assign = x->new_ptr<Assign_t>();
2724 assign->values.push_back(toAst<Exp_t>(accum, Exp, x));
2725 auto assignment = x->new_ptr<ExpListAssign_t>();
2726 assignment->expList.set(assignExpList);
2727 assignment->action.set(assign);
2728 transformAssignment(assignment, temp);
2729 popScope();
2730 temp.push_back(indent() + s("end"sv) + nlr(forEach));
2731 } else {
2732 auto accum = transformForEachInner(forEach, temp);
2733 auto returnNode = x->new_ptr<Return_t>();
2734 auto expListLow = toAst<ExpListLow_t>(accum, ExpListLow, x);
2735 returnNode->valueList.set(expListLow);
2736 transformReturn(returnNode, temp);
2737 }
2738 out.push_back(join(temp));
2739 }
2740
2741 void transform_variable_pair(variable_pair_t* pair, str_list& out) {
2742 auto name = toString(pair->name);
2743 out.push_back(name + s(" = "sv) + name);
2744 }
2745
2746 void transform_normal_pair(normal_pair_t* pair, str_list& out) {
2747 auto key = pair->key.get();
2748 str_list temp;
2749 switch (key->getId()) {
2750 case "KeyName"_id: {
2751 transformKeyName(static_cast<KeyName_t*>(key), temp);
2752 if (State::luaKeywords.find(temp.back()) != State::luaKeywords.end()) {
2753 temp.back() = s("[\""sv) + temp.back() + s("\"]");
2754 }
2755 break;
2756 }
2757 case "Exp"_id:
2758 transformExp(static_cast<Exp_t*>(key), temp);
2759 temp.back() = s("["sv) + temp.back() + s("]"sv);
2760 break;
2761 case "DoubleString"_id:
2762 transformDoubleString(static_cast<DoubleString_t*>(key), temp);
2763 temp.back() = s("["sv) + temp.back() + s("]"sv);
2764 break;
2765 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(key), temp);
2766 temp.back() = s("["sv) + temp.back() + s("]"sv);
2767 break;
2768 default: break;
2769 }
2770 auto value = pair->value.get();
2771 switch (value->getId()) {
2772 case "Exp"_id: transformExp(static_cast<Exp_t*>(value), temp); break;
2773 case "TableBlock"_id: transformTableBlock(static_cast<TableBlock_t*>(value), temp); break;
2774 default: break;
2775 }
2776 out.push_back(temp.front() + s(" = "sv) + temp.back());
2777 }
2778
2779 void transformKeyName(KeyName_t* keyName, str_list& out) {
2780 auto name = keyName->name.get();
2781 switch (name->getId()) {
2782 case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(name), out, false); break;
2783 case "Name"_id: out.push_back(toString(name)); break;
2784 default: break;
2785 }
2786 }
2787
2788 void replace(std::string& str, std::string_view from, std::string_view to) {
2789 size_t start_pos = 0;
2790 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
2791 str.replace(start_pos, from.size(), to);
2792 start_pos += to.size();
2793 }
2794 }
2795
2796 void transformLuaString(LuaString_t* luaString, str_list& out) {
2797 auto content = toString(luaString->content);
2798 replace(content, "\r"sv, "");
2799 if (content[0] == '\n') content.erase(content.begin());
2800 out.push_back(toString(luaString->open) + content + toString(luaString->close));
2801 }
2802
2803 void transformSingleString(SingleString_t* singleString, str_list& out) {
2804 auto str = toString(singleString);
2805 replace(str, "\r"sv, "");
2806 replace(str, "\n"sv, "\\n"sv);
2807 out.push_back(str);
2808 }
2809
2810 void transformDoubleString(DoubleString_t* doubleString, str_list& out) {
2811 str_list temp;
2812 for (auto _seg : doubleString->segments.objects()) {
2813 auto seg = static_cast<double_string_content_t*>(_seg);
2814 auto content = seg->content.get();
2815 switch (content->getId()) {
2816 case "double_string_inner"_id: {
2817 auto str = toString(content);
2818 replace(str, "\r"sv, "");
2819 replace(str, "\n"sv, "\\n"sv);
2820 temp.push_back(s("\""sv) + str + s("\""sv));
2821 break;
2822 }
2823 case "Exp"_id:
2824 transformExp(static_cast<Exp_t*>(content), temp);
2825 temp.back() = s("tostring("sv) + temp.back() + s(")"sv);
2826 break;
2827 default: break;
2828 }
2829 }
2830 out.push_back(temp.empty() ? s("\"\""sv) : join(temp, " .. "sv));
2831 }
2832
2833 void transformString(String_t* string, str_list& out) {
2834 auto str = string->str.get();
2835 switch (str->getId()) {
2836 case "SingleString"_id: transformSingleString(static_cast<SingleString_t*>(str), out); break;
2837 case "DoubleString"_id: transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
2838 case "LuaString"_id: transformLuaString(static_cast<LuaString_t*>(str), out); break;
2839 default: break;
2840 }
2841 }
2842
2843 std::pair<std::string,bool> defineClassVariable(Assignable_t* assignable) {
2844 if (auto variable = assignable->item.as<Variable_t>()) {
2845 auto name = toString(variable);
2846 if (addToScope(name)) {
2847 return {name, true};
2848 } else {
2849 return {name, false};
2850 }
2851 }
2852 return {Empty, false};
2853 }
2854
2855 void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) {
2856 str_list temp;
2857 temp.push_back(s("(function()"sv) + nll(classDecl));
2858 pushScope();
2859 transformClassDecl(classDecl, temp, ExpUsage::Return);
2860 popScope();
2861 temp.push_back(s("end)()"sv));
2862 out.push_back(join(temp));
2863 }
2864
2865 void transformClassDecl(ClassDecl_t* classDecl, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) {
2866 str_list temp;
2867 auto x = classDecl;
2868 auto body = classDecl->body.get();
2869 auto assignable = classDecl->name.get();
2870 auto extend = classDecl->extend.get();
2871 std::string className;
2872 std::string assignItem;
2873 if (assignable) {
2874 if (!isAssignable(assignable)) {
2875 throw std::logic_error(debugInfo("Left hand expression is not assignable."sv, assignable));
2876 }
2877 bool newDefined = false;
2878 std::tie(className, newDefined) = defineClassVariable(assignable);
2879 if (newDefined) {
2880 temp.push_back(indent() + s("local "sv) + className + nll(classDecl));
2881 }
2882 if (className.empty()) {
2883 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
2884 if (auto dotChain = ast_cast<DotChainItem_t>(chain->items.back())) {
2885 className = s("\""sv) + toString(dotChain->name) + s("\""sv);
2886 } else if (auto index = ast_cast<Exp_t>(chain->items.back())) {
2887 if (auto name = index->getByPath<Value_t, String_t>()) {
2888 transformString(name, temp);
2889 className = temp.back();
2890 temp.pop_back();
2891 }
2892 }
2893 }
2894 } else {
2895 className = s("\""sv) + className + s("\""sv);
2896 }
2897 pushScope();
2898 transformAssignable(assignable, temp);
2899 popScope();
2900 assignItem = temp.back();
2901 temp.pop_back();
2902 } else if (expList) {
2903 auto name = singleVariableFrom(expList);
2904 if (!name.empty()) {
2905 className = s("\""sv) + name + s("\""sv);
2906 }
2907 }
2908 temp.push_back(indent() + s("do"sv) + nll(classDecl));
2909 pushScope();
2910 auto classVar = getUnusedName("_class_"sv);
2911 addToScope(classVar);
2912 temp.push_back(indent() + s("local "sv) + classVar + nll(classDecl));
2913 if (body) {
2914 str_list varDefs;
2915 for (auto item : body->contents.objects()) {
2916 if (auto statement = ast_cast<Statement_t>(item)) {
2917 ClassDecl_t* clsDecl = nullptr;
2918 if (auto assignment = assignmentFrom(statement)) {
2919 auto names = transformAssignDefs(assignment->expList.get());
2920 varDefs.insert(varDefs.end(), names.begin(), names.end());
2921 auto info = extractDestructureInfo(assignment);
2922 if (!info.first.empty()) {
2923 for (const auto& destruct : info.first)
2924 for (const auto& item : destruct.items)
2925 if (item.isVariable && addToScope(item.name))
2926 varDefs.push_back(item.name);
2927 }
2928 BLOCK_START
2929 auto assign = assignment->action.as<Assign_t>();
2930 BREAK_IF(!assign);
2931 BREAK_IF(assign->values.objects().size() != 1);
2932 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
2933 BREAK_IF(!exp);
2934 auto value = singleValueFrom(exp);
2935 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2936 BLOCK_END
2937 } else if (auto expList = expListFrom(statement)) {
2938 auto value = singleValueFrom(expList);
2939 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
2940 }
2941 if (clsDecl) {
2942 std::string clsName;
2943 bool newDefined = false;
2944 std::tie(clsName,newDefined) = defineClassVariable(clsDecl->name);
2945 if (newDefined) varDefs.push_back(clsName);
2946 }
2947 }
2948 }
2949 if (!varDefs.empty()) {
2950 temp.push_back(indent() + s("local ") + join(varDefs, ", "sv) + nll(body));
2951 }
2952 }
2953 std::string parent, parentVar;
2954 if (extend) {
2955 parentVar = getUnusedName("_parent_"sv);
2956 addToScope(parentVar);
2957 transformExp(extend, temp);
2958 parent = temp.back();
2959 temp.pop_back();
2960 temp.push_back(indent() + s("local "sv) + parentVar + s(" = "sv) + parent + nll(classDecl));
2961 }
2962 auto baseVar = getUnusedName("_base_"sv);
2963 addToScope(baseVar);
2964 temp.push_back(indent() + s("local "sv) + baseVar + s(" = "sv));
2965 str_list builtins;
2966 str_list commons;
2967 str_list statements;
2968 if (body) {
2969 std::list<ClassMember> members;
2970 for (auto content : classDecl->body->contents.objects()) {
2971 switch (content->getId()) {
2972 case "class_member_list"_id: {
2973 size_t inc = transform_class_member_list(static_cast<class_member_list_t*>(content), members, classVar);
2974 auto it = members.end();
2975 for (size_t i = 0; i < inc; ++i, --it);
2976 for (; it != members.end(); ++it) {
2977 auto& member = *it;
2978 if (member.type == MemType::Property) {
2979 statements.push_back(indent() + member.item + nll(content));
2980 } else {
2981 member.item = indent(1) + member.item;
2982 }
2983 }
2984 break;
2985 }
2986 case "Statement"_id:
2987 transformStatement(static_cast<Statement_t*>(content), statements);
2988 break;
2989 default: break;
2990 }
2991 }
2992 for (auto& member : members) {
2993 switch (member.type) {
2994 case MemType::Common:
2995 commons.push_back((commons.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
2996 break;
2997 case MemType::Builtin:
2998 builtins.push_back((builtins.empty() ? Empty : s(","sv) + nll(member.node)) + member.item);
2999 break;
3000 default: break;
3001 }
3002 }
3003 if (!commons.empty()) {
3004 temp.back() += s("{"sv) + nll(body);
3005 temp.push_back(join(commons) + nll(body));
3006 temp.push_back(indent() + s("}"sv) + nll(body));
3007 } else {
3008 temp.back() += s("{ }"sv) + nll(body);
3009 }
3010 } else {
3011 temp.back() += s("{ }"sv) + nll(classDecl);
3012 }
3013 temp.push_back(indent() + baseVar + s(".__index = "sv) + baseVar + nll(classDecl));
3014 str_list tmp;
3015 if (usage == ExpUsage::Assignment) {
3016 auto assign = x->new_ptr<Assign_t>();
3017 assign->values.push_back(toAst<Exp_t>(classVar, Exp, x));
3018 auto assignment = x->new_ptr<ExpListAssign_t>();
3019 assignment->expList.set(expList);
3020 assignment->action.set(assign);
3021 transformAssignment(assignment, tmp);
3022 }
3023 if (extend) {
3024 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl);
3025 }
3026 _buf << indent() << classVar << " = setmetatable({" << nll(classDecl);
3027 if (!builtins.empty()) {
3028 _buf << join(builtins) << ","sv << nll(classDecl);
3029 } else {
3030 if (extend) {
3031 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl);
3032 _buf << indent(2) << "return _class_0.__parent.__init(self, ...)"sv << nll(classDecl);
3033 _buf << indent(1) << "end,"sv << nll(classDecl);
3034 } else {
3035 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl);
3036 }
3037 }
3038 _buf << indent(1) << "__base = "sv << baseVar;
3039 if (!className.empty()) {
3040 _buf << ","sv << nll(classDecl) << indent(1) << "__name = "sv << className << (extend ? s(","sv) : Empty) << nll(classDecl);
3041 } else {
3042 _buf << nll(classDecl);
3043 }
3044 if (extend) {
3045 _buf << indent(1) << "__parent = "sv << parentVar << nll(classDecl);
3046 }
3047 _buf << indent() << "}, {"sv << nll(classDecl);
3048 if (extend) {
3049 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl);
3050 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl);
3051 _buf << indent(2) << "if val == nil then"sv << nll(classDecl);
3052 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl);
3053 _buf << indent(3) << "if parent then"sv << nll(classDecl);
3054 _buf << indent(4) << "return parent[name]"sv << nll(classDecl);
3055 _buf << indent(3) << "end"sv << nll(classDecl);
3056 _buf << indent(2) << "else"sv << nll(classDecl);
3057 _buf << indent(3) << "return val"sv << nll(classDecl);
3058 _buf << indent(2) << "end"sv << nll(classDecl);
3059 _buf << indent(1) << "end,"sv << nll(classDecl);
3060 } else {
3061 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl);
3062 }
3063 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl);
3064 pushScope();
3065 auto selfVar = getUnusedName("_self_"sv);
3066 addToScope(selfVar);
3067 _buf << indent(1) << "local " << selfVar << " = setmetatable({}, "sv << baseVar << ")"sv << nll(classDecl);
3068 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl);
3069 _buf << indent(1) << "return "sv << selfVar << nll(classDecl);
3070 popScope();
3071 _buf << indent(1) << "end"sv << nll(classDecl);
3072 _buf << indent() << "})"sv << nll(classDecl);
3073 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl);
3074 if (!statements.empty()) _buf << indent() << "local self = "sv << classVar << nll(classDecl);
3075 _buf << join(statements);
3076 if (extend) {
3077 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl);
3078 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl);
3079 _buf << indent() << "end"sv << nll(classDecl);
3080 }
3081 if (!assignItem.empty()) {
3082 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl);
3083 }
3084 switch (usage) {
3085 case ExpUsage::Return: {
3086 _buf << indent() << "return "sv << classVar << nlr(classDecl);
3087 break;
3088 }
3089 case ExpUsage::Assignment: {
3090 _buf << tmp.back();
3091 break;
3092 }
3093 default: break;
3094 }
3095 temp.push_back(clearBuf());
3096 popScope();
3097 temp.push_back(indent() + s("end"sv) + nlr(classDecl));
3098 out.push_back(join(temp));
3099 }
3100
3101 size_t transform_class_member_list(class_member_list_t* class_member_list, std::list<ClassMember>& out, const std::string& classVar) {
3102 str_list temp;
3103 size_t count = 0;
3104 for (auto keyValue : class_member_list->values.objects()) {
3105 MemType type = MemType::Common;
3106 BLOCK_START
3107 auto normal_pair = ast_cast<normal_pair_t>(keyValue);
3108 BREAK_IF(!normal_pair);
3109 auto keyName = normal_pair->key.as<KeyName_t>();
3110 BREAK_IF(!keyName);
3111 std::string newSuperCall;
3112 auto selfName = keyName->name.as<SelfName_t>();
3113 if (selfName) {
3114 type = MemType::Property;
3115 auto name = ast_cast<self_name_t>(selfName->name);
3116 if (!name) throw std::logic_error(debugInfo("Invalid class poperty name."sv, selfName->name));
3117 newSuperCall = classVar + s(".__parent."sv) + toString(name->name);
3118 } else {
3119 auto x = keyName;
3120 auto nameNode = keyName->name.as<Name_t>();
3121 if (!nameNode) break;
3122 auto name = toString(nameNode);
3123 if (name == "new"sv) {
3124 type = MemType::Builtin;
3125 keyName->name.set(toAst<Name_t>("__init"sv, Name, x));
3126 newSuperCall = classVar + s(".__parent.__init"sv);
3127 } else {
3128 newSuperCall = classVar + s(".__parent.__base."sv) + name;
3129 }
3130 }
3131 normal_pair->value->traverse([&](ast_node* node) {
3132 if (node->getId() == "ClassDecl"_id) return traversal::Return;
3133 if (auto chainValue = ast_cast<ChainValue_t>(node)) {
3134 if (auto callable = ast_cast<Callable_t>(chainValue->items.front())) {
3135 auto var = callable->item.get();
3136 if (toString(var) == "super"sv) {
3137 auto insertSelfToArguments = [&](ast_node* item) {
3138 auto x = item;
3139 switch (item->getId()) {
3140 case "InvokeArgs"_id: {
3141 auto invoke = static_cast<InvokeArgs_t*>(item);
3142 invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x));
3143 return true;
3144 }
3145 case "Invoke"_id: {
3146 auto invoke = static_cast<Invoke_t*>(item);
3147 invoke->args.push_front(toAst<Exp_t>("self"sv, Exp, x));
3148 return true;
3149 }
3150 default:
3151 return false;
3152 }
3153 };
3154 const auto& chainList = chainValue->items.objects();
3155 if (chainList.size() >= 2) {
3156 auto it = chainList.begin();
3157 auto secondItem = *(++it);
3158 if (!insertSelfToArguments(secondItem)) {
3159 if (auto colonChainItem = ast_cast<ColonChainItem_t>(secondItem)) {
3160 if (chainList.size() > 2 && insertSelfToArguments(*(++it))) {
3161 colonChainItem->switchToDot = true;
3162 }
3163 }
3164 newSuperCall = classVar + s(".__parent"sv);
3165 }
3166 } else {
3167 newSuperCall = classVar + s(".__parent"sv);
3168 }
3169 auto newChain = toAst<ChainValue_t>(newSuperCall, ChainValue, chainValue);
3170 chainValue->items.pop_front();
3171 const auto& items = newChain->items.objects();
3172 for (auto it = items.rbegin(); it != items.rend(); ++it) {
3173 chainValue->items.push_front(*it);
3174 }
3175 }
3176 }
3177 }
3178 return traversal::Continue;
3179 });
3180 BLOCK_END
3181 pushScope();
3182 if (type == MemType::Property) {
3183 decIndentOffset();
3184 }
3185 switch (keyValue->getId()) {
3186 case "variable_pair"_id:
3187 transform_variable_pair(static_cast<variable_pair_t*>(keyValue), temp);
3188 break;
3189 case "normal_pair"_id:
3190 transform_normal_pair(static_cast<normal_pair_t*>(keyValue), temp);
3191 break;
3192 }
3193 if (type == MemType::Property) {
3194 incIndentOffset();
3195 }
3196 popScope();
3197 out.push_back({temp.back(), type, keyValue});
3198 temp.clear();
3199 ++count;
3200 }
3201 return count;
3202 }
3203
3204 void transformAssignable(Assignable_t* assignable, str_list& out) {
3205 auto item = assignable->item.get();
3206 switch (item->getId()) {
3207 case "AssignableChain"_id: transformAssignableChain(static_cast<AssignableChain_t*>(item), out); break;
3208 case "Variable"_id: transformVariable(static_cast<Variable_t*>(item), out); break;
3209 case "SelfName"_id: transformSelfName(static_cast<SelfName_t*>(item), out, false); break;
3210 default: break;
3211 }
3212 }
3213
3214 void transformWithClosure(With_t* with, str_list& out) {
3215 str_list temp;
3216 temp.push_back(s("(function()"sv) + nll(with));
3217 pushScope();
3218 transformWith(with, temp, nullptr, true);
3219 popScope();
3220 temp.push_back(indent() + s("end)()"sv));
3221 out.push_back(join(temp));
3222 }
3223
3224 void transformWith(With_t* with, str_list& out, ExpList_t* assignList = nullptr, bool returnValue = false) {
3225 auto x = with;
3226 str_list temp;
3227 std::string withVar;
3228 bool scoped = false;
3229 if (with->assigns) {
3230 checkAssignable(with->valueList);
3231 auto vars = getAssignVars(with);
3232 if (vars.front().empty()) {
3233 if (with->assigns->values.objects().size() == 1) {
3234 auto var = singleVariableFrom(with->assigns->values.objects().front());
3235 if (!var.empty()) {
3236 withVar = var;
3237 }
3238 }
3239 if (withVar.empty()) {
3240 withVar = getUnusedName("_with_");
3241 auto assignment = x->new_ptr<ExpListAssign_t>();
3242 assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x));
3243 auto assign = x->new_ptr<Assign_t>();
3244 assign->values.push_back(with->assigns->values.objects().front());
3245 assignment->action.set(assign);
3246 if (!returnValue) {
3247 scoped = true;
3248 temp.push_back(indent() + s("do"sv) + nll(with));
3249 pushScope();
3250 }
3251 transformAssignment(assignment, temp);
3252 }
3253 auto assignment = x->new_ptr<ExpListAssign_t>();
3254 assignment->expList.set(with->valueList);
3255 auto assign = x->new_ptr<Assign_t>();
3256 assign->values.push_back(toAst<Exp_t>(withVar, Exp, x));
3257 bool skipFirst = true;
3258 for (auto value : with->assigns->values.objects()) {
3259 if (skipFirst) {
3260 skipFirst = false;
3261 continue;
3262 }
3263 assign->values.push_back(value);
3264 }
3265 assignment->action.set(assign);
3266 transformAssignment(assignment, temp);
3267 } else {
3268 withVar = vars.front();
3269 auto assignment = x->new_ptr<ExpListAssign_t>();
3270 assignment->expList.set(with->valueList);
3271 assignment->action.set(with->assigns);
3272 if (!returnValue) {
3273 scoped = true;
3274 temp.push_back(indent() + s("do"sv) + nll(with));
3275 pushScope();
3276 }
3277 transformAssignment(assignment, temp);
3278 }
3279 } else {
3280 withVar = singleVariableFrom(with->valueList);
3281 if (withVar.empty()) {
3282 withVar = getUnusedName("_with_");
3283 auto assignment = x->new_ptr<ExpListAssign_t>();
3284 assignment->expList.set(toAst<ExpList_t>(withVar, ExpList, x));
3285 auto assign = x->new_ptr<Assign_t>();
3286 assign->values.dup(with->valueList->exprs);
3287 assignment->action.set(assign);
3288 if (!returnValue) {
3289 scoped = true;
3290 temp.push_back(indent() + s("do"sv) + nll(with));
3291 pushScope();
3292 }
3293 transformAssignment(assignment, temp);
3294 }
3295 }
3296 if (!scoped && !returnValue) {
3297 pushScope();
3298 scoped = traversal::Stop == with->body->traverse([&](ast_node* node) {
3299 if (auto statement = ast_cast<Statement_t>(node)) {
3300 ClassDecl_t* clsDecl = nullptr;
3301 if (auto assignment = assignmentFrom(statement)) {
3302 auto names = getAssignDefs(assignment->expList.get());
3303 if (!names.empty()) {
3304 return traversal::Stop;
3305 }
3306 auto info = extractDestructureInfo(assignment);
3307 if (!info.first.empty()) {
3308 for (const auto& destruct : info.first)
3309 for (const auto& item : destruct.items)
3310 if (item.isVariable && !isDefined(item.name))
3311 return traversal::Stop;
3312 }
3313 BLOCK_START
3314 auto assign = assignment->action.as<Assign_t>();
3315 BREAK_IF(!assign);
3316 BREAK_IF(assign->values.objects().size() != 1);
3317 auto exp = ast_cast<Exp_t>(assign->values.objects().front());
3318 BREAK_IF(!exp);
3319 if (auto value = singleValueFrom(exp)) {
3320 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
3321 }
3322 BLOCK_END
3323 } else if (auto expList = expListFrom(statement)) {
3324 auto value = singleValueFrom(expList);
3325 clsDecl = value->getByPath<SimpleValue_t, ClassDecl_t>();
3326 }
3327 if (clsDecl) {
3328 auto variable = clsDecl->name.as<Variable_t>();
3329 if (!isDefined(toString(variable))) return traversal::Stop;
3330 }
3331 return traversal::Return;
3332 }
3333 return traversal::Continue;
3334 });
3335 popScope();
3336 if (scoped) {
3337 temp.push_back(indent() + s("do"sv) + nll(with));
3338 pushScope();
3339 }
3340 }
3341 _withVars.push(withVar);
3342 transformBody(with->body, temp);
3343 _withVars.pop();
3344 if (assignList) {
3345 auto assignment = x->new_ptr<ExpListAssign_t>();
3346 assignment->expList.set(assignList);
3347 auto assign = x->new_ptr<Assign_t>();
3348 assign->values.push_back(toAst<Exp_t>(withVar, Exp, x));
3349 assignment->action.set(assign);
3350 transformAssignment(assignment, temp);
3351 }
3352 if (returnValue) {
3353 auto stmt = lastStatementFrom(with->body);
3354 if (!stmt->content.is<Return_t>()) {
3355 temp.push_back(indent() + s("return "sv) + withVar + nll(with));
3356 }
3357 }
3358 if (scoped) {
3359 popScope();
3360 temp.push_back(indent() + s("end"sv) + nll(with));
3361 }
3362 out.push_back(join(temp));
3363 }
3364
3365 void transform_const_value(const_value_t* const_value, str_list& out) {
3366 out.push_back(toString(const_value));
3367 }
3368
3369 void transformExport(Export_t* exportNode, str_list& out) {
3370 auto x = exportNode;
3371 auto item = exportNode->item.get();
3372 switch (item->getId()) {
3373 case "ClassDecl"_id: {
3374 auto classDecl = static_cast<ClassDecl_t*>(item);
3375 if (classDecl->name && classDecl->name->item->getId() == "Variable"_id) {
3376 markVarExported(ExportMode::Any, true);
3377 addExportedVar(toString(classDecl->name->item));
3378 }
3379 transformClassDecl(classDecl, out);
3380 break;
3381 }
3382 case "export_op"_id:
3383 if (toString(item) == "*"sv) {
3384 markVarExported(ExportMode::Any, false);
3385 } else {
3386 markVarExported(ExportMode::Capital, false);
3387 }
3388 break;
3389 case "export_values"_id: {
3390 markVarExported(ExportMode::Any, true);
3391 auto values = exportNode->item.to<export_values_t>();
3392 if (values->valueList) {
3393 auto expList = x->new_ptr<ExpList_t>();
3394 for (auto name : values->nameList->names.objects()) {
3395 addExportedVar(toString(name));
3396 auto callable = x->new_ptr<Callable_t>();
3397 callable->item.set(name);
3398 auto chainValue = x->new_ptr<ChainValue_t>();
3399 chainValue->items.push_back(callable);
3400 auto value = x->new_ptr<Value_t>();
3401 value->item.set(chainValue);
3402 auto exp = x->new_ptr<Exp_t>();
3403 exp->value.set(value);
3404 expList->exprs.push_back(exp);
3405 }
3406 auto assignment = x->new_ptr<ExpListAssign_t>();
3407 assignment->expList.set(expList);
3408 auto assign = x->new_ptr<Assign_t>();
3409 assign->values.dup(values->valueList->exprs);
3410 assignment->action.set(assign);
3411 transformAssignment(assignment, out);
3412 } else {
3413 for (auto name : values->nameList->names.objects()) {
3414 addExportedVar(toString(name));
3415 }
3416 }
3417 break;
3418 }
3419 default:
3420 break;
3421 }
3422 }
3423
3424 void transformTable(ast_node* table, const node_container& pairs, str_list& out) {
3425 if (pairs.empty()) {
3426 out.push_back(s("{ }"sv));
3427 return;
3428 }
3429 str_list temp;
3430 pushScope();
3431 for (auto pair : pairs) {
3432 switch (pair->getId()) {
3433 case "Exp"_id: transformExp(static_cast<Exp_t*>(pair), temp); break;
3434 case "variable_pair"_id: transform_variable_pair(static_cast<variable_pair_t*>(pair), temp); break;
3435 case "normal_pair"_id: transform_normal_pair(static_cast<normal_pair_t*>(pair), temp); break;
3436 }
3437 temp.back() = indent() + temp.back() + (pair == pairs.back() ? Empty : s(","sv)) + nll(pair);
3438 }
3439 out.push_back(s("{"sv) + nll(table) + join(temp));
3440 popScope();
3441 out.back() += (indent() + s("}"sv));
3442 }
3443
3444 void transform_simple_table(simple_table_t* table, str_list& out) {
3445 transformTable(table, table->pairs.objects(), out);
3446 }
3447
3448 void transformTblComprehension(TblComprehension_t* comp, str_list& out) {
3449 str_list kv;
3450 std::string tbl = getUnusedName("_tbl_");
3451 addToScope(tbl);
3452 str_list temp;
3453 auto compInner = comp->forLoop.get();
3454 for (auto item : compInner->items.objects()) {
3455 switch (item->getId()) {
3456 case "CompForEach"_id:
3457 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
3458 break;
3459 case "CompFor"_id:
3460 transformCompFor(static_cast<CompFor_t*>(item), temp);
3461 break;
3462 case "Exp"_id:
3463 transformExp(static_cast<Exp_t*>(item), temp);
3464 temp.back() = indent() + s("if "sv) + temp.back() + s(" then"sv) + nll(item);
3465 pushScope();
3466 break;
3467 }
3468 }
3469 transformExp(comp->key, kv);
3470 if (comp->value) {
3471 transformExp(comp->value->value, kv);
3472 }
3473 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
3474 popScope();
3475 }
3476 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp);
3477 _buf << join(temp);
3478 pushScope();
3479 if (!comp->value) {
3480 auto keyVar = getUnusedName("_key_");
3481 auto valVar = getUnusedName("_val_");
3482 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp);
3483 kv.front() = keyVar;
3484 kv.push_back(valVar);
3485 }
3486 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp);
3487 for (int ind = int(temp.size()) - 2; ind > -1 ; --ind) {
3488 _buf << indent(ind) << "end"sv << nll(comp);
3489 }
3490 popScope();
3491 _buf << indent() << "end"sv << nll(comp);
3492 out.push_back(tbl);
3493 out.push_back(clearBuf());
3494 }
3495
3496 void transformTblCompInPlace(TblComprehension_t* comp, ExpList_t* expList, str_list& out) {
3497 auto x = comp;
3498 str_list temp;
3499 auto ind = indent();
3500 pushScope();
3501 transformTblComprehension(comp, temp);
3502 auto assign = x->new_ptr<Assign_t>();
3503 assign->values.push_back(toAst<Exp_t>(temp.front(), Exp, x));
3504 auto assignment = x->new_ptr<ExpListAssign_t>();
3505 assignment->expList.set(expList);
3506 assignment->action.set(assign);
3507 transformAssignment(assignment, temp);
3508 out.push_back(
3509 ind + s("do"sv) + nll(comp) +
3510 *(++temp.begin()) +
3511 temp.back());
3512 popScope();
3513 out.back() = out.back() + indent() + s("end"sv) + nlr(comp);
3514 }
3515
3516 void transformTblCompReturn(TblComprehension_t* comp, str_list& out) {
3517 str_list temp;
3518 transformTblComprehension(comp, temp);
3519 out.push_back(temp.back() + indent() + s("return "sv) + temp.front() + nlr(comp));
3520 }
3521
3522 void transformTblCompClosure(TblComprehension_t* comp, str_list& out) {
3523 str_list temp;
3524 std::string before = s("(function()"sv) + nll(comp);
3525 pushScope();
3526 transformTblComprehension(comp, temp);
3527 const auto& tbVar = temp.front();
3528 const auto& compBody = temp.back();
3529 out.push_back(
3530 before +
3531 compBody +
3532 indent() + s("return "sv) + tbVar + nlr(comp));
3533 popScope();
3534 out.back() = out.back() + indent() + s("end)()"sv);
3535 }
3536
3537 void transformCompFor(CompFor_t* comp, str_list& out) {
3538 str_list temp;
3539 std::string varName = toString(comp->varName);
3540 transformExp(comp->startValue, temp);
3541 transformExp(comp->stopValue, temp);
3542 if (comp->stepValue) {
3543 transformExp(comp->stepValue->value, temp);
3544 } else {
3545 temp.emplace_back();
3546 }
3547 auto it = temp.begin();
3548 const auto& start = *it;
3549 const auto& stop = *(++it);
3550 const auto& step = *(++it);
3551 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : s(", "sv) + step) << " do"sv << nll(comp);
3552 out.push_back(clearBuf());
3553 pushScope();
3554 addToScope(varName);
3555 }
3556
3557 void transformTableBlock(TableBlock_t* table, str_list& out) {
3558 transformTable(table, table->values.objects(), out);
3559 }
3560
3561 void transformDo(Do_t* doNode, str_list& out, bool implicitReturn = false) {
3562 str_list temp;
3563 temp.push_back(indent() + s("do"sv) + nll(doNode));
3564 pushScope();
3565 transformBody(doNode->body, temp, implicitReturn);
3566 popScope();
3567 temp.push_back(indent() + s("end"sv) + nlr(doNode));
3568 out.push_back(join(temp));
3569 }
3570
3571 void transformDoClosure(Do_t* doNode, str_list& out) {
3572 str_list temp;
3573 temp.push_back(s("(function()"sv) + nll(doNode));
3574 pushScope();
3575 transformBody(doNode->body, temp, true);
3576 popScope();
3577 temp.push_back(indent() + s("end)()"sv));
3578 out.push_back(join(temp));
3579 }
3580
3581 void transformImport(Import_t* import, str_list& out) {
3582 str_list temp;
3583 auto x = import;
3584 auto objVar = singleVariableFrom(import->exp);
3585 ast_ptr<false, ExpListAssign_t> objAssign;
3586 if (objVar.empty()) {
3587 objVar = getUnusedName("_obj_"sv);
3588 auto expList = toAst<ExpList_t>(objVar, ExpList, x);
3589 auto assign = x->new_ptr<Assign_t>();
3590 assign->values.push_back(import->exp);
3591 auto assignment = x->new_ptr<ExpListAssign_t>();
3592 assignment->expList.set(expList);
3593 assignment->action.set(assign);
3594 objAssign.set(assignment);
3595 }
3596 auto expList = x->new_ptr<ExpList_t>();
3597 auto assign = x->new_ptr<Assign_t>();
3598 for (auto name : import->names.objects()) {
3599 switch (name->getId()) {
3600 case "Variable"_id: {
3601 auto var = ast_to<Variable_t>(name);
3602 {
3603 auto callable = toAst<Callable_t>(objVar, Callable, x);
3604 auto dotChainItem = x->new_ptr<DotChainItem_t>();
3605 dotChainItem->name.set(var->name);
3606 auto chainValue = x->new_ptr<ChainValue_t>();
3607 chainValue->items.push_back(callable);
3608 chainValue->items.push_back(dotChainItem);
3609 auto value = x->new_ptr<Value_t>();
3610 value->item.set(chainValue);
3611 auto exp = x->new_ptr<Exp_t>();
3612 exp->value.set(value);
3613 assign->values.push_back(exp);
3614 }
3615 auto callable = x->new_ptr<Callable_t>();
3616 callable->item.set(var);
3617 auto chainValue = x->new_ptr<ChainValue_t>();
3618 chainValue->items.push_back(callable);
3619 auto value = x->new_ptr<Value_t>();
3620 value->item.set(chainValue);
3621 auto exp = x->new_ptr<Exp_t>();
3622 exp->value.set(value);
3623 expList->exprs.push_back(exp);
3624 break;
3625 }
3626 case "colon_import_name"_id: {
3627 auto var = static_cast<colon_import_name_t*>(name)->name.get();
3628 {
3629 auto nameNode = var->name.get();
3630 auto callable = toAst<Callable_t>(objVar, Callable, x);
3631 auto colonChain = x->new_ptr<ColonChainItem_t>();
3632 colonChain->name.set(nameNode);
3633 auto chainValue = x->new_ptr<ChainValue_t>();
3634 chainValue->items.push_back(callable);
3635 chainValue->items.push_back(colonChain);
3636 auto value = x->new_ptr<Value_t>();
3637 value->item.set(chainValue);
3638 auto exp = x->new_ptr<Exp_t>();
3639 exp->value.set(value);
3640 assign->values.push_back(exp);
3641 }
3642 auto callable = x->new_ptr<Callable_t>();
3643 callable->item.set(var);
3644 auto chainValue = x->new_ptr<ChainValue_t>();
3645 chainValue->items.push_back(callable);
3646 auto value = x->new_ptr<Value_t>();
3647 value->item.set(chainValue);
3648 auto exp = x->new_ptr<Exp_t>();
3649 exp->value.set(value);
3650 expList->exprs.push_back(exp);
3651 break;
3652 }
3653 }
3654 }
3655 if (objAssign) {
3656 auto preDef = getPredefine(transformAssignDefs(expList));
3657 if (!preDef.empty()) {
3658 temp.push_back(preDef + nll(import));
3659 }
3660 temp.push_back(indent() + s("do"sv) + nll(import));
3661 pushScope();
3662 transformAssignment(objAssign, temp);
3663 }
3664 auto assignment = x->new_ptr<ExpListAssign_t>();
3665 assignment->expList.set(expList);
3666 assignment->action.set(assign);
3667 transformAssignment(assignment, temp);
3668 if (objAssign) {
3669 popScope();
3670 temp.push_back(indent() + s("end"sv) + nlr(import));
3671 }
3672 out.push_back(join(temp));
3673 }
3674
3675 void transformWhileInPlace(While_t* whileNode, str_list& out, ExpList_t* expList = nullptr) {
3676 auto x = whileNode;
3677 str_list temp;
3678 if (expList) {
3679 temp.push_back(indent() + s("do"sv) + nll(whileNode));
3680 }
3681 pushScope();
3682 auto accumVar = getUnusedName("_accum_"sv);
3683 addToScope(accumVar);
3684 auto lenVar = getUnusedName("_len_"sv);
3685 addToScope(lenVar);
3686 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
3687 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
3688 transformExp(whileNode->condition, temp);
3689 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
3690 pushScope();
3691 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x);
3692 assignLastExplist(assignLeft, whileNode->body);
3693 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
3694 transformLoopBody(whileNode->body, temp, lenLine);
3695 popScope();
3696 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3697 if (expList) {
3698 auto assign = x->new_ptr<Assign_t>();
3699 assign->values.push_back(toAst<Exp_t>(accumVar, Exp, x));
3700 auto assignment = x->new_ptr<ExpListAssign_t>();
3701 assignment->expList.set(expList);
3702 assignment->action.set(assign);
3703 transformAssignment(assignment, temp);
3704 } else {
3705 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
3706 }
3707 popScope();
3708 if (expList) {
3709 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3710 }
3711 out.push_back(join(temp));
3712 }
3713
3714 void transformWhileClosure(While_t* whileNode, str_list& out) {
3715 auto x = whileNode;
3716 str_list temp;
3717 temp.push_back(s("(function() "sv) + nll(whileNode));
3718 pushScope();
3719 auto accumVar = getUnusedName("_accum_"sv);
3720 addToScope(accumVar);
3721 auto lenVar = getUnusedName("_len_"sv);
3722 addToScope(lenVar);
3723 temp.push_back(indent() + s("local "sv) + accumVar + s(" = { }"sv) + nll(whileNode));
3724 temp.push_back(indent() + s("local "sv) + lenVar + s(" = 1"sv) + nll(whileNode));
3725 transformExp(whileNode->condition, temp);
3726 temp.back() = indent() + s("while "sv) + temp.back() + s(" do"sv) + nll(whileNode);
3727 pushScope();
3728 auto assignLeft = toAst<ExpList_t>(accumVar + s("["sv) + lenVar + s("]"sv), ExpList, x);
3729 assignLastExplist(assignLeft, whileNode->body);
3730 auto lenLine = lenVar + s(" = "sv) + lenVar + s(" + 1"sv) + nlr(whileNode);
3731 transformLoopBody(whileNode->body, temp, lenLine);
3732 popScope();
3733 temp.push_back(indent() + s("end"sv) + nlr(whileNode));
3734 temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode));
3735 popScope();
3736 temp.push_back(indent() + s("end)()"sv));
3737 out.push_back(join(temp));
3738 }
3739
3740 void transformWhile(While_t* whileNode, str_list& out) {
3741 str_list temp;
3742 pushScope();
3743 transformExp(whileNode->condition, temp);
3744 transformLoopBody(whileNode->body, temp, Empty);
3745 popScope();
3746 _buf << indent() << "while "sv << temp.front() << " do"sv << nll(whileNode);
3747 _buf << temp.back();
3748 _buf << indent() << "end"sv << nlr(whileNode);
3749 out.push_back(clearBuf());
3750 }
3751
3752 void transformSwitchClosure(Switch_t* switchNode, str_list& out) {
3753 str_list temp;
3754 temp.push_back(s("(function()"sv) + nll(switchNode));
3755 pushScope();
3756 transformSwitch(switchNode, temp, true);
3757 popScope();
3758 temp.push_back(indent() + s("end)()"sv));
3759 out.push_back(join(temp));
3760 }
3761
3762 void transformSwitch(Switch_t* switchNode, str_list& out, bool implicitReturn = false) {
3763 str_list temp;
3764 auto objVar = singleVariableFrom(switchNode->target);
3765 if (objVar.empty()) {
3766 objVar = getUnusedName("_exp_"sv);
3767 addToScope(objVar);
3768 transformExp(switchNode->target, temp);
3769 _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode);
3770 temp.back() = clearBuf();
3771 }
3772 const auto& branches = switchNode->branches.objects();
3773 for (auto branch_ : branches) {
3774 auto branch = static_cast<SwitchCase_t*>(branch_);
3775 temp.push_back(indent() + s(branches.front() == branch ? "if"sv : "elseif"sv));
3776 str_list tmp;
3777 const auto& exprs = branch->valueList->exprs.objects();
3778 for (auto exp_ : exprs) {
3779 auto exp = static_cast<Exp_t*>(exp_);
3780 transformExp(exp, tmp);
3781 if (!singleValueFrom(exp)) {
3782 tmp.back() = s("("sv) + tmp.back() + s(")"sv);
3783 }
3784 temp.back().append(s(" "sv) + tmp.back() + s(" == "sv) + objVar +
3785 s(exp == exprs.back() ? ""sv : " or"sv));
3786 }
3787 temp.back().append(s(" then"sv) + nll(branch));
3788 pushScope();
3789 transformBody(branch->body, temp, implicitReturn);
3790 popScope();
3791 }
3792 if (switchNode->lastBranch) {
3793 temp.push_back(indent() + s("else"sv) + nll(switchNode->lastBranch));
3794 pushScope();
3795 transformBody(switchNode->lastBranch, temp, implicitReturn);
3796 popScope();
3797 }
3798 temp.push_back(indent() + s("end"sv) + nlr(switchNode));
3799 out.push_back(join(temp));
3800 }
3801
3802 void transformLocal(Local_t* local, str_list& out) {
3803 if (!local->forceDecls.empty() || !local->decls.empty()) {
3804 str_list defs;
3805 for (const auto& decl : local->forceDecls) {
3806 forceAddToScope(decl);
3807 defs.push_back(decl);
3808 }
3809 for (const auto& decl : local->decls) {
3810 if (addToScope(decl)) {
3811 defs.push_back(decl);
3812 }
3813 }
3814 auto preDefine = getPredefine(defs);
3815 if (!preDefine.empty()) {
3816 out.push_back(preDefine + nll(local));
3817 }
3818 }
3819 }
3820
3821 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
3822 auto keyword = toString(breakLoop);
3823 if (keyword == "break"sv) {
3824 out.push_back(indent() + keyword + nll(breakLoop));
3825 return;
3826 }
3827 if (_continueVars.empty()) throw std::logic_error(debugInfo("Continue is not inside a loop."sv, breakLoop));
3828 _buf << indent() << _continueVars.top() << " = true"sv << nll(breakLoop);
3829 _buf << indent() << "break"sv << nll(breakLoop);
3830 out.push_back(clearBuf());
3831 }
3832};
3833
3834const std::string MoonCompliler::Empty;
3835
3836std::pair<std::string,std::string> moonCompile(const std::string& codes, bool implicitReturnRoot, bool lineNumber) {
3837 return MoonCompliler{}.complile(codes, false, implicitReturnRoot, lineNumber);
3838}
3839
3840std::pair<std::string,std::string> moonCompile(const std::string& codes, std::list<GlobalVar>& globals, bool implicitReturnRoot, bool lineNumber) {
3841 auto compiler = MoonCompliler{};
3842 auto result = compiler.complile(codes, true, implicitReturnRoot, lineNumber);
3843 for (const auto& var : compiler.getGlobals()) {
3844 int line,col;
3845 std::tie(line,col) = var.second;
3846 globals.push_back({var.first, line, col});
3847 }
3848 return result;
3849}
3850
3851} // namespace MoonP