diff options
author | Li Jin <dragon-fly@qq.com> | 2022-05-16 01:03:05 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-05-16 01:03:05 +0800 |
commit | c4935826eea8df7a161b2b4ba9262dce66d9d366 (patch) | |
tree | 12f7fe952a777b98244253c5ecd3e0d0a73e8de8 | |
parent | e9926f70a53639c09a5605f71a34ec370395f5a9 (diff) | |
download | yuescript-c4935826eea8df7a161b2b4ba9262dce66d9d366.tar.gz yuescript-c4935826eea8df7a161b2b4ba9262dce66d9d366.tar.bz2 yuescript-c4935826eea8df7a161b2b4ba9262dce66d9d366.zip |
fix issue #102. fix `continue` statement locating issue.
-rw-r--r-- | spec/inputs/loops.yue | 8 | ||||
-rw-r--r-- | spec/outputs/loops.lua | 23 | ||||
-rwxr-xr-x | 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 | |||
109 | print a | 109 | print a |
110 | until a == 10 | 110 | until a == 10 |
111 | 111 | ||
112 | x = 0 | ||
113 | repeat | ||
114 | x += 1 | ||
115 | y = x | ||
116 | continue if x < 5 | ||
117 | print y | ||
118 | until y == 10 | ||
119 | |||
112 | a = 3 | 120 | a = 3 |
113 | until a == 0 | 121 | until a == 0 |
114 | a -= 1 | 122 | 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 | |||
187 | end | 187 | end |
188 | local a = 1 | 188 | local a = 1 |
189 | repeat | 189 | repeat |
190 | local _cond_0 | ||
190 | local _continue_0 = false | 191 | local _continue_0 = false |
191 | repeat | 192 | repeat |
192 | a = a + 1 | 193 | a = a + 1 |
@@ -198,12 +199,32 @@ repeat | |||
198 | break | 199 | break |
199 | end | 200 | end |
200 | print(a) | 201 | print(a) |
202 | _cond_0 = a == 10 | ||
201 | _continue_0 = true | 203 | _continue_0 = true |
202 | until true | 204 | until true |
203 | if not _continue_0 then | 205 | if not _continue_0 then |
204 | break | 206 | break |
205 | end | 207 | end |
206 | until a == 10 | 208 | until _cond_0 |
209 | x = 0 | ||
210 | repeat | ||
211 | local _cond_0 | ||
212 | local _continue_0 = false | ||
213 | repeat | ||
214 | x = x + 1 | ||
215 | y = x | ||
216 | if x < 5 then | ||
217 | _continue_0 = true | ||
218 | break | ||
219 | end | ||
220 | print(y) | ||
221 | _cond_0 = y == 10 | ||
222 | _continue_0 = true | ||
223 | until true | ||
224 | if not _continue_0 then | ||
225 | break | ||
226 | end | ||
227 | until _cond_0 | ||
207 | a = 3 | 228 | a = 3 |
208 | while not (a == 0) do | 229 | while not (a == 0) do |
209 | a = a - 1 | 230 | 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; | |||
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(); |