aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-05-21 11:44:54 +0800
committerLi Jin <dragon-fly@qq.com>2025-05-21 11:44:54 +0800
commit0603800a4114ed8b4c9572a7d7852995c9b9f334 (patch)
tree456524685562bcd0d874530e3ddc2a0fc0731525 /src
parentff137ac73d999a5849f02706cfd52f4659b025ef (diff)
downloadyuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.tar.gz
yuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.tar.bz2
yuescript-0603800a4114ed8b4c9572a7d7852995c9b9f334.zip
Added break with value syntax.
Diffstat (limited to 'src')
-rw-r--r--src/yuescript/yue_ast.cpp12
-rw-r--r--src/yuescript/yue_ast.h14
-rw-r--r--src/yuescript/yue_compiler.cpp183
-rw-r--r--src/yuescript/yue_parser.cpp4
-rw-r--r--src/yuescript/yue_parser.h2
5 files changed, 150 insertions, 65 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index fe6e726..612bdcd 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -188,9 +188,17 @@ std::string ConstValue_t::to_string(void* ud) const {
188std::string NotIn_t::to_string(void*) const { 188std::string NotIn_t::to_string(void*) const {
189 return {}; 189 return {};
190} 190}
191std::string Break_t::to_string(void*) const {
192 return "break"s;
193}
194std::string Continue_t::to_string(void*) const {
195 return "continue"s;
196}
191std::string BreakLoop_t::to_string(void* ud) const { 197std::string BreakLoop_t::to_string(void* ud) const {
192 auto info = reinterpret_cast<YueFormat*>(ud); 198 if (value) {
193 return info->convert(this); 199 return type->to_string(ud) + ' ' + value->to_string(ud);
200 }
201 return type->to_string(ud);
194} 202}
195std::string YueLineComment_t::to_string(void* ud) const { 203std::string YueLineComment_t::to_string(void* ud) const {
196 auto info = reinterpret_cast<YueFormat*>(ud); 204 auto info = reinterpret_cast<YueFormat*>(ud);
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 5e70645..782db5a 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -273,6 +273,8 @@ AST_NODE(ExpList)
273 ast_ptr<true, Seperator_t> sep; 273 ast_ptr<true, Seperator_t> sep;
274 ast_list<true, Exp_t> exprs; 274 ast_list<true, Exp_t> exprs;
275 AST_MEMBER(ExpList, &sep, &exprs) 275 AST_MEMBER(ExpList, &sep, &exprs)
276 bool followStmtProcessed = false;
277 Statement_t* followStmt = nullptr;
276AST_END(ExpList) 278AST_END(ExpList)
277 279
278AST_NODE(Return) 280AST_NODE(Return)
@@ -856,7 +858,17 @@ AST_NODE(WhileLine)
856 AST_MEMBER(WhileLine, &type, &condition) 858 AST_MEMBER(WhileLine, &type, &condition)
857AST_END(WhileLine) 859AST_END(WhileLine)
858 860
859AST_LEAF(BreakLoop) 861AST_LEAF(Break)
862AST_END(Break)
863
864AST_LEAF(Continue)
865AST_END(Continue)
866
867AST_NODE(BreakLoop)
868 ast_sel<true, Break_t, Continue_t> type;
869 ast_ptr<false, Exp_t> value;
870 AST_MEMBER(BreakLoop, &type, &value)
871 std::string varBWV;
860AST_END(BreakLoop) 872AST_END(BreakLoop)
861 873
862AST_NODE(PipeBody) 874AST_NODE(PipeBody)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index bc4574b..1a9387b 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.27.6"sv; 81const std::string_view version = "0.28.0"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -2464,6 +2464,10 @@ private:
2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2465 if (info.destructures.empty()) { 2465 if (info.destructures.empty()) {
2466 transformAssignmentCommon(assignment, out); 2466 transformAssignmentCommon(assignment, out);
2467 if (assignment->expList->followStmt) {
2468 transformStatement(assignment->expList->followStmt, out);
2469 assignment->expList->followStmtProcessed = true;
2470 }
2467 return true; 2471 return true;
2468 } else { 2472 } else {
2469 auto x = assignment; 2473 auto x = assignment;
@@ -2729,8 +2733,12 @@ private:
2729 temp.push_back(indent() + "end"s + nlr(x)); 2733 temp.push_back(indent() + "end"s + nlr(x));
2730 } 2734 }
2731 out.push_back(join(temp)); 2735 out.push_back(join(temp));
2736 if (assignment->expList->followStmt) {
2737 transformStatement(assignment->expList->followStmt, out);
2738 assignment->expList->followStmtProcessed = true;
2739 }
2740 return false;
2732 } 2741 }
2733 return false;
2734 } 2742 }
2735 2743
2736 void transformAssignItem(ast_node* value, str_list& out) { 2744 void transformAssignItem(ast_node* value, str_list& out) {
@@ -4329,7 +4337,9 @@ private:
4329 return false; 4337 return false;
4330 }; 4338 };
4331 switch (usage) { 4339 switch (usage) {
4332 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4340 case ExpUsage::Common:
4341 YUEE("AST node mismatch", x);
4342 return;
4333 case ExpUsage::Return: 4343 case ExpUsage::Return:
4334 case ExpUsage::Closure: { 4344 case ExpUsage::Closure: {
4335 prepareValue(); 4345 prepareValue();
@@ -7195,7 +7205,7 @@ private:
7195 try { 7205 try {
7196 unsigned long long value = std::stoull(binaryPart, nullptr, 2); 7206 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7197 numStr = std::to_string(value); 7207 numStr = std::to_string(value);
7198 } catch (const std::exception& e) { 7208 } catch (const std::exception&) {
7199 throw CompileError("invalid binary literal"sv, num); 7209 throw CompileError("invalid binary literal"sv, num);
7200 } 7210 }
7201 } else if (getLuaTarget(num) < 502) { 7211 } else if (getLuaTarget(num) < 502) {
@@ -8162,11 +8172,44 @@ private:
8162 } 8172 }
8163 } 8173 }
8164 8174
8165 bool hasContinueStatement(ast_node* body) { 8175 enum class BreakLoopType {
8166 return traversal::Stop == body->traverse([&](ast_node* node) { 8176 None = 0,
8177 Break = 1,
8178 BreakWithValue = 1 << 1,
8179 Continue = 1 << 2
8180 };
8181
8182 bool hasBreak(uint32_t breakLoopType) const {
8183 return (breakLoopType & int(BreakLoopType::Break)) != 0;
8184 }
8185
8186 bool hasBreakWithValue(uint32_t breakLoopType) const {
8187 return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0;
8188 }
8189
8190 bool hasContinue(uint32_t breakLoopType) const {
8191 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8192 }
8193
8194 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) {
8195 uint32_t type = 0;
8196 body->traverse([&](ast_node* node) {
8167 if (auto stmt = ast_cast<Statement_t>(node)) { 8197 if (auto stmt = ast_cast<Statement_t>(node)) {
8168 if (stmt->content.is<BreakLoop_t>()) { 8198 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8169 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 8199 if (breakLoop->type.is<Continue_t>()) {
8200 type |= int(BreakLoopType::Continue);
8201 return traversal::Return;
8202 } else {
8203 if (breakLoop->value) {
8204 if (varBWV.empty()) {
8205 throw CompileError("break with a value is not allowed here"sv, breakLoop->value);
8206 }
8207 type |= int(BreakLoopType::BreakWithValue);
8208 breakLoop->varBWV = varBWV;
8209 } else {
8210 type |= int(BreakLoopType::Break);
8211 }
8212 }
8170 } else if (auto expList = expListFrom(stmt)) { 8213 } else if (auto expList = expListFrom(stmt)) {
8171 BLOCK_START 8214 BLOCK_START
8172 auto value = singleValueFrom(expList); 8215 auto value = singleValueFrom(expList);
@@ -8177,40 +8220,30 @@ private:
8177 switch (sVal->get_id()) { 8220 switch (sVal->get_id()) {
8178 case id<With_t>(): { 8221 case id<With_t>(): {
8179 auto withNode = static_cast<With_t*>(sVal); 8222 auto withNode = static_cast<With_t*>(sVal);
8180 if (hasContinueStatement(withNode->body)) { 8223 type |= getBreakLoopType(withNode->body, varBWV);
8181 return traversal::Stop; 8224 return traversal::Return;
8182 }
8183 break;
8184 } 8225 }
8185 case id<Do_t>(): { 8226 case id<Do_t>(): {
8186 auto doNode = static_cast<Do_t*>(sVal); 8227 auto doNode = static_cast<Do_t*>(sVal);
8187 if (hasContinueStatement(doNode->body)) { 8228 type |= getBreakLoopType(doNode->body, varBWV);
8188 return traversal::Stop; 8229 return traversal::Return;
8189 }
8190 break;
8191 } 8230 }
8192 case id<If_t>(): { 8231 case id<If_t>(): {
8193 auto ifNode = static_cast<If_t*>(sVal); 8232 auto ifNode = static_cast<If_t*>(sVal);
8194 for (auto n : ifNode->nodes.objects()) { 8233 for (auto n : ifNode->nodes.objects()) {
8195 if (hasContinueStatement(n)) { 8234 type |= getBreakLoopType(n, varBWV);
8196 return traversal::Stop;
8197 }
8198 } 8235 }
8199 break; 8236 return traversal::Return;
8200 } 8237 }
8201 case id<Switch_t>(): { 8238 case id<Switch_t>(): {
8202 auto switchNode = static_cast<Switch_t*>(sVal); 8239 auto switchNode = static_cast<Switch_t*>(sVal);
8203 for (auto branch : switchNode->branches.objects()) { 8240 for (auto branch : switchNode->branches.objects()) {
8204 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8241 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8205 return traversal::Stop;
8206 }
8207 } 8242 }
8208 if (switchNode->lastBranch) { 8243 if (switchNode->lastBranch) {
8209 if (hasContinueStatement(switchNode->lastBranch)) { 8244 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8210 return traversal::Stop;
8211 }
8212 } 8245 }
8213 break; 8246 return traversal::Return;
8214 } 8247 }
8215 } 8248 }
8216 BLOCK_END 8249 BLOCK_END
@@ -8224,6 +8257,7 @@ private:
8224 } 8257 }
8225 return traversal::Return; 8258 return traversal::Return;
8226 }); 8259 });
8260 return type;
8227 } 8261 }
8228 8262
8229 void addDoToLastLineReturn(ast_node* body) { 8263 void addDoToLastLineReturn(ast_node* body) {
@@ -8247,10 +8281,10 @@ private:
8247 } 8281 }
8248 } 8282 }
8249 8283
8250 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { 8284 void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) {
8251 str_list temp; 8285 str_list temp;
8252 bool extraDo = false; 8286 bool extraDo = false;
8253 bool withContinue = hasContinueStatement(body); 8287 bool withContinue = hasContinue(breakLoopType);
8254 int target = getLuaTarget(body); 8288 int target = getLuaTarget(body);
8255 std::string extraLabel; 8289 std::string extraLabel;
8256 if (withContinue) { 8290 if (withContinue) {
@@ -8259,7 +8293,7 @@ private:
8259 if (!block->statements.empty()) { 8293 if (!block->statements.empty()) {
8260 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8294 auto stmt = static_cast<Statement_t*>(block->statements.back());
8261 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8295 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8262 extraDo = _parser.toString(breakLoop) == "break"sv; 8296 extraDo = breakLoop->type.is<Break_t>();
8263 } 8297 }
8264 } 8298 }
8265 } 8299 }
@@ -8292,9 +8326,6 @@ private:
8292 popScope(); 8326 popScope();
8293 _buf << indent() << "end"sv << nll(body); 8327 _buf << indent() << "end"sv << nll(body);
8294 } 8328 }
8295 if (!appendContent.empty()) {
8296 _buf << indent() << appendContent;
8297 }
8298 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8329 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body);
8299 popScope(); 8330 popScope();
8300 _buf << indent() << "until true"sv << nlr(body); 8331 _buf << indent() << "until true"sv << nlr(body);
@@ -8304,14 +8335,9 @@ private:
8304 temp.push_back(clearBuf()); 8335 temp.push_back(clearBuf());
8305 _continueVars.pop(); 8336 _continueVars.pop();
8306 } else { 8337 } else {
8307 if (!appendContent.empty()) {
8308 temp.push_back(indent() + appendContent);
8309 }
8310 temp.push_back(extraLabel); 8338 temp.push_back(extraLabel);
8311 _continueVars.pop(); 8339 _continueVars.pop();
8312 } 8340 }
8313 } else if (!appendContent.empty()) {
8314 temp.back().append(indent() + appendContent);
8315 } 8341 }
8316 out.push_back(join(temp)); 8342 out.push_back(join(temp));
8317 } 8343 }
@@ -8320,7 +8346,8 @@ private:
8320 str_list temp; 8346 str_list temp;
8321 bool extraDo = false; 8347 bool extraDo = false;
8322 auto body = repeatNode->body->content.get(); 8348 auto body = repeatNode->body->content.get();
8323 bool withContinue = hasContinueStatement(body); 8349 auto breakLoopType = getBreakLoopType(body, Empty);
8350 bool withContinue = hasContinue(breakLoopType);
8324 std::string conditionVar; 8351 std::string conditionVar;
8325 std::string extraLabel; 8352 std::string extraLabel;
8326 ast_ptr<false, ExpListAssign_t> condAssign; 8353 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8331,7 +8358,7 @@ private:
8331 if (!block->statements.empty()) { 8358 if (!block->statements.empty()) {
8332 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8359 auto stmt = static_cast<Statement_t*>(block->statements.back());
8333 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8360 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8334 extraDo = _parser.toString(breakLoop) == "break"sv; 8361 extraDo = breakLoop->type.is<Break_t>();
8335 } 8362 }
8336 } 8363 }
8337 } 8364 }
@@ -8394,7 +8421,8 @@ private:
8394 void transformFor(For_t* forNode, str_list& out) { 8421 void transformFor(For_t* forNode, str_list& out) {
8395 str_list temp; 8422 str_list temp;
8396 transformForHead(forNode, temp); 8423 transformForHead(forNode, temp);
8397 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 8424 auto breakLoopType = getBreakLoopType(forNode->body, Empty);
8425 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common);
8398 popScope(); 8426 popScope();
8399 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 8427 out.push_back(join(temp) + indent() + "end"s + nlr(forNode));
8400 } 8428 }
@@ -8405,13 +8433,19 @@ private:
8405 addToScope(accum); 8433 addToScope(accum);
8406 std::string len = getUnusedName("_len_"sv); 8434 std::string len = getUnusedName("_len_"sv);
8407 addToScope(len); 8435 addToScope(len);
8408 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); 8436 auto breakLoopType = getBreakLoopType(forNode->body, accum);
8437 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode);
8438 out.emplace_back(clearBuf());
8409 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 8439 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
8410 out.push_back(clearBuf()); 8440 auto& lenAssign = out.emplace_back(clearBuf());
8411 transformForHead(forNode, out); 8441 transformForHead(forNode, out);
8412 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8442 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8413 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 8443 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body);
8414 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); 8444 expList->followStmt = followStmt.get();
8445 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList);
8446 if (!expList->followStmtProcessed) {
8447 lenAssign.clear();
8448 }
8415 popScope(); 8449 popScope();
8416 out.push_back(indent() + "end"s + nlr(forNode)); 8450 out.push_back(indent() + "end"s + nlr(forNode));
8417 return accum; 8451 return accum;
@@ -8490,7 +8524,8 @@ private:
8490 void transformForEach(ForEach_t* forEach, str_list& out) { 8524 void transformForEach(ForEach_t* forEach, str_list& out) {
8491 str_list temp; 8525 str_list temp;
8492 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 8526 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8493 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 8527 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
8528 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8494 popScope(); 8529 popScope();
8495 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 8530 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach));
8496 if (extraScoped) { 8531 if (extraScoped) {
@@ -8505,13 +8540,19 @@ private:
8505 addToScope(accum); 8540 addToScope(accum);
8506 std::string len = getUnusedName("_len_"sv); 8541 std::string len = getUnusedName("_len_"sv);
8507 addToScope(len); 8542 addToScope(len);
8508 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); 8543 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8544 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach);
8545 out.emplace_back(clearBuf());
8509 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 8546 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
8510 out.push_back(clearBuf()); 8547 auto& lenAssign = out.emplace_back(clearBuf());
8511 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 8548 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8512 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8549 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8513 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 8550 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
8514 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); 8551 expList->followStmt = followStmt.get();
8552 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
8553 if (!expList->followStmtProcessed) {
8554 lenAssign.clear();
8555 }
8515 popScope(); 8556 popScope();
8516 out.push_back(indent() + "end"s + nlr(forEach)); 8557 out.push_back(indent() + "end"s + nlr(forEach));
8517 return accum; 8558 return accum;
@@ -10440,15 +10481,22 @@ private:
10440 addToScope(accumVar); 10481 addToScope(accumVar);
10441 auto lenVar = getUnusedName("_len_"sv); 10482 auto lenVar = getUnusedName("_len_"sv);
10442 addToScope(lenVar); 10483 addToScope(lenVar);
10443 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 10484 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10444 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 10485 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
10486 temp.emplace_back(clearBuf());
10487 _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode);
10488 auto& lenAssign = temp.emplace_back(clearBuf());
10445 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 10489 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10446 auto condStr = transformCondExp(whileNode->condition, isUntil); 10490 auto condStr = transformCondExp(whileNode->condition, isUntil);
10447 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 10491 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10448 pushScope(); 10492 pushScope();
10449 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 10493 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
10450 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 10494 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10451 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 10495 assignLeft->followStmt = followStmt.get();
10496 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10497 if (!assignLeft->followStmtProcessed) {
10498 lenAssign.clear();
10499 }
10452 popScope(); 10500 popScope();
10453 temp.push_back(indent() + "end"s + nlr(whileNode)); 10501 temp.push_back(indent() + "end"s + nlr(whileNode));
10454 if (expList) { 10502 if (expList) {
@@ -10484,15 +10532,21 @@ private:
10484 addToScope(accumVar); 10532 addToScope(accumVar);
10485 auto lenVar = getUnusedName("_len_"sv); 10533 auto lenVar = getUnusedName("_len_"sv);
10486 addToScope(lenVar); 10534 addToScope(lenVar);
10487 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 10535 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10488 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 10536 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
10537 temp.emplace_back(clearBuf());
10538 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode));
10489 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 10539 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10490 auto condStr = transformCondExp(whileNode->condition, isUntil); 10540 auto condStr = transformCondExp(whileNode->condition, isUntil);
10491 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 10541 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10492 pushScope(); 10542 pushScope();
10493 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 10543 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
10494 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 10544 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
10495 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 10545 assignLeft->followStmt = followStmt.get();
10546 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
10547 if (!assignLeft->followStmtProcessed) {
10548 lenAssign.clear();
10549 }
10496 popScope(); 10550 popScope();
10497 temp.push_back(indent() + "end"s + nlr(whileNode)); 10551 temp.push_back(indent() + "end"s + nlr(whileNode));
10498 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 10552 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode));
@@ -10537,7 +10591,8 @@ private:
10537 pushScope(); 10591 pushScope();
10538 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 10592 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10539 auto condStr = transformCondExp(whileNode->condition, isUntil); 10593 auto condStr = transformCondExp(whileNode->condition, isUntil);
10540 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 10594 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
10595 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10541 popScope(); 10596 popScope();
10542 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 10597 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode);
10543 _buf << temp.back(); 10598 _buf << temp.back();
@@ -11077,11 +11132,17 @@ private:
11077 } 11132 }
11078 11133
11079 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 11134 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
11080 auto keyword = _parser.toString(breakLoop); 11135 auto isBreak = breakLoop->type.is<Break_t>();
11136 auto keyword = isBreak ? "break"s : "continue"s;
11081 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 11137 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
11082 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 11138 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
11083 } 11139 }
11084 if (keyword == "break"sv) { 11140 if (isBreak) {
11141 if (breakLoop->value) {
11142 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value);
11143 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
11144 transformAssignment(assignment, out);
11145 }
11085 out.push_back(indent() + keyword + nll(breakLoop)); 11146 out.push_back(indent() + keyword + nll(breakLoop));
11086 return; 11147 return;
11087 } 11148 }
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 77c5901..eaabf0d 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -350,7 +350,9 @@ YueParser::YueParser() {
350 350
351 ShortTabAppending = "[]" >> space >> Assign; 351 ShortTabAppending = "[]" >> space >> Assign;
352 352
353 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 353 Break = key("break");
354 Continue = key("continue");
355 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
354 356
355 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 357 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
356 358
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 7281ec3..63afcb9 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -427,6 +427,8 @@ private:
427 AST_RULE(ExpListAssign); 427 AST_RULE(ExpListAssign);
428 AST_RULE(IfLine); 428 AST_RULE(IfLine);
429 AST_RULE(WhileLine); 429 AST_RULE(WhileLine);
430 AST_RULE(Break);
431 AST_RULE(Continue);
430 AST_RULE(BreakLoop); 432 AST_RULE(BreakLoop);
431 AST_RULE(StatementAppendix); 433 AST_RULE(StatementAppendix);
432 AST_RULE(Statement); 434 AST_RULE(Statement);