Skip to content

Commit

Permalink
[clang-format] Recognize Verilog non-blocking assignment
Browse files Browse the repository at this point in the history
Reviewed By: HazardyKnusperkeks, owenpan

Differential Revision: https://reviews.llvm.org/D142891
  • Loading branch information
eywdck2l committed Feb 6, 2023
1 parent 26182df commit cad708b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 1 deletion.
12 changes: 12 additions & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Expand Up @@ -1647,6 +1647,7 @@ class AnnotatingParser {
bool CaretFound = false;
bool InCpp11AttributeSpecifier = false;
bool InCSharpAttributeSpecifier = false;
bool VerilogAssignmentFound = false;
enum {
Unknown,
// Like the part after `:` in a constructor.
Expand Down Expand Up @@ -1944,6 +1945,17 @@ class AnnotatingParser {
(!Current.Previous || Current.Previous->isNot(tok::l_square)) &&
(!Current.is(tok::greater) &&
Style.Language != FormatStyle::LK_TextProto)) {
if (Style.isVerilog()) {
if (Current.is(tok::lessequal) && Contexts.size() == 1 &&
!Contexts.back().VerilogAssignmentFound) {
// In Verilog `<=` is assignment if in its own statement. It is a
// statement instead of an expression, that is it can not be chained.
Current.ForcedPrecedence = prec::Assignment;
Current.setFinalizedType(TT_BinaryOperator);
}
if (Current.getPrecedence() == prec::Assignment)
Contexts.back().VerilogAssignmentFound = true;
}
Current.setType(TT_BinaryOperator);
} else if (Current.is(tok::comment)) {
if (Current.TokenText.startswith("/*")) {
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Format/WhitespaceManager.cpp
Expand Up @@ -838,7 +838,12 @@ void WhitespaceManager::alignConsecutiveAssignments() {

return Style.AlignConsecutiveAssignments.AlignCompound
? C.Tok->getPrecedence() == prec::Assignment
: C.Tok->is(tok::equal);
: (C.Tok->is(tok::equal) ||
// In Verilog the '<=' is not a compound assignment, thus
// it is aligned even when the AlignCompound option is not
// set.
(Style.isVerilog() && C.Tok->is(tok::lessequal) &&
C.Tok->getPrecedence() == prec::Assignment));
},
Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments,
/*RightJustify=*/true);
Expand Down
52 changes: 52 additions & 0 deletions clang/unittests/Format/FormatTestVerilog.cpp
Expand Up @@ -45,6 +45,58 @@ class FormatTestVerilog : public ::testing::Test {
}
};

TEST_F(FormatTestVerilog, Align) {
FormatStyle Style = getLLVMStyle(FormatStyle::LK_Verilog);
Style.AlignConsecutiveAssignments.Enabled = true;
verifyFormat("x <= x;\n"
"sfdbddfbdfbb <= x;\n"
"x = x;",
Style);
verifyFormat("x = x;\n"
"sfdbddfbdfbb = x;\n"
"x = x;",
Style);
// Compound assignments are not aligned by default. '<=' is not a compound
// assignment.
verifyFormat("x <= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x += x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x <<= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x <<<= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x >>= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x >>>= x;\n"
"sfdbddfbdfbb <= x;",
Style);
Style.AlignConsecutiveAssignments.AlignCompound = true;
verifyFormat("x <= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x += x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x <<= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x <<<= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x >>= x;\n"
"sfdbddfbdfbb <= x;",
Style);
verifyFormat("x >>>= x;\n"
"sfdbddfbdfbb <= x;",
Style);
}

TEST_F(FormatTestVerilog, BasedLiteral) {
verifyFormat("x = '0;");
verifyFormat("x = '1;");
Expand Down
15 changes: 15 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Expand Up @@ -1314,6 +1314,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) {
EXPECT_TOKEN(Tokens[5], tok::question, TT_ConditionalExpr);
EXPECT_TOKEN(Tokens[7], tok::colon, TT_ConditionalExpr);
EXPECT_TOKEN(Tokens[9], tok::colon, TT_GotoLabelColon);
// Non-blocking assignments.
Tokens = Annotate("a <= b;");
ASSERT_EQ(Tokens.size(), 5u);
EXPECT_TOKEN(Tokens[1], tok::lessequal, TT_BinaryOperator);
EXPECT_TOKEN_PRECEDENCE(Tokens[1], prec::Assignment);
Tokens = Annotate("if (a <= b) break;");
ASSERT_EQ(Tokens.size(), 9u);
EXPECT_TOKEN(Tokens[3], tok::lessequal, TT_BinaryOperator);
EXPECT_TOKEN_PRECEDENCE(Tokens[3], prec::Relational);
Tokens = Annotate("a <= b <= a;");
ASSERT_EQ(Tokens.size(), 7u);
EXPECT_TOKEN(Tokens[1], tok::lessequal, TT_BinaryOperator);
EXPECT_TOKEN_PRECEDENCE(Tokens[1], prec::Assignment);
EXPECT_TOKEN(Tokens[3], tok::lessequal, TT_BinaryOperator);
EXPECT_TOKEN_PRECEDENCE(Tokens[3], prec::Relational);
}

TEST_F(TokenAnnotatorTest, UnderstandConstructors) {
Expand Down

0 comments on commit cad708b

Please sign in to comment.