diff options
| author | Li Jin <dragon-fly@qq.com> | 2025-05-21 11:44:54 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2025-05-21 11:44:54 +0800 |
| commit | 0603800a4114ed8b4c9572a7d7852995c9b9f334 (patch) | |
| tree | 456524685562bcd0d874530e3ddc2a0fc0731525 /src | |
| parent | ff137ac73d999a5849f02706cfd52f4659b025ef (diff) | |
| download | yuescript-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.cpp | 12 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 14 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 183 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 4 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 2 |
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 { | |||
| 188 | std::string NotIn_t::to_string(void*) const { | 188 | std::string NotIn_t::to_string(void*) const { |
| 189 | return {}; | 189 | return {}; |
| 190 | } | 190 | } |
| 191 | std::string Break_t::to_string(void*) const { | ||
| 192 | return "break"s; | ||
| 193 | } | ||
| 194 | std::string Continue_t::to_string(void*) const { | ||
| 195 | return "continue"s; | ||
| 196 | } | ||
| 191 | std::string BreakLoop_t::to_string(void* ud) const { | 197 | std::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 | } |
| 195 | std::string YueLineComment_t::to_string(void* ud) const { | 203 | std::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; | ||
| 276 | AST_END(ExpList) | 278 | AST_END(ExpList) |
| 277 | 279 | ||
| 278 | AST_NODE(Return) | 280 | AST_NODE(Return) |
| @@ -856,7 +858,17 @@ AST_NODE(WhileLine) | |||
| 856 | AST_MEMBER(WhileLine, &type, &condition) | 858 | AST_MEMBER(WhileLine, &type, &condition) |
| 857 | AST_END(WhileLine) | 859 | AST_END(WhileLine) |
| 858 | 860 | ||
| 859 | AST_LEAF(BreakLoop) | 861 | AST_LEAF(Break) |
| 862 | AST_END(Break) | ||
| 863 | |||
| 864 | AST_LEAF(Continue) | ||
| 865 | AST_END(Continue) | ||
| 866 | |||
| 867 | AST_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; | ||
| 860 | AST_END(BreakLoop) | 872 | AST_END(BreakLoop) |
| 861 | 873 | ||
| 862 | AST_NODE(PipeBody) | 874 | AST_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 | ||
| 81 | const std::string_view version = "0.27.6"sv; | 81 | const std::string_view version = "0.28.0"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class 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); |
