aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2024-03-19 02:22:56 +0800
committerLi Jin <dragon-fly@qq.com>2024-03-19 02:22:56 +0800
commitafc86619d710a578dc3f2bfc2ee1d62913f9abe8 (patch)
tree726ffe4d33bbaf8be411f73add51a1ffe734bc6f /src
parent4f399a181dc773bcc1a86737522915c2c776fb2b (diff)
downloadyuescript-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.cpp266
-rw-r--r--src/yuescript/yue_ast.h5
-rw-r--r--src/yuescript/yue_compiler.cpp604
-rw-r--r--src/yuescript/yue_compiler.h12
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}
196std::string MultilineCommentInner_t::to_string(void* ud) const { 196std::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}
200std::string Variable_t::to_string(void* ud) const { 200std::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}
593std::string Try_t::to_string(void* ud) const { 593std::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}
612std::string Comprehension_t::to_string(void* ud) const { 612static 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}
715std::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}
837static 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}
940std::string Invoke_t::to_string(void* ud) const { 974std::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
369AST_NODE(CatchBlock) 369AST_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)
373AST_END(CatchBlock, "catch_block"sv) 373AST_END(CatchBlock, "catch_block"sv)
374 374
375AST_NODE(Try) 375AST_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)
763AST_END(FunLit, "fun_lit"sv) 764AST_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
78const std::string_view version = "0.22.3"sv; 78const std::string_view version = "0.23.0"sv;
79const std::string_view extension = "yue"sv; 79const std::string_view extension = "yue"sv;
80 80
81class CompileError : public std::logic_error { 81class 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
106CompileInfo::CompileInfo(CompileInfo&& other) 108CompileInfo::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
42enum class AccessType {
43 None,
44 Read,
45 Capture,
46 Write
47};
48
42struct GlobalVar { 49struct 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
48using GlobalVars = std::vector<GlobalVar>; 56using 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};