diff options
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) { |
