From 461bf7c32408553125d71b23e04e21fed690c4f5 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Wed, 4 Sep 2024 12:16:10 +0800 Subject: fix more cases for evaluation order of multi-value assignments. --- spec/inputs/assign.yue | 20 ++++++ spec/outputs/assign.lua | 97 ++++++++++++++++++++-------- spec/outputs/destructure.lua | 5 +- spec/outputs/metatable.lua | 5 +- spec/outputs/unicode/assign.lua | 37 +++++------ spec/outputs/unicode/destructure.lua | 5 +- spec/outputs/unicode/metatable.lua | 5 +- src/yuescript/yue_compiler.cpp | 121 +++++++++++++++++++++-------------- 8 files changed, 194 insertions(+), 101 deletions(-) diff --git a/spec/inputs/assign.yue b/spec/inputs/assign.yue index 2c89a99..514aeed 100644 --- a/spec/inputs/assign.yue +++ b/spec/inputs/assign.yue @@ -62,6 +62,20 @@ do else 123, tb +do + a, b[] = if x + switch y + when 1 + f! + print a, b + +do + a, {b} = if x + f! + else + 123, tb + print a, b + do a, b[], c, d. = if x switch y @@ -75,6 +89,12 @@ do do print 123 1, f2! + print a, b, c, d + +do + x, [a, b], tb.<>, c[] = 1, if cond + f! + print x, a, b do a = b = c = d = 0 diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index 1978df1..162a563 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -67,50 +67,95 @@ return _(function() end do local a + local _obj_0, _obj_1 if x then local _exp_0 = y if 1 == _exp_0 then - local _obj_0, _obj_1 = f() - b[#b + 1] = _obj_1 - a = _obj_0 + _obj_0, _obj_1 = f() end end + a = _obj_0 + b[#b + 1] = _obj_1 end do local a, b + local _obj_0, _obj_1 if x then - local _obj_0, _obj_1 = f() + _obj_0, _obj_1 = f() + else + _obj_0, _obj_1 = 123, tb + end + a = _obj_0 + b = _obj_1[1] + end + do + local a + do + local _obj_0, _obj_1 + if x then + local _exp_0 = y + if 1 == _exp_0 then + _obj_0, _obj_1 = f() + end + end + a = _obj_0 + b[#b + 1] = _obj_1 + end + print(a, b) + end + do + local a, b + do + local _obj_0, _obj_1 + if x then + _obj_0, _obj_1 = f() + else + _obj_0, _obj_1 = 123, tb + end a = _obj_0 b = _obj_1[1] - else - a = 123 - b = tb[1] end + print(a, b) end do local a, c - if x then - local _exp_0 = y - if 1 == _exp_0 then - local _obj_0, _obj_1, _obj_2, _obj_3 = f() - b[#b + 1] = _obj_1 - a, c, getmetatable(d).__add = _obj_0, _obj_2, _obj_3 - end - elseif x2 then - if y2 then - local _obj_0, _obj_1, _obj_2, _obj_3 = f1() - b[#b + 1] = _obj_1 - a, c, getmetatable(d).__add = _obj_0, _obj_2, _obj_3 + do + local _obj_0, _obj_1, _obj_2, _obj_3 + if x then + local _exp_0 = y + if 1 == _exp_0 then + _obj_0, _obj_1, _obj_2, _obj_3 = f() + end + elseif x2 then + if y2 then + _obj_0, _obj_1, _obj_2, _obj_3 = f1() + end + else + print("hello") + do + print(123) + _obj_0, _obj_1, _obj_2, _obj_3 = 1, f2() + end end - else - print("hello") - do - print(123) - local _obj_0, _obj_1, _obj_2 = f2() - b[#b + 1] = _obj_0 - a, c, getmetatable(d).__add = 1, _obj_1, _obj_2 + a = _obj_0 + b[#b + 1] = _obj_1 + c, getmetatable(d).__add = _obj_2, _obj_3 + end + print(a, b, c, d) + end + do + local x, a, b + do + local _obj_0, _obj_1, _obj_2 + if cond then + _obj_0, _obj_1, _obj_2 = f() end + x = 1 + a, b = _obj_0[1], _obj_0[2] + setmetatable(tb, _obj_1) + c[#c + 1] = _obj_2 end + print(x, a, b) end do local a = 0 diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index d8517a0..44da58b 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -427,14 +427,15 @@ do local x1, x2, x3, d, b, e do local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = f() + x1, x2, x3 = 1, 2, 3 do local _obj_5 = a _obj_5[#_obj_5 + 1] = _obj_0 end - setmetatable(c, _obj_4) - x1, x2, x3, d = 1, 2, 3, _obj_1 + d = _obj_1 b = _obj_2[1] e = _obj_3 + setmetatable(c, _obj_4) end local y1, y2, y3, y4 local _obj_0, _obj_1 = f2() diff --git a/spec/outputs/metatable.lua b/spec/outputs/metatable.lua index 0715b58..974a6e4 100644 --- a/spec/outputs/metatable.lua +++ b/spec/outputs/metatable.lua @@ -58,11 +58,12 @@ do local _obj_2 = getmetatable(_obj_1) add, sub = _obj_2.__add, _obj_2.__sub end -setmetatable(a.b, { }) x.abc = 123 +setmetatable(a.b, { }) setmetatable(func(), mt) +a = 1 setmetatable(b.c, mt) -a, d, e = 1, "abc", nil +d, e = "abc", nil local is_same = getmetatable(a).__index == getmetatable(a).__index setmetatable(a, { __index = tb diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua index e883d68..bf43953 100644 --- a/spec/outputs/unicode/assign.lua +++ b/spec/outputs/unicode/assign.lua @@ -71,53 +71,50 @@ return __u65e0_u6548_u53d8_u91cf(function() end do local _u53d8_u91cfa + local _obj_0, _obj_1 if x_u6761_u4ef6 then local _exp_0 = _u5bf9_u8c61y if 1 == _exp_0 then - local _obj_0, _obj_1 = _u51fd_u6570() - _u53d8_u91cfb[#_u53d8_u91cfb + 1] = _obj_1 - _u53d8_u91cfa = _obj_0 + _obj_0, _obj_1 = _u51fd_u6570() end end + _u53d8_u91cfa = _obj_0 + _u53d8_u91cfb[#_u53d8_u91cfb + 1] = _obj_1 end do local _u53d8_u91cfa, _u5143_u7d20b + local _obj_0, _obj_1 if x_u6761_u4ef6 then - local _obj_0, _obj_1 = _u51fd_u6570() - _u53d8_u91cfa = _obj_0 - _u5143_u7d20b = _obj_1[1] + _obj_0, _obj_1 = _u51fd_u6570() else - _u53d8_u91cfa = 123 - _u5143_u7d20b = _u8868[1] + _obj_0, _obj_1 = 123, _u8868 end + _u53d8_u91cfa = _obj_0 + _u5143_u7d20b = _obj_1[1] end do local _u53d8_u91cfa, _u5bf9_u8c61c + local _obj_0, _obj_1, _obj_2, _obj_3 if _u6761_u4ef6x then local _exp_0 = _u5bf9_u8c61y if 1 == _exp_0 then - local _obj_0, _obj_1, _obj_2, _obj_3 = _u51fd_u6570() - local _obj_4 = _u6570_u7ec4b - _obj_4[#_obj_4 + 1] = _obj_1 - _u53d8_u91cfa, _u5bf9_u8c61c, getmetatable(_u5bf9_u8c61d).__add = _obj_0, _obj_2, _obj_3 + _obj_0, _obj_1, _obj_2, _obj_3 = _u51fd_u6570() end elseif _u6761_u4ef6x2 then if _u6761_u4ef6y2 then - local _obj_0, _obj_1, _obj_2, _obj_3 = _u51fd_u65701() - local _obj_4 = _u6570_u7ec4b - _obj_4[#_obj_4 + 1] = _obj_1 - _u53d8_u91cfa, _u5bf9_u8c61c, getmetatable(_u5bf9_u8c61d).__add = _obj_0, _obj_2, _obj_3 + _obj_0, _obj_1, _obj_2, _obj_3 = _u51fd_u65701() end else _u6253_u5370("hello") do _u6253_u5370(123) - local _obj_0, _obj_1, _obj_2 = _u51fd_u65702() - local _obj_3 = _u6570_u7ec4b - _obj_3[#_obj_3 + 1] = _obj_0 - _u53d8_u91cfa, _u5bf9_u8c61c, getmetatable(_u5bf9_u8c61d).__add = 1, _obj_1, _obj_2 + _obj_0, _obj_1, _obj_2, _obj_3 = 1, _u51fd_u65702() end end + _u53d8_u91cfa = _obj_0 + local _obj_4 = _u6570_u7ec4b + _obj_4[#_obj_4 + 1] = _obj_1 + _u5bf9_u8c61c, getmetatable(_u5bf9_u8c61d).__add = _obj_2, _obj_3 end do local _u53d8_u91cfa = 0 diff --git a/spec/outputs/unicode/destructure.lua b/spec/outputs/unicode/destructure.lua index 29697fa..27c4d47 100644 --- a/spec/outputs/unicode/destructure.lua +++ b/spec/outputs/unicode/destructure.lua @@ -389,14 +389,15 @@ do 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() + _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3 = 1, 2, 3 do local _obj_5 = _u6570_u7ec4a _obj_5[#_obj_5 + 1] = _obj_0 end - setmetatable(_u5bf9_u8c61c, _obj_4) - _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd = 1, 2, 3, _obj_1 + _u53d8_u91cfd = _obj_1 _u5143_u7d20b = _obj_2[1] _u53d8_u91cfe = _obj_3 + setmetatable(_u5bf9_u8c61c, _obj_4) end local _u53d8_u91cfy1, _u5b57_u6bb5y2, _u5b57_u6bb5y3, _u53d8_u91cfy4 local _obj_0, _obj_1 = _u51fd_u65702() diff --git a/spec/outputs/unicode/metatable.lua b/spec/outputs/unicode/metatable.lua index f948d21..970e52c 100644 --- a/spec/outputs/unicode/metatable.lua +++ b/spec/outputs/unicode/metatable.lua @@ -58,11 +58,12 @@ do local _obj_2 = getmetatable(_obj_1) add, sub = _obj_2.__add, _obj_2.__sub end -setmetatable(_u53d8_u91cfa["变量b"], { }) _u53d8_u91cfx.abc = 123 +setmetatable(_u53d8_u91cfa["变量b"], { }) setmetatable(_u51fd_u6570(), mt) +_u53d8_u91cfa = 1 setmetatable(_u53d8_u91cfb["变量c"], mt) -_u53d8_u91cfa, _u53d8_u91cfd, _u53d8_u91cfe = 1, "abc", nil +_u53d8_u91cfd, _u53d8_u91cfe = "abc", nil local _u76f8_u540c = getmetatable(_u53d8_u91cfa).__index == getmetatable(_u53d8_u91cfa).__index setmetatable(_u53d8_u91cfa, { __index = _u8868 diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index cbb5f81..5d031db 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.25.0"sv; +const std::string_view version = "0.25.1"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -2047,34 +2047,34 @@ private: } throw CompileError(clearBuf(), values.front()); } - bool checkValuesLater = false; if (exprs.size() > values.size()) { BLOCK_START + bool needHoldValues = false; switch (values.back()->get_id()) { case id(): case id(): - checkValuesLater = true; + needHoldValues = true; break; } - BREAK_IF(checkValuesLater); - auto value = singleValueFrom(values.back()); - if (!value) { - _buf << exprs.size() << " right values expected, got "sv << values.size(); - throw CompileError(clearBuf(), values.front()); - } - if (auto val = value->item.as()) { - switch (val->value->get_id()) { - case id(): - case id(): - case id(): - case id(): - checkValuesLater = true; - break; + if (!needHoldValues) { + if (auto value = singleValueFrom(values.back())) { + if (auto val = value->item.as()) { + switch (val->value->get_id()) { + case id(): + case id(): + case id(): + case id(): + needHoldValues = true; + break; + } + } else if (auto chainValue = value->item.as()) { + if (chainValue && ast_is(chainValue->items.back())) { + needHoldValues = true; + } + } } - BREAK_IF(checkValuesLater); } - auto chainValue = value->item.as(); - if (!chainValue || !ast_is(chainValue->items.back())) { + if (!needHoldValues) { _buf << exprs.size() << " right values expected, got "sv << values.size(); throw CompileError(clearBuf(), values.front()); } @@ -2138,7 +2138,7 @@ private: temp.push_back(indent() + "do"s + nll(assignment)); pushScope(); } - transformAssignmentCommon(preAssignment, temp); + transformAssignment(preAssignment, temp); transformAssignment(assignment, temp); if (needScope) { popScope(); @@ -2148,17 +2148,52 @@ private: return; BLOCK_END } - if (!checkValuesLater) { + { auto vit = values.begin(); for (auto it = exprs.begin(); it != exprs.end(); ++it) { + auto splitAssignment = [&]() { + auto beforeAssignment = x->new_ptr(); + auto afterAssignment = x->new_ptr(); + { + auto beforeExpList = x->new_ptr(); + auto beforeAssign = x->new_ptr(); + beforeAssignment->expList.set(beforeExpList); + beforeAssignment->action.set(beforeAssign); + auto afterExpList = x->new_ptr(); + auto afterAssign = x->new_ptr(); + afterAssignment->expList.set(afterExpList); + afterAssignment->action.set(afterAssign); + ExpList_t* currentExpList = beforeExpList.get(); + for (auto exp : exprs) { + if (exp != *it) { + currentExpList->exprs.push_back(exp); + } else { + currentExpList = afterExpList.get(); + } + } + Assign_t* currentAssign = beforeAssign.get(); + for (auto value : values) { + if (value != *vit) { + currentAssign->values.push_back(value); + } else { + currentAssign = afterAssign.get(); + } + } + } + return std::make_pair(beforeAssignment, afterAssignment); + }; BLOCK_START auto value = singleValueFrom(*it); BREAK_IF(!value); auto chainValue = value->item.as(); BREAK_IF(!chainValue); - str_list temp; if (auto dot = ast_cast(chainValue->items.back())) { BREAK_IF(!dot->name.is()); + str_list temp; + auto [beforeAssignment, afterAssignment] = splitAssignment(); + if (!beforeAssignment->expList->exprs.empty()) { + transformAssignment(beforeAssignment, temp); + } str_list args; auto tmpChain = chainValue->new_ptr(); tmpChain->items.dup(chainValue->items); @@ -2178,7 +2213,17 @@ private: transformAssignItem(*vit, args); _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); temp.push_back(clearBuf()); + if (!afterAssignment->expList->exprs.empty()) { + transformAssignment(afterAssignment, temp); + } + out.push_back(join(temp)); + return; } else if (ast_is(chainValue->items.back())) { + str_list temp; + auto [beforeAssignment, afterAssignment] = splitAssignment(); + if (!beforeAssignment->expList->exprs.empty()) { + transformAssignment(beforeAssignment, temp); + } auto tmpChain = chainValue->new_ptr(); tmpChain->items.dup(chainValue->items); tmpChain->items.pop_back(); @@ -2220,32 +2265,14 @@ private: popScope(); temp.push_back(indent() + "end"s + nlr(x)); } - } else - break; - auto newExpList = x->new_ptr(); - auto newAssign = x->new_ptr(); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(newExpList); - newAssignment->action.set(newAssign); - for (auto exp : exprs) { - if (exp != *it) newExpList->exprs.push_back(exp); - } - for (auto value : values) { - if (value != *vit) newAssign->values.push_back(value); - } - if (newExpList->exprs.empty() && newAssign->values.empty()) { + if (!afterAssignment->expList->exprs.empty()) { + transformAssignment(afterAssignment, temp); + } out.push_back(join(temp)); return; + } else { + break; } - if (newExpList->exprs.size() < newAssign->values.size()) { - auto exp = toAst("_"sv, x); - while (newExpList->exprs.size() < newAssign->values.size()) { - newExpList->exprs.push_back(exp); - } - } - transformAssignment(newAssignment, temp); - out.push_back(join(temp)); - return; BLOCK_END if (vit != values.end()) ++vit; } @@ -2432,7 +2459,7 @@ private: if (!assignment.extraAssignment) { auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get); for (const auto& name : names) { - if (addToScope(name.first)) { + if (!isDefined(name.first)) { defs.push_back(name.first); } } -- cgit v1.2.3-55-g6feb