From 2f8215df7288e0aac690c8e8b1ff79865f114302 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 3 Sep 2024 23:23:25 +0800 Subject: fix correct evaluation order for multi-value assignments. --- spec/inputs/destructure.yue | 8 ++ spec/outputs/assign.lua | 3 +- spec/outputs/destructure.lua | 49 +++++-- spec/outputs/metatable.lua | 13 +- spec/outputs/unicode/assign.lua | 3 +- spec/outputs/unicode/destructure.lua | 24 ++-- spec/outputs/unicode/metatable.lua | 13 +- src/yuescript/parser.cpp | 10 +- src/yuescript/parser.hpp | 11 ++ src/yuescript/yue_compiler.cpp | 247 ++++++++++++++++++++++++----------- 10 files changed, 257 insertions(+), 124 deletions(-) diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue index 5017ee1..674dfe4 100644 --- a/spec/inputs/destructure.yue +++ b/spec/inputs/destructure.yue @@ -6,6 +6,14 @@ do { :hello, :world } = value +do + x, [a, b] = f! + print x, a, b + +do + list = [ [1, 2], [3, 4]] + {x, y}, list = lume.first(list), lume.slice list, 2 + do { yes: no, thing } = world diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index 5552f73..1978df1 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -77,8 +77,7 @@ return _(function() end end do - local a - local b + local a, b if x then local _obj_0, _obj_1 = f() a = _obj_0 diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 2d0d46f..d8517a0 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -13,6 +13,31 @@ do local _obj_0 = value hello, world = _obj_0.hello, _obj_0.world end +do + local x, a, b + do + local _obj_0, _obj_1 = f() + x = _obj_0 + a, b = _obj_1[1], _obj_1[2] + end + print(x, a, b) +end +do + local list = { + { + 1, + 2 + }, + { + 3, + 4 + } + } + local x, y + local _obj_0 = lume.first(list) + x, y = _obj_0[1], _obj_0[2] + list = lume.slice(list, 2) +end do local no, thing do @@ -24,12 +49,12 @@ do local _obj_0 = yeah a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d end - b = two a = one[1] - c = nil + b = two b = one[1] - local e = two + c = nil d = one[1] + local e = two local x = one local y = two[1] local xx, yy = 1, 2 @@ -46,9 +71,9 @@ do a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] end do - c = nil local _obj_0 = tbl a, b = _obj_0.a, _obj_0.b + c = nil end do a = tbl @@ -56,8 +81,8 @@ do b, c = _obj_0.b, _obj_0.c end do - b = _ a = tbl.a + b = _ c = _.c end end @@ -211,8 +236,8 @@ do end one, two, three = _tbl_0.one, _tbl_0.two, _tbl_0.three end - b = 123 a = (a["if"](a, 123) + t).a + b = 123 end do local name, job @@ -399,8 +424,7 @@ do end end do - local x1, x2, x3, d, e - local b + local x1, x2, x3, d, b, e do local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = f() do @@ -408,14 +432,15 @@ do _obj_5[#_obj_5 + 1] = _obj_0 end setmetatable(c, _obj_4) - x1, x2, x3, d, e = 1, 2, 3, _obj_1, _obj_3 + x1, x2, x3, d = 1, 2, 3, _obj_1 b = _obj_2[1] + e = _obj_3 end - local y1, y4 - local y2, y3 + local y1, y2, y3, y4 local _obj_0, _obj_1 = f2() - y1, y4 = f1(), _obj_1 + y1 = f1() y2, y3 = _obj_0.y2, _obj_0.y3 + y4 = _obj_1 end do local v1, v2, v3, v4 diff --git a/spec/outputs/metatable.lua b/spec/outputs/metatable.lua index 6af10e5..0715b58 100644 --- a/spec/outputs/metatable.lua +++ b/spec/outputs/metatable.lua @@ -48,14 +48,15 @@ do end do local x, new, var, close, closeA, num, add, sub - local _obj_0, _obj_1 - x, _obj_0, _obj_1 = 123, a.b.c, func() + x = 123 + local _obj_0 = a.b.c new, var = _obj_0.new, _obj_0.var - local _obj_2 = getmetatable(_obj_0) - close, closeA = _obj_2.__close, _obj_2.__close + local _obj_1 = getmetatable(_obj_0) + close, closeA = _obj_1.__close, _obj_1.__close + _obj_1 = func() num = _obj_1.num - local _obj_3 = getmetatable(_obj_1) - add, sub = _obj_3.__add, _obj_3.__sub + local _obj_2 = getmetatable(_obj_1) + add, sub = _obj_2.__add, _obj_2.__sub end setmetatable(a.b, { }) x.abc = 123 diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua index cb53159..e883d68 100644 --- a/spec/outputs/unicode/assign.lua +++ b/spec/outputs/unicode/assign.lua @@ -81,8 +81,7 @@ return __u65e0_u6548_u53d8_u91cf(function() end end do - local _u53d8_u91cfa - local _u5143_u7d20b + local _u53d8_u91cfa, _u5143_u7d20b if x_u6761_u4ef6 then local _obj_0, _obj_1 = _u51fd_u6570() _u53d8_u91cfa = _obj_0 diff --git a/spec/outputs/unicode/destructure.lua b/spec/outputs/unicode/destructure.lua index e1cd6ae..29697fa 100644 --- a/spec/outputs/unicode/destructure.lua +++ b/spec/outputs/unicode/destructure.lua @@ -24,12 +24,12 @@ do local _obj_0 = _u597d _u5b57_u6bb5a, _u5b57_u6bb5b, _u5b57_u6bb5c, d_u5b57_u6bb5 = _obj_0["字段a"], _obj_0["字段b"], _obj_0["字段c"], _obj_0["d字段"] end - local _u53d8_u91cfb = _u4e8c local a_u5143_u7d20 = _u4e00[1] - local _u53d8_u91cfc = nil + local _u53d8_u91cfb = _u4e8c local b_u5143_u7d20 = _u4e00[1] - local _u53d8_u91cfe = _u4e8c + local _u53d8_u91cfc = nil local d_u5143_u7d20 = _u4e00[1] + local _u53d8_u91cfe = _u4e8c local _u53d8_u91cfx = _u4e00 local _u5143_u7d20y = _u4e8c[1] local _u53d8_u91cfxx, _u53d8_u91cfyy = 1, 2 @@ -47,9 +47,9 @@ do _u5143_u7d20a, _u5b57_u6bb5b, _u5143_u7d20c, _u5b57_u6bb5d, _u5143_u7d20e, _u5b57_u6bb5f, _u5143_u7d20g = _obj_0[1], _obj_0["字段b"], _obj_0[2], _obj_0["字段d"], _obj_0[3], _obj_0["字段f"], _obj_0[4] end do - _u53d8_u91cfc = nil local _obj_0 = _u8868 _u5b57_u6bb5a, _u5b57_u6bb5b = _obj_0["字段a"], _obj_0["字段b"] + _u53d8_u91cfc = nil end do local _u53d8_u91cfa = _u8868 @@ -57,8 +57,8 @@ do _u5b57_u6bb5b, _u5b57_u6bb5c = _obj_0["字段b"], _obj_0["字段c"] end do - _u53d8_u91cfb = __u65e0_u6548_u53d8_u91cf _u5b57_u6bb5a = _u8868["字段a"] + _u53d8_u91cfb = __u65e0_u6548_u53d8_u91cf _u5b57_u6bb5c = __u65e0_u6548_u53d8_u91cf["字段c"] end end @@ -212,11 +212,11 @@ do end _u4e00, _u4e8c, _u4e09 = _tbl_0["一"], _tbl_0["二"], _tbl_0["三"] end - local _u53d8_u91cfb = 123 _u5b57_u6bb5a = ((function() local _call_0 = _u5bf9_u8c61a return _call_0["如果"](_call_0, 123) end)() + _u53d8_u91cft)["字段a"] + local _u53d8_u91cfb = 123 end do local _u540d_u79f0, _u5de5_u4f5c @@ -386,8 +386,7 @@ do end end do - local _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u53d8_u91cfe - local _u5143_u7d20b + local _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u5143_u7d20b, _u53d8_u91cfe do local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = _u51fd_u6570() do @@ -395,14 +394,15 @@ do _obj_5[#_obj_5 + 1] = _obj_0 end setmetatable(_u5bf9_u8c61c, _obj_4) - _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u53d8_u91cfe = 1, 2, 3, _obj_1, _obj_3 + _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd = 1, 2, 3, _obj_1 _u5143_u7d20b = _obj_2[1] + _u53d8_u91cfe = _obj_3 end - local _u53d8_u91cfy1, _u53d8_u91cfy4 - local _u5b57_u6bb5y2, _u5b57_u6bb5y3 + local _u53d8_u91cfy1, _u5b57_u6bb5y2, _u5b57_u6bb5y3, _u53d8_u91cfy4 local _obj_0, _obj_1 = _u51fd_u65702() - _u53d8_u91cfy1, _u53d8_u91cfy4 = _u51fd_u65701(), _obj_1 + _u53d8_u91cfy1 = _u51fd_u65701() _u5b57_u6bb5y2, _u5b57_u6bb5y3 = _obj_0["字段y2"], _obj_0["字段y3"] + _u53d8_u91cfy4 = _obj_1 end do local _u53d8_u91cfv1, _u53d8_u91cfv2, _u53d8_u91cfv3, _u53d8_u91cfv4 diff --git a/spec/outputs/unicode/metatable.lua b/spec/outputs/unicode/metatable.lua index ca48d0d..f948d21 100644 --- a/spec/outputs/unicode/metatable.lua +++ b/spec/outputs/unicode/metatable.lua @@ -48,14 +48,15 @@ do end do local _u53d8_u91cfx, _u65b0, _u53d8_u91cf, close, _u5173_u95edA, num, add, sub - local _obj_0, _obj_1 - _u53d8_u91cfx, _obj_0, _obj_1 = 123, _u53d8_u91cfa["变量b"]["变量c"], _u51fd_u6570() + _u53d8_u91cfx = 123 + local _obj_0 = _u53d8_u91cfa["变量b"]["变量c"] _u65b0, _u53d8_u91cf = _obj_0["新"], _obj_0["变量"] - local _obj_2 = getmetatable(_obj_0) - close, _u5173_u95edA = _obj_2.__close, _obj_2.__close + local _obj_1 = getmetatable(_obj_0) + close, _u5173_u95edA = _obj_1.__close, _obj_1.__close + _obj_1 = _u51fd_u6570() num = _obj_1.num - local _obj_3 = getmetatable(_obj_1) - add, sub = _obj_3.__add, _obj_3.__sub + local _obj_2 = getmetatable(_obj_1) + add, sub = _obj_2.__add, _obj_2.__sub end setmetatable(_u53d8_u91cfa["变量b"], { }) _u53d8_u91cfx.abc = 123 diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp index 5e4caa2..5d0773c 100644 --- a/src/yuescript/parser.cpp +++ b/src/yuescript/parser.cpp @@ -15,15 +15,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND #include #include #include -#include #include "yuescript/parser.hpp" -#define _DEFER(code, line) std::shared_ptr _defer_##line(nullptr, [&](auto) { \ - code; \ -}) -#define DEFER(code) _DEFER(code, __LINE__) - namespace parserlib { // internal private class that manages access to the public classes' internals. @@ -914,7 +908,7 @@ bool _context::parse_non_term(rule& r) { // save the state of the rule rule::_state old_state = r.m_state; // restore the rule's state - DEFER(r.m_state = old_state); + rule::_state_guard quard(old_state, &r.m_state); // success/failure result bool ok = false; @@ -1008,7 +1002,7 @@ bool _context::parse_term(rule& r) { // save the state of the rule rule::_state old_state = r.m_state; // restore the rule's state - DEFER(r.m_state = old_state); + rule::_state_guard quard(old_state, &r.m_state); // success/failure result bool ok = false; diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp index 71bbc1a..5ab327f 100644 --- a/src/yuescript/parser.hpp +++ b/src/yuescript/parser.hpp @@ -294,6 +294,17 @@ private: , m_mode(mode) { } }; + struct _state_guard { + _state m_old_state; + _state* m_current_state; + _state_guard(const _state& old, _state* new_) + : m_old_state(old) + , m_current_state(new_) { } + ~_state_guard() { + *m_current_state = m_old_state; + } + }; + // internal expression _expr* m_expr; diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 32db488..cbb5f81 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -75,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.24.1"sv; +const std::string_view version = "0.25.0"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -1943,16 +1943,26 @@ private: std::string getDestrucureDefine(ExpListAssign_t* assignment) { auto info = extractDestructureInfo(assignment, true, false); - if (info.assignment) { - _buf << getPreDefineLine(info.assignment); - } if (!info.destructures.empty()) { str_list defs; - for (const auto& destruct : info.destructures) { - for (const auto& item : destruct.items) { - if (!item.targetVar.empty()) { - if (addToScope(item.targetVar)) { - defs.push_back(item.targetVar); + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (!item.targetVar.empty()) { + if (addToScope(item.targetVar)) { + defs.push_back(item.targetVar); + } + } + } + } else { + const auto& assignment = std::get(des); + if (!assignment.extraAssignment) { + auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get); + for (const auto& name : names) { + if (addToScope(name.first)) { + defs.push_back(name.first); + } } } } @@ -2007,12 +2017,15 @@ private: void markDestructureConst(ExpListAssign_t* assignment) { auto info = extractDestructureInfo(assignment, true, false); - for (auto& destruct : info.destructures) { - for (auto& item : destruct.items) { - if (item.targetVar.empty()) { - throw CompileError("can only declare variable as const"sv, item.target); + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (item.targetVar.empty()) { + throw CompileError("can only declare variable as const"sv, item.target); + } + markVarConst(item.targetVar); } - markVarConst(item.targetVar); } } } @@ -2079,7 +2092,7 @@ private: BLOCK_START auto value = singleValueFrom(*it); BREAK_IF(!value); - if (value->item.is() || value->get_by_path()) { + if (value->item.is() || value->get_by_path() || value->get_by_path()) { holdItem = true; break; } @@ -2404,11 +2417,24 @@ private: bool extraScope = false; if (info.extraScope) { str_list defs; - for (auto& destruct : info.destructures) { - for (auto& item : destruct.items) { - if (!item.targetVar.empty()) { - if (!isDefined(item.targetVar)) { - defs.push_back(item.targetVar); + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + const auto& destruct = std::get(des); + for (auto& item : destruct.items) { + if (!item.targetVar.empty()) { + if (!isDefined(item.targetVar)) { + defs.push_back(item.targetVar); + } + } + } + } else { + const auto& assignment = std::get(des); + if (!assignment.extraAssignment) { + auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get); + for (const auto& name : names) { + if (addToScope(name.first)) { + defs.push_back(name.first); + } } } } @@ -2426,10 +2452,13 @@ private: pushScope(); } } - if (info.assignment) { - transformAssignmentCommon(info.assignment, temp); - } - for (auto& destruct : info.destructures) { + for (auto& des : info.destructures) { + if (std::holds_alternative(des)) { + auto assignment = std::get(des).ptr.get(); + transformAssignment(assignment, temp); + continue; + } + auto& destruct = std::get(des); std::list, ast_ptr>> leftPairs; bool extraScope = false; if (!destruct.inlineAssignment && destruct.items.size() == 1) { @@ -2931,17 +2960,21 @@ private: return pairs; } + struct AssignmentPtr { + ast_ptr ptr; + bool extraAssignment = false; + }; + struct DestructureInfo { - std::list destructures; - ast_ptr assignment; + std::list> destructures; bool extraScope = false; }; DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { + if (!assignment->action.is()) return {}; auto x = assignment; bool extraScope = false; - std::list destructs; - if (!assignment->action.is()) return {destructs, nullptr}; + std::list> destructs; auto exprs = assignment->expList->exprs.objects(); auto values = assignment->action.to()->values.objects(); size_t size = std::max(exprs.size(), values.size()); @@ -2951,10 +2984,26 @@ private: while (values.size() < size) values.emplace_back(nil); } using iter = node_container::iterator; - std::vector> destructPairs; + std::vector> assignPairs; ast_list valueItems; str_list temp; pushScope(); + auto checkCommonAssignment = [&]() { + if (!assignPairs.empty()) { + auto expList = x->new_ptr(); + auto newAssign = x->new_ptr(); + newAssign->expList.set(expList); + auto assign = x->new_ptr(); + newAssign->action.set(assign); + for (const auto& pair : assignPairs) { + expList->exprs.push_back(*pair.first); + assign->values.push_back(*pair.second); + } + assignPairs.clear(); + destructs.push_back(AssignmentPtr{newAssign, false}); + } + }; + bool hasDestructuring = false; for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { auto expr = *i; auto value = singleValueFrom(expr); @@ -2974,6 +3023,8 @@ private: } } if (destructNode) { + hasDestructuring = true; + checkCommonAssignment(); if (*j != nil) { if (auto ssVal = simpleSingleValueFrom(*j)) { switch (ssVal->value->get_id()) { @@ -2989,7 +3040,6 @@ private: } } } - destructPairs.push_back({i, j}); auto subDestruct = destructNode->new_ptr(); auto subMetaDestruct = destructNode->new_ptr(); const node_container* dlist = nullptr; @@ -3113,19 +3163,26 @@ private: if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { auto var = singleVariableFrom(*j, AccessType::None); if (var.empty() || !isLocal(var)) { + checkCommonAssignment(); auto objVar = getUnusedName("_obj_"sv); addToScope(objVar); valueItems.pop_back(); valueItems.push_back(toAst(objVar, *j)); - exprs.push_back(valueItems.back()); - values.push_back(*j); + auto expList = x->new_ptr(); + auto newAssign = x->new_ptr(); + newAssign->expList.set(expList); + auto assign = x->new_ptr(); + newAssign->action.set(assign); + expList->exprs.push_back(valueItems.back()); + assign->values.push_back(*j); + destructs.push_back(AssignmentPtr{newAssign, true}); extraScope = true; } } TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; for (auto tab : tabs) { if (!tab->values.empty()) { - auto& destruct = destructs.emplace_back(); + Destructure destruct; if (!varDefOnly) { destruct.value = valueItems.back(); destruct.valueVar = singleVariableFrom(destruct.value, AccessType::None); @@ -3172,29 +3229,28 @@ private: destruct.valueVar.clear(); } } + destructs.push_back(destruct); } } + } else { + assignPairs.push_back({i, j}); } } - for (const auto& p : destructPairs) { - exprs.erase(p.first); - values.erase(p.second); - } - ast_ptr newAssignment; - if (!destructPairs.empty() && !exprs.empty()) { - auto x = assignment; - auto expList = x->new_ptr(); - auto newAssign = x->new_ptr(); - newAssign->expList.set(expList); - for (auto expr : exprs) expList->exprs.push_back(expr); - auto assign = x->new_ptr(); - for (auto value : values) assign->values.push_back(value); - newAssign->action.set(assign); - newAssignment = newAssign; + if (!hasDestructuring) { + popScope(); + return {}; } + checkCommonAssignment(); if (!varDefOnly) { - for (auto& des : destructs) { + for (auto& d : destructs) { + if (std::holds_alternative(d)) { + continue; + } + auto& des = std::get(d); for (const auto& item : des.items) { + if (!item.structure) { + continue; + } for (auto node : item.structure->items.objects()) { if (auto exp = ast_cast(node)) { if (auto value = simpleSingleValueFrom(node)) { @@ -3236,7 +3292,7 @@ private: } } popScope(); - return {std::move(destructs), newAssignment, extraScope}; + return {std::move(destructs), extraScope}; } void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) { @@ -4746,23 +4802,30 @@ private: } auto info = extractDestructureInfo(assignment, true, false); if (!info.destructures.empty()) { - for (const auto& destruct : info.destructures) - for (const auto& item : destruct.items) - if (!item.targetVar.empty()) { - if (std::isupper(item.targetVar[0]) && capital) { - capital->decls.push_back(item.targetVar); - } else if (any) { - any->decls.push_back(item.targetVar); + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (!item.targetVar.empty()) { + if (std::isupper(item.targetVar[0]) && capital) { + capital->decls.push_back(item.targetVar); + } else if (any) { + any->decls.push_back(item.targetVar); + } + } + } + } else { + const auto& assignment = std::get(des); + if (!assignment.extraAssignment) { + auto defs = transformAssignDefs(assignment.ptr->expList, DefOp::Get); + for (const auto& def : defs) { + if (std::isupper(def.first[0]) && capital) { + capital->decls.push_back(def.first); + } else if (any) { + any->decls.push_back(def.first); + } } } - } - if (info.assignment) { - auto defs = transformAssignDefs(info.assignment->expList, DefOp::Get); - for (const auto& def : defs) { - if (std::isupper(def.first[0]) && capital) { - capital->decls.push_back(def.first); - } else if (any) { - any->decls.push_back(def.first); } } } @@ -8551,10 +8614,17 @@ private: } auto info = extractDestructureInfo(assignment, true, false); if (!info.destructures.empty()) { - for (const auto& destruct : info.destructures) - for (const auto& item : destruct.items) - if (!item.targetVar.empty() && addToScope(item.targetVar)) + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (!item.targetVar.empty() && addToScope(item.targetVar)) { varDefs.push_back(item.targetVar); + } + } + } } BLOCK_START auto assign = assignment->action.as(); @@ -9006,10 +9076,17 @@ private: } auto info = extractDestructureInfo(assignment, true, false); if (!info.destructures.empty()) { - for (const auto& destruct : info.destructures) - for (const auto& item : destruct.items) - if (!item.targetVar.empty() && !isDefined(item.targetVar)) + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (!item.targetVar.empty() && !isDefined(item.targetVar)) { return traversal::Stop; + } + } + } } BLOCK_START auto assign = assignment->action.as(); @@ -9248,13 +9325,19 @@ private: auto names = transformAssignDefs(expList, DefOp::Get); auto info = extractDestructureInfo(assignment, true, false); if (!info.destructures.empty()) { - for (const auto& destruct : info.destructures) - for (const auto& item : destruct.items) + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { if (!item.targetVar.empty()) { auto dot = ast_cast(item.structure->items.back()); auto uname = dot->name.as(); names.emplace_back(item.targetVar, uname ? _parser.toString(uname) : Empty); } + } + } } if (_info.exportDefault) { out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); @@ -10213,7 +10296,11 @@ private: auto info = extractDestructureInfo(assignment, true, false); transformAssignment(assignment, temp, true); str_list conds; - for (const auto& destruct : info.destructures) { + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); for (const auto& item : destruct.items) { if (!item.defVal) { transformExp(item.target, conds, ExpUsage::Closure); @@ -10475,7 +10562,11 @@ private: assignment->expList.set(leftList); assignment->action.set(assign); auto info = extractDestructureInfo(assignment, true, false); - for (auto& destruct : info.destructures) { + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); for (auto& item : destruct.items) { if (item.targetVar.empty()) { throw CompileError("can only declare variable as const"sv, item.target); @@ -10569,7 +10660,11 @@ private: assignment->action.set(assignB); auto info = extractDestructureInfo(assignment, true, false); str_list vars; - for (auto& destruct : info.destructures) { + for (auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); for (auto& item : destruct.items) { if (item.targetVar.empty()) { throw CompileError("can only declare variable as const"sv, item.target); -- cgit v1.2.3-55-g6feb