Skip to content

Commit

Permalink
Improve parser error when encountering extra end delimiter in member …
Browse files Browse the repository at this point in the history
…list
  • Loading branch information
MikePopoloski committed May 19, 2024
1 parent ff952d5 commit 7d97140
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 1 deletion.
3 changes: 3 additions & 0 deletions include/slang/parsing/ParserBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class SLANG_EXPORT ParserBase {
Token getLastConsumed() const;
bool haveDiagAtCurrentLoc();

const std::pair<Token, Token>& getLastPoppedDelims() const { return lastPoppedDelims; }

Preprocessor& getPP() { return window.tokenSource; }

/// Helper class that maintains a sliding window of tokens, with lookahead.
Expand Down Expand Up @@ -236,6 +238,7 @@ class SLANG_EXPORT ParserBase {
Window window;
SmallVector<Token> skippedTokens;
SmallVector<Token> openDelims;
std::pair<Token, Token> lastPoppedDelims;
};

} // namespace slang::parsing
3 changes: 3 additions & 0 deletions scripts/diagnostics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ error StaticFuncSpecifier "static members cannot have override specifiers"
error OverridingExtends "'{}' is marked 'extends' but doesn't override a base class virtual member"
error DerivedCovergroupNotInClass "covergroup inheritance can only be used inside a class"
error DerivedCovergroupNoBase "covergroup is marked 'extends' but is in a class that has no base class"
error UnexpectedEndDelim "unexpected '{}' delimiter"
warning dpi-pure-task DPIPureTask "DPI tasks cannot be marked 'pure'"
warning nonstandard-generate NonStandardGenBlock "standalone generate block without loop or condition is not allowed in SystemVerilog"
warning empty-pattern EmptyAssignmentPattern "empty assignment patterns are disallowed by SystemVerilog"
Expand All @@ -307,6 +308,8 @@ warning nonstandard-dist NonstandardDist "use of parentheses around 'dist' expre
warning empty-body EmptyBody "{} has empty body (put the semicolon on a separate line to silence this warning)"
warning split-distweight-op SplitDistWeightOp "split dist weight operator is not allowed; SystemVerilog requires that they be joined together"
note NoteToMatchThis "to match this '{}'"
note NoteLastBlockStarted "last complete block started here"
note NoteLastBlockEnded "and ended here"

subsystem Declarations
error LocalParamNoInitializer "local parameter is missing an initializer"
Expand Down
5 changes: 4 additions & 1 deletion source/parsing/ParserBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ Token ParserBase::consume() {

if (SF::isOpenDelimOrKeyword(result.kind))
openDelims.push_back(result);
else if (SF::isCloseDelimOrKeyword(result.kind) && !openDelims.empty())
else if (SF::isCloseDelimOrKeyword(result.kind) && !openDelims.empty()) {
lastPoppedDelims = {openDelims.back(), result};
openDelims.pop_back();
}

return result;
}
Expand Down Expand Up @@ -107,6 +109,7 @@ Token ParserBase::expect(TokenKind kind) {
// become unbalanced and flush it.
openDelims.clear();
}
lastPoppedDelims = {};
}

Token result = Token::createExpected(alloc, getDiagnostics(), peek(), kind, window.lastConsumed,
Expand Down
12 changes: 12 additions & 0 deletions source/parsing/Parser_members.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,18 @@ std::span<TMember*> Parser::parseMemberList(TokenKind endKind, Token& endToken,
errored = false;
}
else {
if (isCloseDelimOrKeyword(kind)) {
auto& diag = addDiag(diag::UnexpectedEndDelim, peek().range());
diag << peek().valueText();
errored = true;

auto& lastBlock = getLastPoppedDelims();
if (lastBlock.first && lastBlock.second) {
diag.addNote(diag::NoteLastBlockStarted, lastBlock.first.location());
diag.addNote(diag::NoteLastBlockEnded, lastBlock.second.location());
}
}

skipToken(errored ? std::nullopt : std::make_optional(diag::ExpectedMember));
errored = true;
}
Expand Down
18 changes: 18 additions & 0 deletions tests/unittests/parsing/MemberParsingTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1458,3 +1458,21 @@ endgroup
CHECK(diagnostics[4].code == diag::WrongLanguageVersion);
CHECK(diagnostics[5].code == diag::DerivedCovergroupNotInClass);
}

TEST_CASE("Parser error recovery with extra end token") {
auto& text = R"(
module m;
int i;
if (1) begin
initial /* begin */
i = 1;
end
end
endmodule
)";

parseCompilationUnit(text);

REQUIRE(diagnostics.size() == 1);
CHECK(diagnostics[0].code == diag::UnexpectedEndDelim);
}

0 comments on commit 7d97140

Please sign in to comment.