aboutsummaryrefslogtreecommitdiff
path: root/src/yuescript/yue_compiler.cpp
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-08-07 09:57:27 +0800
committerLi Jin <dragon-fly@qq.com>2023-08-07 09:57:27 +0800
commitc9b70274787ed8a77e7b47c4628197f0c6c1ba30 (patch)
treefae88047d312962aebfd97a0183c2f9f19e2cc76 /src/yuescript/yue_compiler.cpp
parentaff8e69bf589d2ee5f4a7b72b7e2f643d55b87fa (diff)
downloadyuescript-c9b70274787ed8a77e7b47c4628197f0c6c1ba30.tar.gz
yuescript-c9b70274787ed8a77e7b47c4628197f0c6c1ba30.tar.bz2
yuescript-c9b70274787ed8a77e7b47c4628197f0c6c1ba30.zip
fixing issue #143 and #144.
Diffstat (limited to '')
-rw-r--r--src/yuescript/yue_compiler.cpp375
1 files changed, 333 insertions, 42 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 7dc4558..a6f74de 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -50,7 +50,9 @@ namespace yue {
50#define BREAK_IF(cond) \ 50#define BREAK_IF(cond) \
51 if (cond) break 51 if (cond) break
52 52
53#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { code; }) 53#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \
54 code; \
55})
54#define DEFER(code) _DEFER(code, __LINE__) 56#define DEFER(code) _DEFER(code, __LINE__)
55#define YUEE(msg, node) throw CompileError( \ 57#define YUEE(msg, node) throw CompileError( \
56 "[File] "s + __FILE__ \ 58 "[File] "s + __FILE__ \
@@ -72,7 +74,7 @@ static std::unordered_set<std::string> Metamethods = {
72 "close"s // Lua 5.4 74 "close"s // Lua 5.4
73}; 75};
74 76
75const std::string_view version = "0.17.14"sv; 77const std::string_view version = "0.18.0"sv;
76const std::string_view extension = "yue"sv; 78const std::string_view extension = "yue"sv;
77 79
78class CompileError : public std::logic_error { 80class CompileError : public std::logic_error {
@@ -1248,9 +1250,6 @@ private:
1248 throw CompileError("metamethod is not supported until Lua 5.3"sv, x); 1250 throw CompileError("metamethod is not supported until Lua 5.3"sv, x);
1249 } 1251 }
1250 metamethod53: 1252 metamethod53:
1251 if (name == "close"sv) {
1252 throw CompileError("metamethod is not supported until Lua 5.4"sv, x);
1253 }
1254 metamethod54: 1253 metamethod54:
1255 return; 1254 return;
1256 } 1255 }
@@ -1573,8 +1572,8 @@ private:
1573 _buf << getPreDefineLine(info.assignment); 1572 _buf << getPreDefineLine(info.assignment);
1574 } 1573 }
1575 if (!info.destructures.empty()) { 1574 if (!info.destructures.empty()) {
1575 str_list defs;
1576 for (const auto& destruct : info.destructures) { 1576 for (const auto& destruct : info.destructures) {
1577 str_list defs;
1578 for (const auto& item : destruct.items) { 1577 for (const auto& item : destruct.items) {
1579 if (!item.targetVar.empty()) { 1578 if (!item.targetVar.empty()) {
1580 if (addToScope(item.targetVar)) { 1579 if (addToScope(item.targetVar)) {
@@ -1582,8 +1581,8 @@ private:
1582 } 1581 }
1583 } 1582 }
1584 } 1583 }
1585 if (!defs.empty()) _buf << indent() << "local "sv << join(defs, ", "sv);
1586 } 1584 }
1585 if (!defs.empty()) _buf << indent() << "local "sv << join(defs, ", "sv);
1587 } 1586 }
1588 return clearBuf(); 1587 return clearBuf();
1589 } 1588 }
@@ -2256,7 +2255,7 @@ private:
2256 } 2255 }
2257 } 2256 }
2258 2257
2259 std::list<DestructItem> destructFromExp(ast_node* node, bool optional) { 2258 std::list<DestructItem> destructFromExp(ast_node* node, bool varDefOnly, bool optional) {
2260 const node_container* tableItems = nullptr; 2259 const node_container* tableItems = nullptr;
2261 ast_ptr<false, ExistentialOp_t> sep = optional ? node->new_ptr<ExistentialOp_t>() : nullptr; 2260 ast_ptr<false, ExistentialOp_t> sep = optional ? node->new_ptr<ExistentialOp_t>() : nullptr;
2262 switch (node->get_id()) { 2261 switch (node->get_id()) {
@@ -2308,13 +2307,13 @@ private:
2308 defVal = nd->defVal.get(); 2307 defVal = nd->defVal.get();
2309 } 2308 }
2310 ++index; 2309 ++index;
2311 if (!isAssignable(static_cast<Exp_t*>(pair))) { 2310 if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) {
2312 throw CompileError("can't destructure value"sv, pair); 2311 throw CompileError("can't destructure value"sv, pair);
2313 } 2312 }
2314 auto value = singleValueFrom(pair); 2313 auto value = singleValueFrom(pair);
2315 auto item = value->item.get(); 2314 auto item = value->item.get();
2316 if (ast_is<SimpleTable_t>(item) || item->get_by_path<TableLit_t>()) { 2315 if (ast_is<SimpleTable_t>(item) || item->get_by_path<TableLit_t>()) {
2317 auto subPairs = destructFromExp(pair, optional); 2316 auto subPairs = destructFromExp(pair, varDefOnly, optional);
2318 if (!subPairs.empty()) { 2317 if (!subPairs.empty()) {
2319 if (defVal) { 2318 if (defVal) {
2320 throw CompileError("default value is not supported here"sv, defVal); 2319 throw CompileError("default value is not supported here"sv, defVal);
@@ -2388,10 +2387,10 @@ private:
2388 } 2387 }
2389 } 2388 }
2390 if (auto exp = np->value.as<Exp_t>()) { 2389 if (auto exp = np->value.as<Exp_t>()) {
2391 if (!isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); 2390 if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp);
2392 auto item = singleValueFrom(exp)->item.get(); 2391 auto item = singleValueFrom(exp)->item.get();
2393 if (ast_is<SimpleTable_t>(item) || item->get_by_path<TableLit_t>()) { 2392 if (ast_is<SimpleTable_t>(item) || item->get_by_path<TableLit_t>()) {
2394 auto subPairs = destructFromExp(exp, optional); 2393 auto subPairs = destructFromExp(exp, varDefOnly, optional);
2395 if (!subPairs.empty()) { 2394 if (!subPairs.empty()) {
2396 if (defVal) { 2395 if (defVal) {
2397 throw CompileError("default value is not supported here"sv, defVal); 2396 throw CompileError("default value is not supported here"sv, defVal);
@@ -2416,7 +2415,7 @@ private:
2416 break; 2415 break;
2417 } 2416 }
2418 if (np->value.is<TableBlock_t>()) { 2417 if (np->value.is<TableBlock_t>()) {
2419 auto subPairs = destructFromExp(np->value, optional); 2418 auto subPairs = destructFromExp(np->value, varDefOnly, optional);
2420 if (!subPairs.empty()) { 2419 if (!subPairs.empty()) {
2421 if (defVal) { 2420 if (defVal) {
2422 throw CompileError("default value is not supported here"sv, defVal); 2421 throw CompileError("default value is not supported here"sv, defVal);
@@ -2435,7 +2434,7 @@ private:
2435 case id<TableBlockIndent_t>(): { 2434 case id<TableBlockIndent_t>(): {
2436 auto tb = static_cast<TableBlockIndent_t*>(pair); 2435 auto tb = static_cast<TableBlockIndent_t*>(pair);
2437 ++index; 2436 ++index;
2438 auto subPairs = destructFromExp(tb, optional); 2437 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2439 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 2438 auto indexItem = toAst<Exp_t>(std::to_string(index), tb);
2440 for (auto& p : subPairs) { 2439 for (auto& p : subPairs) {
2441 if (sep) p.structure->items.push_front(sep); 2440 if (sep) p.structure->items.push_front(sep);
@@ -2499,7 +2498,7 @@ private:
2499 if (!subMetaDestruct->values.empty()) { 2498 if (!subMetaDestruct->values.empty()) {
2500 auto simpleValue = subMetaDestruct->new_ptr<SimpleValue_t>(); 2499 auto simpleValue = subMetaDestruct->new_ptr<SimpleValue_t>();
2501 simpleValue->value.set(subMetaDestruct); 2500 simpleValue->value.set(subMetaDestruct);
2502 auto subPairs = destructFromExp(newExp(simpleValue, subMetaDestruct), optional); 2501 auto subPairs = destructFromExp(newExp(simpleValue, subMetaDestruct), varDefOnly, optional);
2503 auto mt = simpleValue->new_ptr<Metatable_t>(); 2502 auto mt = simpleValue->new_ptr<Metatable_t>();
2504 auto dot = mt->new_ptr<DotChainItem_t>(); 2503 auto dot = mt->new_ptr<DotChainItem_t>();
2505 dot->name.set(mt); 2504 dot->name.set(mt);
@@ -2700,7 +2699,7 @@ private:
2700 } 2699 }
2701 auto simpleValue = tab->new_ptr<SimpleValue_t>(); 2700 auto simpleValue = tab->new_ptr<SimpleValue_t>();
2702 simpleValue->value.set(tab); 2701 simpleValue->value.set(tab);
2703 auto pairs = destructFromExp(newExp(simpleValue, expr), optional); 2702 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
2704 if (pairs.empty()) { 2703 if (pairs.empty()) {
2705 throw CompileError("expect items to be destructured"sv, tab); 2704 throw CompileError("expect items to be destructured"sv, tab);
2706 } 2705 }
@@ -3609,6 +3608,155 @@ private:
3609 } 3608 }
3610 transformBlock(newBlock, out, usage, assignList, isRoot); 3609 transformBlock(newBlock, out, usage, assignList, isRoot);
3611 return; 3610 return;
3611 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
3612 expListAssign && expListAssign->action && expListAssign->action.is<Assign_t>()) {
3613 BLOCK_START
3614 auto unary = singleUnaryExpFrom(expListAssign->expList->exprs.back());
3615 BREAK_IF(!unary->ops.empty());
3616 auto value = static_cast<Value_t*>(unary->expos.front());
3617 auto simpleValue = value->item.as<SimpleValue_t>();
3618 BREAK_IF(!simpleValue);
3619 auto varArg = simpleValue->value.as<VarArg_t>();
3620 BREAK_IF(!varArg);
3621 auto assignAction = static_cast<Assign_t*>(expListAssign->action.get());
3622 bool isExps = true;
3623 for (auto item : assignAction->values.objects()) {
3624 if (!ast_is<Exp_t, TableBlock_t>(item)) {
3625 isExps = false;
3626 break;
3627 }
3628 }
3629 BREAK_IF(!isExps);
3630 auto x = *nodes.begin();
3631 auto newBlock = x->new_ptr<Block_t>();
3632 if (it != nodes.begin()) {
3633 for (auto i = nodes.begin(); i != it; ++i) {
3634 newBlock->statements.push_back(*i);
3635 }
3636 }
3637 x = expListAssign;
3638 auto followingBlock = x->new_ptr<Block_t>();
3639 {
3640 auto next = it;
3641 ++next;
3642 if (next != nodes.end()) {
3643 for (auto i = next; i != nodes.end(); ++i) {
3644 followingBlock->statements.push_back(*i);
3645 }
3646 }
3647 }
3648 str_list argNames;
3649 if (expListAssign->expList->exprs.size() > 1) {
3650 pushScope();
3651 for (size_t i = 0; i < expListAssign->expList->exprs.size() - 1; i++) {
3652 auto argName = getUnusedName("_arg_"sv);
3653 addToScope(argName);
3654 argNames.push_back(argName);
3655 }
3656 popScope();
3657 auto newExpList = x->new_ptr<ExpList_t>();
3658 for (auto exp : expListAssign->expList->exprs.objects()) {
3659 if (exp != expListAssign->expList->exprs.back()) {
3660 newExpList->exprs.push_back(exp);
3661 }
3662 }
3663 auto newAssign = x->new_ptr<Assign_t>();
3664 for (const auto& argName : argNames) {
3665 newAssign->values.push_back(toAst<Exp_t>(argName, x));
3666 }
3667 auto newAssignment = x->new_ptr<ExpListAssign_t>();
3668 newAssignment->expList.set(newExpList);
3669 newAssignment->action.set(newAssign);
3670 auto newStatement = x->new_ptr<Statement_t>();
3671 newStatement->content.set(newAssignment);
3672 followingBlock->statements.push_front(newStatement);
3673 }
3674 argNames.push_back("..."s);
3675 auto newBody = x->new_ptr<Body_t>();
3676 newBody->content.set(followingBlock);
3677 auto funLit = toAst<FunLit_t>('(' + join(argNames, ","sv) + ")->"s, x);
3678 funLit->body.set(newBody);
3679 auto newSimpleValue = x->new_ptr<SimpleValue_t>();
3680 newSimpleValue->value.set(funLit);
3681 auto newExpInParens = newExp(newSimpleValue, x);
3682 auto newParens = x->new_ptr<Parens_t>();
3683 newParens->expr.set(newExpInParens);
3684 auto newCallable = x->new_ptr<Callable_t>();
3685 newCallable->item.set(newParens);
3686 auto newChainValue = x->new_ptr<ChainValue_t>();
3687 newChainValue->items.push_back(newCallable);
3688 auto newInvoke = x->new_ptr<InvokeArgs_t>();
3689 newInvoke->args.dup(assignAction->values);
3690 newChainValue->items.push_back(newInvoke);
3691 auto newItem = newExp(newChainValue, x);
3692 auto newItemList = x->new_ptr<ExpList_t>();
3693 newItemList->exprs.push_back(newItem);
3694 auto newItemListAssign = x->new_ptr<ExpListAssign_t>();
3695 newItemListAssign->expList.set(newItemList);
3696 auto newItemStatement = x->new_ptr<Statement_t>();
3697 newItemStatement->content.set(newItemListAssign);
3698 newBlock->statements.push_back(newItemStatement);
3699 transformBlock(newBlock, out, usage, assignList, isRoot);
3700 return;
3701 BLOCK_END
3702 } else if (auto localAttrib = stmt->content.as<LocalAttrib_t>(); localAttrib && localAttrib->attrib.is<CloseAttrib_t>() && getLuaTarget(localAttrib) < 504) {
3703 auto x = *nodes.begin();
3704 auto newBlock = x->new_ptr<Block_t>();
3705 if (it != nodes.begin()) {
3706 for (auto i = nodes.begin(); i != it; ++i) {
3707 newBlock->statements.push_back(*i);
3708 }
3709 }
3710 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>());
3711 newBlock->statements.push_back(*it);
3712 x = localAttrib;
3713 auto followingBlock = x->new_ptr<Block_t>();
3714 {
3715 auto next = it;
3716 ++next;
3717 if (next != nodes.end()) {
3718 for (auto i = next; i != nodes.end(); ++i) {
3719 followingBlock->statements.push_back(*i);
3720 }
3721 }
3722 }
3723 str_list getCloses;
3724 str_list doCloses;
3725 pushScope();
3726 for (auto var : localAttrib->leftList.objects()) {
3727 auto varName = _parser.toString(ast_to<Variable_t>(var));
3728 auto closeVar = getUnusedName("_close_"sv);
3729 addToScope(closeVar);
3730 getCloses.push_back(closeVar + "=assert "s + varName + ".<close>"s);
3731 doCloses.push_front(closeVar + ' ' + varName);
3732 }
3733 popScope();
3734 auto okVar = getUnusedName("_ok_"sv);
3735 std::string pCallStmtStr;
3736 if (!_varArgs.empty() && _varArgs.top().hasVar) {
3737 pCallStmtStr = okVar + ", ... = pcall((...)->, ...)"s;
3738 } else {
3739 pCallStmtStr = okVar + ", ... = pcall(->)"s;
3740 }
3741 auto pCallStmt = toAst<Statement_t>(pCallStmtStr, x);
3742 auto pCallExp = ast_to<Exp_t>(pCallStmt->content.to<ExpListAssign_t>()->action.to<Assign_t>()->values.back());
3743 auto value = singleValueFrom(pCallExp);
3744 auto invoke = ast_to<Invoke_t>(value->item.to<ChainValue_t>()->items.back());
3745 auto pCallValue = singleValueFrom(ast_to<Exp_t>(invoke->args.front()));
3746 auto pCallFunc = pCallValue->item.to<SimpleValue_t>()->value.to<FunLit_t>();
3747 auto pCallBody = x->new_ptr<Body_t>();
3748 pCallBody->content.set(followingBlock);
3749 pCallFunc->body.set(pCallBody);
3750 for (const auto& stmt : getCloses) {
3751 newBlock->statements.push_back(toAst<Statement_t>(stmt, x));
3752 }
3753 newBlock->statements.push_back(pCallStmt);
3754 for (const auto& stmt : doCloses) {
3755 newBlock->statements.push_back(toAst<Statement_t>(stmt, x));
3756 }
3757 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
3758 transformBlock(newBlock, out, usage, assignList, isRoot);
3759 return;
3612 } 3760 }
3613 if (auto local = stmt->content.as<Local_t>()) { 3761 if (auto local = stmt->content.as<Local_t>()) {
3614 if (!local->collected) { 3762 if (!local->collected) {
@@ -3811,7 +3959,7 @@ private:
3811 int top = lua_gettop(L); 3959 int top = lua_gettop(L);
3812 DEFER(lua_settop(L, top)); 3960 DEFER(lua_settop(L, top));
3813 pushYue("options"sv); // options 3961 pushYue("options"sv); // options
3814 lua_pushlstring(L, &key.front(), key.size()); 3962 lua_pushlstring(L, key.data(), key.size());
3815 lua_gettable(L, -2); 3963 lua_gettable(L, -2);
3816 if (lua_isstring(L, -1) != 0) { 3964 if (lua_isstring(L, -1) != 0) {
3817 size_t size = 0; 3965 size_t size = 0;
@@ -3909,7 +4057,7 @@ private:
3909 lua_getglobal(L, "package"); // package 4057 lua_getglobal(L, "package"); // package
3910 lua_getfield(L, -1, "loaded"); // package loaded 4058 lua_getfield(L, -1, "loaded"); // package loaded
3911 lua_getfield(L, -1, "yue"); // package loaded yue 4059 lua_getfield(L, -1, "yue"); // package loaded yue
3912 lua_pushlstring(L, &name.front(), name.size()); // package loaded yue name 4060 lua_pushlstring(L, name.data(), name.size()); // package loaded yue name
3913 lua_gettable(L, -2); // loaded[name], package loaded yue item 4061 lua_gettable(L, -2); // loaded[name], package loaded yue item
3914 lua_insert(L, -4); // item package loaded yue 4062 lua_insert(L, -4); // item package loaded yue
3915 lua_pop(L, 3); // item 4063 lua_pop(L, 3); // item
@@ -4340,7 +4488,9 @@ private:
4340 } 4488 }
4341 4489
4342 bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList, bool optionalDestruct) { 4490 bool transformChainWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList, bool optionalDestruct) {
4343 auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) { return ast_is<ExistentialOp_t>(node); }); 4491 auto opIt = std::find_if(chainList.begin(), chainList.end(), [](ast_node* node) {
4492 return ast_is<ExistentialOp_t>(node);
4493 });
4344 if (opIt != chainList.end()) { 4494 if (opIt != chainList.end()) {
4345 auto x = chainList.front(); 4495 auto x = chainList.front();
4346 str_list temp; 4496 str_list temp;
@@ -5239,12 +5389,30 @@ private:
5239 auto stmt = static_cast<Statement_t*>(stmt_); 5389 auto stmt = static_cast<Statement_t*>(stmt_);
5240 if (auto global = stmt->content.as<Global_t>()) { 5390 if (auto global = stmt->content.as<Global_t>()) {
5241 if (global->item.is<GlobalOp_t>()) { 5391 if (global->item.is<GlobalOp_t>()) {
5242 throw CompileError("can not insert global statement with wildcard operator from macro"sv, x); 5392 throw CompileError("can not use global statement with wildcard operator in macro"sv, x);
5243 } 5393 }
5244 } else if (auto local = stmt->content.as<Local_t>()) { 5394 } else if (auto local = stmt->content.as<Local_t>()) {
5245 if (local->item.is<LocalFlag_t>()) { 5395 if (local->item.is<LocalFlag_t>()) {
5246 throw CompileError("can not insert local statement with wildcard operator from macro"sv, x); 5396 throw CompileError("can not use local statement with wildcard operator in macro"sv, x);
5397 }
5398 } else if (auto localAttrib = stmt->content.as<LocalAttrib_t>()) {
5399 if (localAttrib->attrib.is<CloseAttrib_t>()) {
5400 throw CompileError("can not use close attribute statement in macro"sv, x);
5247 } 5401 }
5402 } else if (stmt->content.as<Backcall_t>()) {
5403 throw CompileError("can not use back call statement in macro"sv, x);
5404 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
5405 expListAssign && expListAssign->action && expListAssign->action.is<Assign_t>()) {
5406 BLOCK_START
5407 auto unary = singleUnaryExpFrom(expListAssign->expList->exprs.back());
5408 BREAK_IF(!unary->ops.empty());
5409 auto value = static_cast<Value_t*>(unary->expos.front());
5410 auto simpleValue = value->item.as<SimpleValue_t>();
5411 BREAK_IF(!simpleValue);
5412 auto varArg = simpleValue->value.as<VarArg_t>();
5413 BREAK_IF(!varArg);
5414 throw CompileError("can not use variant arguments assignment statement in macro"sv, x);
5415 BLOCK_END
5248 } 5416 }
5249 } 5417 }
5250 } 5418 }
@@ -8729,6 +8897,92 @@ private:
8729 ++i; 8897 ++i;
8730 if (j != je) ++j; 8898 if (j != je) ++j;
8731 } 8899 }
8900 bool checkValuesLater = false;
8901 if (listA->names.size() > assignA->values.size()) {
8902 BLOCK_START
8903 switch (assignA->values.back()->get_id()) {
8904 case id<If_t>():
8905 case id<Switch_t>():
8906 checkValuesLater = true;
8907 break;
8908 }
8909 BREAK_IF(checkValuesLater);
8910 auto value = singleValueFrom(assignA->values.back());
8911 if (!value) {
8912 _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size();
8913 throw CompileError(clearBuf(), assignA->values.front());
8914 }
8915 if (auto val = value->item.as<SimpleValue_t>()) {
8916 switch (val->value->get_id()) {
8917 case id<If_t>():
8918 case id<Switch_t>():
8919 case id<Do_t>():
8920 case id<Try_t>():
8921 checkValuesLater = true;
8922 break;
8923 }
8924 BREAK_IF(checkValuesLater);
8925 }
8926 auto chainValue = value->item.as<ChainValue_t>();
8927 if (!chainValue || !ast_is<Invoke_t, InvokeArgs_t>(chainValue->items.back())) {
8928 _buf << listA->names.size() << " right values expected, got "sv << assignA->values.size();
8929 throw CompileError(clearBuf(), assignA->values.front());
8930 }
8931 BLOCK_END
8932 }
8933 if (checkValuesLater || (!listB->exprs.empty() && assignB->values.empty())) {
8934 auto leftList = x->new_ptr<ExpList_t>();
8935 auto assign = x->new_ptr<Assign_t>();
8936 str_list vars;
8937 for (auto varNode : listA->names.objects()) {
8938 auto var = _parser.toString(varNode);
8939 forceAddToScope(var);
8940 vars.push_back(var);
8941 auto callable = x->new_ptr<Callable_t>();
8942 callable->item.set(varNode);
8943 auto chainValue = x->new_ptr<ChainValue_t>();
8944 chainValue->items.push_back(callable);
8945 leftList->exprs.push_back(newExp(chainValue, x));
8946 }
8947 leftList->exprs.dup(listB->exprs);
8948 assign->values.dup(assignA->values);
8949 assign->values.dup(assignB->values);
8950 auto assignment = x->new_ptr<ExpListAssign_t>();
8951 assignment->expList.set(leftList);
8952 assignment->action.set(assign);
8953 auto info = extractDestructureInfo(assignment, true, false);
8954 for (auto& destruct : info.destructures) {
8955 for (auto& item : destruct.items) {
8956 if (item.targetVar.empty()) {
8957 throw CompileError("can only declare variable as const"sv, item.target);
8958 }
8959 forceAddToScope(item.targetVar);
8960 vars.push_back(item.targetVar);
8961 }
8962 }
8963 str_list temp;
8964 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x));
8965 transformAssignment(assignment, temp);
8966 for (const auto& name : vars) {
8967 markVarConst(name);
8968 }
8969 if (localAttrib->attrib.is<CloseAttrib_t>()) {
8970 str_list leftVars, rightVars;
8971 pushScope();
8972 for (auto name : listA->names.objects()) {
8973 auto closeName = getUnusedName("_close_"sv);
8974 leftVars.push_back(closeName);
8975 rightVars.push_back(_parser.toString(name));
8976 addToScope(closeName);
8977 }
8978 popScope();
8979 auto postAssignment = toAst<LocalAttrib_t>("close "s + join(leftVars, ","sv) + '=' + join(rightVars, ","sv), x);
8980 transformLocalAttrib(postAssignment, temp);
8981 }
8982 out.push_back(join(temp));
8983 return;
8984 }
8985 str_list temp;
8732 if (!listA->names.empty()) { 8986 if (!listA->names.empty()) {
8733 str_list vars; 8987 str_list vars;
8734 for (auto name : listA->names.objects()) { 8988 for (auto name : listA->names.objects()) {
@@ -8736,40 +8990,77 @@ private:
8736 forceAddToScope(var); 8990 forceAddToScope(var);
8737 vars.push_back(var); 8991 vars.push_back(var);
8738 } 8992 }
8739 if (getLuaTarget(x) >= 504) { 8993 int target = getLuaTarget(x);
8740 std::string attrib; 8994 if (target < 504) {
8741 if (localAttrib->attrib.is<ConstAttrib_t>()) { 8995 if (localAttrib->attrib.is<CloseAttrib_t>()) {
8742 attrib = " <const>"s; 8996 throw CompileError("close attribute is not available when not targeting Lua version 5.4 or higher"sv, x);
8743 } else if (localAttrib->attrib.is<CloseAttrib_t>()) {
8744 attrib = " <close>"s;
8745 } else {
8746 YUEE("AST node mismatch", localAttrib->attrib);
8747 } 8997 }
8748 for (auto& var : vars) { 8998 }
8749 markVarConst(var); 8999 if (localAttrib->attrib.is<CloseAttrib_t>()) {
8750 var.append(attrib); 9000 str_list items;
9001 for (auto item : assignA->values.objects()) {
9002 transformAssignItem(item, items);
9003 }
9004 if (listA->names.size() == assignA->values.size()) {
9005 auto lit = vars.begin();
9006 auto rit = items.begin();
9007 str_list tmp;
9008 while (lit != vars.end()) {
9009 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x));
9010 lit++;
9011 rit++;
9012 }
9013 temp.push_back(join(tmp));
9014 } else {
9015 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x));
9016 str_list leftVars;
9017 pushScope();
9018 for (size_t i = 0; i < vars.size(); i++) {
9019 auto closeName = getUnusedName("_close_"sv);
9020 leftVars.push_back(closeName);
9021 addToScope(closeName);
9022 }
9023 popScope();
9024 auto postAssignment = toAst<LocalAttrib_t>("close "s + join(leftVars, ","sv) + '=' + join(vars, ","sv), x);
9025 transformLocalAttrib(postAssignment, temp);
8751 } 9026 }
8752 } else { 9027 } else {
8753 if (localAttrib->attrib.is<CloseAttrib_t>()) { 9028 str_list leftVars;
8754 throw CompileError("close attribute is not available when not targeting Lua version 5.4 or higher"sv, x); 9029 for (const auto& var : vars) {
9030 leftVars.push_back(var + (target >= 504 ? " <const>"s : ""s));
8755 } 9031 }
8756 for (auto& var : vars) { 9032 str_list items;
8757 markVarConst(var); 9033 for (auto item : assignA->values.objects()) {
9034 transformAssignItem(item, items);
8758 } 9035 }
9036 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x));
8759 } 9037 }
8760 str_list temp; 9038 for (const auto& var : vars) {
8761 for (auto item : assignA->values.objects()) { 9039 markVarConst(var);
8762 transformAssignItem(item, temp);
8763 } 9040 }
8764 out.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(temp, ", "sv) + nll(x));
8765 } 9041 }
8766 if (!listB->exprs.empty()) { 9042 if (!listB->exprs.empty()) {
8767 auto assignment = x->new_ptr<ExpListAssign_t>(); 9043 auto assignment = x->new_ptr<ExpListAssign_t>();
8768 assignment->expList.set(listB); 9044 assignment->expList.set(listB);
8769 assignment->action.set(assignB); 9045 assignment->action.set(assignB);
8770 transformAssignment(assignment, out); 9046 auto info = extractDestructureInfo(assignment, true, false);
8771 markDestructureConst(assignment); 9047 str_list vars;
9048 for (auto& destruct : info.destructures) {
9049 for (auto& item : destruct.items) {
9050 if (item.targetVar.empty()) {
9051 throw CompileError("can only declare variable as const"sv, item.target);
9052 }
9053 forceAddToScope(item.targetVar);
9054 vars.push_back(item.targetVar);
9055 }
9056 }
9057 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x));
9058 transformAssignment(assignment, temp);
9059 for (const auto& name : vars) {
9060 markVarConst(name);
9061 }
8772 } 9062 }
9063 out.push_back(join(temp));
8773 } 9064 }
8774 9065
8775 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 9066 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {