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