diff options
Diffstat (limited to '')
| -rwxr-xr-x | src/yuescript/yue_compiler.cpp | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 469dfea..6f641d9 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -60,7 +60,7 @@ using namespace parserlib; | |||
| 60 | 60 | ||
| 61 | typedef std::list<std::string> str_list; | 61 | typedef std::list<std::string> str_list; |
| 62 | 62 | ||
| 63 | const std::string_view version = "0.10.19"sv; | 63 | const std::string_view version = "0.10.20"sv; |
| 64 | const std::string_view extension = "yue"sv; | 64 | const std::string_view extension = "yue"sv; |
| 65 | 65 | ||
| 66 | class YueCompilerImpl { | 66 | class YueCompilerImpl { |
| @@ -5257,9 +5257,8 @@ private: | |||
| 5257 | } | 5257 | } |
| 5258 | } | 5258 | } |
| 5259 | 5259 | ||
| 5260 | void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { | 5260 | bool hasContinueStatement(ast_node* body) { |
| 5261 | str_list temp; | 5261 | return traversal::Stop == body->traverse([&](ast_node* node) { |
| 5262 | bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) { | ||
| 5263 | if (auto stmt = ast_cast<Statement_t>(node)) { | 5262 | if (auto stmt = ast_cast<Statement_t>(node)) { |
| 5264 | if (stmt->content.is<BreakLoop_t>()) { | 5263 | if (stmt->content.is<BreakLoop_t>()) { |
| 5265 | return _parser.toString(stmt->content) == "continue"sv ? | 5264 | return _parser.toString(stmt->content) == "continue"sv ? |
| @@ -5268,10 +5267,20 @@ private: | |||
| 5268 | return traversal::Continue; | 5267 | return traversal::Continue; |
| 5269 | } | 5268 | } |
| 5270 | return traversal::Return; | 5269 | return traversal::Return; |
| 5270 | } else switch (node->getId()) { | ||
| 5271 | case id<FunLit_t>(): | ||
| 5272 | case id<Invoke_t>(): | ||
| 5273 | case id<InvokeArgs_t>(): | ||
| 5274 | return traversal::Return; | ||
| 5271 | } | 5275 | } |
| 5272 | return traversal::Continue; | 5276 | return traversal::Continue; |
| 5273 | }); | 5277 | }); |
| 5278 | } | ||
| 5279 | |||
| 5280 | void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { | ||
| 5281 | str_list temp; | ||
| 5274 | bool extraDo = false; | 5282 | bool extraDo = false; |
| 5283 | bool withContinue = hasContinueStatement(body); | ||
| 5275 | if (withContinue) { | 5284 | if (withContinue) { |
| 5276 | if (auto block = ast_cast<Block_t>(body)) { | 5285 | if (auto block = ast_cast<Block_t>(body)) { |
| 5277 | if (!block->statements.empty()) { | 5286 | if (!block->statements.empty()) { |
| @@ -5316,6 +5325,65 @@ private: | |||
| 5316 | out.push_back(join(temp)); | 5325 | out.push_back(join(temp)); |
| 5317 | } | 5326 | } |
| 5318 | 5327 | ||
| 5328 | std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { | ||
| 5329 | str_list temp; | ||
| 5330 | bool extraDo = false; | ||
| 5331 | auto body = repeatNode->body->content.get(); | ||
| 5332 | bool withContinue = hasContinueStatement(body); | ||
| 5333 | std::string conditionVar; | ||
| 5334 | if (withContinue) { | ||
| 5335 | if (auto block = ast_cast<Block_t>(body)) { | ||
| 5336 | if (!block->statements.empty()) { | ||
| 5337 | auto stmt = static_cast<Statement_t*>(block->statements.back()); | ||
| 5338 | if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { | ||
| 5339 | extraDo = _parser.toString(breakLoop) == "break"sv; | ||
| 5340 | } | ||
| 5341 | } | ||
| 5342 | } | ||
| 5343 | conditionVar = getUnusedName("_cond_"); | ||
| 5344 | forceAddToScope(conditionVar); | ||
| 5345 | auto continueVar = getUnusedName("_continue_"sv); | ||
| 5346 | forceAddToScope(continueVar); | ||
| 5347 | _continueVars.push(continueVar); | ||
| 5348 | _buf << indent() << "local "sv << conditionVar << nll(body); | ||
| 5349 | _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); | ||
| 5350 | _buf << indent() << "repeat"sv << nll(body); | ||
| 5351 | pushScope(); | ||
| 5352 | if (extraDo) { | ||
| 5353 | _buf << indent() << "do"sv << nll(body); | ||
| 5354 | pushScope(); | ||
| 5355 | } | ||
| 5356 | temp.push_back(clearBuf()); | ||
| 5357 | } | ||
| 5358 | transform_plain_body(body, temp, ExpUsage::Common); | ||
| 5359 | if (withContinue) { | ||
| 5360 | { | ||
| 5361 | auto assignment = toAst<ExpListAssign_t>(conditionVar + "=nil"s, body); | ||
| 5362 | auto assign = assignment->action.to<Assign_t>(); | ||
| 5363 | assign->values.clear(); | ||
| 5364 | assign->values.push_back(repeatNode->condition); | ||
| 5365 | transformAssignment(assignment, temp); | ||
| 5366 | auto assignCond = std::move(temp.back()); | ||
| 5367 | temp.pop_back(); | ||
| 5368 | temp.back().append(assignCond); | ||
| 5369 | } | ||
| 5370 | if (extraDo) { | ||
| 5371 | popScope(); | ||
| 5372 | _buf << indent() << "end"sv << nll(body); | ||
| 5373 | } | ||
| 5374 | _buf << indent() << _continueVars.top() << " = true"sv << nll(body); | ||
| 5375 | popScope(); | ||
| 5376 | _buf << indent() << "until true"sv << nlr(body); | ||
| 5377 | _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body); | ||
| 5378 | _buf << indent(1) << "break"sv << nlr(body); | ||
| 5379 | _buf << indent() << "end"sv << nlr(body); | ||
| 5380 | temp.push_back(clearBuf()); | ||
| 5381 | _continueVars.pop(); | ||
| 5382 | } | ||
| 5383 | out.push_back(join(temp)); | ||
| 5384 | return conditionVar; | ||
| 5385 | } | ||
| 5386 | |||
| 5319 | void transformFor(For_t* forNode, str_list& out) { | 5387 | void transformFor(For_t* forNode, str_list& out) { |
| 5320 | str_list temp; | 5388 | str_list temp; |
| 5321 | transformForHead(forNode, temp); | 5389 | transformForHead(forNode, temp); |
| @@ -6838,8 +6906,12 @@ private: | |||
| 6838 | void transformRepeat(Repeat_t* repeat, str_list& out) { | 6906 | void transformRepeat(Repeat_t* repeat, str_list& out) { |
| 6839 | str_list temp; | 6907 | str_list temp; |
| 6840 | pushScope(); | 6908 | pushScope(); |
| 6841 | transformLoopBody(repeat->body->content, temp, Empty, ExpUsage::Common); | 6909 | auto condVar = transformRepeatBody(repeat, temp); |
| 6842 | transformExp(repeat->condition, temp, ExpUsage::Closure); | 6910 | if (condVar.empty()) { |
| 6911 | transformExp(repeat->condition, temp, ExpUsage::Closure); | ||
| 6912 | } else { | ||
| 6913 | temp.push_back(condVar); | ||
| 6914 | } | ||
| 6843 | popScope(); | 6915 | popScope(); |
| 6844 | _buf << indent() << "repeat"sv << nll(repeat); | 6916 | _buf << indent() << "repeat"sv << nll(repeat); |
| 6845 | _buf << temp.front(); | 6917 | _buf << temp.front(); |
