diff options
| author | Li Jin <dragon-fly@qq.com> | 2022-09-30 11:29:41 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2022-09-30 11:29:41 +0800 |
| commit | 5aa41b436b3fdf29f5a0046c68cb60b16fa09eb2 (patch) | |
| tree | 5c5c0ecdab0d19544652bc05b70d8131e1645337 /src/yuescript/yue_compiler.cpp | |
| parent | a6b6753fda9745f316f3236462b74794b35b85c9 (diff) | |
| download | yuescript-5aa41b436b3fdf29f5a0046c68cb60b16fa09eb2.tar.gz yuescript-5aa41b436b3fdf29f5a0046c68cb60b16fa09eb2.tar.bz2 yuescript-5aa41b436b3fdf29f5a0046c68cb60b16fa09eb2.zip | |
fix issue #81, refactor continue with gotos.
Diffstat (limited to '')
| -rw-r--r--[-rwxr-xr-x] | src/yuescript/yue_compiler.cpp | 348 |
1 files changed, 240 insertions, 108 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 1d949fe..672f2d4 100755..100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -14,6 +14,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI | |||
| 14 | #include <unordered_map> | 14 | #include <unordered_map> |
| 15 | #include <unordered_set> | 15 | #include <unordered_set> |
| 16 | #include <vector> | 16 | #include <vector> |
| 17 | #include <optional> | ||
| 17 | 18 | ||
| 18 | #include "yuescript/yue_compiler.h" | 19 | #include "yuescript/yue_compiler.h" |
| 19 | #include "yuescript/yue_parser.h" | 20 | #include "yuescript/yue_parser.h" |
| @@ -59,7 +60,7 @@ namespace yue { | |||
| 59 | 60 | ||
| 60 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
| 61 | 62 | ||
| 62 | const std::string_view version = "0.15.3"sv; | 63 | const std::string_view version = "0.15.4"sv; |
| 63 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
| 64 | 65 | ||
| 65 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
| @@ -146,11 +147,30 @@ public: | |||
| 146 | str_list out; | 147 | str_list out; |
| 147 | pushScope(); | 148 | pushScope(); |
| 148 | _enableReturn.push(_info.moduleName.empty()); | 149 | _enableReturn.push(_info.moduleName.empty()); |
| 150 | _gotoScopes.push(0); | ||
| 151 | _gotoScope = 1; | ||
| 149 | _varArgs.push({true, false}); | 152 | _varArgs.push({true, false}); |
| 150 | transformBlock(block, out, | 153 | transformBlock(block, out, |
| 151 | config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common, | 154 | config.implicitReturnRoot ? ExpUsage::Return : ExpUsage::Common, |
| 152 | nullptr, true); | 155 | nullptr, true); |
| 153 | popScope(); | 156 | popScope(); |
| 157 | if (!gotos.empty()) { | ||
| 158 | for (const auto& gotoNode : gotos) { | ||
| 159 | bool noLabel = true; | ||
| 160 | BLOCK_START | ||
| 161 | BREAK_IF(static_cast<int>(_labels.size()) <= gotoNode.scope); | ||
| 162 | BREAK_IF(_labels[gotoNode.scope] == std::nullopt); | ||
| 163 | const auto& scope = _labels[gotoNode.scope].value(); | ||
| 164 | auto it = scope.find(gotoNode.label); | ||
| 165 | BREAK_IF(it == scope.end()); | ||
| 166 | BREAK_IF(gotoNode.level < it->second.level); | ||
| 167 | noLabel = false; | ||
| 168 | BLOCK_END | ||
| 169 | if (noLabel) { | ||
| 170 | throw std::logic_error(_info.errorMessage("no visible label '"s + gotoNode.label + "' for <goto>"s, gotoNode.ptr->label)); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 154 | if (config.lintGlobalVariable) { | 174 | if (config.lintGlobalVariable) { |
| 155 | globals = std::make_unique<GlobalVars>(); | 175 | globals = std::make_unique<GlobalVars>(); |
| 156 | for (const auto& var : _globals) { | 176 | for (const auto& var : _globals) { |
| @@ -256,6 +276,20 @@ private: | |||
| 256 | std::ostringstream _buf; | 276 | std::ostringstream _buf; |
| 257 | std::ostringstream _joinBuf; | 277 | std::ostringstream _joinBuf; |
| 258 | const std::string _newLine = "\n"; | 278 | const std::string _newLine = "\n"; |
| 279 | int _gotoScope = 0; | ||
| 280 | std::stack<int> _gotoScopes; | ||
| 281 | struct LabelNode { | ||
| 282 | int line; | ||
| 283 | int level; | ||
| 284 | }; | ||
| 285 | std::vector<std::optional<std::unordered_map<std::string, LabelNode>>> _labels; | ||
| 286 | struct GotoNode { | ||
| 287 | ast_ptr<true, Goto_t> ptr; | ||
| 288 | std::string label; | ||
| 289 | int scope; | ||
| 290 | int level; | ||
| 291 | }; | ||
| 292 | std::list<GotoNode> gotos; | ||
| 259 | 293 | ||
| 260 | enum class LocalMode { | 294 | enum class LocalMode { |
| 261 | None = 0, | 295 | None = 0, |
| @@ -457,13 +491,30 @@ private: | |||
| 457 | std::string getUnusedName(std::string_view name) const { | 491 | std::string getUnusedName(std::string_view name) const { |
| 458 | int index = 0; | 492 | int index = 0; |
| 459 | std::string newName; | 493 | std::string newName; |
| 494 | std::string nameStr(name); | ||
| 460 | do { | 495 | do { |
| 461 | newName = std::string(name) + std::to_string(index); | 496 | newName = nameStr + std::to_string(index); |
| 462 | index++; | 497 | index++; |
| 463 | } while (isLocal(newName)); | 498 | } while (isLocal(newName)); |
| 464 | return newName; | 499 | return newName; |
| 465 | } | 500 | } |
| 466 | 501 | ||
| 502 | std::string getUnusedLabel(std::string_view label) const { | ||
| 503 | int scopeIndex = _gotoScopes.top(); | ||
| 504 | if (static_cast<int>(_labels.size()) <= scopeIndex || _labels[scopeIndex] == std::nullopt) { | ||
| 505 | return std::string(label) + '0'; | ||
| 506 | } | ||
| 507 | auto& scope = _labels[scopeIndex].value(); | ||
| 508 | int index = 0; | ||
| 509 | std::string newLabel; | ||
| 510 | std::string labelStr(label); | ||
| 511 | do { | ||
| 512 | newLabel = labelStr + std::to_string(index); | ||
| 513 | index++; | ||
| 514 | } while (scope.find(newLabel) != scope.end()); | ||
| 515 | return newLabel; | ||
| 516 | } | ||
| 517 | |||
| 467 | std::string transformCondExp(Exp_t* cond, bool unless) { | 518 | std::string transformCondExp(Exp_t* cond, bool unless) { |
| 468 | str_list tmp; | 519 | str_list tmp; |
| 469 | if (unless) { | 520 | if (unless) { |
| @@ -975,6 +1026,17 @@ private: | |||
| 975 | return false; | 1026 | return false; |
| 976 | } | 1027 | } |
| 977 | 1028 | ||
| 1029 | void pushFunctionScope() { | ||
| 1030 | _enableReturn.push(true); | ||
| 1031 | _gotoScopes.push(_gotoScope); | ||
| 1032 | _gotoScope++; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | void popFunctionScope() { | ||
| 1036 | _enableReturn.pop(); | ||
| 1037 | _gotoScopes.pop(); | ||
| 1038 | } | ||
| 1039 | |||
| 978 | void pushAnonVarArg() { | 1040 | void pushAnonVarArg() { |
| 979 | if (!_varArgs.empty() && _varArgs.top().hasVar) { | 1041 | if (!_varArgs.empty() && _varArgs.top().hasVar) { |
| 980 | _varArgs.push({true, false}); | 1042 | _varArgs.push({true, false}); |
| @@ -2642,7 +2704,7 @@ private: | |||
| 2642 | str_list temp; | 2704 | str_list temp; |
| 2643 | std::string* funcStart = nullptr; | 2705 | std::string* funcStart = nullptr; |
| 2644 | if (usage == ExpUsage::Closure) { | 2706 | if (usage == ExpUsage::Closure) { |
| 2645 | _enableReturn.push(true); | 2707 | pushFunctionScope(); |
| 2646 | pushAnonVarArg(); | 2708 | pushAnonVarArg(); |
| 2647 | funcStart = &temp.emplace_back(); | 2709 | funcStart = &temp.emplace_back(); |
| 2648 | pushScope(); | 2710 | pushScope(); |
| @@ -2765,7 +2827,7 @@ private: | |||
| 2765 | *funcStart = anonFuncStart() + nll(nodes.front()); | 2827 | *funcStart = anonFuncStart() + nll(nodes.front()); |
| 2766 | temp.push_back(indent() + anonFuncEnd()); | 2828 | temp.push_back(indent() + anonFuncEnd()); |
| 2767 | popAnonVarArg(); | 2829 | popAnonVarArg(); |
| 2768 | _enableReturn.pop(); | 2830 | popFunctionScope(); |
| 2769 | } | 2831 | } |
| 2770 | out.push_back(join(temp)); | 2832 | out.push_back(join(temp)); |
| 2771 | } | 2833 | } |
| @@ -2928,7 +2990,7 @@ private: | |||
| 2928 | } | 2990 | } |
| 2929 | std::string* funcStart = nullptr; | 2991 | std::string* funcStart = nullptr; |
| 2930 | if (usage == ExpUsage::Closure) { | 2992 | if (usage == ExpUsage::Closure) { |
| 2931 | _enableReturn.push(true); | 2993 | pushFunctionScope(); |
| 2932 | pushAnonVarArg(); | 2994 | pushAnonVarArg(); |
| 2933 | funcStart = &temp.emplace_back(); | 2995 | funcStart = &temp.emplace_back(); |
| 2934 | pushScope(); | 2996 | pushScope(); |
| @@ -2974,7 +3036,7 @@ private: | |||
| 2974 | *funcStart = anonFuncStart() + nll(x); | 3036 | *funcStart = anonFuncStart() + nll(x); |
| 2975 | temp.push_back(indent() + anonFuncEnd()); | 3037 | temp.push_back(indent() + anonFuncEnd()); |
| 2976 | popAnonVarArg(); | 3038 | popAnonVarArg(); |
| 2977 | _enableReturn.pop(); | 3039 | popFunctionScope(); |
| 2978 | } | 3040 | } |
| 2979 | break; | 3041 | break; |
| 2980 | } | 3042 | } |
| @@ -3091,7 +3153,7 @@ private: | |||
| 3091 | } | 3153 | } |
| 3092 | 3154 | ||
| 3093 | void transformFunLit(FunLit_t* funLit, str_list& out) { | 3155 | void transformFunLit(FunLit_t* funLit, str_list& out) { |
| 3094 | _enableReturn.push(true); | 3156 | pushFunctionScope(); |
| 3095 | _varArgs.push({false, false}); | 3157 | _varArgs.push({false, false}); |
| 3096 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; | 3158 | bool isFatArrow = _parser.toString(funLit->arrow) == "=>"sv; |
| 3097 | pushScope(); | 3159 | pushScope(); |
| @@ -3142,7 +3204,7 @@ private: | |||
| 3142 | } | 3204 | } |
| 3143 | } | 3205 | } |
| 3144 | out.push_back(clearBuf()); | 3206 | out.push_back(clearBuf()); |
| 3145 | _enableReturn.pop(); | 3207 | popFunctionScope(); |
| 3146 | _varArgs.pop(); | 3208 | _varArgs.pop(); |
| 3147 | } | 3209 | } |
| 3148 | 3210 | ||
| @@ -3979,7 +4041,7 @@ private: | |||
| 3979 | str_list temp; | 4041 | str_list temp; |
| 3980 | std::string* funcStart = nullptr; | 4042 | std::string* funcStart = nullptr; |
| 3981 | if (usage == ExpUsage::Closure) { | 4043 | if (usage == ExpUsage::Closure) { |
| 3982 | _enableReturn.push(true); | 4044 | pushFunctionScope(); |
| 3983 | pushAnonVarArg(); | 4045 | pushAnonVarArg(); |
| 3984 | funcStart = &temp.emplace_back(); | 4046 | funcStart = &temp.emplace_back(); |
| 3985 | pushScope(); | 4047 | pushScope(); |
| @@ -4122,7 +4184,7 @@ private: | |||
| 4122 | *funcStart = anonFuncStart() + nll(x); | 4184 | *funcStart = anonFuncStart() + nll(x); |
| 4123 | temp.push_back(indent() + anonFuncEnd()); | 4185 | temp.push_back(indent() + anonFuncEnd()); |
| 4124 | popAnonVarArg(); | 4186 | popAnonVarArg(); |
| 4125 | _enableReturn.pop(); | 4187 | popFunctionScope(); |
| 4126 | break; | 4188 | break; |
| 4127 | default: | 4189 | default: |
| 4128 | break; | 4190 | break; |
| @@ -4148,7 +4210,7 @@ private: | |||
| 4148 | pushScope(); | 4210 | pushScope(); |
| 4149 | break; | 4211 | break; |
| 4150 | case ExpUsage::Closure: | 4212 | case ExpUsage::Closure: |
| 4151 | _enableReturn.push(true); | 4213 | pushFunctionScope(); |
| 4152 | pushAnonVarArg(); | 4214 | pushAnonVarArg(); |
| 4153 | funcStart = &temp.emplace_back(); | 4215 | funcStart = &temp.emplace_back(); |
| 4154 | pushScope(); | 4216 | pushScope(); |
| @@ -4226,7 +4288,7 @@ private: | |||
| 4226 | *funcStart = anonFuncStart() + nll(x); | 4288 | *funcStart = anonFuncStart() + nll(x); |
| 4227 | temp.push_back(indent() + anonFuncEnd()); | 4289 | temp.push_back(indent() + anonFuncEnd()); |
| 4228 | popAnonVarArg(); | 4290 | popAnonVarArg(); |
| 4229 | _enableReturn.pop(); | 4291 | popFunctionScope(); |
| 4230 | break; | 4292 | break; |
| 4231 | default: | 4293 | default: |
| 4232 | break; | 4294 | break; |
| @@ -4283,7 +4345,7 @@ private: | |||
| 4283 | str_list temp; | 4345 | str_list temp; |
| 4284 | std::string* funcStart = nullptr; | 4346 | std::string* funcStart = nullptr; |
| 4285 | if (usage == ExpUsage::Closure) { | 4347 | if (usage == ExpUsage::Closure) { |
| 4286 | _enableReturn.push(true); | 4348 | pushFunctionScope(); |
| 4287 | pushAnonVarArg(); | 4349 | pushAnonVarArg(); |
| 4288 | funcStart = &temp.emplace_back(); | 4350 | funcStart = &temp.emplace_back(); |
| 4289 | pushScope(); | 4351 | pushScope(); |
| @@ -4326,7 +4388,7 @@ private: | |||
| 4326 | *funcStart = anonFuncStart() + nll(x); | 4388 | *funcStart = anonFuncStart() + nll(x); |
| 4327 | temp.push_back(indent() + anonFuncEnd()); | 4389 | temp.push_back(indent() + anonFuncEnd()); |
| 4328 | popAnonVarArg(); | 4390 | popAnonVarArg(); |
| 4329 | _enableReturn.pop(); | 4391 | popFunctionScope(); |
| 4330 | break; | 4392 | break; |
| 4331 | } | 4393 | } |
| 4332 | case ExpUsage::Return: { | 4394 | case ExpUsage::Return: { |
| @@ -5052,7 +5114,7 @@ private: | |||
| 5052 | auto x = values.front(); | 5114 | auto x = values.front(); |
| 5053 | switch (usage) { | 5115 | switch (usage) { |
| 5054 | case ExpUsage::Closure: | 5116 | case ExpUsage::Closure: |
| 5055 | _enableReturn.push(true); | 5117 | pushFunctionScope(); |
| 5056 | pushAnonVarArg(); | 5118 | pushAnonVarArg(); |
| 5057 | pushScope(); | 5119 | pushScope(); |
| 5058 | break; | 5120 | break; |
| @@ -5255,7 +5317,7 @@ private: | |||
| 5255 | out.back().insert(0, anonFuncStart() + nll(x)); | 5317 | out.back().insert(0, anonFuncStart() + nll(x)); |
| 5256 | out.back().append(indent() + anonFuncEnd()); | 5318 | out.back().append(indent() + anonFuncEnd()); |
| 5257 | popAnonVarArg(); | 5319 | popAnonVarArg(); |
| 5258 | _enableReturn.pop(); | 5320 | popFunctionScope(); |
| 5259 | break; | 5321 | break; |
| 5260 | } | 5322 | } |
| 5261 | case ExpUsage::Assignment: { | 5323 | case ExpUsage::Assignment: { |
| @@ -5447,7 +5509,7 @@ private: | |||
| 5447 | auto x = comp; | 5509 | auto x = comp; |
| 5448 | switch (usage) { | 5510 | switch (usage) { |
| 5449 | case ExpUsage::Closure: | 5511 | case ExpUsage::Closure: |
| 5450 | _enableReturn.push(true); | 5512 | pushFunctionScope(); |
| 5451 | pushAnonVarArg(); | 5513 | pushAnonVarArg(); |
| 5452 | pushScope(); | 5514 | pushScope(); |
| 5453 | break; | 5515 | break; |
| @@ -5511,7 +5573,7 @@ private: | |||
| 5511 | out.back().insert(0, anonFuncStart() + nll(comp)); | 5573 | out.back().insert(0, anonFuncStart() + nll(comp)); |
| 5512 | out.back().append(indent() + anonFuncEnd()); | 5574 | out.back().append(indent() + anonFuncEnd()); |
| 5513 | popAnonVarArg(); | 5575 | popAnonVarArg(); |
| 5514 | _enableReturn.pop(); | 5576 | popFunctionScope(); |
| 5515 | break; | 5577 | break; |
| 5516 | } | 5578 | } |
| 5517 | case ExpUsage::Assignment: { | 5579 | case ExpUsage::Assignment: { |
| @@ -5804,44 +5866,80 @@ private: | |||
| 5804 | str_list temp; | 5866 | str_list temp; |
| 5805 | bool extraDo = false; | 5867 | bool extraDo = false; |
| 5806 | bool withContinue = hasContinueStatement(body); | 5868 | bool withContinue = hasContinueStatement(body); |
| 5869 | int target = getLuaTarget(body); | ||
| 5870 | std::string extraLabel; | ||
| 5807 | if (withContinue) { | 5871 | if (withContinue) { |
| 5808 | if (auto block = ast_cast<Block_t>(body)) { | 5872 | if (target < 502) { |
| 5809 | if (!block->statements.empty()) { | 5873 | if (auto block = ast_cast<Block_t>(body)) { |
| 5810 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 5874 | if (!block->statements.empty()) { |
| 5811 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 5875 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
| 5812 | extraDo = _parser.toString(breakLoop) == "break"sv; | 5876 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 5877 | extraDo = _parser.toString(breakLoop) == "break"sv; | ||
| 5878 | } | ||
| 5813 | } | 5879 | } |
| 5814 | } | 5880 | } |
| 5815 | } | 5881 | auto continueVar = getUnusedName("_continue_"sv); |
| 5816 | auto continueVar = getUnusedName("_continue_"sv); | 5882 | addToScope(continueVar); |
| 5817 | addToScope(continueVar); | 5883 | _continueVars.push({continueVar, nullptr}); |
| 5818 | _continueVars.push({continueVar, nullptr}); | 5884 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); |
| 5819 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 5885 | _buf << indent() << "repeat"sv << nll(body); |
| 5820 | _buf << indent() << "repeat"sv << nll(body); | ||
| 5821 | pushScope(); | ||
| 5822 | if (extraDo) { | ||
| 5823 | _buf << indent() << "do"sv << nll(body); | ||
| 5824 | pushScope(); | 5886 | pushScope(); |
| 5887 | if (extraDo) { | ||
| 5888 | _buf << indent() << "do"sv << nll(body); | ||
| 5889 | pushScope(); | ||
| 5890 | } | ||
| 5891 | temp.push_back(clearBuf()); | ||
| 5892 | } else { | ||
| 5893 | auto continueLabel = getUnusedLabel("_continue_"sv); | ||
| 5894 | _continueVars.push({continueLabel, nullptr}); | ||
| 5895 | transformLabel(toAst<Label_t>("::"s + _continueVars.top().var + "::"s, body), temp); | ||
| 5896 | extraLabel = temp.back(); | ||
| 5897 | temp.pop_back(); | ||
| 5898 | } | ||
| 5899 | if (auto block = ast_cast<Block_t>(body); body && !block->statements.empty()) { | ||
| 5900 | auto last = static_cast<Statement_t*>(block->statements.back()); | ||
| 5901 | if (last->content.is<Return_t>()) { | ||
| 5902 | auto doNode = last->new_ptr<Do_t>(); | ||
| 5903 | auto newBody = last->new_ptr<Body_t>(); | ||
| 5904 | auto newStmt = last->new_ptr<Statement_t>(); | ||
| 5905 | newStmt->content.set(last->content); | ||
| 5906 | newBody->content.set(newStmt); | ||
| 5907 | doNode->body.set(newBody); | ||
| 5908 | auto simpleValue = last->new_ptr<SimpleValue_t>(); | ||
| 5909 | simpleValue->value.set(doNode); | ||
| 5910 | auto expList = last->new_ptr<ExpList_t>(); | ||
| 5911 | expList->exprs.push_back(newExp(simpleValue, last)); | ||
| 5912 | auto expListAssign = last->new_ptr<ExpListAssign_t>(); | ||
| 5913 | expListAssign->expList.set(expList); | ||
| 5914 | last->content.set(expListAssign); | ||
| 5915 | } | ||
| 5825 | } | 5916 | } |
| 5826 | temp.push_back(clearBuf()); | ||
| 5827 | } | 5917 | } |
| 5828 | transform_plain_body(body, temp, usage, assignList); | 5918 | transform_plain_body(body, temp, usage, assignList); |
| 5829 | if (withContinue) { | 5919 | if (withContinue) { |
| 5830 | if (extraDo) { | 5920 | if (target < 502) { |
| 5921 | if (extraDo) { | ||
| 5922 | popScope(); | ||
| 5923 | _buf << indent() << "end"sv << nll(body); | ||
| 5924 | } | ||
| 5925 | if (!appendContent.empty()) { | ||
| 5926 | _buf << indent() << appendContent; | ||
| 5927 | } | ||
| 5928 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
| 5831 | popScope(); | 5929 | popScope(); |
| 5832 | _buf << indent() << "end"sv << nll(body); | 5930 | _buf << indent() << "until true"sv << nlr(body); |
| 5833 | } | 5931 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); |
| 5834 | if (!appendContent.empty()) { | 5932 | _buf << indent(1) << "break"sv << nlr(body); |
| 5835 | _buf << indent() << appendContent; | 5933 | _buf << indent() << "end"sv << nlr(body); |
| 5934 | temp.push_back(clearBuf()); | ||
| 5935 | _continueVars.pop(); | ||
| 5936 | } else { | ||
| 5937 | if (!appendContent.empty()) { | ||
| 5938 | temp.push_back(indent() + appendContent); | ||
| 5939 | } | ||
| 5940 | temp.push_back(extraLabel); | ||
| 5941 | _continueVars.pop(); | ||
| 5836 | } | 5942 | } |
| 5837 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
| 5838 | popScope(); | ||
| 5839 | _buf << indent() << "until true"sv << nlr(body); | ||
| 5840 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
| 5841 | _buf << indent(1) << "break"sv << nlr(body); | ||
| 5842 | _buf << indent() << "end"sv << nlr(body); | ||
| 5843 | temp.push_back(clearBuf()); | ||
| 5844 | _continueVars.pop(); | ||
| 5845 | } else if (!appendContent.empty()) { | 5943 | } else if (!appendContent.empty()) { |
| 5846 | temp.back().append(indent() + appendContent); | 5944 | temp.back().append(indent() + appendContent); |
| 5847 | } | 5945 | } |
| @@ -5854,56 +5952,67 @@ private: | |||
| 5854 | auto body = repeatNode->body->content.get(); | 5952 | auto body = repeatNode->body->content.get(); |
| 5855 | bool withContinue = hasContinueStatement(body); | 5953 | bool withContinue = hasContinueStatement(body); |
| 5856 | std::string conditionVar; | 5954 | std::string conditionVar; |
| 5955 | std::string extraLabel; | ||
| 5956 | ast_ptr<false, ExpListAssign_t> condAssign; | ||
| 5957 | int target = getLuaTarget(repeatNode); | ||
| 5857 | if (withContinue) { | 5958 | if (withContinue) { |
| 5858 | if (auto block = ast_cast<Block_t>(body)) { | 5959 | if (target < 502) { |
| 5859 | if (!block->statements.empty()) { | 5960 | if (auto block = ast_cast<Block_t>(body)) { |
| 5860 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | 5961 | if (!block->statements.empty()) { |
| 5861 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | 5962 | auto stmt = static_cast<Statement_t*>(block->statements.back()); |
| 5862 | extraDo = _parser.toString(breakLoop) == "break"sv; | 5963 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { |
| 5964 | extraDo = _parser.toString(breakLoop) == "break"sv; | ||
| 5965 | } | ||
| 5863 | } | 5966 | } |
| 5864 | } | 5967 | } |
| 5865 | } | 5968 | conditionVar = getUnusedName("_cond_"); |
| 5866 | conditionVar = getUnusedName("_cond_"); | 5969 | forceAddToScope(conditionVar); |
| 5867 | forceAddToScope(conditionVar); | 5970 | auto continueVar = getUnusedName("_continue_"sv); |
| 5868 | auto continueVar = getUnusedName("_continue_"sv); | 5971 | forceAddToScope(continueVar); |
| 5869 | forceAddToScope(continueVar); | 5972 | { |
| 5870 | { | 5973 | auto assignment = toAst<ExpListAssign_t>(conditionVar + "=nil"s, repeatNode->condition); |
| 5871 | auto assignment = toAst<ExpListAssign_t>(conditionVar + "=nil"s, repeatNode->condition); | 5974 | auto assign = assignment->action.to<Assign_t>(); |
| 5872 | auto assign = assignment->action.to<Assign_t>(); | 5975 | assign->values.clear(); |
| 5873 | assign->values.clear(); | 5976 | assign->values.push_back(repeatNode->condition); |
| 5874 | assign->values.push_back(repeatNode->condition); | 5977 | _continueVars.push({continueVar, assignment.get()}); |
| 5875 | _continueVars.push({continueVar, assignment.get()}); | 5978 | } |
| 5876 | } | 5979 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); |
| 5877 | _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); | 5980 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); |
| 5878 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | 5981 | _buf << indent() << "repeat"sv << nll(body); |
| 5879 | _buf << indent() << "repeat"sv << nll(body); | ||
| 5880 | pushScope(); | ||
| 5881 | if (extraDo) { | ||
| 5882 | _buf << indent() << "do"sv << nll(body); | ||
| 5883 | pushScope(); | 5982 | pushScope(); |
| 5983 | if (extraDo) { | ||
| 5984 | _buf << indent() << "do"sv << nll(body); | ||
| 5985 | pushScope(); | ||
| 5986 | } | ||
| 5987 | temp.push_back(clearBuf()); | ||
| 5988 | } else { | ||
| 5989 | auto continueLabel = getUnusedLabel("_continue_"sv); | ||
| 5990 | _continueVars.push({continueLabel, nullptr}); | ||
| 5991 | transformLabel(toAst<Label_t>("::"s + _continueVars.top().var + "::"s, body), temp); | ||
| 5992 | extraLabel = temp.back(); | ||
| 5993 | temp.pop_back(); | ||
| 5884 | } | 5994 | } |
| 5885 | temp.push_back(clearBuf()); | ||
| 5886 | } | 5995 | } |
| 5887 | transform_plain_body(body, temp, ExpUsage::Common); | 5996 | transform_plain_body(body, temp, ExpUsage::Common); |
| 5888 | if (withContinue) { | 5997 | if (withContinue) { |
| 5889 | { | 5998 | if (target < 502) { |
| 5890 | transformAssignment(_continueVars.top().condAssign, temp); | 5999 | transformAssignment(_continueVars.top().condAssign, temp); |
| 5891 | auto assignCond = std::move(temp.back()); | 6000 | if (extraDo) { |
| 5892 | temp.pop_back(); | 6001 | popScope(); |
| 5893 | temp.back().append(assignCond); | 6002 | _buf << indent() << "end"sv << nll(body); |
| 5894 | } | 6003 | } |
| 5895 | if (extraDo) { | 6004 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); |
| 5896 | popScope(); | 6005 | popScope(); |
| 5897 | _buf << indent() << "end"sv << nll(body); | 6006 | _buf << indent() << "until true"sv << nlr(body); |
| 6007 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
| 6008 | _buf << indent(1) << "break"sv << nlr(body); | ||
| 6009 | _buf << indent() << "end"sv << nlr(body); | ||
| 6010 | temp.push_back(clearBuf()); | ||
| 6011 | _continueVars.pop(); | ||
| 6012 | } else { | ||
| 6013 | temp.push_back(extraLabel); | ||
| 6014 | _continueVars.pop(); | ||
| 5898 | } | 6015 | } |
| 5899 | _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); | ||
| 5900 | popScope(); | ||
| 5901 | _buf << indent() << "until true"sv << nlr(body); | ||
| 5902 | _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); | ||
| 5903 | _buf << indent(1) << "break"sv << nlr(body); | ||
| 5904 | _buf << indent() << "end"sv << nlr(body); | ||
| 5905 | temp.push_back(clearBuf()); | ||
| 5906 | _continueVars.pop(); | ||
| 5907 | } | 6016 | } |
| 5908 | out.push_back(join(temp)); | 6017 | out.push_back(join(temp)); |
| 5909 | return conditionVar; | 6018 | return conditionVar; |
| @@ -5937,7 +6046,7 @@ private: | |||
| 5937 | 6046 | ||
| 5938 | void transformForClosure(For_t* forNode, str_list& out) { | 6047 | void transformForClosure(For_t* forNode, str_list& out) { |
| 5939 | str_list temp; | 6048 | str_list temp; |
| 5940 | _enableReturn.push(true); | 6049 | pushFunctionScope(); |
| 5941 | pushAnonVarArg(); | 6050 | pushAnonVarArg(); |
| 5942 | std::string& funcStart = temp.emplace_back(); | 6051 | std::string& funcStart = temp.emplace_back(); |
| 5943 | pushScope(); | 6052 | pushScope(); |
| @@ -5947,7 +6056,7 @@ private: | |||
| 5947 | funcStart = anonFuncStart() + nll(forNode); | 6056 | funcStart = anonFuncStart() + nll(forNode); |
| 5948 | temp.push_back(indent() + anonFuncEnd()); | 6057 | temp.push_back(indent() + anonFuncEnd()); |
| 5949 | popAnonVarArg(); | 6058 | popAnonVarArg(); |
| 5950 | _enableReturn.pop(); | 6059 | popFunctionScope(); |
| 5951 | out.push_back(join(temp)); | 6060 | out.push_back(join(temp)); |
| 5952 | } | 6061 | } |
| 5953 | 6062 | ||
| @@ -6026,7 +6135,7 @@ private: | |||
| 6026 | 6135 | ||
| 6027 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 6136 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
| 6028 | str_list temp; | 6137 | str_list temp; |
| 6029 | _enableReturn.push(true); | 6138 | pushFunctionScope(); |
| 6030 | pushAnonVarArg(); | 6139 | pushAnonVarArg(); |
| 6031 | std::string& funcStart = temp.emplace_back(); | 6140 | std::string& funcStart = temp.emplace_back(); |
| 6032 | pushScope(); | 6141 | pushScope(); |
| @@ -6036,7 +6145,7 @@ private: | |||
| 6036 | funcStart = anonFuncStart() + nll(forEach); | 6145 | funcStart = anonFuncStart() + nll(forEach); |
| 6037 | temp.push_back(indent() + anonFuncEnd()); | 6146 | temp.push_back(indent() + anonFuncEnd()); |
| 6038 | popAnonVarArg(); | 6147 | popAnonVarArg(); |
| 6039 | _enableReturn.pop(); | 6148 | popFunctionScope(); |
| 6040 | out.push_back(join(temp)); | 6149 | out.push_back(join(temp)); |
| 6041 | } | 6150 | } |
| 6042 | 6151 | ||
| @@ -6202,7 +6311,7 @@ private: | |||
| 6202 | 6311 | ||
| 6203 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { | 6312 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { |
| 6204 | str_list temp; | 6313 | str_list temp; |
| 6205 | _enableReturn.push(true); | 6314 | pushFunctionScope(); |
| 6206 | pushAnonVarArg(); | 6315 | pushAnonVarArg(); |
| 6207 | std::string& funcStart = temp.emplace_back(); | 6316 | std::string& funcStart = temp.emplace_back(); |
| 6208 | pushScope(); | 6317 | pushScope(); |
| @@ -6211,7 +6320,7 @@ private: | |||
| 6211 | funcStart = anonFuncStart() + nll(classDecl); | 6320 | funcStart = anonFuncStart() + nll(classDecl); |
| 6212 | temp.push_back(indent() + anonFuncEnd()); | 6321 | temp.push_back(indent() + anonFuncEnd()); |
| 6213 | popAnonVarArg(); | 6322 | popAnonVarArg(); |
| 6214 | _enableReturn.pop(); | 6323 | popFunctionScope(); |
| 6215 | out.push_back(join(temp)); | 6324 | out.push_back(join(temp)); |
| 6216 | } | 6325 | } |
| 6217 | 6326 | ||
| @@ -6611,7 +6720,7 @@ private: | |||
| 6611 | 6720 | ||
| 6612 | void transformWithClosure(With_t* with, str_list& out) { | 6721 | void transformWithClosure(With_t* with, str_list& out) { |
| 6613 | str_list temp; | 6722 | str_list temp; |
| 6614 | _enableReturn.push(true); | 6723 | pushFunctionScope(); |
| 6615 | pushAnonVarArg(); | 6724 | pushAnonVarArg(); |
| 6616 | std::string& funcStart = temp.emplace_back(); | 6725 | std::string& funcStart = temp.emplace_back(); |
| 6617 | pushScope(); | 6726 | pushScope(); |
| @@ -6620,7 +6729,7 @@ private: | |||
| 6620 | funcStart = anonFuncStart() + nll(with); | 6729 | funcStart = anonFuncStart() + nll(with); |
| 6621 | temp.push_back(indent() + anonFuncEnd()); | 6730 | temp.push_back(indent() + anonFuncEnd()); |
| 6622 | popAnonVarArg(); | 6731 | popAnonVarArg(); |
| 6623 | _enableReturn.pop(); | 6732 | popFunctionScope(); |
| 6624 | out.push_back(join(temp)); | 6733 | out.push_back(join(temp)); |
| 6625 | } | 6734 | } |
| 6626 | 6735 | ||
| @@ -6918,7 +7027,7 @@ private: | |||
| 6918 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 7027 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 6919 | switch (usage) { | 7028 | switch (usage) { |
| 6920 | case ExpUsage::Closure: | 7029 | case ExpUsage::Closure: |
| 6921 | _enableReturn.push(true); | 7030 | pushFunctionScope(); |
| 6922 | pushAnonVarArg(); | 7031 | pushAnonVarArg(); |
| 6923 | pushScope(); | 7032 | pushScope(); |
| 6924 | break; | 7033 | break; |
| @@ -6980,7 +7089,7 @@ private: | |||
| 6980 | out.back().insert(0, anonFuncStart() + nll(comp)); | 7089 | out.back().insert(0, anonFuncStart() + nll(comp)); |
| 6981 | out.back().append(indent() + anonFuncEnd()); | 7090 | out.back().append(indent() + anonFuncEnd()); |
| 6982 | popAnonVarArg(); | 7091 | popAnonVarArg(); |
| 6983 | _enableReturn.pop(); | 7092 | popFunctionScope(); |
| 6984 | break; | 7093 | break; |
| 6985 | case ExpUsage::Assignment: { | 7094 | case ExpUsage::Assignment: { |
| 6986 | out.push_back(clearBuf()); | 7095 | out.push_back(clearBuf()); |
| @@ -7025,7 +7134,7 @@ private: | |||
| 7025 | str_list temp; | 7134 | str_list temp; |
| 7026 | std::string* funcStart = nullptr; | 7135 | std::string* funcStart = nullptr; |
| 7027 | if (usage == ExpUsage::Closure) { | 7136 | if (usage == ExpUsage::Closure) { |
| 7028 | _enableReturn.push(true); | 7137 | pushFunctionScope(); |
| 7029 | pushAnonVarArg(); | 7138 | pushAnonVarArg(); |
| 7030 | funcStart = &temp.emplace_back(); | 7139 | funcStart = &temp.emplace_back(); |
| 7031 | } else { | 7140 | } else { |
| @@ -7038,7 +7147,7 @@ private: | |||
| 7038 | *funcStart = anonFuncStart() + nll(doNode); | 7147 | *funcStart = anonFuncStart() + nll(doNode); |
| 7039 | temp.push_back(indent() + anonFuncEnd()); | 7148 | temp.push_back(indent() + anonFuncEnd()); |
| 7040 | popAnonVarArg(); | 7149 | popAnonVarArg(); |
| 7041 | _enableReturn.pop(); | 7150 | popFunctionScope(); |
| 7042 | } else { | 7151 | } else { |
| 7043 | temp.push_back(indent() + "end"s + nlr(doNode)); | 7152 | temp.push_back(indent() + "end"s + nlr(doNode)); |
| 7044 | } | 7153 | } |
| @@ -7445,7 +7554,7 @@ private: | |||
| 7445 | void transformWhileClosure(While_t* whileNode, str_list& out) { | 7554 | void transformWhileClosure(While_t* whileNode, str_list& out) { |
| 7446 | auto x = whileNode; | 7555 | auto x = whileNode; |
| 7447 | str_list temp; | 7556 | str_list temp; |
| 7448 | _enableReturn.push(true); | 7557 | pushFunctionScope(); |
| 7449 | pushAnonVarArg(); | 7558 | pushAnonVarArg(); |
| 7450 | std::string& funcStart = temp.emplace_back(); | 7559 | std::string& funcStart = temp.emplace_back(); |
| 7451 | pushScope(); | 7560 | pushScope(); |
| @@ -7469,7 +7578,7 @@ private: | |||
| 7469 | funcStart = anonFuncStart() + nll(whileNode); | 7578 | funcStart = anonFuncStart() + nll(whileNode); |
| 7470 | temp.push_back(indent() + anonFuncEnd()); | 7579 | temp.push_back(indent() + anonFuncEnd()); |
| 7471 | popAnonVarArg(); | 7580 | popAnonVarArg(); |
| 7472 | _enableReturn.pop(); | 7581 | popFunctionScope(); |
| 7473 | out.push_back(join(temp)); | 7582 | out.push_back(join(temp)); |
| 7474 | } | 7583 | } |
| 7475 | 7584 | ||
| @@ -7507,7 +7616,7 @@ private: | |||
| 7507 | str_list temp; | 7616 | str_list temp; |
| 7508 | std::string* funcStart = nullptr; | 7617 | std::string* funcStart = nullptr; |
| 7509 | if (usage == ExpUsage::Closure) { | 7618 | if (usage == ExpUsage::Closure) { |
| 7510 | _enableReturn.push(true); | 7619 | pushFunctionScope(); |
| 7511 | pushAnonVarArg(); | 7620 | pushAnonVarArg(); |
| 7512 | funcStart = &temp.emplace_back(); | 7621 | funcStart = &temp.emplace_back(); |
| 7513 | pushScope(); | 7622 | pushScope(); |
| @@ -7631,7 +7740,7 @@ private: | |||
| 7631 | } | 7740 | } |
| 7632 | temp.push_back(indent() + "end"s + nlr(switchNode)); | 7741 | temp.push_back(indent() + "end"s + nlr(switchNode)); |
| 7633 | if (usage == ExpUsage::Closure) { | 7742 | if (usage == ExpUsage::Closure) { |
| 7634 | _enableReturn.pop(); | 7743 | popFunctionScope(); |
| 7635 | popScope(); | 7744 | popScope(); |
| 7636 | *funcStart = anonFuncStart() + nll(switchNode); | 7745 | *funcStart = anonFuncStart() + nll(switchNode); |
| 7637 | temp.push_back(indent() + anonFuncEnd()); | 7746 | temp.push_back(indent() + anonFuncEnd()); |
| @@ -7798,29 +7907,52 @@ private: | |||
| 7798 | return; | 7907 | return; |
| 7799 | } | 7908 | } |
| 7800 | if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop)); | 7909 | if (_continueVars.empty()) throw std::logic_error(_info.errorMessage("continue is not inside a loop"sv, breakLoop)); |
| 7910 | str_list temp; | ||
| 7801 | auto& item = _continueVars.top(); | 7911 | auto& item = _continueVars.top(); |
| 7802 | if (item.condAssign) { | 7912 | if (item.condAssign) { |
| 7803 | str_list temp; | ||
| 7804 | transformAssignment(item.condAssign, temp); | 7913 | transformAssignment(item.condAssign, temp); |
| 7805 | _buf << temp.back(); | ||
| 7806 | } | 7914 | } |
| 7807 | _buf << indent() << item.var << " = true"sv << nll(breakLoop); | 7915 | if (getLuaTarget(breakLoop) < 502) { |
| 7808 | _buf << indent() << "break"sv << nll(breakLoop); | 7916 | if (!temp.empty()) { |
| 7809 | out.push_back(clearBuf()); | 7917 | _buf << temp.back(); |
| 7918 | } | ||
| 7919 | _buf << indent() << item.var << " = true"sv << nll(breakLoop); | ||
| 7920 | _buf << indent() << "break"sv << nll(breakLoop); | ||
| 7921 | out.push_back(clearBuf()); | ||
| 7922 | } else { | ||
| 7923 | transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); | ||
| 7924 | out.push_back(join(temp)); | ||
| 7925 | } | ||
| 7810 | } | 7926 | } |
| 7811 | 7927 | ||
| 7812 | void transformLabel(Label_t* label, str_list& out) { | 7928 | void transformLabel(Label_t* label, str_list& out) { |
| 7813 | if (getLuaTarget(label) < 502) { | 7929 | if (getLuaTarget(label) < 502) { |
| 7814 | throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua version 5.2 or higher"sv, label)); | 7930 | throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua version 5.2 or higher"sv, label)); |
| 7815 | } | 7931 | } |
| 7816 | out.push_back(indent() + "::"s + _parser.toString(label->label) + "::"s + nll(label)); | 7932 | auto labelStr = _parser.toString(label->label); |
| 7933 | int currentScope = _gotoScopes.top(); | ||
| 7934 | if (static_cast<int>(_labels.size()) <= currentScope) { | ||
| 7935 | _labels.resize(currentScope + 1, std::nullopt); | ||
| 7936 | _labels[currentScope] = std::unordered_map<std::string, LabelNode>(); | ||
| 7937 | } | ||
| 7938 | if (!_labels[currentScope]) { | ||
| 7939 | _labels[currentScope] = std::unordered_map<std::string, LabelNode>(); | ||
| 7940 | } | ||
| 7941 | auto& scope = _labels[currentScope].value(); | ||
| 7942 | if (auto it = scope.find(labelStr); it != scope.end()) { | ||
| 7943 | throw std::logic_error(_info.errorMessage("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label)); | ||
| 7944 | } | ||
| 7945 | scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; | ||
| 7946 | out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); | ||
| 7817 | } | 7947 | } |
| 7818 | 7948 | ||
| 7819 | void transformGoto(Goto_t* gotoNode, str_list& out) { | 7949 | void transformGoto(Goto_t* gotoNode, str_list& out) { |
| 7820 | if (getLuaTarget(gotoNode) < 502) { | 7950 | if (getLuaTarget(gotoNode) < 502) { |
| 7821 | throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode)); | 7951 | throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode)); |
| 7822 | } | 7952 | } |
| 7823 | out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); | 7953 | auto labelStr = _parser.toString(gotoNode->label); |
| 7954 | gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); | ||
| 7955 | out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); | ||
| 7824 | } | 7956 | } |
| 7825 | 7957 | ||
| 7826 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { | 7958 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { |
