diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -143,6 +143,8 @@ TYPE(VerilogDimensionedTypeName) \ /* for the base in a number literal, not including the quote */ \ TYPE(VerilogNumberBase) \ + /* Things inside the table in user-defined primitives. */ \ + TYPE(VerilogTableItem) \ TYPE(Unknown) /// Determines the semantic type of a syntactic token, e.g. whether "<" is a diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -917,6 +917,10 @@ bool consumeToken() { FormatToken *Tok = CurrentToken; next(); + // In Verilog primitives' state tables, `:`, `?`, and `-` aren't normal + // operators. + if (Tok->is(TT_VerilogTableItem)) + return true; switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: @@ -3996,8 +4000,16 @@ return true; } } else if (Style.isVerilog()) { + // Add space between things in a primitive's state table unless in a + // transition like `(0?)`. + if ((Left.is(TT_VerilogTableItem) && + !Right.isOneOf(tok::r_paren, tok::semi)) || + (Right.is(TT_VerilogTableItem) && Left.isNot(tok::l_paren))) { + const FormatToken *Next = Right.getNextNonComment(); + return !(Next && Next->is(tok::r_paren)); + } // Don't add space within a delay like `#0`. - if (!Left.is(TT_BinaryOperator) && + if (Left.isNot(TT_BinaryOperator) && Left.isOneOf(Keywords.kw_verilogHash, Keywords.kw_verilogHashHash)) { return false; } diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -183,6 +183,7 @@ // Returns the number of levels of indentation in addition to the normal 1 // level for a block, used for indenting case labels. unsigned parseVerilogHierarchyHeader(); + void parseVerilogTable(); // Used by addUnwrappedLine to denote whether to keep or remove a level // when resetting the line state. diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1913,6 +1913,10 @@ } if (Style.isVerilog()) { + if (FormatTok->is(Keywords.kw_table)) { + parseVerilogTable(); + return; + } if (Keywords.isVerilogBegin(*FormatTok) || Keywords.isVerilogHierarchy(*FormatTok)) { parseBlock(); @@ -4039,7 +4043,8 @@ } void UnwrappedLineParser::parseVerilogSensitivityList() { - assert(FormatTok->is(tok::at)); + if (!FormatTok->is(tok::at)) + return; nextToken(); // A block event expression has 2 at signs. if (FormatTok->is(tok::at)) @@ -4064,15 +4069,13 @@ nextToken(); if (Keywords.isVerilogIdentifier(*FormatTok)) nextToken(); - if (FormatTok->is(tok::at)) - parseVerilogSensitivityList(); + parseVerilogSensitivityList(); if (FormatTok->is(tok::semi)) nextToken(); } else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex, Keywords.kw_casez, Keywords.kw_randcase, Keywords.kw_randsequence)) { - if (Style.IndentCaseLabels) - ++AddLevels; + AddLevels += Style.IndentCaseLabels; nextToken(); if (FormatTok->is(tok::l_paren)) parseParens(); @@ -4154,6 +4157,25 @@ return AddLevels; } +void UnwrappedLineParser::parseVerilogTable() { + assert(FormatTok->is(Keywords.kw_table)); + nextToken(/*LevelDifference=*/1); + addUnwrappedLine(); + + auto InitialLevel = Line->Level++; + while (!eof() && !Keywords.isVerilogEnd(*FormatTok)) { + FormatToken *Tok = FormatTok; + nextToken(); + if (Tok->is(tok::semi)) + addUnwrappedLine(); + else if (Tok->isOneOf(tok::star, tok::colon, tok::question, tok::minus)) + Tok->setFinalizedType(TT_VerilogTableItem); + } + Line->Level = InitialLevel; + nextToken(/*LevelDifference=*/-1); + addUnwrappedLine(); +} + LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, StringRef Prefix = "") { llvm::dbgs() << Prefix << "Line(" << Line.Level diff --git a/clang/unittests/Format/FormatTestVerilog.cpp b/clang/unittests/Format/FormatTestVerilog.cpp --- a/clang/unittests/Format/FormatTestVerilog.cpp +++ b/clang/unittests/Format/FormatTestVerilog.cpp @@ -441,5 +441,46 @@ } } +TEST_F(FormatTestVerilog, Primitive) { + verifyFormat("primitive multiplexer\n" + " (mux, control, dataA, dataB);\n" + " output mux;\n" + " input control, dataA, dataB;\n" + " table\n" + " 0 1 ? : 1;\n" + " 0 0 ? : 0;\n" + " 1 ? 1 : 1;\n" + " 1 ? 0 : 0;\n" + " x 0 0 : 0;\n" + " x 1 1 : 1;\n" + " endtable\n" + "endprimitive"); + verifyFormat("primitive latch\n" + " (q, ena_, data);\n" + " output q;\n" + " reg q;\n" + " input ena_, data;\n" + " table\n" + " 0 1 : ? : 1;\n" + " 0 0 : ? : 0;\n" + " 1 ? : ? : -;\n" + " ? * : ? : -;\n" + " endtable\n" + "endprimitive"); + verifyFormat("primitive d\n" + " (q, clock, data);\n" + " output q;\n" + " reg q;\n" + " input clock, data;\n" + " table\n" + " (01) 0 : ? : 0;\n" + " (01) 1 : ? : 1;\n" + " (0?) 1 : 1 : 1;\n" + " (0?) 0 : 0 : 0;\n" + " (?0) ? : ? : -;\n" + " (?\?) ? : ? : -;\n" + " endtable\n" + "endprimitive"); +} } // namespace format } // end namespace clang