aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-01-29 16:39:35 +0800
committerLi Jin <dragon-fly@qq.com>2023-01-29 16:39:35 +0800
commit8d648dc8c075fc1cf8d89d74c1425cdeb47e8089 (patch)
treed038d12f7e683e490a36d431376c2da6dd2b17bf
parente10b1b163a9a173f32b956bf1fb9be00194352b5 (diff)
downloadyuescript-8d648dc8c075fc1cf8d89d74c1425cdeb47e8089.tar.gz
yuescript-8d648dc8c075fc1cf8d89d74c1425cdeb47e8089.tar.bz2
yuescript-8d648dc8c075fc1cf8d89d74c1425cdeb47e8089.zip
refactor break loop keyword checking.
-rw-r--r--spec/inputs/loops.yue24
-rw-r--r--spec/outputs/5.1/loops.lua60
-rw-r--r--spec/outputs/loops.lua41
-rw-r--r--src/yuescript/yue_compiler.cpp86
4 files changed, 198 insertions, 13 deletions
diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue
index 51eb10b..5cadbf0 100644
--- a/spec/inputs/loops.yue
+++ b/spec/inputs/loops.yue
@@ -173,4 +173,26 @@ do
173 for thing in *xxx 173 for thing in *xxx
174 print thing 174 print thing
175 175
176 176do
177 for i = 1, 10
178 repeat
179 with? tb
180 .a = 1
181 continue if .b
182 do
183 if .c
184 break
185 until true
186 switch x
187 when 123
188 break
189 else
190 continue
191 if y
192 continue
193 else
194 break
195 do do do
196 print i
197 continue
198 print "abc"
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua
index 85e9de8..6f0d072 100644
--- a/spec/outputs/5.1/loops.lua
+++ b/spec/outputs/5.1/loops.lua
@@ -382,3 +382,63 @@ do
382 print(thing) 382 print(thing)
383 end 383 end
384end 384end
385do
386 for i = 1, 10 do
387 local _continue_0 = false
388 repeat
389 repeat
390 local _cond_0 = false
391 local _continue_1 = false
392 repeat
393 do
394 local _with_0 = tb
395 if _with_0 ~= nil then
396 _with_0.a = 1
397 if _with_0.b then
398 _cond_0 = true
399 _continue_1 = true
400 break
401 end
402 do
403 if _with_0.c then
404 break
405 end
406 end
407 end
408 end
409 _cond_0 = true
410 _continue_1 = true
411 until true
412 if not _continue_1 then
413 break
414 end
415 until _cond_0
416 if 123 == x then
417 break
418 else
419 _continue_0 = true
420 break
421 end
422 if y then
423 _continue_0 = true
424 break
425 else
426 break
427 end
428 do
429 do
430 do
431 print(i)
432 _continue_0 = true
433 break
434 end
435 end
436 end
437 print("abc")
438 _continue_0 = true
439 until true
440 if not _continue_0 then
441 break
442 end
443 end
444end
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua
index eeea15f..79ef789 100644
--- a/spec/outputs/loops.lua
+++ b/spec/outputs/loops.lua
@@ -294,3 +294,44 @@ do
294 print(thing) 294 print(thing)
295 end 295 end
296end 296end
297do
298 for i = 1, 10 do
299 repeat
300 do
301 local _with_0 = tb
302 if _with_0 ~= nil then
303 _with_0.a = 1
304 if _with_0.b then
305 goto _continue_12
306 end
307 do
308 if _with_0.c then
309 break
310 end
311 end
312 end
313 end
314 ::_continue_12::
315 until true
316 if 123 == x then
317 break
318 else
319 goto _continue_11
320 end
321 if y then
322 goto _continue_11
323 else
324 break
325 end
326 do
327 do
328 do
329 print(i)
330 goto _continue_11
331 end
332 end
333 end
334 print("abc")
335 ::_continue_11::
336 end
337end
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index c7f0f27..83933d1 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -71,7 +71,7 @@ static std::unordered_set<std::string> Metamethods = {
71 "close"s // Lua 5.4 71 "close"s // Lua 5.4
72}; 72};
73 73
74const std::string_view version = "0.15.24"sv; 74const std::string_view version = "0.15.25"sv;
75const std::string_view extension = "yue"sv; 75const std::string_view extension = "yue"sv;
76 76
77class YueCompilerImpl { 77class YueCompilerImpl {
@@ -296,6 +296,7 @@ private:
296 }; 296 };
297 std::stack<VarArgState> _varArgs; 297 std::stack<VarArgState> _varArgs;
298 std::stack<bool> _enableReturn; 298 std::stack<bool> _enableReturn;
299 std::stack<bool> _enableBreakLoop;
299 std::stack<std::string> _withVars; 300 std::stack<std::string> _withVars;
300 struct ContinueVar { 301 struct ContinueVar {
301 std::string var; 302 std::string var;
@@ -1072,12 +1073,14 @@ private:
1072 1073
1073 void pushFunctionScope() { 1074 void pushFunctionScope() {
1074 _enableReturn.push(true); 1075 _enableReturn.push(true);
1076 _enableBreakLoop.push(false);
1075 _gotoScopes.push(_gotoScope); 1077 _gotoScopes.push(_gotoScope);
1076 _gotoScope++; 1078 _gotoScope++;
1077 } 1079 }
1078 1080
1079 void popFunctionScope() { 1081 void popFunctionScope() {
1080 _enableReturn.pop(); 1082 _enableReturn.pop();
1083 _enableBreakLoop.pop();
1081 _gotoScopes.pop(); 1084 _gotoScopes.pop();
1082 } 1085 }
1083 1086
@@ -1224,8 +1227,16 @@ private:
1224 } 1227 }
1225 default: YUEE("AST node mismatch", appendix->item.get()); break; 1228 default: YUEE("AST node mismatch", appendix->item.get()); break;
1226 } 1229 }
1227 } else if (statement->content.is<Return_t>() && !statement->appendix->item.is<IfLine_t>()) { 1230 } else if (!statement->appendix->item.is<IfLine_t>()) {
1228 throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a return statement"sv, statement->appendix->item)); 1231 auto appendix = statement->appendix->item.get();
1232 switch (statement->content->getId()) {
1233 case id<Return_t>():
1234 throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a return statement"sv, appendix));
1235 break;
1236 case id<BreakLoop_t>():
1237 throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a break-loop statement"sv, appendix));
1238 break;
1239 }
1229 } 1240 }
1230 auto appendix = statement->appendix.get(); 1241 auto appendix = statement->appendix.get();
1231 switch (appendix->item->getId()) { 1242 switch (appendix->item->getId()) {
@@ -6099,18 +6110,62 @@ private:
6099 if (auto stmt = ast_cast<Statement_t>(node)) { 6110 if (auto stmt = ast_cast<Statement_t>(node)) {
6100 if (stmt->content.is<BreakLoop_t>()) { 6111 if (stmt->content.is<BreakLoop_t>()) {
6101 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 6112 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return;
6102 } else if (expListFrom(stmt)) { 6113 } else if (auto expList = expListFrom(stmt)) {
6103 return traversal::Continue; 6114 BLOCK_START
6115 auto value = singleValueFrom(expList);
6116 BREAK_IF(!value);
6117 auto simpleValue = value->item.as<SimpleValue_t>();
6118 BREAK_IF(!simpleValue);
6119 auto sVal = simpleValue->value.get();
6120 switch (sVal->getId()) {
6121 case id<With_t>(): {
6122 auto withNode = static_cast<With_t*>(sVal);
6123 if (hasContinueStatement(withNode->body)) {
6124 return traversal::Stop;
6125 }
6126 break;
6127 }
6128 case id<Do_t>(): {
6129 auto doNode = static_cast<Do_t*>(sVal);
6130 if (hasContinueStatement(doNode->body)) {
6131 return traversal::Stop;
6132 }
6133 break;
6134 }
6135 case id<If_t>(): {
6136 auto ifNode = static_cast<If_t*>(sVal);
6137 for (auto n : ifNode->nodes.objects()) {
6138 if (hasContinueStatement(n)) {
6139 return traversal::Stop;
6140 }
6141 }
6142 break;
6143 }
6144 case id<Switch_t>(): {
6145 auto switchNode = static_cast<Switch_t*>(sVal);
6146 for (auto branch : switchNode->branches.objects()) {
6147 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) {
6148 return traversal::Stop;
6149 }
6150 }
6151 if (switchNode->lastBranch) {
6152 if (hasContinueStatement(switchNode->lastBranch)) {
6153 return traversal::Stop;
6154 }
6155 }
6156 break;
6157 }
6158 }
6159 BLOCK_END
6104 } 6160 }
6105 return traversal::Return; 6161 } else {
6106 } else
6107 switch (node->getId()) { 6162 switch (node->getId()) {
6108 case id<FunLit_t>(): 6163 case id<Body_t>():
6109 case id<Invoke_t>(): 6164 case id<Block_t>():
6110 case id<InvokeArgs_t>(): 6165 return traversal::Continue;
6111 return traversal::Return;
6112 } 6166 }
6113 return traversal::Continue; 6167 }
6168 return traversal::Return;
6114 }); 6169 });
6115 } 6170 }
6116 6171
@@ -6171,7 +6226,9 @@ private:
6171 } 6226 }
6172 addDoToLastLineReturn(body); 6227 addDoToLastLineReturn(body);
6173 } 6228 }
6229 _enableBreakLoop.push(true);
6174 transform_plain_body(body, temp, usage, assignList); 6230 transform_plain_body(body, temp, usage, assignList);
6231 _enableBreakLoop.pop();
6175 if (withContinue) { 6232 if (withContinue) {
6176 if (target < 502) { 6233 if (target < 502) {
6177 if (extraDo) { 6234 if (extraDo) {
@@ -6250,7 +6307,9 @@ private:
6250 } 6307 }
6251 addDoToLastLineReturn(body); 6308 addDoToLastLineReturn(body);
6252 } 6309 }
6310 _enableBreakLoop.push(true);
6253 transform_plain_body(body, temp, ExpUsage::Common); 6311 transform_plain_body(body, temp, ExpUsage::Common);
6312 _enableBreakLoop.pop();
6254 if (withContinue) { 6313 if (withContinue) {
6255 if (target < 502) { 6314 if (target < 502) {
6256 transformAssignment(_continueVars.top().condAssign, temp); 6315 transformAssignment(_continueVars.top().condAssign, temp);
@@ -8203,6 +8262,9 @@ private:
8203 8262
8204 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 8263 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
8205 auto keyword = _parser.toString(breakLoop); 8264 auto keyword = _parser.toString(breakLoop);
8265 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
8266 throw std::logic_error(_info.errorMessage(keyword + " is not inside a loop"s, breakLoop));
8267 }
8206 if (keyword == "break"sv) { 8268 if (keyword == "break"sv) {
8207 out.push_back(indent() + keyword + nll(breakLoop)); 8269 out.push_back(indent() + keyword + nll(breakLoop));
8208 return; 8270 return;