diff options
Diffstat (limited to '')
| -rw-r--r-- | src/MoonP/moon_compiler.cpp | 508 |
1 files changed, 357 insertions, 151 deletions
diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp index d30f413..9164f6a 100644 --- a/src/MoonP/moon_compiler.cpp +++ b/src/MoonP/moon_compiler.cpp | |||
| @@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 15 | #include <memory> | 15 | #include <memory> |
| 16 | #include <sstream> | 16 | #include <sstream> |
| 17 | #include <string_view> | 17 | #include <string_view> |
| 18 | #include <iostream> | ||
| 18 | using namespace std::string_view_literals; | 19 | using namespace std::string_view_literals; |
| 19 | #include "MoonP/parser.hpp" | 20 | #include "MoonP/parser.hpp" |
| 20 | #include "MoonP/moon_ast.h" | 21 | #include "MoonP/moon_ast.h" |
| @@ -426,6 +427,35 @@ private: | |||
| 426 | return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back()); | 427 | return ast_is<InvokeArgs_t, Invoke_t>(chainValue->items.back()); |
| 427 | } | 428 | } |
| 428 | 429 | ||
| 430 | bool isSpecialChainValue(ChainValue_t* chainValue) { | ||
| 431 | if (ast_is<ColonChainItem_t>(chainValue->items.back())) { | ||
| 432 | return true; | ||
| 433 | } | ||
| 434 | for (auto item : chainValue->items.objects()) { | ||
| 435 | if (auto colonChain = ast_cast<ColonChainItem_t>(item)) { | ||
| 436 | if (ast_is<LuaKeyword_t>(colonChain->name)) { | ||
| 437 | return true; | ||
| 438 | } | ||
| 439 | } else if (ast_is<existential_op_t>(item) && item != chainValue->items.back()) { | ||
| 440 | return true; | ||
| 441 | } | ||
| 442 | } | ||
| 443 | return false; | ||
| 444 | } | ||
| 445 | |||
| 446 | std::string singleVariableFrom(ChainValue_t* chainValue) { | ||
| 447 | BLOCK_START | ||
| 448 | BREAK_IF(!chainValue); | ||
| 449 | BREAK_IF(chainValue->items.size() != 1); | ||
| 450 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); | ||
| 451 | BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>())); | ||
| 452 | str_list tmp; | ||
| 453 | transformCallable(callable, tmp); | ||
| 454 | return tmp.back(); | ||
| 455 | BLOCK_END | ||
| 456 | return Empty; | ||
| 457 | } | ||
| 458 | |||
| 429 | std::string singleVariableFrom(ast_node* expList) { | 459 | std::string singleVariableFrom(ast_node* expList) { |
| 430 | if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty; | 460 | if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty; |
| 431 | BLOCK_START | 461 | BLOCK_START |
| @@ -435,7 +465,7 @@ private: | |||
| 435 | BREAK_IF(!chainValue); | 465 | BREAK_IF(!chainValue); |
| 436 | BREAK_IF(chainValue->items.size() != 1); | 466 | BREAK_IF(chainValue->items.size() != 1); |
| 437 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); | 467 | auto callable = ast_cast<Callable_t>(chainValue->items.front()); |
| 438 | BREAK_IF(!callable || !callable->item.is<Variable_t>()); | 468 | BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>())); |
| 439 | str_list tmp; | 469 | str_list tmp; |
| 440 | transformCallable(callable, tmp); | 470 | transformCallable(callable, tmp); |
| 441 | return tmp.back(); | 471 | return tmp.back(); |
| @@ -443,22 +473,6 @@ private: | |||
| 443 | return Empty; | 473 | return Empty; |
| 444 | } | 474 | } |
| 445 | 475 | ||
| 446 | bool isColonChain(ChainValue_t* chainValue) { | ||
| 447 | return ast_is<ColonChainItem_t>(chainValue->items.back()); | ||
| 448 | } | ||
| 449 | |||
| 450 | bool hasKeywordColonChainItem(ChainValue_t* chainValue) { | ||
| 451 | const auto& chainList = chainValue->items.objects(); | ||
| 452 | for (auto it = chainList.begin(); it != chainList.end(); ++it) { | ||
| 453 | if (auto colonItem = ast_cast<ColonChainItem_t>(*it)) { | ||
| 454 | if (colonItem->name.is<LuaKeyword_t>()) { | ||
| 455 | return true; | ||
| 456 | } | ||
| 457 | } | ||
| 458 | } | ||
| 459 | return false; | ||
| 460 | } | ||
| 461 | |||
| 462 | bool isAssignable(const node_container& chainItems) { | 476 | bool isAssignable(const node_container& chainItems) { |
| 463 | if (chainItems.size() == 1) { | 477 | if (chainItems.size() == 1) { |
| 464 | auto firstItem = chainItems.back(); | 478 | auto firstItem = chainItems.back(); |
| @@ -539,7 +553,7 @@ private: | |||
| 539 | } | 553 | } |
| 540 | auto line = _converter.to_bytes(std::wstring(begin, end)); | 554 | auto line = _converter.to_bytes(std::wstring(begin, end)); |
| 541 | int oldCol = loc->m_begin.m_col; | 555 | int oldCol = loc->m_begin.m_col; |
| 542 | int col = loc->m_begin.m_col - 1; | 556 | int col = std::max(0, oldCol - 1); |
| 543 | auto it = begin; | 557 | auto it = begin; |
| 544 | for (int i = 0; i < oldCol; ++i) { | 558 | for (int i = 0; i < oldCol; ++i) { |
| 545 | if (*it > ASCII) { | 559 | if (*it > ASCII) { |
| @@ -558,7 +572,7 @@ private: | |||
| 558 | auto x = statement; | 572 | auto x = statement; |
| 559 | if (statement->appendix) { | 573 | if (statement->appendix) { |
| 560 | if (auto assignment = assignmentFrom(statement)) { | 574 | if (auto assignment = assignmentFrom(statement)) { |
| 561 | auto preDefine = getPredefine(transformAssignDefs(assignment->expList)); | 575 | auto preDefine = getPredefine(assignment); |
| 562 | if (!preDefine.empty()) out.push_back(preDefine + nll(statement)); | 576 | if (!preDefine.empty()) out.push_back(preDefine + nll(statement)); |
| 563 | } | 577 | } |
| 564 | auto appendix = statement->appendix.get(); | 578 | auto appendix = statement->appendix.get(); |
| @@ -790,7 +804,7 @@ private: | |||
| 790 | } | 804 | } |
| 791 | 805 | ||
| 792 | std::string getDestrucureDefine(ExpListAssign_t* assignment) { | 806 | std::string getDestrucureDefine(ExpListAssign_t* assignment) { |
| 793 | auto info = extractDestructureInfo(assignment); | 807 | auto info = extractDestructureInfo(assignment, true); |
| 794 | if (!info.first.empty()) { | 808 | if (!info.first.empty()) { |
| 795 | for (const auto& destruct : info.first) { | 809 | for (const auto& destruct : info.first) { |
| 796 | str_list defs; | 810 | str_list defs; |
| @@ -909,11 +923,10 @@ private: | |||
| 909 | } | 923 | } |
| 910 | case "With"_id: { | 924 | case "With"_id: { |
| 911 | auto withNode = static_cast<With_t*>(value); | 925 | auto withNode = static_cast<With_t*>(value); |
| 912 | str_list temp; | ||
| 913 | auto expList = assignment->expList.get(); | 926 | auto expList = assignment->expList.get(); |
| 914 | std::string preDefine = getPredefine(assignment); | 927 | std::string preDefine = getPredefine(assignment); |
| 915 | transformWith(withNode, temp, expList); | 928 | transformWith(withNode, out, expList); |
| 916 | out.push_back(preDefine + temp.back()); | 929 | out.back() = preDefine + out.back(); |
| 917 | return; | 930 | return; |
| 918 | } | 931 | } |
| 919 | case "Do"_id: { | 932 | case "Do"_id: { |
| @@ -940,50 +953,42 @@ private: | |||
| 940 | return; | 953 | return; |
| 941 | } | 954 | } |
| 942 | case "For"_id: { | 955 | case "For"_id: { |
| 943 | str_list temp; | ||
| 944 | auto expList = assignment->expList.get(); | 956 | auto expList = assignment->expList.get(); |
| 945 | std::string preDefine = getPredefine(assignment); | 957 | std::string preDefine = getPredefine(assignment); |
| 946 | transformForInPlace(static_cast<For_t*>(value), temp, expList); | 958 | transformForInPlace(static_cast<For_t*>(value), out, expList); |
| 947 | out.push_back(preDefine + temp.back()); | 959 | out.back() = preDefine + out.back(); |
| 948 | return; | 960 | return; |
| 949 | } | 961 | } |
| 950 | case "ForEach"_id: { | 962 | case "ForEach"_id: { |
| 951 | str_list temp; | ||
| 952 | auto expList = assignment->expList.get(); | 963 | auto expList = assignment->expList.get(); |
| 953 | std::string preDefine = getPredefine(assignment); | 964 | std::string preDefine = getPredefine(assignment); |
| 954 | transformForEachInPlace(static_cast<ForEach_t*>(value), temp, expList); | 965 | transformForEachInPlace(static_cast<ForEach_t*>(value), out, expList); |
| 955 | out.push_back(preDefine + temp.back()); | 966 | out.back() = preDefine + out.back(); |
| 956 | return; | 967 | return; |
| 957 | } | 968 | } |
| 958 | case "ClassDecl"_id: { | 969 | case "ClassDecl"_id: { |
| 959 | str_list temp; | ||
| 960 | auto expList = assignment->expList.get(); | 970 | auto expList = assignment->expList.get(); |
| 961 | std::string preDefine = getPredefine(assignment); | 971 | std::string preDefine = getPredefine(assignment); |
| 962 | transformClassDecl(static_cast<ClassDecl_t*>(value), temp, ExpUsage::Assignment, expList); | 972 | transformClassDecl(static_cast<ClassDecl_t*>(value), out, ExpUsage::Assignment, expList); |
| 963 | out.push_back(preDefine + temp.back()); | 973 | out.back() = preDefine + out.back(); |
| 964 | return; | 974 | return; |
| 965 | } | 975 | } |
| 966 | case "While"_id: { | 976 | case "While"_id: { |
| 967 | str_list temp; | ||
| 968 | auto expList = assignment->expList.get(); | 977 | auto expList = assignment->expList.get(); |
| 969 | std::string preDefine = getPredefine(assignment); | 978 | std::string preDefine = getPredefine(assignment); |
| 970 | transformWhileInPlace(static_cast<While_t*>(value), temp, expList); | 979 | transformWhileInPlace(static_cast<While_t*>(value), out, expList); |
| 971 | out.push_back(preDefine + temp.back()); | 980 | out.back() = preDefine + out.back(); |
| 972 | return; | 981 | return; |
| 973 | } | 982 | } |
| 974 | } | 983 | } |
| 975 | auto exp = ast_cast<Exp_t>(value); | 984 | auto exp = ast_cast<Exp_t>(value); |
| 976 | BREAK_IF(!exp); | 985 | BREAK_IF(!exp); |
| 977 | if (auto chainValue = exp->value->item.as<ChainValue_t>()) { | 986 | if (auto chainValue = exp->value->item.as<ChainValue_t>()) { |
| 978 | if (isColonChain(chainValue)) { | 987 | if (isSpecialChainValue(chainValue)) { |
| 979 | auto assignable = assignment->expList.get(); | 988 | auto expList = assignment->expList.get(); |
| 980 | std::string preDefine = getPredefine(transformAssignDefs(assignable)); | 989 | std::string preDefine = getPredefine(assignment); |
| 981 | transformColonChain(chainValue, out, ExpUsage::Assignment, assignable); | 990 | transformChainValue(chainValue, out, ExpUsage::Assignment, expList); |
| 982 | auto nl = preDefine.empty() ? Empty : nll(chainValue); | 991 | out.back() = preDefine + out.back(); |
| 983 | if (!preDefine.empty()) out.back() = preDefine + nl + out.back(); | ||
| 984 | return; | ||
| 985 | } else if (hasKeywordColonChainItem(chainValue)) { | ||
| 986 | transformChainValue(chainValue, out, ExpUsage::Assignment, assignment->expList); | ||
| 987 | return; | 992 | return; |
| 988 | } | 993 | } |
| 989 | } | 994 | } |
| @@ -1169,7 +1174,7 @@ private: | |||
| 1169 | } | 1174 | } |
| 1170 | 1175 | ||
| 1171 | std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> | 1176 | std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> |
| 1172 | extractDestructureInfo(ExpListAssign_t* assignment) { | 1177 | extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly = false) { |
| 1173 | auto x = assignment; | 1178 | auto x = assignment; |
| 1174 | std::list<Destructure> destructs; | 1179 | std::list<Destructure> destructs; |
| 1175 | if (!assignment->action.is<Assign_t>()) return { destructs, nullptr }; | 1180 | if (!assignment->action.is<Assign_t>()) return { destructs, nullptr }; |
| @@ -1187,19 +1192,21 @@ private: | |||
| 1187 | while (values.size() < size) values.emplace_back(nullNode); | 1192 | while (values.size() < size) values.emplace_back(nullNode); |
| 1188 | } | 1193 | } |
| 1189 | using iter = node_container::iterator; | 1194 | using iter = node_container::iterator; |
| 1190 | std::vector<std::pair<iter, iter>> destructPairs; | 1195 | std::vector<std::pair<iter,iter>> destructPairs; |
| 1191 | str_list temp; | 1196 | str_list temp; |
| 1192 | for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { | 1197 | for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { |
| 1193 | auto expr = *i; | 1198 | auto expr = *i; |
| 1194 | ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>(); | 1199 | ast_node* destructNode = expr->getByPath<Value_t, SimpleValue_t, TableLit_t>(); |
| 1195 | if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) { | 1200 | if (destructNode || (destructNode = expr->getByPath<Value_t, simple_table_t>())) { |
| 1196 | destructPairs.push_back({i,j}); | 1201 | destructPairs.push_back({i,j}); |
| 1197 | pushScope(); | ||
| 1198 | transformAssignItem(*j, temp); | ||
| 1199 | popScope(); | ||
| 1200 | auto& destruct = destructs.emplace_back(); | 1202 | auto& destruct = destructs.emplace_back(); |
| 1201 | destruct.value = temp.back(); | 1203 | if (!varDefOnly) { |
| 1202 | temp.pop_back(); | 1204 | pushScope(); |
| 1205 | transformAssignItem(*j, temp); | ||
| 1206 | destruct.value = temp.back(); | ||
| 1207 | temp.pop_back(); | ||
| 1208 | popScope(); | ||
| 1209 | } | ||
| 1203 | auto pairs = destructFromExp(expr); | 1210 | auto pairs = destructFromExp(expr); |
| 1204 | destruct.items = std::move(pairs); | 1211 | destruct.items = std::move(pairs); |
| 1205 | } | 1212 | } |
| @@ -1244,7 +1251,7 @@ private: | |||
| 1244 | BREAK_IF(!exp); | 1251 | BREAK_IF(!exp); |
| 1245 | auto var = singleVariableFrom(exp); | 1252 | auto var = singleVariableFrom(exp); |
| 1246 | BREAK_IF(!var.empty()); | 1253 | BREAK_IF(!var.empty()); |
| 1247 | auto upVar = getUnusedName("_update_"); | 1254 | auto upVar = getUnusedName("_update_"sv); |
| 1248 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 1255 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 1249 | assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x)); | 1256 | assignment->expList.set(toAst<ExpList_t>(upVar, ExpList, x)); |
| 1250 | auto assign = x->new_ptr<Assign_t>(); | 1257 | auto assign = x->new_ptr<Assign_t>(); |
| @@ -1532,11 +1539,7 @@ private: | |||
| 1532 | case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break; | 1539 | case "simple_table"_id: transform_simple_table(static_cast<simple_table_t*>(item), out); break; |
| 1533 | case "ChainValue"_id: { | 1540 | case "ChainValue"_id: { |
| 1534 | auto chainValue = static_cast<ChainValue_t*>(item); | 1541 | auto chainValue = static_cast<ChainValue_t*>(item); |
| 1535 | if (isColonChain(chainValue)) { | 1542 | transformChainValue(chainValue, out); |
| 1536 | transformColonChainClosure(chainValue, out); | ||
| 1537 | } else { | ||
| 1538 | transformChainValue(chainValue, out); | ||
| 1539 | } | ||
| 1540 | break; | 1543 | break; |
| 1541 | } | 1544 | } |
| 1542 | case "String"_id: transformString(static_cast<String_t*>(item), out); break; | 1545 | case "String"_id: transformString(static_cast<String_t*>(item), out); break; |
| @@ -1689,7 +1692,7 @@ private: | |||
| 1689 | any->decls.push_back(var); | 1692 | any->decls.push_back(var); |
| 1690 | } | 1693 | } |
| 1691 | } | 1694 | } |
| 1692 | auto info = extractDestructureInfo(assignment); | 1695 | auto info = extractDestructureInfo(assignment, true); |
| 1693 | if (!info.first.empty()) { | 1696 | if (!info.first.empty()) { |
| 1694 | for (const auto& destruct : info.first) | 1697 | for (const auto& destruct : info.first) |
| 1695 | for (const auto& item : destruct.items) | 1698 | for (const auto& item : destruct.items) |
| @@ -1803,12 +1806,10 @@ private: | |||
| 1803 | } | 1806 | } |
| 1804 | } | 1807 | } |
| 1805 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { | 1808 | if (auto chainValue = singleValue->item.as<ChainValue_t>()) { |
| 1806 | if (isColonChain(chainValue)) { | 1809 | if (isSpecialChainValue(chainValue)) { |
| 1807 | transformColonChain(chainValue, out, ExpUsage::Return); | ||
| 1808 | } else { | ||
| 1809 | transformChainValue(chainValue, out, ExpUsage::Return); | 1810 | transformChainValue(chainValue, out, ExpUsage::Return); |
| 1811 | return; | ||
| 1810 | } | 1812 | } |
| 1811 | return; | ||
| 1812 | } | 1813 | } |
| 1813 | transformValue(singleValue, out); | 1814 | transformValue(singleValue, out); |
| 1814 | out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode); | 1815 | out.back() = indent() + s("return "sv) + out.back() + nlr(returnNode); |
| @@ -1980,111 +1981,292 @@ private: | |||
| 1980 | } | 1981 | } |
| 1981 | } | 1982 | } |
| 1982 | 1983 | ||
| 1983 | void transformColonChainClosure(ChainValue_t* chainValue, str_list& out) { | 1984 | bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t*) { |
| 1984 | str_list temp; | 1985 | auto x = chainList.front(); |
| 1985 | temp.push_back(s("(function()"sv) + nll(chainValue)); | 1986 | if (ast_cast<existential_op_t>(chainList.back())) { |
| 1986 | pushScope(); | 1987 | auto parens = x->new_ptr<Parens_t>(); |
| 1987 | transformColonChain(chainValue, temp, ExpUsage::Return); | 1988 | { |
| 1988 | popScope(); | 1989 | auto chainValue = x->new_ptr<ChainValue_t>(); |
| 1989 | temp.push_back(indent() + s("end)()"sv)); | 1990 | for (auto item : chainList) { |
| 1990 | out.push_back(join(temp)); | 1991 | chainValue->items.push_back(item); |
| 1992 | } | ||
| 1993 | chainValue->items.pop_back(); | ||
| 1994 | auto value = x->new_ptr<Value_t>(); | ||
| 1995 | value->item.set(chainValue); | ||
| 1996 | auto opValue = x->new_ptr<exp_op_value_t>(); | ||
| 1997 | opValue->op.set(toAst<BinaryOperator_t>("!="sv, BinaryOperator, x)); | ||
| 1998 | opValue->value.set(toAst<Value_t>("nil"sv, Value, x)); | ||
| 1999 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2000 | exp->value.set(value); | ||
| 2001 | exp->opValues.push_back(opValue); | ||
| 2002 | parens->expr.set(exp); | ||
| 2003 | } | ||
| 2004 | transformParens(parens, out); | ||
| 2005 | if (usage == ExpUsage::Return) { | ||
| 2006 | out.back().insert(0, indent() + s("return "sv)); | ||
| 2007 | out.back().append(nlr(x)); | ||
| 2008 | } | ||
| 2009 | return true; | ||
| 2010 | } | ||
| 2011 | return false; | ||
| 1991 | } | 2012 | } |
| 1992 | 2013 | ||
| 1993 | void transformColonChain(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Common, ExpList_t* expList = nullptr) { | 2014 | bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { |
| 1994 | auto x = chainValue; | 2015 | auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is<existential_op_t>(node); }); |
| 1995 | const auto& chainList = chainValue->items.objects(); | 2016 | if (opIt != chainList.end()) { |
| 1996 | auto baseChain = x->new_ptr<ChainValue_t>(); | 2017 | auto x = chainList.front(); |
| 1997 | switch (chainList.front()->getId()) { | 2018 | str_list temp; |
| 1998 | case "DotChainItem"_id: | 2019 | if (usage == ExpUsage::Closure) { |
| 1999 | case "ColonChainItem"_id: | 2020 | temp.push_back(s("(function()"sv) + nll(x)); |
| 2000 | if (_withVars.empty()) { | 2021 | pushScope(); |
| 2001 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); | 2022 | } |
| 2002 | } else { | 2023 | auto partOne = x->new_ptr<ChainValue_t>(); |
| 2003 | baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | 2024 | for (auto it = chainList.begin();it != opIt;++it) { |
| 2004 | } | 2025 | partOne->items.push_back(*it); |
| 2026 | } | ||
| 2027 | BLOCK_START | ||
| 2028 | auto back = ast_cast<Callable_t>(partOne->items.back()); | ||
| 2029 | BREAK_IF(!back); | ||
| 2030 | auto selfName = ast_cast<SelfName_t>(back->item); | ||
| 2031 | BREAK_IF(!selfName); | ||
| 2032 | if (auto sname = ast_cast<self_name_t>(selfName->name)) { | ||
| 2033 | auto colonItem = x->new_ptr<ColonChainItem_t>(); | ||
| 2034 | colonItem->name.set(sname->name); | ||
| 2035 | partOne->items.pop_back(); | ||
| 2036 | partOne->items.push_back(toAst<Callable_t>("@"sv, Callable, x)); | ||
| 2037 | partOne->items.push_back(colonItem); | ||
| 2005 | break; | 2038 | break; |
| 2006 | } | 2039 | } |
| 2007 | auto end = --chainList.end(); | 2040 | if (auto cname = ast_cast<self_class_name_t>(selfName->name)) { |
| 2008 | for (auto it = chainList.begin(); it != end; ++it) { | 2041 | auto colonItem = x->new_ptr<ColonChainItem_t>(); |
| 2009 | baseChain->items.push_back(*it); | 2042 | colonItem->name.set(cname->name); |
| 2010 | } | 2043 | partOne->items.pop_back(); |
| 2011 | auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back()); | 2044 | partOne->items.push_back(toAst<Callable_t>("@@"sv, Callable, x)); |
| 2012 | auto funcName = toString(colonChainItem->name); | 2045 | partOne->items.push_back(colonItem); |
| 2013 | if (usage != ExpUsage::Return) pushScope(); | ||
| 2014 | auto baseVar = getUnusedName("_base_"sv); | ||
| 2015 | auto fnVar = getUnusedName("_fn_"sv); | ||
| 2016 | str_list temp; | ||
| 2017 | { | ||
| 2018 | auto value = x->new_ptr<Value_t>(); | ||
| 2019 | value->item.set(baseChain); | ||
| 2020 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2021 | exp->value.set(value); | ||
| 2022 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2023 | assign->values.push_back(exp); | ||
| 2024 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2025 | assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x)); | ||
| 2026 | assignment->action.set(assign); | ||
| 2027 | transformAssignment(assignment, temp); | ||
| 2028 | } | ||
| 2029 | { | ||
| 2030 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2031 | assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x)); | ||
| 2032 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2033 | assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x)); | ||
| 2034 | assignment->action.set(assign); | ||
| 2035 | transformAssignment(assignment, temp); | ||
| 2036 | } | ||
| 2037 | auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x); | ||
| 2038 | switch (usage) { | ||
| 2039 | case ExpUsage::Return: | ||
| 2040 | transformExp(funLit, temp); | ||
| 2041 | _buf << temp.front(); | ||
| 2042 | _buf << *(++temp.begin()); | ||
| 2043 | _buf << indent() << "return " << temp.back() << nll(chainValue); | ||
| 2044 | break; | 2046 | break; |
| 2045 | case ExpUsage::Assignment: { | 2047 | } |
| 2048 | BLOCK_END | ||
| 2049 | auto objVar = singleVariableFrom(partOne); | ||
| 2050 | if (objVar.empty()) { | ||
| 2051 | objVar = getUnusedName("_obj_"sv); | ||
| 2052 | if (auto colonItem = ast_cast<ColonChainItem_t>(partOne->items.back())) { | ||
| 2053 | auto chainValue = x->new_ptr<ChainValue_t>(); | ||
| 2054 | chainValue->items.dup(partOne->items); | ||
| 2055 | chainValue->items.pop_back(); | ||
| 2056 | if (chainValue->items.empty()) { | ||
| 2057 | if (_withVars.empty()) { | ||
| 2058 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x)); | ||
| 2059 | } | ||
| 2060 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | ||
| 2061 | } | ||
| 2062 | auto newObj = singleVariableFrom(chainValue); | ||
| 2063 | if (!newObj.empty()) { | ||
| 2064 | objVar = newObj; | ||
| 2065 | } else { | ||
| 2066 | auto value = x->new_ptr<Value_t>(); | ||
| 2067 | value->item.set(chainValue); | ||
| 2068 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2069 | exp->value.set(value); | ||
| 2070 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2071 | assign->values.push_back(exp); | ||
| 2072 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
| 2073 | expListAssign->expList.set(toAst<ExpList_t>(objVar, ExpList, x)); | ||
| 2074 | expListAssign->action.set(assign); | ||
| 2075 | transformAssignment(expListAssign, temp); | ||
| 2076 | } | ||
| 2077 | auto dotItem = x->new_ptr<DotChainItem_t>(); | ||
| 2078 | auto name = colonItem->name.get(); | ||
| 2079 | if (auto keyword = ast_cast<LuaKeyword_t>(name)) { | ||
| 2080 | name = keyword->name.get(); | ||
| 2081 | } | ||
| 2082 | dotItem->name.set(name); | ||
| 2083 | partOne->items.clear(); | ||
| 2084 | partOne->items.push_back(toAst<Callable_t>(objVar, Callable, x)); | ||
| 2085 | partOne->items.push_back(dotItem); | ||
| 2086 | auto it = opIt; ++it; | ||
| 2087 | if (it != chainList.end() && ast_is<Invoke_t, InvokeArgs_t>(*it)) { | ||
| 2088 | |||
| 2089 | if (auto invoke = ast_cast<Invoke_t>(*it)) { | ||
| 2090 | invoke->args.push_front(toAst<Exp_t>(objVar, Exp, x)); | ||
| 2091 | } else { | ||
| 2092 | auto invokeArgs = static_cast<InvokeArgs_t*>(*it); | ||
| 2093 | invokeArgs->args.push_front(toAst<Exp_t>(objVar, Exp, x)); | ||
| 2094 | } | ||
| 2095 | } | ||
| 2096 | objVar = getUnusedName("_obj_"sv); | ||
| 2097 | } | ||
| 2098 | auto value = x->new_ptr<Value_t>(); | ||
| 2099 | value->item.set(partOne); | ||
| 2100 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2101 | exp->value.set(value); | ||
| 2102 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2103 | assign->values.push_back(exp); | ||
| 2104 | auto expListAssign = x->new_ptr<ExpListAssign_t>(); | ||
| 2105 | expListAssign->expList.set(toAst<ExpList_t>(objVar, ExpList, x)); | ||
| 2106 | expListAssign->action.set(assign); | ||
| 2107 | transformAssignment(expListAssign, temp); | ||
| 2108 | } | ||
| 2109 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | ||
| 2110 | temp.push_back(clearBuf()); | ||
| 2111 | pushScope(); | ||
| 2112 | auto partTwo = x->new_ptr<ChainValue_t>(); | ||
| 2113 | partTwo->items.push_back(toAst<Callable_t>(objVar, Callable, x)); | ||
| 2114 | for (auto it = ++opIt;it != chainList.end();++it) { | ||
| 2115 | partTwo->items.push_back(*it); | ||
| 2116 | } | ||
| 2117 | switch (usage) { | ||
| 2118 | case ExpUsage::Common: | ||
| 2119 | transformChainValue(partTwo, temp, ExpUsage::Common); | ||
| 2120 | break; | ||
| 2121 | case ExpUsage::Assignment: { | ||
| 2122 | auto value = x->new_ptr<Value_t>(); | ||
| 2123 | value->item.set(partTwo); | ||
| 2124 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2125 | exp->value.set(value); | ||
| 2126 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2127 | assign->values.push_back(exp); | ||
| 2128 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2129 | assignment->expList.set(assignList); | ||
| 2130 | assignment->action.set(assign); | ||
| 2131 | transformAssignment(assignment, temp); | ||
| 2132 | break; | ||
| 2133 | } | ||
| 2134 | case ExpUsage::Return: | ||
| 2135 | case ExpUsage::Closure: { | ||
| 2136 | auto value = x->new_ptr<Value_t>(); | ||
| 2137 | value->item.set(partTwo); | ||
| 2138 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2139 | exp->value.set(value); | ||
| 2140 | auto ret = x->new_ptr<Return_t>(); | ||
| 2141 | auto expListLow = x->new_ptr<ExpListLow_t>(); | ||
| 2142 | expListLow->exprs.push_back(exp); | ||
| 2143 | ret->valueList.set(expListLow); | ||
| 2144 | transformReturn(ret, temp); | ||
| 2145 | break; | ||
| 2146 | } | ||
| 2147 | } | ||
| 2148 | popScope(); | ||
| 2149 | temp.push_back(indent() + s("end"sv) + nlr(x)); | ||
| 2150 | switch (usage) { | ||
| 2151 | case ExpUsage::Return: | ||
| 2152 | temp.push_back(indent() + s("return nil"sv) + nlr(x)); | ||
| 2153 | break; | ||
| 2154 | case ExpUsage::Closure: | ||
| 2155 | temp.push_back(indent() + s("return nil"sv) + nlr(x)); | ||
| 2156 | popScope(); | ||
| 2157 | temp.push_back(indent() + s("end)()"sv)); | ||
| 2158 | break; | ||
| 2159 | default: | ||
| 2160 | break; | ||
| 2161 | } | ||
| 2162 | out.push_back(join(temp)); | ||
| 2163 | return true; | ||
| 2164 | } | ||
| 2165 | return false; | ||
| 2166 | } | ||
| 2167 | |||
| 2168 | bool transformChainEndWithColonItem(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { | ||
| 2169 | if (ast_is<ColonChainItem_t>(chainList.back())) { | ||
| 2170 | auto x = chainList.front(); | ||
| 2171 | str_list temp; | ||
| 2172 | switch (usage) { | ||
| 2173 | case ExpUsage::Assignment: | ||
| 2174 | temp.push_back(indent() + s("do"sv) + nll(x)); | ||
| 2175 | pushScope(); | ||
| 2176 | break; | ||
| 2177 | case ExpUsage::Closure: | ||
| 2178 | temp.push_back(s("(function()"sv) + nll(x)); | ||
| 2179 | pushScope(); | ||
| 2180 | break; | ||
| 2181 | default: | ||
| 2182 | break; | ||
| 2183 | } | ||
| 2184 | auto baseChain = x->new_ptr<ChainValue_t>(); | ||
| 2185 | switch (chainList.front()->getId()) { | ||
| 2186 | case "DotChainItem"_id: | ||
| 2187 | case "ColonChainItem"_id: | ||
| 2188 | if (_withVars.empty()) { | ||
| 2189 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); | ||
| 2190 | } else { | ||
| 2191 | baseChain->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | ||
| 2192 | } | ||
| 2193 | break; | ||
| 2194 | } | ||
| 2195 | auto end = --chainList.end(); | ||
| 2196 | for (auto it = chainList.begin(); it != end; ++it) { | ||
| 2197 | baseChain->items.push_back(*it); | ||
| 2198 | } | ||
| 2199 | auto colonChainItem = static_cast<ColonChainItem_t*>(chainList.back()); | ||
| 2200 | auto funcName = toString(colonChainItem->name); | ||
| 2201 | auto baseVar = getUnusedName("_base_"sv); | ||
| 2202 | auto fnVar = getUnusedName("_fn_"sv); | ||
| 2203 | { | ||
| 2204 | auto value = x->new_ptr<Value_t>(); | ||
| 2205 | value->item.set(baseChain); | ||
| 2206 | auto exp = x->new_ptr<Exp_t>(); | ||
| 2207 | exp->value.set(value); | ||
| 2046 | auto assign = x->new_ptr<Assign_t>(); | 2208 | auto assign = x->new_ptr<Assign_t>(); |
| 2047 | assign->values.push_back(funLit); | 2209 | assign->values.push_back(exp); |
| 2048 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 2210 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 2049 | assignment->expList.set(expList); | 2211 | assignment->expList.set(toAst<ExpList_t>(baseVar, ExpList, x)); |
| 2050 | assignment->action.set(assign); | 2212 | assignment->action.set(assign); |
| 2051 | transformAssignment(assignment, temp); | 2213 | transformAssignment(assignment, temp); |
| 2052 | _buf << indent(-1) << "do"sv << nll(chainValue); | ||
| 2053 | _buf << temp.front(); | ||
| 2054 | _buf << *(++temp.begin()); | ||
| 2055 | _buf << temp.back(); | ||
| 2056 | popScope(); | ||
| 2057 | _buf << indent() << "end"sv << nll(chainValue); | ||
| 2058 | break; | ||
| 2059 | } | 2214 | } |
| 2060 | case ExpUsage::Common: { | 2215 | { |
| 2061 | auto assign = x->new_ptr<Assign_t>(); | 2216 | auto assign = x->new_ptr<Assign_t>(); |
| 2062 | assign->values.push_back(funLit); | 2217 | assign->values.push_back(toAst<Exp_t>(baseVar + "." + funcName, Exp, x)); |
| 2063 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 2218 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 2064 | assignment->expList.set(toAst<ExpList_t>("_"sv, ExpList, x)); | 2219 | assignment->expList.set(toAst<ExpList_t>(fnVar, ExpList, x)); |
| 2065 | assignment->action.set(assign); | 2220 | assignment->action.set(assign); |
| 2066 | transformAssignment(assignment, temp); | 2221 | transformAssignment(assignment, temp); |
| 2067 | _buf << indent(-1) << "do"sv << nll(chainValue); | ||
| 2068 | _buf << temp.front(); | ||
| 2069 | _buf << *(++temp.begin()); | ||
| 2070 | _buf << temp.back(); | ||
| 2071 | popScope(); | ||
| 2072 | _buf << indent() << "end"sv << nll(chainValue); | ||
| 2073 | break; | ||
| 2074 | } | 2222 | } |
| 2075 | default: break; | 2223 | auto funLit = toAst<Exp_t>(s("(...)-> "sv) + fnVar + s(" "sv) + baseVar + s(", ..."sv), Exp, x); |
| 2224 | switch (usage) { | ||
| 2225 | case ExpUsage::Closure: | ||
| 2226 | case ExpUsage::Return: | ||
| 2227 | transformExp(funLit, temp); | ||
| 2228 | _buf << temp.front(); | ||
| 2229 | _buf << *(++temp.begin()); | ||
| 2230 | _buf << indent() << "return " << temp.back() << nll(x); | ||
| 2231 | break; | ||
| 2232 | case ExpUsage::Assignment: { | ||
| 2233 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2234 | assign->values.push_back(funLit); | ||
| 2235 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2236 | assignment->expList.set(assignList); | ||
| 2237 | assignment->action.set(assign); | ||
| 2238 | transformAssignment(assignment, temp); | ||
| 2239 | break; | ||
| 2240 | } | ||
| 2241 | default: | ||
| 2242 | break; | ||
| 2243 | } | ||
| 2244 | switch (usage) { | ||
| 2245 | case ExpUsage::Assignment: | ||
| 2246 | popScope(); | ||
| 2247 | temp.push_back(indent() + s("end"sv) + nlr(x)); | ||
| 2248 | break; | ||
| 2249 | case ExpUsage::Closure: | ||
| 2250 | popScope(); | ||
| 2251 | temp.push_back(indent() + s("end)()"sv)); | ||
| 2252 | break; | ||
| 2253 | default: | ||
| 2254 | break; | ||
| 2255 | } | ||
| 2256 | out.push_back(join(temp)); | ||
| 2257 | return true; | ||
| 2076 | } | 2258 | } |
| 2077 | out.push_back(clearBuf()); | 2259 | return false; |
| 2078 | } | 2260 | } |
| 2079 | 2261 | ||
| 2080 | void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 2262 | void transformChainList(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 2081 | auto x = chainList.front(); | 2263 | auto x = chainList.front(); |
| 2082 | str_list temp; | 2264 | str_list temp; |
| 2083 | switch (chainList.front()->getId()) { | 2265 | switch (x->getId()) { |
| 2084 | case "DotChainItem"_id: | 2266 | case "DotChainItem"_id: |
| 2085 | case "ColonChainItem"_id: | 2267 | case "ColonChainItem"_id: |
| 2086 | if (_withVars.empty()) { | 2268 | if (_withVars.empty()) { |
| 2087 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, chainList.front())); | 2269 | throw std::logic_error(debugInfo("Short dot/colon syntax must be called within a with block."sv, x)); |
| 2088 | } else { | 2270 | } else { |
| 2089 | temp.push_back(_withVars.top()); | 2271 | temp.push_back(_withVars.top()); |
| 2090 | } | 2272 | } |
| @@ -2101,8 +2283,20 @@ private: | |||
| 2101 | break; | 2283 | break; |
| 2102 | case "ColonChainItem"_id: { | 2284 | case "ColonChainItem"_id: { |
| 2103 | auto colonItem = static_cast<ColonChainItem_t*>(item); | 2285 | auto colonItem = static_cast<ColonChainItem_t*>(item); |
| 2104 | auto next = it; ++next; | 2286 | auto current = it; |
| 2287 | auto next = current; ++next; | ||
| 2105 | auto followItem = next != chainList.end() ? *next : nullptr; | 2288 | auto followItem = next != chainList.end() ? *next : nullptr; |
| 2289 | if (current != chainList.begin()) { | ||
| 2290 | --current; | ||
| 2291 | if (!ast_is<existential_op_t>(*current)) { | ||
| 2292 | ++current; | ||
| 2293 | } | ||
| 2294 | } | ||
| 2295 | if (ast_is<existential_op_t>(followItem)) { | ||
| 2296 | ++next; | ||
| 2297 | followItem = next != chainList.end() ? *next : nullptr; | ||
| 2298 | --next; | ||
| 2299 | } | ||
| 2106 | if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) { | 2300 | if (!ast_is<Invoke_t, InvokeArgs_t>(followItem)) { |
| 2107 | throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem)); | 2301 | throw std::logic_error(debugInfo("Colon chain item must be followed by invoke arguments."sv, colonItem)); |
| 2108 | } | 2302 | } |
| @@ -2117,7 +2311,7 @@ private: | |||
| 2117 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); | 2311 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), Callable, x)); |
| 2118 | break; | 2312 | break; |
| 2119 | } | 2313 | } |
| 2120 | for (auto i = chainList.begin(); i != it; ++i) { | 2314 | for (auto i = chainList.begin(); i != current; ++i) { |
| 2121 | chainValue->items.push_back(*i); | 2315 | chainValue->items.push_back(*i); |
| 2122 | } | 2316 | } |
| 2123 | auto value = x->new_ptr<Value_t>(); | 2317 | auto value = x->new_ptr<Value_t>(); |
| @@ -2141,6 +2335,9 @@ private: | |||
| 2141 | auto name = toString(colonItem->name); | 2335 | auto name = toString(colonItem->name); |
| 2142 | auto chainValue = x->new_ptr<ChainValue_t>(); | 2336 | auto chainValue = x->new_ptr<ChainValue_t>(); |
| 2143 | chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x)); | 2337 | chainValue->items.push_back(toAst<Callable_t>(callVar, Callable, x)); |
| 2338 | if (ast_is<existential_op_t>(*current)) { | ||
| 2339 | chainValue->items.push_back(x->new_ptr<existential_op_t>()); | ||
| 2340 | } | ||
| 2144 | chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x)); | 2341 | chainValue->items.push_back(toAst<Exp_t>(s("\""sv) + name + s("\""sv), Exp, x)); |
| 2145 | if (auto invoke = ast_cast<Invoke_t>(followItem)) { | 2342 | if (auto invoke = ast_cast<Invoke_t>(followItem)) { |
| 2146 | invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x)); | 2343 | invoke->args.push_front(toAst<Exp_t>(callVar, Exp, x)); |
| @@ -2148,8 +2345,7 @@ private: | |||
| 2148 | auto invokeArgs = static_cast<InvokeArgs_t*>(followItem); | 2345 | auto invokeArgs = static_cast<InvokeArgs_t*>(followItem); |
| 2149 | invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x)); | 2346 | invokeArgs->args.push_front(toAst<Exp_t>(callVar, Exp, x)); |
| 2150 | } | 2347 | } |
| 2151 | chainValue->items.push_back(followItem); | 2348 | for (auto i = next; i != chainList.end(); ++i) { |
| 2152 | for (auto i = ++next; i != chainList.end(); ++i) { | ||
| 2153 | chainValue->items.push_back(*i); | 2349 | chainValue->items.push_back(*i); |
| 2154 | } | 2350 | } |
| 2155 | auto value = x->new_ptr<Value_t>(); | 2351 | auto value = x->new_ptr<Value_t>(); |
| @@ -2244,7 +2440,17 @@ private: | |||
| 2244 | } | 2440 | } |
| 2245 | 2441 | ||
| 2246 | void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) { | 2442 | void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage = ExpUsage::Closure, ExpList_t* assignList = nullptr) { |
| 2247 | transformChainList(chainValue->items.objects(), out, usage, assignList); | 2443 | const auto& chainList = chainValue->items.objects(); |
| 2444 | if (transformChainEndWithEOP(chainList, out, usage, assignList)) { | ||
| 2445 | return; | ||
| 2446 | } | ||
| 2447 | if (transformChainWithEOP(chainList, out, usage, assignList)) { | ||
| 2448 | return; | ||
| 2449 | } | ||
| 2450 | if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { | ||
| 2451 | return; | ||
| 2452 | } | ||
| 2453 | transformChainList(chainList, out, usage, assignList); | ||
| 2248 | } | 2454 | } |
| 2249 | 2455 | ||
| 2250 | void transformAssignableChain(AssignableChain_t* chain, str_list& out) { | 2456 | void transformAssignableChain(AssignableChain_t* chain, str_list& out) { |
| @@ -2957,7 +3163,7 @@ private: | |||
| 2957 | if (auto assignment = assignmentFrom(statement)) { | 3163 | if (auto assignment = assignmentFrom(statement)) { |
| 2958 | auto names = transformAssignDefs(assignment->expList.get()); | 3164 | auto names = transformAssignDefs(assignment->expList.get()); |
| 2959 | varDefs.insert(varDefs.end(), names.begin(), names.end()); | 3165 | varDefs.insert(varDefs.end(), names.begin(), names.end()); |
| 2960 | auto info = extractDestructureInfo(assignment); | 3166 | auto info = extractDestructureInfo(assignment, true); |
| 2961 | if (!info.first.empty()) { | 3167 | if (!info.first.empty()) { |
| 2962 | for (const auto& destruct : info.first) | 3168 | for (const auto& destruct : info.first) |
| 2963 | for (const auto& item : destruct.items) | 3169 | for (const auto& item : destruct.items) |
| @@ -3342,7 +3548,7 @@ private: | |||
| 3342 | if (!names.empty()) { | 3548 | if (!names.empty()) { |
| 3343 | return traversal::Stop; | 3549 | return traversal::Stop; |
| 3344 | } | 3550 | } |
| 3345 | auto info = extractDestructureInfo(assignment); | 3551 | auto info = extractDestructureInfo(assignment, true); |
| 3346 | if (!info.first.empty()) { | 3552 | if (!info.first.empty()) { |
| 3347 | for (const auto& destruct : info.first) | 3553 | for (const auto& destruct : info.first) |
| 3348 | for (const auto& item : destruct.items) | 3554 | for (const auto& item : destruct.items) |
