From 8d648dc8c075fc1cf8d89d74c1425cdeb47e8089 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sun, 29 Jan 2023 16:39:35 +0800 Subject: refactor break loop keyword checking. --- src/yuescript/yue_compiler.cpp | 86 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 12 deletions(-) (limited to 'src') 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 Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.15.24"sv; +const std::string_view version = "0.15.25"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -296,6 +296,7 @@ private: }; std::stack _varArgs; std::stack _enableReturn; + std::stack _enableBreakLoop; std::stack _withVars; struct ContinueVar { std::string var; @@ -1072,12 +1073,14 @@ private: void pushFunctionScope() { _enableReturn.push(true); + _enableBreakLoop.push(false); _gotoScopes.push(_gotoScope); _gotoScope++; } void popFunctionScope() { _enableReturn.pop(); + _enableBreakLoop.pop(); _gotoScopes.pop(); } @@ -1224,8 +1227,16 @@ private: } default: YUEE("AST node mismatch", appendix->item.get()); break; } - } else if (statement->content.is() && !statement->appendix->item.is()) { - throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a return statement"sv, statement->appendix->item)); + } else if (!statement->appendix->item.is()) { + auto appendix = statement->appendix->item.get(); + switch (statement->content->getId()) { + case id(): + throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a return statement"sv, appendix)); + break; + case id(): + throw std::logic_error(_info.errorMessage("loop line decorator can not be used in a break-loop statement"sv, appendix)); + break; + } } auto appendix = statement->appendix.get(); switch (appendix->item->getId()) { @@ -6099,18 +6110,62 @@ private: if (auto stmt = ast_cast(node)) { if (stmt->content.is()) { return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; - } else if (expListFrom(stmt)) { - return traversal::Continue; + } else if (auto expList = expListFrom(stmt)) { + BLOCK_START + auto value = singleValueFrom(expList); + BREAK_IF(!value); + auto simpleValue = value->item.as(); + BREAK_IF(!simpleValue); + auto sVal = simpleValue->value.get(); + switch (sVal->getId()) { + case id(): { + auto withNode = static_cast(sVal); + if (hasContinueStatement(withNode->body)) { + return traversal::Stop; + } + break; + } + case id(): { + auto doNode = static_cast(sVal); + if (hasContinueStatement(doNode->body)) { + return traversal::Stop; + } + break; + } + case id(): { + auto ifNode = static_cast(sVal); + for (auto n : ifNode->nodes.objects()) { + if (hasContinueStatement(n)) { + return traversal::Stop; + } + } + break; + } + case id(): { + auto switchNode = static_cast(sVal); + for (auto branch : switchNode->branches.objects()) { + if (hasContinueStatement(static_cast(branch)->body)) { + return traversal::Stop; + } + } + if (switchNode->lastBranch) { + if (hasContinueStatement(switchNode->lastBranch)) { + return traversal::Stop; + } + } + break; + } + } + BLOCK_END } - return traversal::Return; - } else + } else { switch (node->getId()) { - case id(): - case id(): - case id(): - return traversal::Return; + case id(): + case id(): + return traversal::Continue; } - return traversal::Continue; + } + return traversal::Return; }); } @@ -6171,7 +6226,9 @@ private: } addDoToLastLineReturn(body); } + _enableBreakLoop.push(true); transform_plain_body(body, temp, usage, assignList); + _enableBreakLoop.pop(); if (withContinue) { if (target < 502) { if (extraDo) { @@ -6250,7 +6307,9 @@ private: } addDoToLastLineReturn(body); } + _enableBreakLoop.push(true); transform_plain_body(body, temp, ExpUsage::Common); + _enableBreakLoop.pop(); if (withContinue) { if (target < 502) { transformAssignment(_continueVars.top().condAssign, temp); @@ -8203,6 +8262,9 @@ private: void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { auto keyword = _parser.toString(breakLoop); + if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { + throw std::logic_error(_info.errorMessage(keyword + " is not inside a loop"s, breakLoop)); + } if (keyword == "break"sv) { out.push_back(indent() + keyword + nll(breakLoop)); return; -- cgit v1.2.3-55-g6feb