Skip to content

Commit b67ee18

Browse files
committed
[clang-format] Handle Verilog user-defined primitives
Differential Revision: https://reviews.llvm.org/D128713
1 parent 6db0c18 commit b67ee18

File tree

5 files changed

+84
-6
lines changed

5 files changed

+84
-6
lines changed

clang/lib/Format/FormatToken.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ namespace format {
143143
TYPE(VerilogDimensionedTypeName) \
144144
/* for the base in a number literal, not including the quote */ \
145145
TYPE(VerilogNumberBase) \
146+
/* Things inside the table in user-defined primitives. */ \
147+
TYPE(VerilogTableItem) \
146148
TYPE(Unknown)
147149

148150
/// Determines the semantic type of a syntactic token, e.g. whether "<" is a

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,10 @@ class AnnotatingParser {
917917
bool consumeToken() {
918918
FormatToken *Tok = CurrentToken;
919919
next();
920+
// In Verilog primitives' state tables, `:`, `?`, and `-` aren't normal
921+
// operators.
922+
if (Tok->is(TT_VerilogTableItem))
923+
return true;
920924
switch (Tok->Tok.getKind()) {
921925
case tok::plus:
922926
case tok::minus:
@@ -3996,8 +4000,16 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line,
39964000
return true;
39974001
}
39984002
} else if (Style.isVerilog()) {
4003+
// Add space between things in a primitive's state table unless in a
4004+
// transition like `(0?)`.
4005+
if ((Left.is(TT_VerilogTableItem) &&
4006+
!Right.isOneOf(tok::r_paren, tok::semi)) ||
4007+
(Right.is(TT_VerilogTableItem) && Left.isNot(tok::l_paren))) {
4008+
const FormatToken *Next = Right.getNextNonComment();
4009+
return !(Next && Next->is(tok::r_paren));
4010+
}
39994011
// Don't add space within a delay like `#0`.
4000-
if (!Left.is(TT_BinaryOperator) &&
4012+
if (Left.isNot(TT_BinaryOperator) &&
40014013
Left.isOneOf(Keywords.kw_verilogHash, Keywords.kw_verilogHashHash)) {
40024014
return false;
40034015
}

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1913,6 +1913,10 @@ void UnwrappedLineParser::parseStructuralElement(
19131913
}
19141914

19151915
if (Style.isVerilog()) {
1916+
if (FormatTok->is(Keywords.kw_table)) {
1917+
parseVerilogTable();
1918+
return;
1919+
}
19161920
if (Keywords.isVerilogBegin(*FormatTok) ||
19171921
Keywords.isVerilogHierarchy(*FormatTok)) {
19181922
parseBlock();
@@ -4039,7 +4043,8 @@ void UnwrappedLineParser::parseVerilogHierarchyIdentifier() {
40394043
}
40404044

40414045
void UnwrappedLineParser::parseVerilogSensitivityList() {
4042-
assert(FormatTok->is(tok::at));
4046+
if (!FormatTok->is(tok::at))
4047+
return;
40434048
nextToken();
40444049
// A block event expression has 2 at signs.
40454050
if (FormatTok->is(tok::at))
@@ -4064,15 +4069,13 @@ unsigned UnwrappedLineParser::parseVerilogHierarchyHeader() {
40644069
nextToken();
40654070
if (Keywords.isVerilogIdentifier(*FormatTok))
40664071
nextToken();
4067-
if (FormatTok->is(tok::at))
4068-
parseVerilogSensitivityList();
4072+
parseVerilogSensitivityList();
40694073
if (FormatTok->is(tok::semi))
40704074
nextToken();
40714075
} else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex,
40724076
Keywords.kw_casez, Keywords.kw_randcase,
40734077
Keywords.kw_randsequence)) {
4074-
if (Style.IndentCaseLabels)
4075-
++AddLevels;
4078+
AddLevels += Style.IndentCaseLabels;
40764079
nextToken();
40774080
if (FormatTok->is(tok::l_paren))
40784081
parseParens();
@@ -4154,6 +4157,25 @@ unsigned UnwrappedLineParser::parseVerilogHierarchyHeader() {
41544157
return AddLevels;
41554158
}
41564159

4160+
void UnwrappedLineParser::parseVerilogTable() {
4161+
assert(FormatTok->is(Keywords.kw_table));
4162+
nextToken(/*LevelDifference=*/1);
4163+
addUnwrappedLine();
4164+
4165+
auto InitialLevel = Line->Level++;
4166+
while (!eof() && !Keywords.isVerilogEnd(*FormatTok)) {
4167+
FormatToken *Tok = FormatTok;
4168+
nextToken();
4169+
if (Tok->is(tok::semi))
4170+
addUnwrappedLine();
4171+
else if (Tok->isOneOf(tok::star, tok::colon, tok::question, tok::minus))
4172+
Tok->setFinalizedType(TT_VerilogTableItem);
4173+
}
4174+
Line->Level = InitialLevel;
4175+
nextToken(/*LevelDifference=*/-1);
4176+
addUnwrappedLine();
4177+
}
4178+
41574179
LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
41584180
StringRef Prefix = "") {
41594181
llvm::dbgs() << Prefix << "Line(" << Line.Level

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ class UnwrappedLineParser {
183183
// Returns the number of levels of indentation in addition to the normal 1
184184
// level for a block, used for indenting case labels.
185185
unsigned parseVerilogHierarchyHeader();
186+
void parseVerilogTable();
186187

187188
// Used by addUnwrappedLine to denote whether to keep or remove a level
188189
// when resetting the line state.

clang/unittests/Format/FormatTestVerilog.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,5 +441,46 @@ TEST_F(FormatTestVerilog, Preprocessor) {
441441
}
442442
}
443443

444+
TEST_F(FormatTestVerilog, Primitive) {
445+
verifyFormat("primitive multiplexer\n"
446+
" (mux, control, dataA, dataB);\n"
447+
" output mux;\n"
448+
" input control, dataA, dataB;\n"
449+
" table\n"
450+
" 0 1 ? : 1;\n"
451+
" 0 0 ? : 0;\n"
452+
" 1 ? 1 : 1;\n"
453+
" 1 ? 0 : 0;\n"
454+
" x 0 0 : 0;\n"
455+
" x 1 1 : 1;\n"
456+
" endtable\n"
457+
"endprimitive");
458+
verifyFormat("primitive latch\n"
459+
" (q, ena_, data);\n"
460+
" output q;\n"
461+
" reg q;\n"
462+
" input ena_, data;\n"
463+
" table\n"
464+
" 0 1 : ? : 1;\n"
465+
" 0 0 : ? : 0;\n"
466+
" 1 ? : ? : -;\n"
467+
" ? * : ? : -;\n"
468+
" endtable\n"
469+
"endprimitive");
470+
verifyFormat("primitive d\n"
471+
" (q, clock, data);\n"
472+
" output q;\n"
473+
" reg q;\n"
474+
" input clock, data;\n"
475+
" table\n"
476+
" (01) 0 : ? : 0;\n"
477+
" (01) 1 : ? : 1;\n"
478+
" (0?) 1 : 1 : 1;\n"
479+
" (0?) 0 : 0 : 0;\n"
480+
" (?0) ? : ? : -;\n"
481+
" (?\?) ? : ? : -;\n"
482+
" endtable\n"
483+
"endprimitive");
484+
}
444485
} // namespace format
445486
} // end namespace clang

0 commit comments

Comments
 (0)