diff options
author | Li Jin <dragon-fly@qq.com> | 2023-08-07 09:57:27 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2023-08-07 09:57:27 +0800 |
commit | c9b70274787ed8a77e7b47c4628197f0c6c1ba30 (patch) | |
tree | fae88047d312962aebfd97a0183c2f9f19e2cc76 /src/yuescript/yue_compiler.cpp | |
parent | aff8e69bf589d2ee5f4a7b72b7e2f643d55b87fa (diff) | |
download | yuescript-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.cpp | 375 |
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 | ||
75 | const std::string_view version = "0.17.14"sv; | 77 | const std::string_view version = "0.18.0"sv; |
76 | const std::string_view extension = "yue"sv; | 78 | const std::string_view extension = "yue"sv; |
77 | 79 | ||
78 | class CompileError : public std::logic_error { | 80 | class 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) { |