From c4935826eea8df7a161b2b4ba9262dce66d9d366 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 16 May 2022 01:03:05 +0800 Subject: fix issue #102. fix `continue` statement locating issue. --- spec/inputs/loops.yue | 8 ++++ spec/outputs/loops.lua | 23 +++++++++++- src/yuescript/yue_compiler.cpp | 84 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue index 3191000..d03e661 100644 --- a/spec/inputs/loops.yue +++ b/spec/inputs/loops.yue @@ -109,6 +109,14 @@ repeat print a until a == 10 +x = 0 +repeat + x += 1 + y = x + continue if x < 5 + print y +until y == 10 + a = 3 until a == 0 a -= 1 diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index aa69840..bcd559c 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -187,6 +187,7 @@ for i = 1, 10 do end local a = 1 repeat + local _cond_0 local _continue_0 = false repeat a = a + 1 @@ -198,12 +199,32 @@ repeat break end print(a) + _cond_0 = a == 10 _continue_0 = true until true if not _continue_0 then break end -until a == 10 +until _cond_0 +x = 0 +repeat + local _cond_0 + local _continue_0 = false + repeat + x = x + 1 + y = x + if x < 5 then + _continue_0 = true + break + end + print(y) + _cond_0 = y == 10 + _continue_0 = true + until true + if not _continue_0 then + break + end +until _cond_0 a = 3 while not (a == 0) do a = a - 1 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; typedef std::list str_list; -const std::string_view version = "0.10.19"sv; +const std::string_view version = "0.10.20"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -5257,9 +5257,8 @@ private: } } - void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { - str_list temp; - bool withContinue = traversal::Stop == body->traverse([&](ast_node* node) { + bool hasContinueStatement(ast_node* body) { + return traversal::Stop == body->traverse([&](ast_node* node) { if (auto stmt = ast_cast(node)) { if (stmt->content.is()) { return _parser.toString(stmt->content) == "continue"sv ? @@ -5268,10 +5267,20 @@ private: return traversal::Continue; } return traversal::Return; + } else switch (node->getId()) { + case id(): + case id(): + case id(): + return traversal::Return; } return traversal::Continue; }); + } + + void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { + str_list temp; bool extraDo = false; + bool withContinue = hasContinueStatement(body); if (withContinue) { if (auto block = ast_cast(body)) { if (!block->statements.empty()) { @@ -5316,6 +5325,65 @@ private: out.push_back(join(temp)); } + std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { + str_list temp; + bool extraDo = false; + auto body = repeatNode->body->content.get(); + bool withContinue = hasContinueStatement(body); + std::string conditionVar; + if (withContinue) { + if (auto block = ast_cast(body)) { + if (!block->statements.empty()) { + auto stmt = static_cast(block->statements.back()); + if (auto breakLoop = ast_cast(stmt->content)) { + extraDo = _parser.toString(breakLoop) == "break"sv; + } + } + } + conditionVar = getUnusedName("_cond_"); + forceAddToScope(conditionVar); + auto continueVar = getUnusedName("_continue_"sv); + forceAddToScope(continueVar); + _continueVars.push(continueVar); + _buf << indent() << "local "sv << conditionVar << nll(body); + _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); + _buf << indent() << "repeat"sv << nll(body); + pushScope(); + if (extraDo) { + _buf << indent() << "do"sv << nll(body); + pushScope(); + } + temp.push_back(clearBuf()); + } + transform_plain_body(body, temp, ExpUsage::Common); + if (withContinue) { + { + auto assignment = toAst(conditionVar + "=nil"s, body); + auto assign = assignment->action.to(); + assign->values.clear(); + assign->values.push_back(repeatNode->condition); + transformAssignment(assignment, temp); + auto assignCond = std::move(temp.back()); + temp.pop_back(); + temp.back().append(assignCond); + } + if (extraDo) { + popScope(); + _buf << indent() << "end"sv << nll(body); + } + _buf << indent() << _continueVars.top() << " = true"sv << nll(body); + popScope(); + _buf << indent() << "until true"sv << nlr(body); + _buf << indent() << "if not "sv << _continueVars.top() << " then"sv << nlr(body); + _buf << indent(1) << "break"sv << nlr(body); + _buf << indent() << "end"sv << nlr(body); + temp.push_back(clearBuf()); + _continueVars.pop(); + } + out.push_back(join(temp)); + return conditionVar; + } + void transformFor(For_t* forNode, str_list& out) { str_list temp; transformForHead(forNode, temp); @@ -6838,8 +6906,12 @@ private: void transformRepeat(Repeat_t* repeat, str_list& out) { str_list temp; pushScope(); - transformLoopBody(repeat->body->content, temp, Empty, ExpUsage::Common); - transformExp(repeat->condition, temp, ExpUsage::Closure); + auto condVar = transformRepeatBody(repeat, temp); + if (condVar.empty()) { + transformExp(repeat->condition, temp, ExpUsage::Closure); + } else { + temp.push_back(condVar); + } popScope(); _buf << indent() << "repeat"sv << nll(repeat); _buf << temp.front(); -- cgit v1.2.3-55-g6feb