diff options
author | Li Jin <dragon-fly@qq.com> | 2024-03-19 02:22:56 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2024-03-19 02:22:56 +0800 |
commit | afc86619d710a578dc3f2bfc2ee1d62913f9abe8 (patch) | |
tree | 726ffe4d33bbaf8be411f73add51a1ffe734bc6f /src | |
parent | 4f399a181dc773bcc1a86737522915c2c776fb2b (diff) | |
download | yuescript-afc86619d710a578dc3f2bfc2ee1d62913f9abe8.tar.gz yuescript-afc86619d710a578dc3f2bfc2ee1d62913f9abe8.tar.bz2 yuescript-afc86619d710a578dc3f2bfc2ee1d62913f9abe8.zip |
try fixing issue #162.
Diffstat (limited to 'src')
-rw-r--r-- | src/yuescript/yue_ast.cpp | 266 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 5 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 604 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.h | 12 |
4 files changed, 646 insertions, 241 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index fbf7a63..3a22345 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
@@ -195,7 +195,7 @@ std::string YueLineComment_t::to_string(void* ud) const { | |||
195 | } | 195 | } |
196 | std::string MultilineCommentInner_t::to_string(void* ud) const { | 196 | std::string MultilineCommentInner_t::to_string(void* ud) const { |
197 | auto info = reinterpret_cast<YueFormat*>(ud); | 197 | auto info = reinterpret_cast<YueFormat*>(ud); |
198 | return "--[["s + info->convert(this) + "]]"s; | 198 | return info->convert(this); |
199 | } | 199 | } |
200 | std::string Variable_t::to_string(void* ud) const { | 200 | std::string Variable_t::to_string(void* ud) const { |
201 | return name->to_string(ud); | 201 | return name->to_string(ud); |
@@ -583,12 +583,12 @@ std::string CatchBlock_t::to_string(void* ud) const { | |||
583 | auto info = reinterpret_cast<YueFormat*>(ud); | 583 | auto info = reinterpret_cast<YueFormat*>(ud); |
584 | auto line = "catch "s + err->to_string(ud); | 584 | auto line = "catch "s + err->to_string(ud); |
585 | info->pushScope(); | 585 | info->pushScope(); |
586 | auto block = body->to_string(ud); | 586 | auto blockStr = block->to_string(ud); |
587 | if (block.empty()) { | 587 | if (blockStr.empty()) { |
588 | block = info->ind() + "--"s; | 588 | blockStr = info->ind() + "--"s; |
589 | } | 589 | } |
590 | info->popScope(); | 590 | info->popScope(); |
591 | return line + '\n' + block; | 591 | return line + '\n' + blockStr; |
592 | } | 592 | } |
593 | std::string Try_t::to_string(void* ud) const { | 593 | std::string Try_t::to_string(void* ud) const { |
594 | auto info = reinterpret_cast<YueFormat*>(ud); | 594 | auto info = reinterpret_cast<YueFormat*>(ud); |
@@ -609,21 +609,158 @@ std::string Try_t::to_string(void* ud) const { | |||
609 | } | 609 | } |
610 | return join(temp, "\n"sv); | 610 | return join(temp, "\n"sv); |
611 | } | 611 | } |
612 | std::string Comprehension_t::to_string(void* ud) const { | 612 | static bool isInBlockExp(ast_node* node, bool last = false) { |
613 | str_list temp; | 613 | if (auto exp = ast_cast<Exp_t>(node)) { |
614 | for (const auto& item : items.objects()) { | 614 | UnaryExp_t* unaryExp = nullptr; |
615 | temp.push_back(item->to_string(ud)); | 615 | if (exp->opValues.empty()) { |
616 | } | 616 | unaryExp = static_cast<UnaryExp_t*>(exp->pipeExprs.back()); |
617 | if (temp.size() > 0) { | 617 | } else { |
618 | temp.front().insert(0, temp.front()[0] == '[' ? " "s : ""s); | 618 | unaryExp = static_cast<UnaryExp_t*>(static_cast<ExpOpValue_t*>(exp->opValues.back())->pipeExprs.back()); |
619 | } | ||
620 | auto value = static_cast<Value_t*>(unaryExp->expos.back()); | ||
621 | if (auto simpleValue = value->item.as<SimpleValue_t>()) { | ||
622 | switch (simpleValue->value->get_id()) { | ||
623 | case id<TableLit_t>(): | ||
624 | case id<ConstValue_t>(): | ||
625 | case id<Num_t>(): | ||
626 | case id<VarArg_t>(): | ||
627 | case id<TblComprehension_t>(): | ||
628 | case id<Comprehension_t>(): | ||
629 | return false; | ||
630 | case id<FunLit_t>(): | ||
631 | if (!last) { | ||
632 | return true; | ||
633 | } | ||
634 | return false; | ||
635 | default: | ||
636 | return true; | ||
637 | } | ||
638 | } else if (auto chainValue = value->item.as<ChainValue_t>()) { | ||
639 | if (ast_is<InvokeArgs_t>(chainValue->items.back())) { | ||
640 | return true; | ||
641 | } | ||
642 | } else if (!last && value->item.is<SimpleTable_t>()) { | ||
643 | return true; | ||
644 | } | ||
645 | } else if (ast_is<TableBlock_t>(node)) { | ||
646 | return true; | ||
647 | } else { | ||
648 | switch (node->get_id()) { | ||
649 | case id<VariablePairDef_t>(): { | ||
650 | auto pair = static_cast<VariablePairDef_t*>(node); | ||
651 | if (pair->defVal) { | ||
652 | return true; | ||
653 | } | ||
654 | return false; | ||
655 | } | ||
656 | case id<NormalPairDef_t>(): { | ||
657 | auto pair = static_cast<NormalPairDef_t*>(node); | ||
658 | if (pair->defVal) { | ||
659 | return true; | ||
660 | } | ||
661 | return isInBlockExp(pair->pair->value); | ||
662 | } | ||
663 | case id<SpreadExp_t>(): { | ||
664 | auto pair = static_cast<SpreadExp_t*>(node); | ||
665 | return isInBlockExp(pair->exp); | ||
666 | } | ||
667 | case id<NormalDef_t>(): { | ||
668 | auto pair = static_cast<NormalDef_t*>(node); | ||
669 | if (pair->defVal) { | ||
670 | return true; | ||
671 | } | ||
672 | return isInBlockExp(pair->item); | ||
673 | } | ||
674 | case id<MetaVariablePairDef_t>(): { | ||
675 | auto pair = static_cast<MetaVariablePairDef_t*>(node); | ||
676 | if (pair->defVal) { | ||
677 | return true; | ||
678 | } | ||
679 | return false; | ||
680 | } | ||
681 | case id<MetaNormalPairDef_t>(): { | ||
682 | auto pair = static_cast<MetaNormalPairDef_t*>(node); | ||
683 | if (pair->defVal) { | ||
684 | return true; | ||
685 | } | ||
686 | return isInBlockExp(pair->pair->value); | ||
687 | } | ||
688 | case id<VariablePair_t>(): { | ||
689 | return false; | ||
690 | } | ||
691 | case id<NormalPair_t>(): { | ||
692 | auto pair = static_cast<NormalPair_t*>(node); | ||
693 | return isInBlockExp(pair->value); | ||
694 | } | ||
695 | case id<MetaVariablePair_t>(): { | ||
696 | return false; | ||
697 | } | ||
698 | case id<MetaNormalPair_t>(): { | ||
699 | auto pair = static_cast<MetaNormalPair_t*>(node); | ||
700 | return isInBlockExp(pair->value); | ||
701 | } | ||
702 | case id<TableBlockIndent_t>(): { | ||
703 | return true; | ||
704 | } | ||
705 | case id<SpreadListExp_t>(): { | ||
706 | auto pair = static_cast<SpreadListExp_t*>(node); | ||
707 | return isInBlockExp(pair->exp); | ||
708 | } | ||
709 | default: | ||
710 | return false; | ||
711 | } | ||
619 | } | 712 | } |
713 | return false; | ||
714 | } | ||
715 | std::string Comprehension_t::to_string(void* ud) const { | ||
620 | if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { | 716 | if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { |
621 | if (items.size() == 1) { | 717 | if (items.size() == 1) { |
718 | str_list temp; | ||
719 | for (const auto& item : items.objects()) { | ||
720 | temp.push_back(item->to_string(ud)); | ||
721 | } | ||
722 | if (temp.size() > 0) { | ||
723 | temp.front().insert(0, temp.front()[0] == '[' ? " "s : ""s); | ||
724 | } | ||
622 | return '[' + join(temp, ", "sv) + ",]"s; | 725 | return '[' + join(temp, ", "sv) + ",]"s; |
623 | } else { | 726 | } else { |
624 | return '[' + join(temp, ", "sv) + ']'; | 727 | bool hasInBlockExp = false; |
728 | for (auto value : items.objects()) { | ||
729 | if (isInBlockExp(value, value == items.back())) { | ||
730 | hasInBlockExp = true; | ||
731 | break; | ||
732 | } | ||
733 | } | ||
734 | if (hasInBlockExp) { | ||
735 | auto info = reinterpret_cast<YueFormat*>(ud); | ||
736 | str_list temp; | ||
737 | temp.emplace_back("["s); | ||
738 | info->pushScope(); | ||
739 | for (auto value : items.objects()) { | ||
740 | temp.emplace_back(info->ind() + value->to_string(ud)); | ||
741 | } | ||
742 | info->popScope(); | ||
743 | temp.emplace_back(info->ind() + ']'); | ||
744 | return join(temp, "\n"sv); | ||
745 | } else { | ||
746 | str_list temp; | ||
747 | for (const auto& item : items.objects()) { | ||
748 | temp.push_back(item->to_string(ud)); | ||
749 | } | ||
750 | if (temp.size() > 0) { | ||
751 | temp.front().insert(0, temp.front()[0] == '[' ? " "s : ""s); | ||
752 | } | ||
753 | return '[' + join(temp, ", "sv) + ']'; | ||
754 | } | ||
625 | } | 755 | } |
626 | } else { | 756 | } else { |
757 | str_list temp; | ||
758 | for (const auto& item : items.objects()) { | ||
759 | temp.push_back(item->to_string(ud)); | ||
760 | } | ||
761 | if (temp.size() > 0) { | ||
762 | temp.front().insert(0, temp.front()[0] == '[' ? " "s : ""s); | ||
763 | } | ||
627 | return '[' + join(temp, " "sv) + ']'; | 764 | return '[' + join(temp, " "sv) + ']'; |
628 | } | 765 | } |
629 | } | 766 | } |
@@ -834,109 +971,6 @@ std::string Slice_t::to_string(void* ud) const { | |||
834 | auto valueStr = join(temp); | 971 | auto valueStr = join(temp); |
835 | return '[' + (valueStr[0] == '[' ? " "s : ""s) + valueStr + ']'; | 972 | return '[' + (valueStr[0] == '[' ? " "s : ""s) + valueStr + ']'; |
836 | } | 973 | } |
837 | static bool isInBlockExp(ast_node* node, bool last = false) { | ||
838 | if (auto exp = ast_cast<Exp_t>(node)) { | ||
839 | UnaryExp_t* unaryExp = nullptr; | ||
840 | if (exp->opValues.empty()) { | ||
841 | unaryExp = static_cast<UnaryExp_t*>(exp->pipeExprs.back()); | ||
842 | } else { | ||
843 | unaryExp = static_cast<UnaryExp_t*>(static_cast<ExpOpValue_t*>(exp->opValues.back())->pipeExprs.back()); | ||
844 | } | ||
845 | auto value = static_cast<Value_t*>(unaryExp->expos.back()); | ||
846 | if (auto simpleValue = value->item.as<SimpleValue_t>()) { | ||
847 | switch (simpleValue->value->get_id()) { | ||
848 | case id<TableLit_t>(): | ||
849 | case id<ConstValue_t>(): | ||
850 | case id<Num_t>(): | ||
851 | case id<VarArg_t>(): | ||
852 | case id<TblComprehension_t>(): | ||
853 | case id<Comprehension_t>(): | ||
854 | return false; | ||
855 | case id<FunLit_t>(): | ||
856 | if (!last) { | ||
857 | return true; | ||
858 | } | ||
859 | return false; | ||
860 | default: | ||
861 | return true; | ||
862 | } | ||
863 | } else if (auto chainValue = value->item.as<ChainValue_t>()) { | ||
864 | if (ast_is<InvokeArgs_t>(chainValue->items.back())) { | ||
865 | return true; | ||
866 | } | ||
867 | } else if (!last && value->item.is<SimpleTable_t>()) { | ||
868 | return true; | ||
869 | } | ||
870 | } else if (ast_is<TableBlock_t>(node)) { | ||
871 | return true; | ||
872 | } else { | ||
873 | switch (node->get_id()) { | ||
874 | case id<VariablePairDef_t>(): { | ||
875 | auto pair = static_cast<VariablePairDef_t*>(node); | ||
876 | if (pair->defVal) { | ||
877 | return true; | ||
878 | } | ||
879 | return false; | ||
880 | } | ||
881 | case id<NormalPairDef_t>(): { | ||
882 | auto pair = static_cast<NormalPairDef_t*>(node); | ||
883 | if (pair->defVal) { | ||
884 | return true; | ||
885 | } | ||
886 | return isInBlockExp(pair->pair->value); | ||
887 | } | ||
888 | case id<SpreadExp_t>(): { | ||
889 | auto pair = static_cast<SpreadExp_t*>(node); | ||
890 | return isInBlockExp(pair->exp); | ||
891 | } | ||
892 | case id<NormalDef_t>(): { | ||
893 | auto pair = static_cast<NormalDef_t*>(node); | ||
894 | if (pair->defVal) { | ||
895 | return true; | ||
896 | } | ||
897 | return isInBlockExp(pair->item); | ||
898 | } | ||
899 | case id<MetaVariablePairDef_t>(): { | ||
900 | auto pair = static_cast<MetaVariablePairDef_t*>(node); | ||
901 | if (pair->defVal) { | ||
902 | return true; | ||
903 | } | ||
904 | return false; | ||
905 | } | ||
906 | case id<MetaNormalPairDef_t>(): { | ||
907 | auto pair = static_cast<MetaNormalPairDef_t*>(node); | ||
908 | if (pair->defVal) { | ||
909 | return true; | ||
910 | } | ||
911 | return isInBlockExp(pair->pair->value); | ||
912 | } | ||
913 | case id<VariablePair_t>(): { | ||
914 | return false; | ||
915 | } | ||
916 | case id<NormalPair_t>(): { | ||
917 | auto pair = static_cast<NormalPair_t*>(node); | ||
918 | return isInBlockExp(pair->value); | ||
919 | } | ||
920 | case id<MetaVariablePair_t>(): { | ||
921 | return false; | ||
922 | } | ||
923 | case id<MetaNormalPair_t>(): { | ||
924 | auto pair = static_cast<MetaNormalPair_t*>(node); | ||
925 | return isInBlockExp(pair->value); | ||
926 | } | ||
927 | case id<TableBlockIndent_t>(): { | ||
928 | return true; | ||
929 | } | ||
930 | case id<SpreadListExp_t>(): { | ||
931 | auto pair = static_cast<SpreadListExp_t*>(node); | ||
932 | return isInBlockExp(pair->exp); | ||
933 | } | ||
934 | default: | ||
935 | return false; | ||
936 | } | ||
937 | } | ||
938 | return false; | ||
939 | } | ||
940 | std::string Invoke_t::to_string(void* ud) const { | 974 | std::string Invoke_t::to_string(void* ud) const { |
941 | if (args.empty()) { | 975 | if (args.empty()) { |
942 | return "!"s; | 976 | return "!"s; |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 73ffc9a..2ea0a85 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -368,8 +368,8 @@ AST_END(Do, "do"sv) | |||
368 | 368 | ||
369 | AST_NODE(CatchBlock) | 369 | AST_NODE(CatchBlock) |
370 | ast_ptr<true, Variable_t> err; | 370 | ast_ptr<true, Variable_t> err; |
371 | ast_ptr<true, Block_t> body; | 371 | ast_ptr<true, Block_t> block; |
372 | AST_MEMBER(CatchBlock, &err, &body) | 372 | AST_MEMBER(CatchBlock, &err, &block) |
373 | AST_END(CatchBlock, "catch_block"sv) | 373 | AST_END(CatchBlock, "catch_block"sv) |
374 | 374 | ||
375 | AST_NODE(Try) | 375 | AST_NODE(Try) |
@@ -759,6 +759,7 @@ AST_NODE(FunLit) | |||
759 | ast_sel<false, ExpListLow_t, DefaultValue_t> defaultReturn; | 759 | ast_sel<false, ExpListLow_t, DefaultValue_t> defaultReturn; |
760 | ast_ptr<true, FnArrow_t> arrow; | 760 | ast_ptr<true, FnArrow_t> arrow; |
761 | ast_ptr<false, Body_t> body; | 761 | ast_ptr<false, Body_t> body; |
762 | bool noRecursion = false; | ||
762 | AST_MEMBER(FunLit, &argsDef, &defaultReturn, &arrow, &body) | 763 | AST_MEMBER(FunLit, &argsDef, &defaultReturn, &arrow, &body) |
763 | AST_END(FunLit, "fun_lit"sv) | 764 | AST_END(FunLit, "fun_lit"sv) |
764 | 765 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index c991733..d416dbd 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
76 | }; | 76 | }; |
77 | 77 | ||
78 | const std::string_view version = "0.22.3"sv; | 78 | const std::string_view version = "0.23.0"sv; |
79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
80 | 80 | ||
81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
@@ -95,13 +95,15 @@ CompileInfo::CompileInfo( | |||
95 | std::unique_ptr<GlobalVars>&& globals, | 95 | std::unique_ptr<GlobalVars>&& globals, |
96 | std::unique_ptr<Options>&& options, | 96 | std::unique_ptr<Options>&& options, |
97 | double parseTime, | 97 | double parseTime, |
98 | double compileTime) | 98 | double compileTime, |
99 | bool usedVar) | ||
99 | : codes(std::move(codes)) | 100 | : codes(std::move(codes)) |
100 | , error(std::move(error)) | 101 | , error(std::move(error)) |
101 | , globals(std::move(globals)) | 102 | , globals(std::move(globals)) |
102 | , options(std::move(options)) | 103 | , options(std::move(options)) |
103 | , parseTime(parseTime) | 104 | , parseTime(parseTime) |
104 | , compileTime(compileTime) { } | 105 | , compileTime(compileTime) |
106 | , usedVar(usedVar) { } | ||
105 | 107 | ||
106 | CompileInfo::CompileInfo(CompileInfo&& other) | 108 | CompileInfo::CompileInfo(CompileInfo&& other) |
107 | : codes(std::move(other.codes)) | 109 | : codes(std::move(other.codes)) |
@@ -214,7 +216,8 @@ public: | |||
214 | } | 216 | } |
215 | str_list out; | 217 | str_list out; |
216 | pushScope(); | 218 | pushScope(); |
217 | _enableReturn.push(_info.moduleName.empty()); | 219 | _funcStates.push({false, _info.moduleName.empty()}); |
220 | _funcLevel = 1; | ||
218 | _gotoScopes.push(0); | 221 | _gotoScopes.push(0); |
219 | _gotoScope = 1; | 222 | _gotoScope = 1; |
220 | _varArgs.push({true, false}); | 223 | _varArgs.push({true, false}); |
@@ -252,9 +255,8 @@ public: | |||
252 | if (config.lintGlobalVariable) { | 255 | if (config.lintGlobalVariable) { |
253 | globals = std::make_unique<GlobalVars>(); | 256 | globals = std::make_unique<GlobalVars>(); |
254 | for (const auto& var : _globals) { | 257 | for (const auto& var : _globals) { |
255 | int line, col; | 258 | auto [name, line, col, accessType] = var.second; |
256 | std::tie(line, col) = var.second; | 259 | globals->push_back({name, line + _config.lineOffset, col, accessType}); |
257 | globals->push_back({var.first, line + _config.lineOffset, col}); | ||
258 | } | 260 | } |
259 | std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) { | 261 | std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) { |
260 | if (varA.line < varB.line) { | 262 | if (varA.line < varB.line) { |
@@ -286,7 +288,8 @@ public: | |||
286 | } | 288 | } |
287 | } | 289 | } |
288 | #endif // YUE_NO_MACRO | 290 | #endif // YUE_NO_MACRO |
289 | return {std::move(out.back()), std::nullopt, std::move(globals), std::move(options), parseTime, compileTime}; | 291 | bool usedVar = _varArgs.top().usedVar; |
292 | return {std::move(out.back()), std::nullopt, std::move(globals), std::move(options), parseTime, compileTime, usedVar}; | ||
290 | } catch (const CompileError& error) { | 293 | } catch (const CompileError& error) { |
291 | auto displayMessage = _info.errorMessage(error.what(), error.line, error.col, _config.lineOffset); | 294 | auto displayMessage = _info.errorMessage(error.what(), error.line, error.col, _config.lineOffset); |
292 | return { | 295 | return { |
@@ -298,7 +301,7 @@ public: | |||
298 | displayMessage}, | 301 | displayMessage}, |
299 | std::move(globals), | 302 | std::move(globals), |
300 | std::move(options), | 303 | std::move(options), |
301 | parseTime, compileTime}; | 304 | parseTime, compileTime, false}; |
302 | } | 305 | } |
303 | } else { | 306 | } else { |
304 | const auto& error = _info.error.value(); | 307 | const auto& error = _info.error.value(); |
@@ -312,7 +315,7 @@ public: | |||
312 | ""}, | 315 | ""}, |
313 | std::move(globals), | 316 | std::move(globals), |
314 | std::move(options), | 317 | std::move(options), |
315 | parseTime, compileTime}; | 318 | parseTime, compileTime, false}; |
316 | } | 319 | } |
317 | auto displayMessage = _info.errorMessage(error.msg, error.line, error.col, _config.lineOffset); | 320 | auto displayMessage = _info.errorMessage(error.msg, error.line, error.col, _config.lineOffset); |
318 | return { | 321 | return { |
@@ -324,7 +327,7 @@ public: | |||
324 | displayMessage}, | 327 | displayMessage}, |
325 | std::move(globals), | 328 | std::move(globals), |
326 | std::move(options), | 329 | std::move(options), |
327 | parseTime, compileTime}; | 330 | parseTime, compileTime, false}; |
328 | } | 331 | } |
329 | } | 332 | } |
330 | 333 | ||
@@ -341,7 +344,7 @@ public: | |||
341 | _varArgs = {}; | 344 | _varArgs = {}; |
342 | _withVars = {}; | 345 | _withVars = {}; |
343 | _continueVars = {}; | 346 | _continueVars = {}; |
344 | _enableReturn = {}; | 347 | _funcStates = {}; |
345 | #ifndef YUE_NO_MACRO | 348 | #ifndef YUE_NO_MACRO |
346 | if (_useModule) { | 349 | if (_useModule) { |
347 | _useModule = false; | 350 | _useModule = false; |
@@ -375,16 +378,22 @@ private: | |||
375 | bool usedVar; | 378 | bool usedVar; |
376 | }; | 379 | }; |
377 | std::stack<VarArgState> _varArgs; | 380 | std::stack<VarArgState> _varArgs; |
378 | std::stack<bool> _enableReturn; | 381 | struct FuncState { |
382 | bool isAnon; | ||
383 | bool enableReturn; | ||
384 | }; | ||
385 | int _funcLevel = 0; | ||
386 | std::stack<FuncState> _funcStates; | ||
379 | std::stack<bool> _enableBreakLoop; | 387 | std::stack<bool> _enableBreakLoop; |
380 | std::stack<std::string> _withVars; | 388 | std::stack<std::string> _withVars; |
389 | str_list _rootDefs; | ||
381 | struct ContinueVar { | 390 | struct ContinueVar { |
382 | std::string var; | 391 | std::string var; |
383 | ast_ptr<false, ExpListAssign_t> condAssign; | 392 | ast_ptr<false, ExpListAssign_t> condAssign; |
384 | }; | 393 | }; |
385 | std::stack<ContinueVar> _continueVars; | 394 | std::stack<ContinueVar> _continueVars; |
386 | std::list<std::unique_ptr<input>> _codeCache; | 395 | std::list<std::unique_ptr<input>> _codeCache; |
387 | std::unordered_map<std::string, std::pair<int, int>> _globals; | 396 | std::unordered_map<std::string, std::tuple<std::string, int, int, AccessType>> _globals; |
388 | std::ostringstream _buf; | 397 | std::ostringstream _buf; |
389 | std::ostringstream _joinBuf; | 398 | std::ostringstream _joinBuf; |
390 | const std::string _newLine = "\n"; | 399 | const std::string _newLine = "\n"; |
@@ -526,7 +535,7 @@ private: | |||
526 | return local; | 535 | return local; |
527 | } | 536 | } |
528 | 537 | ||
529 | bool isGlobal(const std::string& name) const { | 538 | bool isDeclaredAsGlobal(const std::string& name) const { |
530 | bool global = false; | 539 | bool global = false; |
531 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { | 540 | for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { |
532 | auto vars = it->vars.get(); | 541 | auto vars = it->vars.get(); |
@@ -1020,7 +1029,7 @@ private: | |||
1020 | return type; | 1029 | return type; |
1021 | } | 1030 | } |
1022 | 1031 | ||
1023 | std::string singleVariableFrom(ChainValue_t* chainValue) { | 1032 | std::string singleVariableFrom(ChainValue_t* chainValue, AccessType accessType) { |
1024 | BLOCK_START | 1033 | BLOCK_START |
1025 | BREAK_IF(!chainValue); | 1034 | BREAK_IF(!chainValue); |
1026 | BREAK_IF(chainValue->items.size() != 1); | 1035 | BREAK_IF(chainValue->items.size() != 1); |
@@ -1034,7 +1043,7 @@ private: | |||
1034 | } | 1043 | } |
1035 | BREAK_IF(!var); | 1044 | BREAK_IF(!var); |
1036 | str_list tmp; | 1045 | str_list tmp; |
1037 | transformCallable(callable, tmp); | 1046 | transformCallable(callable, tmp, accessType); |
1038 | return tmp.back(); | 1047 | return tmp.back(); |
1039 | BLOCK_END | 1048 | BLOCK_END |
1040 | return Empty; | 1049 | return Empty; |
@@ -1064,7 +1073,7 @@ private: | |||
1064 | } | 1073 | } |
1065 | } | 1074 | } |
1066 | 1075 | ||
1067 | std::string singleVariableFrom(ast_node* expList, bool accessing) { | 1076 | std::string singleVariableFrom(ast_node* expList, AccessType accessType) { |
1068 | if (!ast_is<Exp_t, ExpList_t, Value_t>(expList)) return Empty; | 1077 | if (!ast_is<Exp_t, ExpList_t, Value_t>(expList)) return Empty; |
1069 | BLOCK_START | 1078 | BLOCK_START |
1070 | auto value = ast_cast<Value_t>(expList); | 1079 | auto value = ast_cast<Value_t>(expList); |
@@ -1078,14 +1087,7 @@ private: | |||
1078 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); | 1087 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); |
1079 | BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->get_by_path<SelfItem_t, Self_t>())); | 1088 | BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->get_by_path<SelfItem_t, Self_t>())); |
1080 | str_list tmp; | 1089 | str_list tmp; |
1081 | if (accessing) { | 1090 | transformCallable(callable, tmp, accessType); |
1082 | transformCallable(callable, tmp); | ||
1083 | } else { | ||
1084 | bool lintGlobal = _config.lintGlobalVariable; | ||
1085 | _config.lintGlobalVariable = false; | ||
1086 | transformCallable(callable, tmp); | ||
1087 | _config.lintGlobalVariable = lintGlobal; | ||
1088 | } | ||
1089 | return tmp.back(); | 1091 | return tmp.back(); |
1090 | BLOCK_END | 1092 | BLOCK_END |
1091 | return Empty; | 1093 | return Empty; |
@@ -1235,7 +1237,7 @@ private: | |||
1235 | return unary; | 1237 | return unary; |
1236 | } | 1238 | } |
1237 | auto value = static_cast<Value_t*>(unary->expos.back()); | 1239 | auto value = static_cast<Value_t*>(unary->expos.back()); |
1238 | auto varName = singleVariableFrom(value, false); | 1240 | auto varName = singleVariableFrom(value, AccessType::None); |
1239 | if (varName.empty() || !isLocal(varName)) { | 1241 | if (varName.empty() || !isLocal(varName)) { |
1240 | return unary; | 1242 | return unary; |
1241 | } | 1243 | } |
@@ -1243,15 +1245,26 @@ private: | |||
1243 | return nullptr; | 1245 | return nullptr; |
1244 | } | 1246 | } |
1245 | 1247 | ||
1246 | void pushFunctionScope() { | 1248 | void pushFunctionScope(bool anonFunc) { |
1247 | _enableReturn.push(true); | 1249 | _funcLevel += anonFunc ? 0 : 1; |
1250 | _funcStates.push({anonFunc, true}); | ||
1248 | _enableBreakLoop.push(false); | 1251 | _enableBreakLoop.push(false); |
1249 | _gotoScopes.push(_gotoScope); | 1252 | _gotoScopes.push(_gotoScope); |
1250 | _gotoScope++; | 1253 | _gotoScope++; |
1251 | } | 1254 | } |
1252 | 1255 | ||
1256 | |||
1257 | void pushUserFunctionScope() { | ||
1258 | pushFunctionScope(false); | ||
1259 | } | ||
1260 | |||
1261 | void pushAnonFunctionScope() { | ||
1262 | pushFunctionScope(true); | ||
1263 | } | ||
1264 | |||
1253 | void popFunctionScope() { | 1265 | void popFunctionScope() { |
1254 | _enableReturn.pop(); | 1266 | _funcLevel -= _funcStates.top().isAnon ? 0 : 1; |
1267 | _funcStates.pop(); | ||
1255 | _enableBreakLoop.pop(); | 1268 | _enableBreakLoop.pop(); |
1256 | _gotoScopes.pop(); | 1269 | _gotoScopes.pop(); |
1257 | } | 1270 | } |
@@ -1276,12 +1289,16 @@ private: | |||
1276 | return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s; | 1289 | return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s; |
1277 | } | 1290 | } |
1278 | 1291 | ||
1279 | std::string globalVar(std::string_view var, ast_node* x) { | 1292 | std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { |
1280 | std::string str(var); | 1293 | std::string str(var); |
1281 | if (_config.lintGlobalVariable) { | 1294 | if (_config.lintGlobalVariable) { |
1282 | if (!isDefined(str)) { | 1295 | if (!isLocal(str)) { |
1283 | if (_globals.find(str) == _globals.end()) { | 1296 | auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); |
1284 | _globals[str] = {x->m_begin.m_line, x->m_begin.m_col}; | 1297 | if (_globals.find(key) == _globals.end()) { |
1298 | if (accessType == AccessType::Read && _funcLevel > 1) { | ||
1299 | accessType = AccessType::Capture; | ||
1300 | } | ||
1301 | _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; | ||
1285 | } | 1302 | } |
1286 | } | 1303 | } |
1287 | } | 1304 | } |
@@ -1532,7 +1549,15 @@ private: | |||
1532 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; | 1549 | case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; |
1533 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; | 1550 | case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; |
1534 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; | 1551 | case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; |
1535 | case id<Comprehension_t>(): transformCompCommon(static_cast<Comprehension_t*>(value), out); break; | 1552 | case id<Comprehension_t>(): { |
1553 | auto comp = static_cast<Comprehension_t*>(value); | ||
1554 | if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { | ||
1555 | transformCompCommon(comp, out); | ||
1556 | } else { | ||
1557 | specialSingleValue = false; | ||
1558 | } | ||
1559 | break; | ||
1560 | } | ||
1536 | default: specialSingleValue = false; break; | 1561 | default: specialSingleValue = false; break; |
1537 | } | 1562 | } |
1538 | if (specialSingleValue) { | 1563 | if (specialSingleValue) { |
@@ -1567,7 +1592,7 @@ private: | |||
1567 | _config.lintGlobalVariable = false; | 1592 | _config.lintGlobalVariable = false; |
1568 | if (!assignment->action.is<Assign_t>()) return vars; | 1593 | if (!assignment->action.is<Assign_t>()) return vars; |
1569 | for (auto exp : assignment->expList->exprs.objects()) { | 1594 | for (auto exp : assignment->expList->exprs.objects()) { |
1570 | auto var = singleVariableFrom(exp, true); | 1595 | auto var = singleVariableFrom(exp, AccessType::Write); |
1571 | vars.push_back(var.empty() ? Empty : var); | 1596 | vars.push_back(var.empty() ? Empty : var); |
1572 | } | 1597 | } |
1573 | _config.lintGlobalVariable = lintGlobal; | 1598 | _config.lintGlobalVariable = lintGlobal; |
@@ -1579,7 +1604,7 @@ private: | |||
1579 | bool lintGlobal = _config.lintGlobalVariable; | 1604 | bool lintGlobal = _config.lintGlobalVariable; |
1580 | _config.lintGlobalVariable = false; | 1605 | _config.lintGlobalVariable = false; |
1581 | for (auto exp : with->valueList->exprs.objects()) { | 1606 | for (auto exp : with->valueList->exprs.objects()) { |
1582 | auto var = singleVariableFrom(exp, true); | 1607 | auto var = singleVariableFrom(exp, AccessType::Write); |
1583 | vars.push_back(var.empty() ? Empty : var); | 1608 | vars.push_back(var.empty() ? Empty : var); |
1584 | } | 1609 | } |
1585 | _config.lintGlobalVariable = lintGlobal; | 1610 | _config.lintGlobalVariable = lintGlobal; |
@@ -1867,7 +1892,7 @@ private: | |||
1867 | throw CompileError("right value missing"sv, values.front()); | 1892 | throw CompileError("right value missing"sv, values.front()); |
1868 | } | 1893 | } |
1869 | transformAssignItem(*vit, args); | 1894 | transformAssignItem(*vit, args); |
1870 | _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); | 1895 | _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); |
1871 | temp.push_back(clearBuf()); | 1896 | temp.push_back(clearBuf()); |
1872 | } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { | 1897 | } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { |
1873 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); | 1898 | auto tmpChain = chainValue->new_ptr<ChainValue_t>(); |
@@ -1880,7 +1905,7 @@ private: | |||
1880 | tmpChain->items.push_back(toAst<Callable_t>(_withVars.top(), chainValue)); | 1905 | tmpChain->items.push_back(toAst<Callable_t>(_withVars.top(), chainValue)); |
1881 | } | 1906 | } |
1882 | } | 1907 | } |
1883 | auto varName = singleVariableFrom(tmpChain); | 1908 | auto varName = singleVariableFrom(tmpChain, AccessType::Write); |
1884 | bool isScoped = false; | 1909 | bool isScoped = false; |
1885 | if (varName.empty() || !isLocal(varName)) { | 1910 | if (varName.empty() || !isLocal(varName)) { |
1886 | isScoped = true; | 1911 | isScoped = true; |
@@ -2433,7 +2458,7 @@ private: | |||
2433 | } | 2458 | } |
2434 | } else { | 2459 | } else { |
2435 | auto exp = static_cast<Exp_t*>(pair); | 2460 | auto exp = static_cast<Exp_t*>(pair); |
2436 | auto varName = singleVariableFrom(exp, false); | 2461 | auto varName = singleVariableFrom(exp, AccessType::None); |
2437 | if (varName == "_"sv) break; | 2462 | if (varName == "_"sv) break; |
2438 | auto chain = exp->new_ptr<ChainValue_t>(); | 2463 | auto chain = exp->new_ptr<ChainValue_t>(); |
2439 | auto indexItem = toAst<Exp_t>(std::to_string(index), exp); | 2464 | auto indexItem = toAst<Exp_t>(std::to_string(index), exp); |
@@ -2514,7 +2539,7 @@ private: | |||
2514 | } else { | 2539 | } else { |
2515 | auto chain = exp->new_ptr<ChainValue_t>(); | 2540 | auto chain = exp->new_ptr<ChainValue_t>(); |
2516 | if (keyIndex) chain->items.push_back(keyIndex); | 2541 | if (keyIndex) chain->items.push_back(keyIndex); |
2517 | auto varName = singleVariableFrom(exp, false); | 2542 | auto varName = singleVariableFrom(exp, AccessType::None); |
2518 | pairs.push_back({exp, | 2543 | pairs.push_back({exp, |
2519 | varName, | 2544 | varName, |
2520 | chain, | 2545 | chain, |
@@ -2801,7 +2826,7 @@ private: | |||
2801 | } | 2826 | } |
2802 | valueItems.push_back(*j); | 2827 | valueItems.push_back(*j); |
2803 | if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { | 2828 | if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { |
2804 | auto var = singleVariableFrom(*j, false); | 2829 | auto var = singleVariableFrom(*j, AccessType::None); |
2805 | if (var.empty() || !isLocal(var)) { | 2830 | if (var.empty() || !isLocal(var)) { |
2806 | auto objVar = getUnusedName("_obj_"sv); | 2831 | auto objVar = getUnusedName("_obj_"sv); |
2807 | addToScope(objVar); | 2832 | addToScope(objVar); |
@@ -2818,7 +2843,7 @@ private: | |||
2818 | auto& destruct = destructs.emplace_back(); | 2843 | auto& destruct = destructs.emplace_back(); |
2819 | if (!varDefOnly) { | 2844 | if (!varDefOnly) { |
2820 | destruct.value = valueItems.back(); | 2845 | destruct.value = valueItems.back(); |
2821 | destruct.valueVar = singleVariableFrom(destruct.value, false); | 2846 | destruct.valueVar = singleVariableFrom(destruct.value, AccessType::None); |
2822 | } | 2847 | } |
2823 | auto simpleValue = tab->new_ptr<SimpleValue_t>(); | 2848 | auto simpleValue = tab->new_ptr<SimpleValue_t>(); |
2824 | simpleValue->value.set(tab); | 2849 | simpleValue->value.set(tab); |
@@ -2893,7 +2918,7 @@ private: | |||
2893 | } | 2918 | } |
2894 | } | 2919 | } |
2895 | if (auto value = singleValueFrom(exp); !value || !value->item.is<String_t>()) { | 2920 | if (auto value = singleValueFrom(exp); !value || !value->item.is<String_t>()) { |
2896 | auto var = singleVariableFrom(exp, false); | 2921 | auto var = singleVariableFrom(exp, AccessType::None); |
2897 | if (var.empty()) { | 2922 | if (var.empty()) { |
2898 | if (!des.inlineAssignment) { | 2923 | if (!des.inlineAssignment) { |
2899 | des.inlineAssignment = x->new_ptr<ExpListAssign_t>(); | 2924 | des.inlineAssignment = x->new_ptr<ExpListAssign_t>(); |
@@ -2986,7 +3011,7 @@ private: | |||
2986 | BLOCK_START | 3011 | BLOCK_START |
2987 | auto exp = ast_cast<Exp_t>(item); | 3012 | auto exp = ast_cast<Exp_t>(item); |
2988 | BREAK_IF(!exp); | 3013 | BREAK_IF(!exp); |
2989 | auto var = singleVariableFrom(exp, true); | 3014 | auto var = singleVariableFrom(exp, AccessType::Write); |
2990 | BREAK_IF(!var.empty()); | 3015 | BREAK_IF(!var.empty()); |
2991 | auto upVar = getUnusedName("_update_"sv); | 3016 | auto upVar = getUnusedName("_update_"sv); |
2992 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); | 3017 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); |
@@ -3038,23 +3063,40 @@ private: | |||
3038 | auto assign = static_cast<Assign_t*>(action); | 3063 | auto assign = static_cast<Assign_t*>(action); |
3039 | auto defs = transformAssignDefs(expList, DefOp::Check); | 3064 | auto defs = transformAssignDefs(expList, DefOp::Check); |
3040 | bool oneLined = defs.size() == expList->exprs.objects().size(); | 3065 | bool oneLined = defs.size() == expList->exprs.objects().size(); |
3066 | bool nonRecursionFunLit = false; | ||
3041 | for (auto val : assign->values.objects()) { | 3067 | for (auto val : assign->values.objects()) { |
3042 | if (auto value = singleValueFrom(val)) { | 3068 | if (auto value = singleValueFrom(val)) { |
3043 | if (auto spValue = value->item.as<SimpleValue_t>()) { | 3069 | if (auto spValue = value->item.as<SimpleValue_t>()) { |
3044 | if (spValue->value.is<FunLit_t>()) { | 3070 | if (auto funLit = spValue->value.as<FunLit_t>()) { |
3045 | oneLined = false; | 3071 | if (funLit->noRecursion) { |
3072 | nonRecursionFunLit = true; | ||
3073 | } else { | ||
3074 | oneLined = false; | ||
3075 | } | ||
3046 | break; | 3076 | break; |
3047 | } | 3077 | } |
3048 | } | 3078 | } |
3049 | } | 3079 | } |
3050 | } | 3080 | } |
3051 | if (oneLined) { | 3081 | if (oneLined) { |
3052 | for (auto value : assign->values.objects()) { | ||
3053 | transformAssignItem(value, temp); | ||
3054 | } | ||
3055 | std::string preDefine = toLocalDecl(defs); | 3082 | std::string preDefine = toLocalDecl(defs); |
3056 | for (const auto& def : defs) { | 3083 | if (nonRecursionFunLit) { |
3057 | addToScope(def.first); | 3084 | for (const auto& def : defs) { |
3085 | addToScope(def.first); | ||
3086 | } | ||
3087 | for (auto value : assign->values.objects()) { | ||
3088 | transformAssignItem(value, temp); | ||
3089 | } | ||
3090 | } else { | ||
3091 | for (auto value : assign->values.objects()) { | ||
3092 | transformAssignItem(value, temp); | ||
3093 | } | ||
3094 | for (const auto& def : defs) { | ||
3095 | addToScope(def.first); | ||
3096 | } | ||
3097 | } | ||
3098 | for (ast_node* exp : expList->exprs.objects()) { | ||
3099 | singleVariableFrom(exp, AccessType::Write); | ||
3058 | } | 3100 | } |
3059 | if (preDefine.empty()) { | 3101 | if (preDefine.empty()) { |
3060 | transformExpList(expList, temp); | 3102 | transformExpList(expList, temp); |
@@ -3069,6 +3111,9 @@ private: | |||
3069 | for (const auto& def : defs) { | 3111 | for (const auto& def : defs) { |
3070 | addToScope(def.first); | 3112 | addToScope(def.first); |
3071 | } | 3113 | } |
3114 | for (ast_node* exp : expList->exprs.objects()) { | ||
3115 | singleVariableFrom(exp, AccessType::Write); | ||
3116 | } | ||
3072 | transformExpList(expList, temp); | 3117 | transformExpList(expList, temp); |
3073 | std::string left = std::move(temp.back()); | 3118 | std::string left = std::move(temp.back()); |
3074 | temp.pop_back(); | 3119 | temp.pop_back(); |
@@ -3122,7 +3167,18 @@ private: | |||
3122 | str_list temp; | 3167 | str_list temp; |
3123 | std::string* funcStart = nullptr; | 3168 | std::string* funcStart = nullptr; |
3124 | if (usage == ExpUsage::Closure) { | 3169 | if (usage == ExpUsage::Closure) { |
3125 | pushFunctionScope(); | 3170 | auto x = nodes.front(); |
3171 | auto newIf = x->new_ptr<If_t>(); | ||
3172 | newIf->type.set(toAst<IfType_t>(unless ? "unless"sv : "if"sv, x)); | ||
3173 | for (ast_node* node : nodes) { | ||
3174 | newIf->nodes.push_back(node); | ||
3175 | } | ||
3176 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
3177 | simpleValue->value.set(newIf); | ||
3178 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
3179 | return; | ||
3180 | } | ||
3181 | pushAnonFunctionScope(); | ||
3126 | pushAnonVarArg(); | 3182 | pushAnonVarArg(); |
3127 | funcStart = &temp.emplace_back(); | 3183 | funcStart = &temp.emplace_back(); |
3128 | pushScope(); | 3184 | pushScope(); |
@@ -3149,12 +3205,12 @@ private: | |||
3149 | if (asmt) { | 3205 | if (asmt) { |
3150 | auto exp = firstIfCond->condition.get(); | 3206 | auto exp = firstIfCond->condition.get(); |
3151 | auto x = exp; | 3207 | auto x = exp; |
3152 | auto var = singleVariableFrom(exp, false); | 3208 | auto var = singleVariableFrom(exp, AccessType::None); |
3153 | if (var.empty() || isGlobal(var)) { | 3209 | if (var.empty() || isDeclaredAsGlobal(var)) { |
3154 | storingValue = true; | 3210 | storingValue = true; |
3155 | auto desVar = getUnusedName("_des_"sv); | 3211 | auto desVar = getUnusedName("_des_"sv); |
3156 | if (asmt->assign->values.objects().size() == 1) { | 3212 | if (asmt->assign->values.objects().size() == 1) { |
3157 | auto var = singleVariableFrom(asmt->assign->values.objects().front(), true); | 3213 | auto var = singleVariableFrom(asmt->assign->values.objects().front(), AccessType::Read); |
3158 | if (!var.empty() && isLocal(var)) { | 3214 | if (!var.empty() && isLocal(var)) { |
3159 | desVar = var; | 3215 | desVar = var; |
3160 | storingValue = false; | 3216 | storingValue = false; |
@@ -3300,7 +3356,7 @@ private: | |||
3300 | } | 3356 | } |
3301 | bool findPlaceHolder = false; | 3357 | bool findPlaceHolder = false; |
3302 | for (auto a : args->objects()) { | 3358 | for (auto a : args->objects()) { |
3303 | auto name = singleVariableFrom(a, false); | 3359 | auto name = singleVariableFrom(a, AccessType::None); |
3304 | if (name == "_"sv) { | 3360 | if (name == "_"sv) { |
3305 | if (!findPlaceHolder) { | 3361 | if (!findPlaceHolder) { |
3306 | args->swap(a, arg); | 3362 | args->swap(a, arg); |
@@ -3396,7 +3452,7 @@ private: | |||
3396 | if (item.second->size() == 1) { | 3452 | if (item.second->size() == 1) { |
3397 | if (auto unary = singleUnaryExpFrom(node)) { | 3453 | if (auto unary = singleUnaryExpFrom(node)) { |
3398 | if (auto value = singleValueFrom(unary)) { | 3454 | if (auto value = singleValueFrom(unary)) { |
3399 | varName = singleVariableFrom(value, true); | 3455 | varName = singleVariableFrom(value, AccessType::Read); |
3400 | } | 3456 | } |
3401 | if (varName.empty()) { | 3457 | if (varName.empty()) { |
3402 | if (auto sval = static_cast<Value_t*>(unary->expos.front())->item.as<SimpleValue_t>()) { | 3458 | if (auto sval = static_cast<Value_t*>(unary->expos.front())->item.as<SimpleValue_t>()) { |
@@ -3597,7 +3653,137 @@ private: | |||
3597 | } | 3653 | } |
3598 | } | 3654 | } |
3599 | 3655 | ||
3656 | std::optional<std::pair<std::string, str_list>> upValueFuncFrom(Exp_t* exp, str_list* ensureArgList = nullptr) { | ||
3657 | if (_funcLevel <= 1) return std::nullopt; | ||
3658 | auto result = exp->traverse([&](ast_node* node) { | ||
3659 | switch (node->get_id()) { | ||
3660 | case id<MacroName_t>(): | ||
3661 | return traversal::Stop; | ||
3662 | } | ||
3663 | return traversal::Continue; | ||
3664 | }); | ||
3665 | if (result != traversal::Stop) { | ||
3666 | str_list args; | ||
3667 | bool upVarsAssignedOrCaptured = false; | ||
3668 | bool usedVar = false; | ||
3669 | ast_ptr<false, Statement_t> stmt; | ||
3670 | { | ||
3671 | str_list globals; | ||
3672 | for (const auto& scope : _scopes) { | ||
3673 | if (scope.vars) { | ||
3674 | for (const auto& var : *scope.vars) { | ||
3675 | globals.push_back(var.first); | ||
3676 | } | ||
3677 | } | ||
3678 | } | ||
3679 | auto returnNode = exp->new_ptr<Return_t>(); | ||
3680 | auto returnList = exp->new_ptr<ExpListLow_t>(); | ||
3681 | returnList->exprs.push_back(exp); | ||
3682 | returnNode->valueList.set(returnList); | ||
3683 | std::string codes; | ||
3684 | if (_withVars.empty()) { | ||
3685 | codes = YueFormat{}.toString(returnNode); | ||
3686 | stmt = exp->new_ptr<Statement_t>(); | ||
3687 | stmt->content.set(returnNode); | ||
3688 | } else { | ||
3689 | auto withNode = exp->new_ptr<With_t>(); | ||
3690 | withNode->valueList.set(toAst<ExpList_t>(_withVars.top(), exp)); | ||
3691 | auto returnStmt = exp->new_ptr<Statement_t>(); | ||
3692 | returnStmt->content.set(returnNode); | ||
3693 | withNode->body.set(returnStmt); | ||
3694 | codes = YueFormat{}.toString(withNode); | ||
3695 | stmt = exp->new_ptr<Statement_t>(); | ||
3696 | auto simpleValue = exp->new_ptr<SimpleValue_t>(); | ||
3697 | simpleValue->value.set(withNode); | ||
3698 | auto newExpr = newExp(simpleValue, exp); | ||
3699 | auto explist = exp->new_ptr<ExpList_t>(); | ||
3700 | explist->exprs.push_back(newExpr); | ||
3701 | auto expListAssign = exp->new_ptr<ExpListAssign_t>(); | ||
3702 | expListAssign->expList.set(explist); | ||
3703 | stmt->content.set(expListAssign); | ||
3704 | } | ||
3705 | if (!globals.empty()) { | ||
3706 | codes.insert(0, "global "s + join(globals, ","sv) + '\n'); | ||
3707 | } | ||
3708 | YueConfig config; | ||
3709 | config.lintGlobalVariable = true; | ||
3710 | auto result = YueCompiler{L, _luaOpen, true}.compile(codes, config); | ||
3711 | if (result.error) { | ||
3712 | YUEE("failed to compile dues to Yue formatter", exp); | ||
3713 | } | ||
3714 | usedVar = result.usedVar; | ||
3715 | if (result.globals) { | ||
3716 | for (const auto& global : *result.globals) { | ||
3717 | if (global.accessType != AccessType::Read) { | ||
3718 | upVarsAssignedOrCaptured = true; | ||
3719 | break; | ||
3720 | } else if (std::find(args.begin(), args.end(), global.name) == args.end()) { | ||
3721 | args.push_back(global.name); | ||
3722 | } | ||
3723 | } | ||
3724 | } | ||
3725 | } | ||
3726 | if (!upVarsAssignedOrCaptured) { | ||
3727 | auto x = exp; | ||
3728 | if (usedVar) { | ||
3729 | args.push_back("..."s); | ||
3730 | } | ||
3731 | if (ensureArgList) { | ||
3732 | std::unordered_set<std::string> vars; | ||
3733 | for (const auto& arg : args) { | ||
3734 | vars.insert(arg); | ||
3735 | } | ||
3736 | for (const auto& arg : *ensureArgList) { | ||
3737 | vars.erase(arg); | ||
3738 | } | ||
3739 | str_list finalArgs; | ||
3740 | for (const auto& arg : vars) { | ||
3741 | finalArgs.push_back(arg); | ||
3742 | } | ||
3743 | for (const auto& arg : *ensureArgList) { | ||
3744 | finalArgs.push_back(arg); | ||
3745 | } | ||
3746 | args = std::move(finalArgs); | ||
3747 | } | ||
3748 | auto funLit = toAst<FunLit_t>("("s + join(args, ","sv) + ")-> nil"s, x); | ||
3749 | funLit->body->content.set(stmt.get()); | ||
3750 | funLit->noRecursion = true; | ||
3751 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
3752 | simpleValue->value.set(funLit); | ||
3753 | auto funcName = getUnusedName("_anon_func_"sv); | ||
3754 | auto assignment = assignmentFrom(toAst<Exp_t>(funcName, x), newExp(simpleValue, x), x); | ||
3755 | auto scopes = std::move(_scopes); | ||
3756 | _scopes.push_back(std::move(scopes.front())); | ||
3757 | scopes.pop_front(); | ||
3758 | int offset = _indentOffset; | ||
3759 | _indentOffset = 0; | ||
3760 | transformAssignment(assignment, _rootDefs); | ||
3761 | scopes.push_front(std::move(_scopes.front())); | ||
3762 | _scopes = std::move(scopes); | ||
3763 | _indentOffset = offset; | ||
3764 | return std::make_pair(funcName, args); | ||
3765 | } | ||
3766 | } | ||
3767 | return std::nullopt; | ||
3768 | } | ||
3769 | |||
3770 | bool transformAsUpValueFunc(Exp_t* exp, str_list& out) { | ||
3771 | auto result = upValueFuncFrom(exp); | ||
3772 | if (result) { | ||
3773 | auto [funcName, args] = std::move(*result); | ||
3774 | auto newChainValue = toAst<ChainValue_t>(funcName + '(' + join(args, ","sv) + ')', exp); | ||
3775 | transformChainValue(newChainValue, out, ExpUsage::Closure); | ||
3776 | return true; | ||
3777 | } | ||
3778 | return false; | ||
3779 | } | ||
3780 | |||
3600 | void transformNilCoalesedExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool nilBranchOnly = false) { | 3781 | void transformNilCoalesedExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool nilBranchOnly = false) { |
3782 | if (usage == ExpUsage::Closure) { | ||
3783 | if (transformAsUpValueFunc(exp, out)) { | ||
3784 | return; | ||
3785 | } | ||
3786 | } | ||
3601 | auto x = exp; | 3787 | auto x = exp; |
3602 | str_list temp; | 3788 | str_list temp; |
3603 | auto left = exp->new_ptr<Exp_t>(); | 3789 | auto left = exp->new_ptr<Exp_t>(); |
@@ -3620,12 +3806,12 @@ private: | |||
3620 | } | 3806 | } |
3621 | std::string* funcStart = nullptr; | 3807 | std::string* funcStart = nullptr; |
3622 | if (usage == ExpUsage::Closure) { | 3808 | if (usage == ExpUsage::Closure) { |
3623 | pushFunctionScope(); | 3809 | pushAnonFunctionScope(); |
3624 | pushAnonVarArg(); | 3810 | pushAnonVarArg(); |
3625 | funcStart = &temp.emplace_back(); | 3811 | funcStart = &temp.emplace_back(); |
3626 | pushScope(); | 3812 | pushScope(); |
3627 | } | 3813 | } |
3628 | auto objVar = singleVariableFrom(left, true); | 3814 | auto objVar = singleVariableFrom(left, AccessType::Read); |
3629 | auto prepareValue = [&](bool forAssignment = false) { | 3815 | auto prepareValue = [&](bool forAssignment = false) { |
3630 | if (objVar.empty() || !isLocal(objVar)) { | 3816 | if (objVar.empty() || !isLocal(objVar)) { |
3631 | if (forAssignment) { | 3817 | if (forAssignment) { |
@@ -3724,21 +3910,25 @@ private: | |||
3724 | } | 3910 | } |
3725 | } | 3911 | } |
3726 | 3912 | ||
3727 | void transformCallable(Callable_t* callable, str_list& out, const ast_sel<false, Invoke_t, InvokeArgs_t>& invoke = {}) { | 3913 | void transformCallable(Callable_t* callable, str_list& out, AccessType accessType, const ast_sel<false, Invoke_t, InvokeArgs_t>& invoke = {}) { |
3728 | auto item = callable->item.get(); | 3914 | auto item = callable->item.get(); |
3729 | switch (item->get_id()) { | 3915 | switch (item->get_id()) { |
3730 | case id<Variable_t>(): { | 3916 | case id<Variable_t>(): { |
3731 | transformVariable(static_cast<Variable_t*>(item), out); | 3917 | transformVariable(static_cast<Variable_t*>(item), out); |
3732 | if (_config.lintGlobalVariable && !isLocal(out.back())) { | 3918 | if (_config.lintGlobalVariable && accessType != AccessType::None && !isLocal(out.back())) { |
3733 | if (_globals.find(out.back()) == _globals.end()) { | 3919 | auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); |
3734 | _globals[out.back()] = {item->m_begin.m_line, item->m_begin.m_col}; | 3920 | if (_globals.find(key) == _globals.end()) { |
3921 | if (accessType == AccessType::Read && _funcLevel > 1) { | ||
3922 | accessType = AccessType::Capture; | ||
3923 | } | ||
3924 | _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType}; | ||
3735 | } | 3925 | } |
3736 | } | 3926 | } |
3737 | break; | 3927 | break; |
3738 | } | 3928 | } |
3739 | case id<SelfItem_t>(): { | 3929 | case id<SelfItem_t>(): { |
3740 | transformSelfName(static_cast<SelfItem_t*>(item), out, invoke); | 3930 | transformSelfName(static_cast<SelfItem_t*>(item), out, invoke); |
3741 | globalVar("self"sv, item); | 3931 | globalVar("self"sv, item, accessType); |
3742 | break; | 3932 | break; |
3743 | } | 3933 | } |
3744 | case id<Parens_t>(): transformParens(static_cast<Parens_t*>(item), out); break; | 3934 | case id<Parens_t>(): transformParens(static_cast<Parens_t*>(item), out); break; |
@@ -3777,7 +3967,7 @@ private: | |||
3777 | } | 3967 | } |
3778 | 3968 | ||
3779 | void transformFunLit(FunLit_t* funLit, str_list& out) { | 3969 | void transformFunLit(FunLit_t* funLit, str_list& out) { |
3780 | pushFunctionScope(); | 3970 | pushUserFunctionScope(); |
3781 | _varArgs.push({false, false}); | 3971 | _varArgs.push({false, false}); |
3782 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; | 3972 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; |
3783 | pushScope(); | 3973 | pushScope(); |
@@ -3951,7 +4141,7 @@ private: | |||
3951 | } | 4141 | } |
3952 | bool findPlaceHolder = false; | 4142 | bool findPlaceHolder = false; |
3953 | for (auto a : args->objects()) { | 4143 | for (auto a : args->objects()) { |
3954 | auto name = singleVariableFrom(a, false); | 4144 | auto name = singleVariableFrom(a, AccessType::None); |
3955 | if (name == "_"sv) { | 4145 | if (name == "_"sv) { |
3956 | if (!findPlaceHolder) { | 4146 | if (!findPlaceHolder) { |
3957 | args->swap(a, arg); | 4147 | args->swap(a, arg); |
@@ -4078,6 +4268,26 @@ private: | |||
4078 | argNames.push_back("..."s); | 4268 | argNames.push_back("..."s); |
4079 | auto newBody = x->new_ptr<Body_t>(); | 4269 | auto newBody = x->new_ptr<Body_t>(); |
4080 | newBody->content.set(followingBlock); | 4270 | newBody->content.set(followingBlock); |
4271 | { | ||
4272 | auto doNode = x->new_ptr<Do_t>(); | ||
4273 | doNode->body.set(newBody); | ||
4274 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
4275 | simpleValue->value.set(doNode); | ||
4276 | if (auto result = upValueFuncFrom(newExp(simpleValue, x), &argNames)) { | ||
4277 | auto [funcName, args] = std::move(*result); | ||
4278 | str_list finalArgs; | ||
4279 | for (const auto& arg : args) { | ||
4280 | if (std::find(argNames.begin(), argNames.end(), arg) == argNames.end()) { | ||
4281 | finalArgs.push_back(arg); | ||
4282 | } | ||
4283 | } | ||
4284 | newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); | ||
4285 | auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); | ||
4286 | ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); | ||
4287 | transformBlock(newBlock, out, usage, assignList, isRoot); | ||
4288 | return; | ||
4289 | } | ||
4290 | } | ||
4081 | auto funLit = toAst<FunLit_t>('(' + join(argNames, ","sv) + ")->"s, x); | 4291 | auto funLit = toAst<FunLit_t>('(' + join(argNames, ","sv) + ")->"s, x); |
4082 | funLit->body.set(newBody); | 4292 | funLit->body.set(newBody); |
4083 | auto newSimpleValue = x->new_ptr<SimpleValue_t>(); | 4293 | auto newSimpleValue = x->new_ptr<SimpleValue_t>(); |
@@ -4323,6 +4533,13 @@ private: | |||
4323 | str_list temp; | 4533 | str_list temp; |
4324 | for (auto node : nodes) { | 4534 | for (auto node : nodes) { |
4325 | transformStatement(static_cast<Statement_t*>(node), temp); | 4535 | transformStatement(static_cast<Statement_t*>(node), temp); |
4536 | if (isRoot && !_rootDefs.empty()) { | ||
4537 | auto last = std::move(temp.back()); | ||
4538 | temp.pop_back(); | ||
4539 | temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); | ||
4540 | _rootDefs.clear(); | ||
4541 | temp.push_back(std::move(last)); | ||
4542 | } | ||
4326 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { | 4543 | if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { |
4327 | auto rit = ++temp.rbegin(); | 4544 | auto rit = ++temp.rbegin(); |
4328 | if (rit != temp.rend() && !rit->empty()) { | 4545 | if (rit != temp.rend() && !rit->empty()) { |
@@ -4590,7 +4807,7 @@ private: | |||
4590 | #endif // YUE_NO_MACRO | 4807 | #endif // YUE_NO_MACRO |
4591 | 4808 | ||
4592 | void transformReturn(Return_t* returnNode, str_list& out) { | 4809 | void transformReturn(Return_t* returnNode, str_list& out) { |
4593 | if (!_enableReturn.top()) { | 4810 | if (!_funcStates.top().enableReturn) { |
4594 | ast_node* target = returnNode->valueList.get(); | 4811 | ast_node* target = returnNode->valueList.get(); |
4595 | if (!target) target = returnNode; | 4812 | if (!target) target = returnNode; |
4596 | throw CompileError("can not mix use of return and export statements in module scope"sv, target); | 4813 | throw CompileError("can not mix use of return and export statements in module scope"sv, target); |
@@ -4909,7 +5126,14 @@ private: | |||
4909 | str_list temp; | 5126 | str_list temp; |
4910 | std::string* funcStart = nullptr; | 5127 | std::string* funcStart = nullptr; |
4911 | if (usage == ExpUsage::Closure) { | 5128 | if (usage == ExpUsage::Closure) { |
4912 | pushFunctionScope(); | 5129 | auto chainValue = x->new_ptr<ChainValue_t>(); |
5130 | for (ast_node* node : chainList) { | ||
5131 | chainValue->items.push_back(node); | ||
5132 | } | ||
5133 | if (transformAsUpValueFunc(newExp(chainValue, x), out)) { | ||
5134 | return true; | ||
5135 | } | ||
5136 | pushAnonFunctionScope(); | ||
4913 | pushAnonVarArg(); | 5137 | pushAnonVarArg(); |
4914 | funcStart = &temp.emplace_back(); | 5138 | funcStart = &temp.emplace_back(); |
4915 | pushScope(); | 5139 | pushScope(); |
@@ -4940,7 +5164,7 @@ private: | |||
4940 | break; | 5164 | break; |
4941 | } | 5165 | } |
4942 | BLOCK_END | 5166 | BLOCK_END |
4943 | auto objVar = singleVariableFrom(partOne); | 5167 | auto objVar = singleVariableFrom(partOne, AccessType::Read); |
4944 | bool isScoped = false; | 5168 | bool isScoped = false; |
4945 | if (objVar.empty() || !isLocal(objVar)) { | 5169 | if (objVar.empty() || !isLocal(objVar)) { |
4946 | switch (usage) { | 5170 | switch (usage) { |
@@ -4965,7 +5189,7 @@ private: | |||
4965 | } | 5189 | } |
4966 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x)); | 5190 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), x)); |
4967 | } | 5191 | } |
4968 | auto newObj = singleVariableFrom(chainValue); | 5192 | auto newObj = singleVariableFrom(chainValue, AccessType::Read); |
4969 | if (!newObj.empty()) { | 5193 | if (!newObj.empty()) { |
4970 | objVar = newObj; | 5194 | objVar = newObj; |
4971 | } else { | 5195 | } else { |
@@ -5085,7 +5309,7 @@ private: | |||
5085 | pushScope(); | 5309 | pushScope(); |
5086 | break; | 5310 | break; |
5087 | case ExpUsage::Closure: | 5311 | case ExpUsage::Closure: |
5088 | pushFunctionScope(); | 5312 | pushAnonFunctionScope(); |
5089 | pushAnonVarArg(); | 5313 | pushAnonVarArg(); |
5090 | funcStart = &temp.emplace_back(); | 5314 | funcStart = &temp.emplace_back(); |
5091 | pushScope(); | 5315 | pushScope(); |
@@ -5222,7 +5446,14 @@ private: | |||
5222 | str_list temp; | 5446 | str_list temp; |
5223 | std::string* funcStart = nullptr; | 5447 | std::string* funcStart = nullptr; |
5224 | if (usage == ExpUsage::Closure) { | 5448 | if (usage == ExpUsage::Closure) { |
5225 | pushFunctionScope(); | 5449 | auto chainValue = x->new_ptr<ChainValue_t>(); |
5450 | for (ast_node* node : chainList) { | ||
5451 | chainValue->items.push_back(node); | ||
5452 | } | ||
5453 | if (transformAsUpValueFunc(newExp(chainValue, x), out)) { | ||
5454 | return true; | ||
5455 | } | ||
5456 | pushAnonFunctionScope(); | ||
5226 | pushAnonVarArg(); | 5457 | pushAnonVarArg(); |
5227 | funcStart = &temp.emplace_back(); | 5458 | funcStart = &temp.emplace_back(); |
5228 | pushScope(); | 5459 | pushScope(); |
@@ -5349,12 +5580,6 @@ private: | |||
5349 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { | 5580 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { |
5350 | auto item = *it; | 5581 | auto item = *it; |
5351 | switch (item->get_id()) { | 5582 | switch (item->get_id()) { |
5352 | case id<Invoke_t>(): | ||
5353 | transformInvoke(static_cast<Invoke_t*>(item), temp); | ||
5354 | break; | ||
5355 | case id<DotChainItem_t>(): | ||
5356 | transformDotChainItem(static_cast<DotChainItem_t*>(item), temp); | ||
5357 | break; | ||
5358 | case id<ColonChainItem_t>(): { | 5583 | case id<ColonChainItem_t>(): { |
5359 | auto colonItem = static_cast<ColonChainItem_t*>(item); | 5584 | auto colonItem = static_cast<ColonChainItem_t*>(item); |
5360 | auto current = it; | 5585 | auto current = it; |
@@ -5390,7 +5615,7 @@ private: | |||
5390 | chainValue->items.push_back(*i); | 5615 | chainValue->items.push_back(*i); |
5391 | } | 5616 | } |
5392 | auto exp = newExp(chainValue, x); | 5617 | auto exp = newExp(chainValue, x); |
5393 | callVar = singleVariableFrom(exp, true); | 5618 | callVar = singleVariableFrom(exp, AccessType::Read); |
5394 | if (callVar.empty() || !isLocal(callVar)) { | 5619 | if (callVar.empty() || !isLocal(callVar)) { |
5395 | callVar = getUnusedName("_call_"s); | 5620 | callVar = getUnusedName("_call_"s); |
5396 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 5621 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
@@ -5413,10 +5638,27 @@ private: | |||
5413 | } | 5638 | } |
5414 | chainValue->items.push_back(toAst<Exp_t>('\"' + name + '\"', x)); | 5639 | chainValue->items.push_back(toAst<Exp_t>('\"' + name + '\"', x)); |
5415 | if (auto invoke = ast_cast<Invoke_t>(followItem)) { | 5640 | if (auto invoke = ast_cast<Invoke_t>(followItem)) { |
5416 | invoke->args.push_front(toAst<Exp_t>(callVar, x)); | 5641 | auto newInvoke = x->new_ptr<Invoke_t>(); |
5642 | newInvoke->args.push_back(toAst<Exp_t>(callVar, x)); | ||
5643 | newInvoke->args.dup(invoke->args); | ||
5644 | chainValue->items.push_back(newInvoke); | ||
5645 | ++next; | ||
5417 | } else { | 5646 | } else { |
5418 | auto invokeArgs = static_cast<InvokeArgs_t*>(followItem); | 5647 | auto invokeArgs = static_cast<InvokeArgs_t*>(followItem); |
5419 | invokeArgs->args.push_front(toAst<Exp_t>(callVar, x)); | 5648 | auto newInvokeArgs = x->new_ptr<InvokeArgs_t>(); |
5649 | newInvokeArgs->args.push_back(toAst<Exp_t>(callVar, x)); | ||
5650 | newInvokeArgs->args.dup(invokeArgs->args); | ||
5651 | chainValue->items.push_back(newInvokeArgs); | ||
5652 | ++next; | ||
5653 | if (next != chainList.end()) { | ||
5654 | auto paren = x->new_ptr<Parens_t>(); | ||
5655 | paren->expr.set(newExp(chainValue, x)); | ||
5656 | auto ncallable = x->new_ptr<Callable_t>(); | ||
5657 | ncallable->item.set(paren); | ||
5658 | auto nchainValue = x->new_ptr<ChainValue_t>(); | ||
5659 | nchainValue->items.push_back(ncallable); | ||
5660 | chainValue.set(nchainValue); | ||
5661 | } | ||
5420 | } | 5662 | } |
5421 | for (auto i = next; i != chainList.end(); ++i) { | 5663 | for (auto i = next; i != chainList.end(); ++i) { |
5422 | chainValue->items.push_back(*i); | 5664 | chainValue->items.push_back(*i); |
@@ -5447,6 +5689,15 @@ private: | |||
5447 | } else { | 5689 | } else { |
5448 | auto body = x->new_ptr<Body_t>(); | 5690 | auto body = x->new_ptr<Body_t>(); |
5449 | body->content.set(block); | 5691 | body->content.set(block); |
5692 | { | ||
5693 | auto doNode = x->new_ptr<Do_t>(); | ||
5694 | doNode->body.set(body); | ||
5695 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
5696 | simpleValue->value.set(doNode); | ||
5697 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
5698 | return; | ||
5699 | } | ||
5700 | } | ||
5450 | auto funLit = toAst<FunLit_t>("->"sv, x); | 5701 | auto funLit = toAst<FunLit_t>("->"sv, x); |
5451 | funLit->body.set(body); | 5702 | funLit->body.set(body); |
5452 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | 5703 | auto simpleValue = x->new_ptr<SimpleValue_t>(); |
@@ -5464,9 +5715,21 @@ private: | |||
5464 | } | 5715 | } |
5465 | return; | 5716 | return; |
5466 | } | 5717 | } |
5467 | transformColonChainItem(colonItem, temp); | ||
5468 | break; | ||
5469 | } | 5718 | } |
5719 | } | ||
5720 | } | ||
5721 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { | ||
5722 | auto item = *it; | ||
5723 | switch (item->get_id()) { | ||
5724 | case id<Invoke_t>(): | ||
5725 | transformInvoke(static_cast<Invoke_t*>(item), temp); | ||
5726 | break; | ||
5727 | case id<DotChainItem_t>(): | ||
5728 | transformDotChainItem(static_cast<DotChainItem_t*>(item), temp); | ||
5729 | break; | ||
5730 | case id<ColonChainItem_t>(): | ||
5731 | transformColonChainItem(static_cast<ColonChainItem_t*>(item), temp); | ||
5732 | break; | ||
5470 | case id<Slice_t>(): | 5733 | case id<Slice_t>(): |
5471 | transformSlice(static_cast<Slice_t*>(item), temp); | 5734 | transformSlice(static_cast<Slice_t*>(item), temp); |
5472 | break; | 5735 | break; |
@@ -5478,7 +5741,7 @@ private: | |||
5478 | if (ast_is<Invoke_t, InvokeArgs_t>(followItem)) { | 5741 | if (ast_is<Invoke_t, InvokeArgs_t>(followItem)) { |
5479 | invoke.set(followItem); | 5742 | invoke.set(followItem); |
5480 | } | 5743 | } |
5481 | transformCallable(static_cast<Callable_t*>(item), temp, invoke); | 5744 | transformCallable(static_cast<Callable_t*>(item), temp, AccessType::Read, invoke); |
5482 | break; | 5745 | break; |
5483 | } | 5746 | } |
5484 | case id<String_t>(): | 5747 | case id<String_t>(): |
@@ -5969,7 +6232,7 @@ private: | |||
5969 | std::string varName; | 6232 | std::string varName; |
5970 | if (unary_exp->ops.empty() && unary_exp->expos.size() == 1) { | 6233 | if (unary_exp->ops.empty() && unary_exp->expos.size() == 1) { |
5971 | auto value = static_cast<Value_t*>(unary_exp->expos.back()); | 6234 | auto value = static_cast<Value_t*>(unary_exp->expos.back()); |
5972 | varName = singleVariableFrom(value, false); | 6235 | varName = singleVariableFrom(value, AccessType::None); |
5973 | if (!isLocal(varName)) { | 6236 | if (!isLocal(varName)) { |
5974 | varName.clear(); | 6237 | varName.clear(); |
5975 | } | 6238 | } |
@@ -6018,7 +6281,7 @@ private: | |||
6018 | BLOCK_START | 6281 | BLOCK_START |
6019 | BREAK_IF(discrete); | 6282 | BREAK_IF(discrete); |
6020 | str_list temp; | 6283 | str_list temp; |
6021 | auto checkVar = singleVariableFrom(inExp, false); | 6284 | auto checkVar = singleVariableFrom(inExp, AccessType::None); |
6022 | if (usage == ExpUsage::Assignment) { | 6285 | if (usage == ExpUsage::Assignment) { |
6023 | auto block = x->new_ptr<Block_t>(); | 6286 | auto block = x->new_ptr<Block_t>(); |
6024 | if (checkVar.empty() || !isLocal(checkVar)) { | 6287 | if (checkVar.empty() || !isLocal(checkVar)) { |
@@ -6091,7 +6354,11 @@ private: | |||
6091 | if (usage == ExpUsage::Return) { | 6354 | if (usage == ExpUsage::Return) { |
6092 | arrayCheck(!unary_exp->inExp->not_); | 6355 | arrayCheck(!unary_exp->inExp->not_); |
6093 | } else { | 6356 | } else { |
6094 | pushFunctionScope(); | 6357 | if (transformAsUpValueFunc(newExp(unary_exp, unary_exp), out)) { |
6358 | out.back() = "(#"s + checkVar + " > 0 and "s + out.back() + ')'; | ||
6359 | return; | ||
6360 | } | ||
6361 | pushAnonFunctionScope(); | ||
6095 | pushAnonVarArg(); | 6362 | pushAnonVarArg(); |
6096 | pushScope(); | 6363 | pushScope(); |
6097 | arrayCheck(true); | 6364 | arrayCheck(true); |
@@ -6106,7 +6373,10 @@ private: | |||
6106 | } | 6373 | } |
6107 | } else { | 6374 | } else { |
6108 | if (usage == ExpUsage::Closure) { | 6375 | if (usage == ExpUsage::Closure) { |
6109 | pushFunctionScope(); | 6376 | if (transformAsUpValueFunc(newExp(unary_exp, unary_exp), out)) { |
6377 | return; | ||
6378 | } | ||
6379 | pushAnonFunctionScope(); | ||
6110 | pushAnonVarArg(); | 6380 | pushAnonVarArg(); |
6111 | pushScope(); | 6381 | pushScope(); |
6112 | } | 6382 | } |
@@ -6160,7 +6430,10 @@ private: | |||
6160 | if (varName.empty()) { | 6430 | if (varName.empty()) { |
6161 | str_list temp; | 6431 | str_list temp; |
6162 | if (usage == ExpUsage::Closure) { | 6432 | if (usage == ExpUsage::Closure) { |
6163 | pushFunctionScope(); | 6433 | if (transformAsUpValueFunc(newExp(unary_exp, unary_exp), out)) { |
6434 | return; | ||
6435 | } | ||
6436 | pushAnonFunctionScope(); | ||
6164 | pushAnonVarArg(); | 6437 | pushAnonVarArg(); |
6165 | pushScope(); | 6438 | pushScope(); |
6166 | } else if (usage == ExpUsage::Assignment) { | 6439 | } else if (usage == ExpUsage::Assignment) { |
@@ -6302,11 +6575,21 @@ private: | |||
6302 | void transformSpreadTable(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 6575 | void transformSpreadTable(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
6303 | auto x = values.front(); | 6576 | auto x = values.front(); |
6304 | switch (usage) { | 6577 | switch (usage) { |
6305 | case ExpUsage::Closure: | 6578 | case ExpUsage::Closure: { |
6306 | pushFunctionScope(); | 6579 | auto tableLit = x->new_ptr<TableLit_t>(); |
6580 | for (ast_node* value : values) { | ||
6581 | tableLit->values.push_back(value); | ||
6582 | } | ||
6583 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
6584 | simpleValue->value.set(tableLit); | ||
6585 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
6586 | return; | ||
6587 | } | ||
6588 | pushAnonFunctionScope(); | ||
6307 | pushAnonVarArg(); | 6589 | pushAnonVarArg(); |
6308 | pushScope(); | 6590 | pushScope(); |
6309 | break; | 6591 | break; |
6592 | } | ||
6310 | case ExpUsage::Assignment: | 6593 | case ExpUsage::Assignment: |
6311 | pushScope(); | 6594 | pushScope(); |
6312 | break; | 6595 | break; |
@@ -6336,7 +6619,7 @@ private: | |||
6336 | std::string indexVar = getUnusedName("_idx_"sv); | 6619 | std::string indexVar = getUnusedName("_idx_"sv); |
6337 | std::string keyVar = getUnusedName("_key_"sv); | 6620 | std::string keyVar = getUnusedName("_key_"sv); |
6338 | std::string valueVar = getUnusedName("_value_"sv); | 6621 | std::string valueVar = getUnusedName("_value_"sv); |
6339 | auto objVar = singleVariableFrom(spread->exp, true); | 6622 | auto objVar = singleVariableFrom(spread->exp, AccessType::Read); |
6340 | if (objVar.empty()) { | 6623 | if (objVar.empty()) { |
6341 | objVar = getUnusedName("_obj_"); | 6624 | objVar = getUnusedName("_obj_"); |
6342 | auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); | 6625 | auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); |
@@ -6360,7 +6643,7 @@ private: | |||
6360 | auto spread = static_cast<SpreadListExp_t*>(item); | 6643 | auto spread = static_cast<SpreadListExp_t*>(item); |
6361 | std::string indexVar = getUnusedName("_idx_"sv); | 6644 | std::string indexVar = getUnusedName("_idx_"sv); |
6362 | std::string valueVar = getUnusedName("_value_"sv); | 6645 | std::string valueVar = getUnusedName("_value_"sv); |
6363 | auto objVar = singleVariableFrom(spread->exp, true); | 6646 | auto objVar = singleVariableFrom(spread->exp, AccessType::Read); |
6364 | if (objVar.empty()) { | 6647 | if (objVar.empty()) { |
6365 | objVar = getUnusedName("_obj_"); | 6648 | objVar = getUnusedName("_obj_"); |
6366 | auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); | 6649 | auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); |
@@ -6704,7 +6987,7 @@ private: | |||
6704 | decIndentOffset(); | 6987 | decIndentOffset(); |
6705 | out.back() += (indent() + '}'); | 6988 | out.back() += (indent() + '}'); |
6706 | } else { | 6989 | } else { |
6707 | auto tabStr = globalVar("setmetatable"sv, x); | 6990 | auto tabStr = globalVar("setmetatable"sv, x, AccessType::Read); |
6708 | tabStr += '('; | 6991 | tabStr += '('; |
6709 | if (temp.empty()) { | 6992 | if (temp.empty()) { |
6710 | decIndentOffset(); | 6993 | decIndentOffset(); |
@@ -6825,20 +7108,26 @@ private: | |||
6825 | if (!def || def->defVal) { | 7108 | if (!def || def->defVal) { |
6826 | throw CompileError("invalid comprehension expression", comp->items.front()); | 7109 | throw CompileError("invalid comprehension expression", comp->items.front()); |
6827 | } | 7110 | } |
6828 | auto value = def->item.get(); | ||
6829 | auto compInner = static_cast<CompInner_t*>(comp->items.back()); | ||
6830 | switch (usage) { | 7111 | switch (usage) { |
6831 | case ExpUsage::Closure: | 7112 | case ExpUsage::Closure: { |
6832 | pushFunctionScope(); | 7113 | auto simpleValue = x->new_ptr<SimpleValue_t>(); |
7114 | simpleValue->value.set(comp); | ||
7115 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
7116 | return; | ||
7117 | } | ||
7118 | pushAnonFunctionScope(); | ||
6833 | pushAnonVarArg(); | 7119 | pushAnonVarArg(); |
6834 | pushScope(); | 7120 | pushScope(); |
6835 | break; | 7121 | break; |
7122 | } | ||
6836 | case ExpUsage::Assignment: | 7123 | case ExpUsage::Assignment: |
6837 | pushScope(); | 7124 | pushScope(); |
6838 | break; | 7125 | break; |
6839 | default: | 7126 | default: |
6840 | break; | 7127 | break; |
6841 | } | 7128 | } |
7129 | auto value = def->item.get(); | ||
7130 | auto compInner = static_cast<CompInner_t*>(comp->items.back()); | ||
6842 | str_list temp; | 7131 | str_list temp; |
6843 | std::string accumVar = getUnusedName("_accum_"sv); | 7132 | std::string accumVar = getUnusedName("_accum_"sv); |
6844 | std::string lenVar = getUnusedName("_len_"sv); | 7133 | std::string lenVar = getUnusedName("_len_"sv); |
@@ -6954,7 +7243,7 @@ private: | |||
6954 | switch (loopTarget->get_id()) { | 7243 | switch (loopTarget->get_id()) { |
6955 | case id<StarExp_t>(): { | 7244 | case id<StarExp_t>(): { |
6956 | auto star_exp = static_cast<StarExp_t*>(loopTarget); | 7245 | auto star_exp = static_cast<StarExp_t*>(loopTarget); |
6957 | auto listVar = singleVariableFrom(star_exp->value, true); | 7246 | auto listVar = singleVariableFrom(star_exp->value, AccessType::Read); |
6958 | if (!isLocal(listVar)) listVar.clear(); | 7247 | if (!isLocal(listVar)) listVar.clear(); |
6959 | auto indexVar = getUnusedName("_index_"sv); | 7248 | auto indexVar = getUnusedName("_index_"sv); |
6960 | varAfter.push_back(indexVar); | 7249 | varAfter.push_back(indexVar); |
@@ -7430,8 +7719,13 @@ private: | |||
7430 | } | 7719 | } |
7431 | 7720 | ||
7432 | void transformForClosure(For_t* forNode, str_list& out) { | 7721 | void transformForClosure(For_t* forNode, str_list& out) { |
7722 | auto simpleValue = forNode->new_ptr<SimpleValue_t>(); | ||
7723 | simpleValue->value.set(forNode); | ||
7724 | if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { | ||
7725 | return; | ||
7726 | } | ||
7433 | str_list temp; | 7727 | str_list temp; |
7434 | pushFunctionScope(); | 7728 | pushAnonFunctionScope(); |
7435 | pushAnonVarArg(); | 7729 | pushAnonVarArg(); |
7436 | std::string& funcStart = temp.emplace_back(); | 7730 | std::string& funcStart = temp.emplace_back(); |
7437 | pushScope(); | 7731 | pushScope(); |
@@ -7519,8 +7813,13 @@ private: | |||
7519 | } | 7813 | } |
7520 | 7814 | ||
7521 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 7815 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
7816 | auto simpleValue = forEach->new_ptr<SimpleValue_t>(); | ||
7817 | simpleValue->value.set(forEach); | ||
7818 | if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { | ||
7819 | return; | ||
7820 | } | ||
7522 | str_list temp; | 7821 | str_list temp; |
7523 | pushFunctionScope(); | 7822 | pushAnonFunctionScope(); |
7524 | pushAnonVarArg(); | 7823 | pushAnonVarArg(); |
7525 | std::string& funcStart = temp.emplace_back(); | 7824 | std::string& funcStart = temp.emplace_back(); |
7526 | pushScope(); | 7825 | pushScope(); |
@@ -7569,8 +7868,9 @@ private: | |||
7569 | out.push_back(name + " = "s + name); | 7868 | out.push_back(name + " = "s + name); |
7570 | } | 7869 | } |
7571 | if (_config.lintGlobalVariable && !isLocal(name)) { | 7870 | if (_config.lintGlobalVariable && !isLocal(name)) { |
7572 | if (_globals.find(name) == _globals.end()) { | 7871 | auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); |
7573 | _globals[name] = {pair->name->m_begin.m_line, pair->name->m_begin.m_col}; | 7872 | if (_globals.find(key) != _globals.end()) { |
7873 | _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; | ||
7574 | } | 7874 | } |
7575 | } | 7875 | } |
7576 | } | 7876 | } |
@@ -7675,7 +7975,7 @@ private: | |||
7675 | } | 7975 | } |
7676 | case id<Exp_t>(): { | 7976 | case id<Exp_t>(): { |
7677 | transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure); | 7977 | transformExp(static_cast<Exp_t*>(content), temp, ExpUsage::Closure); |
7678 | temp.back() = globalVar("tostring"sv, content) + '(' + temp.back() + ')'; | 7978 | temp.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + temp.back() + ')'; |
7679 | break; | 7979 | break; |
7680 | } | 7980 | } |
7681 | default: YUEE("AST node mismatch", content); break; | 7981 | default: YUEE("AST node mismatch", content); break; |
@@ -7708,8 +8008,13 @@ private: | |||
7708 | } | 8008 | } |
7709 | 8009 | ||
7710 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { | 8010 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { |
8011 | auto simpleValue = classDecl->new_ptr<SimpleValue_t>(); | ||
8012 | simpleValue->value.set(classDecl); | ||
8013 | if (transformAsUpValueFunc(newExp(simpleValue, classDecl), out)) { | ||
8014 | return; | ||
8015 | } | ||
7711 | str_list temp; | 8016 | str_list temp; |
7712 | pushFunctionScope(); | 8017 | pushAnonFunctionScope(); |
7713 | pushAnonVarArg(); | 8018 | pushAnonVarArg(); |
7714 | std::string& funcStart = temp.emplace_back(); | 8019 | std::string& funcStart = temp.emplace_back(); |
7715 | pushScope(); | 8020 | pushScope(); |
@@ -7918,7 +8223,7 @@ private: | |||
7918 | if (extend) { | 8223 | if (extend) { |
7919 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); | 8224 | _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); |
7920 | } | 8225 | } |
7921 | _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl) << "({"sv << nll(classDecl); | 8226 | _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); |
7922 | if (!builtins.empty()) { | 8227 | if (!builtins.empty()) { |
7923 | _buf << join(builtins) << ',' << nll(classDecl); | 8228 | _buf << join(builtins) << ',' << nll(classDecl); |
7924 | } else { | 8229 | } else { |
@@ -8142,8 +8447,13 @@ private: | |||
8142 | } | 8447 | } |
8143 | 8448 | ||
8144 | void transformWithClosure(With_t* with, str_list& out) { | 8449 | void transformWithClosure(With_t* with, str_list& out) { |
8450 | auto simpleValue = with->new_ptr<SimpleValue_t>(); | ||
8451 | simpleValue->value.set(with); | ||
8452 | if (transformAsUpValueFunc(newExp(simpleValue, with), out)) { | ||
8453 | return; | ||
8454 | } | ||
8145 | str_list temp; | 8455 | str_list temp; |
8146 | pushFunctionScope(); | 8456 | pushAnonFunctionScope(); |
8147 | pushAnonVarArg(); | 8457 | pushAnonVarArg(); |
8148 | std::string& funcStart = temp.emplace_back(); | 8458 | std::string& funcStart = temp.emplace_back(); |
8149 | pushScope(); | 8459 | pushScope(); |
@@ -8163,9 +8473,9 @@ private: | |||
8163 | bool scoped = false; | 8473 | bool scoped = false; |
8164 | if (with->assigns) { | 8474 | if (with->assigns) { |
8165 | auto vars = getAssignVars(with); | 8475 | auto vars = getAssignVars(with); |
8166 | if (vars.front().empty() || isGlobal(vars.front())) { | 8476 | if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { |
8167 | if (with->assigns->values.objects().size() == 1) { | 8477 | if (with->assigns->values.objects().size() == 1) { |
8168 | auto var = singleVariableFrom(with->assigns->values.objects().front(), true); | 8478 | auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); |
8169 | if (!var.empty() && isLocal(var)) { | 8479 | if (!var.empty() && isLocal(var)) { |
8170 | withVar = var; | 8480 | withVar = var; |
8171 | } | 8481 | } |
@@ -8211,7 +8521,7 @@ private: | |||
8211 | transformAssignment(assignment, temp); | 8521 | transformAssignment(assignment, temp); |
8212 | } | 8522 | } |
8213 | } else { | 8523 | } else { |
8214 | withVar = singleVariableFrom(with->valueList, true); | 8524 | withVar = singleVariableFrom(with->valueList, AccessType::Read); |
8215 | if (withVar.empty() || !isLocal(withVar)) { | 8525 | if (withVar.empty() || !isLocal(withVar)) { |
8216 | withVar = getUnusedName("_with_"sv); | 8526 | withVar = getUnusedName("_with_"sv); |
8217 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 8527 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
@@ -8555,11 +8865,17 @@ private: | |||
8555 | 8865 | ||
8556 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 8866 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
8557 | switch (usage) { | 8867 | switch (usage) { |
8558 | case ExpUsage::Closure: | 8868 | case ExpUsage::Closure: { |
8559 | pushFunctionScope(); | 8869 | auto simpleValue = comp->new_ptr<SimpleValue_t>(); |
8870 | simpleValue->value.set(comp); | ||
8871 | if (transformAsUpValueFunc(newExp(simpleValue, comp), out)) { | ||
8872 | return; | ||
8873 | } | ||
8874 | pushAnonFunctionScope(); | ||
8560 | pushAnonVarArg(); | 8875 | pushAnonVarArg(); |
8561 | pushScope(); | 8876 | pushScope(); |
8562 | break; | 8877 | break; |
8878 | } | ||
8563 | case ExpUsage::Assignment: | 8879 | case ExpUsage::Assignment: |
8564 | pushScope(); | 8880 | pushScope(); |
8565 | break; | 8881 | break; |
@@ -8663,7 +8979,12 @@ private: | |||
8663 | str_list temp; | 8979 | str_list temp; |
8664 | std::string* funcStart = nullptr; | 8980 | std::string* funcStart = nullptr; |
8665 | if (usage == ExpUsage::Closure) { | 8981 | if (usage == ExpUsage::Closure) { |
8666 | pushFunctionScope(); | 8982 | auto simpleValue = doNode->new_ptr<SimpleValue_t>(); |
8983 | simpleValue->value.set(doNode); | ||
8984 | if (transformAsUpValueFunc(newExp(simpleValue, doNode), out)) { | ||
8985 | return; | ||
8986 | } | ||
8987 | pushAnonFunctionScope(); | ||
8667 | pushAnonVarArg(); | 8988 | pushAnonVarArg(); |
8668 | funcStart = &temp.emplace_back(); | 8989 | funcStart = &temp.emplace_back(); |
8669 | } else { | 8990 | } else { |
@@ -8691,7 +9012,7 @@ private: | |||
8691 | errHandler.set(toAst<Exp_t>(errHandleStr, x->func)); | 9012 | errHandler.set(toAst<Exp_t>(errHandleStr, x->func)); |
8692 | auto funLit = simpleSingleValueFrom(errHandler)->value.to<FunLit_t>(); | 9013 | auto funLit = simpleSingleValueFrom(errHandler)->value.to<FunLit_t>(); |
8693 | auto body = x->new_ptr<Body_t>(); | 9014 | auto body = x->new_ptr<Body_t>(); |
8694 | body->content.set(tryNode->catchBlock->body); | 9015 | body->content.set(tryNode->catchBlock->block); |
8695 | funLit->body.set(body); | 9016 | funLit->body.set(body); |
8696 | } | 9017 | } |
8697 | if (auto tryBlock = tryNode->func.as<Block_t>()) { | 9018 | if (auto tryBlock = tryNode->func.as<Block_t>()) { |
@@ -8709,6 +9030,35 @@ private: | |||
8709 | BLOCK_END | 9030 | BLOCK_END |
8710 | } | 9031 | } |
8711 | if (auto tryBlock = tryNode->func.as<Block_t>()) { | 9032 | if (auto tryBlock = tryNode->func.as<Block_t>()) { |
9033 | { | ||
9034 | auto body = tryBlock->new_ptr<Body_t>(); | ||
9035 | body->content.set(tryBlock); | ||
9036 | auto doNode = tryBlock->new_ptr<Do_t>(); | ||
9037 | doNode->body.set(body); | ||
9038 | auto simpleValue = tryBlock->new_ptr<SimpleValue_t>(); | ||
9039 | simpleValue->value.set(doNode); | ||
9040 | if (auto result = upValueFuncFrom(newExp(simpleValue, tryBlock))) { | ||
9041 | auto [funcName, args] = std::move(*result); | ||
9042 | if (errHandler) { | ||
9043 | auto xpcall = toAst<ChainValue_t>("xpcall()", x); | ||
9044 | auto invoke = ast_to<Invoke_t>(xpcall->items.back()); | ||
9045 | invoke->args.push_back(toAst<Exp_t>(funcName, x)); | ||
9046 | invoke->args.push_back(errHandler); | ||
9047 | invoke->args.dup(toAst<ExpList_t>(join(args, ","sv), x)->exprs); | ||
9048 | transformChainValue(xpcall, out, ExpUsage::Closure); | ||
9049 | } else { | ||
9050 | auto pcall = toAst<ChainValue_t>("pcall()", x); | ||
9051 | auto invoke = ast_to<Invoke_t>(pcall->items.back()); | ||
9052 | invoke->args.push_back(toAst<Exp_t>(funcName, x)); | ||
9053 | invoke->args.dup(toAst<ExpList_t>(join(args, ","sv), x)->exprs); | ||
9054 | transformChainValue(pcall, out, ExpUsage::Closure); | ||
9055 | } | ||
9056 | if (usage == ExpUsage::Common) { | ||
9057 | out.back().append(nlr(x)); | ||
9058 | } | ||
9059 | return; | ||
9060 | } | ||
9061 | } | ||
8712 | auto tryExp = toAst<Exp_t>("->"sv, x); | 9062 | auto tryExp = toAst<Exp_t>("->"sv, x); |
8713 | auto funLit = simpleSingleValueFrom(tryExp)->value.to<FunLit_t>(); | 9063 | auto funLit = simpleSingleValueFrom(tryExp)->value.to<FunLit_t>(); |
8714 | auto body = x->new_ptr<Body_t>(); | 9064 | auto body = x->new_ptr<Body_t>(); |
@@ -8806,7 +9156,7 @@ private: | |||
8806 | void transformImportFrom(ImportFrom_t* importNode, str_list& out) { | 9156 | void transformImportFrom(ImportFrom_t* importNode, str_list& out) { |
8807 | str_list temp; | 9157 | str_list temp; |
8808 | auto x = importNode; | 9158 | auto x = importNode; |
8809 | auto objVar = singleVariableFrom(importNode->item, true); | 9159 | auto objVar = singleVariableFrom(importNode->item, AccessType::Read); |
8810 | ast_ptr<false, ExpListAssign_t> objAssign; | 9160 | ast_ptr<false, ExpListAssign_t> objAssign; |
8811 | if (objVar.empty()) { | 9161 | if (objVar.empty()) { |
8812 | objVar = getUnusedName("_obj_"sv); | 9162 | objVar = getUnusedName("_obj_"sv); |
@@ -9169,8 +9519,13 @@ private: | |||
9169 | 9519 | ||
9170 | void transformWhileClosure(While_t* whileNode, str_list& out) { | 9520 | void transformWhileClosure(While_t* whileNode, str_list& out) { |
9171 | auto x = whileNode; | 9521 | auto x = whileNode; |
9522 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
9523 | simpleValue->value.set(whileNode); | ||
9524 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
9525 | return; | ||
9526 | } | ||
9172 | str_list temp; | 9527 | str_list temp; |
9173 | pushFunctionScope(); | 9528 | pushAnonFunctionScope(); |
9174 | pushAnonVarArg(); | 9529 | pushAnonVarArg(); |
9175 | std::string& funcStart = temp.emplace_back(); | 9530 | std::string& funcStart = temp.emplace_back(); |
9176 | pushScope(); | 9531 | pushScope(); |
@@ -9232,13 +9587,18 @@ private: | |||
9232 | str_list temp; | 9587 | str_list temp; |
9233 | std::string* funcStart = nullptr; | 9588 | std::string* funcStart = nullptr; |
9234 | if (usage == ExpUsage::Closure) { | 9589 | if (usage == ExpUsage::Closure) { |
9235 | pushFunctionScope(); | 9590 | auto simpleValue = x->new_ptr<SimpleValue_t>(); |
9591 | simpleValue->value.set(switchNode); | ||
9592 | if (transformAsUpValueFunc(newExp(simpleValue, x), out)) { | ||
9593 | return; | ||
9594 | } | ||
9595 | pushAnonFunctionScope(); | ||
9236 | pushAnonVarArg(); | 9596 | pushAnonVarArg(); |
9237 | funcStart = &temp.emplace_back(); | 9597 | funcStart = &temp.emplace_back(); |
9238 | pushScope(); | 9598 | pushScope(); |
9239 | } | 9599 | } |
9240 | bool extraScope = false; | 9600 | bool extraScope = false; |
9241 | auto objVar = singleVariableFrom(switchNode->target, true); | 9601 | auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); |
9242 | if (objVar.empty() || !isLocal(objVar)) { | 9602 | if (objVar.empty() || !isLocal(objVar)) { |
9243 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { | 9603 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { |
9244 | extraScope = true; | 9604 | extraScope = true; |
@@ -9285,7 +9645,7 @@ private: | |||
9285 | forceAddToScope(typeVar); | 9645 | forceAddToScope(typeVar); |
9286 | tabCheckVar = getUnusedName("_tab_"sv); | 9646 | tabCheckVar = getUnusedName("_tab_"sv); |
9287 | forceAddToScope(tabCheckVar); | 9647 | forceAddToScope(tabCheckVar); |
9288 | temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch) + '(' + objVar + ')' + nll(branch)); | 9648 | temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); |
9289 | temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); | 9649 | temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); |
9290 | } | 9650 | } |
9291 | std::string matchVar; | 9651 | std::string matchVar; |
@@ -9730,12 +10090,12 @@ private: | |||
9730 | constVal = ast_is<ConstValue_t, Num_t>(simpleVal->value); | 10090 | constVal = ast_is<ConstValue_t, Num_t>(simpleVal->value); |
9731 | } | 10091 | } |
9732 | bool localVal = false; | 10092 | bool localVal = false; |
9733 | if (auto var = singleVariableFrom(value, false); isLocal(var)) { | 10093 | if (auto var = singleVariableFrom(value, AccessType::None); isLocal(var)) { |
9734 | localVal = true; | 10094 | localVal = true; |
9735 | } | 10095 | } |
9736 | if (!constVal && !localVal) { | 10096 | if (!constVal && !localVal) { |
9737 | for (auto exp : chainAssign->exprs.objects()) { | 10097 | for (auto exp : chainAssign->exprs.objects()) { |
9738 | std::string var = singleVariableFrom(exp, false); | 10098 | std::string var = singleVariableFrom(exp, AccessType::None); |
9739 | if (!var.empty()) { | 10099 | if (!var.empty()) { |
9740 | str_list temp; | 10100 | str_list temp; |
9741 | transformAssignment(assignmentFrom(static_cast<Exp_t*>(exp), value, exp), temp); | 10101 | transformAssignment(assignmentFrom(static_cast<Exp_t*>(exp), value, exp), temp); |
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h index a781b58..8c8ea61 100644 --- a/src/yuescript/yue_compiler.h +++ b/src/yuescript/yue_compiler.h | |||
@@ -39,10 +39,18 @@ struct YueConfig { | |||
39 | Options options; | 39 | Options options; |
40 | }; | 40 | }; |
41 | 41 | ||
42 | enum class AccessType { | ||
43 | None, | ||
44 | Read, | ||
45 | Capture, | ||
46 | Write | ||
47 | }; | ||
48 | |||
42 | struct GlobalVar { | 49 | struct GlobalVar { |
43 | std::string name; | 50 | std::string name; |
44 | int line; | 51 | int line; |
45 | int col; | 52 | int col; |
53 | AccessType accessType; | ||
46 | }; | 54 | }; |
47 | 55 | ||
48 | using GlobalVars = std::vector<GlobalVar>; | 56 | using GlobalVars = std::vector<GlobalVar>; |
@@ -60,6 +68,7 @@ struct CompileInfo { | |||
60 | std::unique_ptr<Options> options; | 68 | std::unique_ptr<Options> options; |
61 | double parseTime; | 69 | double parseTime; |
62 | double compileTime; | 70 | double compileTime; |
71 | bool usedVar; | ||
63 | 72 | ||
64 | CompileInfo() { } | 73 | CompileInfo() { } |
65 | CompileInfo( | 74 | CompileInfo( |
@@ -68,7 +77,8 @@ struct CompileInfo { | |||
68 | std::unique_ptr<GlobalVars>&& globals, | 77 | std::unique_ptr<GlobalVars>&& globals, |
69 | std::unique_ptr<Options>&& options, | 78 | std::unique_ptr<Options>&& options, |
70 | double parseTime, | 79 | double parseTime, |
71 | double compileTime); | 80 | double compileTime, |
81 | bool usedVar); | ||
72 | CompileInfo(CompileInfo&& other); | 82 | CompileInfo(CompileInfo&& other); |
73 | void operator=(CompileInfo&& other); | 83 | void operator=(CompileInfo&& other); |
74 | }; | 84 | }; |