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