diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1090,8 +1090,12 @@ CurrentState.Indent + Style.ContinuationIndentWidth); } - if (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && - State.Line->First->is(tok::kw_enum)) { + // After a goto label. Usually labels are on separate lines. However + // for Verilog the labels may be only recognized by the annotator and + // thus are on the same line as the current token. + if ((Style.isVerilog() && Keywords.isVerilogEndOfLabel(Previous)) || + (Style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths && + State.Line->First->is(tok::kw_enum))) { return (Style.IndentWidth * State.Line->First->IndentLevel) + Style.IndentWidth; } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1347,10 +1347,19 @@ LLVMStyle.WhitespaceSensitiveMacros.push_back("CF_SWIFT_NAME"); // Defaults that differ when not C++. - if (Language == FormatStyle::LK_TableGen) + switch (Language) { + case FormatStyle::LK_TableGen: LLVMStyle.SpacesInContainerLiterals = false; - if (LLVMStyle.isJson()) + break; + case FormatStyle::LK_Json: LLVMStyle.ColumnLimit = 0; + break; + case FormatStyle::LK_Verilog: + LLVMStyle.IndentCaseLabels = true; + break; + default: + break; + } return LLVMStyle; } 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 @@ -39,7 +39,10 @@ TYPE(CastRParen) \ TYPE(ClassLBrace) \ TYPE(CompoundRequirementLBrace) \ + /* ternary ?: expression */ \ TYPE(ConditionalExpr) \ + /* the condition in an if statement */ \ + TYPE(ConditionLParen) \ TYPE(ConflictAlternative) \ TYPE(ConflictEnd) \ TYPE(ConflictStart) \ @@ -67,6 +70,9 @@ TYPE(FunctionLBrace) \ TYPE(FunctionLikeOrFreestandingMacro) \ TYPE(FunctionTypeLParen) \ + /* The colon at the end of a goto label or a case label. Currently only used \ + * for Verilog. */ \ + TYPE(GotoLabelColon) \ TYPE(IfMacro) \ TYPE(ImplicitStringLiteral) \ TYPE(InheritanceColon) \ @@ -1765,6 +1771,15 @@ kw_task); } + bool isVerilogEndOfLabel(const FormatToken &Tok) const { + const FormatToken *Next = Tok.getNextNonComment(); + // In Verilog the colon in a default label is optional. + return Tok.is(TT_GotoLabelColon) || + (Tok.is(tok::kw_default) && + !(Next && Next->isOneOf(tok::colon, tok::semi, kw_clocking, kw_iff, + kw_input, kw_output, kw_sequence))); + } + /// Whether the token begins a block. bool isBlockBegin(const FormatToken &Tok, const FormatStyle &Style) const { return Tok.is(TT_MacroBlockBegin) || 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 @@ -955,11 +955,22 @@ break; } } else if (Style.isVerilog() && Tok->isNot(TT_BinaryOperator)) { + // The distribution weight operators are labeled + // TT_BinaryOperator by the lexer. if (Keywords.isVerilogEnd(*Tok->Previous) || Keywords.isVerilogBegin(*Tok->Previous)) { Tok->setType(TT_VerilogBlockLabelColon); } else if (Contexts.back().ContextKind == tok::l_square) { Tok->setType(TT_BitFieldColon); + } else if (Contexts.back().ColonIsDictLiteral) { + Tok->setType(TT_DictLiteral); + } else if (Contexts.size() == 1) { + // In Verilog a case label doesn't have the case keyword. We + // assume a colon following an expression is a case label. + // Colons from ?: are annotated in parseConditional(). + Tok->setType(TT_GotoLabelColon); + if (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0)) + --Line.Level; } break; } @@ -1230,6 +1241,13 @@ if (Contexts.back().ContextType == Context::ForEachMacro) Contexts.back().IsExpression = true; break; + case tok::kw_default: + // Unindent case labels. + if (Style.isVerilog() && Keywords.isVerilogEndOfLabel(*Tok) && + (Line.Level > 1 || (!Line.InPPDirective && Line.Level > 0))) { + --Line.Level; + } + break; case tok::identifier: if (Tok->isOneOf(Keywords.kw___has_include, Keywords.kw___has_include_next)) { @@ -2609,6 +2627,10 @@ Keywords.kw_throws)) { return 0; } + // In Verilog case labels are not on separate lines straight out of + // UnwrappedLineParser. The colon is not part of an expression. + if (Style.isVerilog() && Current->is(tok::colon)) + return 0; } return -1; } @@ -3614,7 +3636,8 @@ return true; if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) || - Left.isIf(Line.Type != LT_PreprocessorDirective)) { + Left.isIf(Line.Type != LT_PreprocessorDirective) || + Right.is(TT_ConditionLParen)) { return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); } @@ -4085,6 +4108,11 @@ Style.BitFieldColonSpacing == FormatStyle::BFCS_After; } if (Right.is(tok::colon)) { + if (Right.is(TT_GotoLabelColon) || + (!Style.isVerilog() && + Line.First->isOneOf(tok::kw_default, tok::kw_case))) { + return Style.SpaceBeforeCaseColon; + } if (Line.First->isOneOf(tok::kw_default, tok::kw_case)) return Style.SpaceBeforeCaseColon; const FormatToken *Next = Right.getNextNonComment(); @@ -4347,6 +4375,11 @@ Right.Next->is(tok::string_literal)) { return true; } + } else if (Style.isVerilog()) { + // Break after labels. In Verilog labels don't have the 'case' keyword, so + // it is hard to identify them in UnwrappedLineParser. + if (!Keywords.isVerilogBegin(Right) && Keywords.isVerilogEndOfLabel(Left)) + return true; } else if (Style.Language == FormatStyle::LK_Cpp || Style.Language == FormatStyle::LK_ObjC || Style.Language == FormatStyle::LK_Proto || 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 @@ -184,6 +184,7 @@ // level for a block, used for indenting case labels. unsigned parseVerilogHierarchyHeader(); void parseVerilogTable(); + void parseVerilogCaseLabel(); // 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 @@ -576,9 +576,12 @@ LLVM_FALLTHROUGH; } case tok::kw_case: - if (Style.isJavaScript() && Line->MustBeDeclaration) { - // A 'case: string' style field declaration. - parseStructuralElement(); + if (Style.isVerilog() || + (Style.isJavaScript() && Line->MustBeDeclaration)) { + // Verilog: Case labels don't have this word. We handle case + // labels including default in TokenAnnotator. + // JavaScript: A 'case: string' style field declaration. + ParseDefault(); break; } if (!SwitchLabelEncountered && @@ -1534,6 +1537,9 @@ parseSwitch(); return; case tok::kw_default: + // In Verilog default along with other labels are handled in the next loop. + if (Style.isVerilog()) + break; if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'default: string' field declaration. break; @@ -1546,6 +1552,12 @@ // e.g. "default void f() {}" in a Java interface. break; case tok::kw_case: + // In Verilog switch is called case. + if (Style.isVerilog()) { + parseBlock(); + addUnwrappedLine(); + return; + } if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'case: string' field declaration. nextToken(); @@ -1956,7 +1968,9 @@ return I != E && (++I == E); }; if (OneTokenSoFar()) { - if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) { + // In Verilog labels can be any expression, so we don't do them here. + if (!Style.isVerilog() && FormatTok->is(tok::colon) && + !Line->MustBeDeclaration) { Line->Tokens.begin()->Tok->MustBreakBefore = true; parseLabel(!Style.IndentGotoLabels); if (HasLabel) @@ -2013,6 +2027,12 @@ parseNew(); break; case tok::kw_case: + // In Verilog switch is called case. + if (Style.isVerilog()) { + parseBlock(); + addUnwrappedLine(); + return; + } if (Style.isJavaScript() && Line->MustBeDeclaration) { // 'case: string' field declaration. nextToken(); @@ -2020,6 +2040,30 @@ } parseCaseLabel(); break; + case tok::kw_default: + nextToken(); + if (Style.isVerilog()) { + if (FormatTok->is(tok::colon)) { + // The label will be handled in the next iteration. + break; + } + if (FormatTok->is(Keywords.kw_clocking)) { + // A default clocking block. + parseBlock(); + addUnwrappedLine(); + return; + } + parseVerilogCaseLabel(); + return; + } + break; + case tok::colon: + nextToken(); + if (Style.isVerilog()) { + parseVerilogCaseLabel(); + return; + } + break; default: nextToken(); break; @@ -4075,10 +4119,13 @@ } else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex, Keywords.kw_casez, Keywords.kw_randcase, Keywords.kw_randsequence)) { - AddLevels += Style.IndentCaseLabels; + if (Style.IndentCaseLabels) + AddLevels++; nextToken(); - if (FormatTok->is(tok::l_paren)) + if (FormatTok->is(tok::l_paren)) { + FormatTok->setFinalizedType(TT_ConditionLParen); parseParens(); + } if (FormatTok->isOneOf(Keywords.kw_inside, Keywords.kw_matches)) nextToken(); // The case header has no semicolon. @@ -4176,6 +4223,26 @@ addUnwrappedLine(); } +void UnwrappedLineParser::parseVerilogCaseLabel() { + // The label will get unindented in AnnotatingParser. If there are no leading + // spaces, indent the rest here so that things inside the block will be + // indented relative to things outside. We don't use parseLabel because we + // don't know whether this colon is a label or a ternary expression at this + // point. + auto OrigLevel = Line->Level; + auto FirstLine = CurrentLines->size(); + if (Line->Level == 0 || (Line->InPPDirective && Line->Level <= 1)) + ++Line->Level; + else if (!Style.IndentCaseBlocks && Keywords.isVerilogBegin(*FormatTok)) + --Line->Level; + parseStructuralElement(); + // Restore the indentation in both the new line and the line that has the + // label. + if (CurrentLines->size() > FirstLine) + (*CurrentLines)[FirstLine].Level = OrigLevel; + Line->Level = OrigLevel; +} + 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 @@ -116,6 +116,90 @@ "x = x;"); } +TEST_F(FormatTestVerilog, Case) { + verifyFormat("case (data)\n" + "endcase"); + verifyFormat("casex (data)\n" + "endcase"); + verifyFormat("casez (data)\n" + "endcase"); + verifyFormat("case (data) inside\n" + "endcase"); + verifyFormat("case (data)\n" + " 16'd0:\n" + " result = 10'b0111111111;\n" + "endcase"); + verifyFormat("case (data)\n" + " xxxxxxxx:\n" + " result = 10'b0111111111;\n" + "endcase"); + // Test labels with multiple options. + verifyFormat("case (data)\n" + " 16'd0, 16'd1:\n" + " result = 10'b0111111111;\n" + "endcase"); + verifyFormat("case (data)\n" + " 16'd0, //\n" + " 16'd1:\n" + " result = 10'b0111111111;\n" + "endcase"); + // Test that blocks following labels are indented. + verifyFormat("case (data)\n" + " 16'd1: fork\n" + " result = 10'b1011111111;\n" + " join\n" + "endcase\n"); + verifyFormat("case (data)\n" + " 16'd1: fork : x\n" + " result = 10'b1011111111;\n" + " join : x\n" + "endcase\n"); + // Test default. + verifyFormat("case (data)\n" + " default\n" + " result = 10'b1011111111;\n" + "endcase"); + verifyFormat("case (data)\n" + " default:\n" + " result = 10'b1011111111;\n" + "endcase"); + // Test that question marks and colons don't get mistaken as labels. + verifyFormat("case (data)\n" + " 8'b1???????:\n" + " instruction1(ir);\n" + "endcase"); + verifyFormat("case (data)\n" + " x ? 8'b1??????? : 1:\n" + " instruction3(ir);\n" + "endcase"); + // Test indention options. + auto Style = getLLVMStyle(FormatStyle::LK_Verilog); + Style.IndentCaseLabels = false; + verifyFormat("case (data)\n" + "16'd0:\n" + " result = 10'b0111111111;\n" + "endcase", + Style); + verifyFormat("case (data)\n" + "16'd0: begin\n" + " result = 10'b0111111111;\n" + "end\n" + "endcase", + Style); + Style.IndentCaseLabels = true; + verifyFormat("case (data)\n" + " 16'd0:\n" + " result = 10'b0111111111;\n" + "endcase", + Style); + verifyFormat("case (data)\n" + " 16'd0: begin\n" + " result = 10'b0111111111;\n" + " end\n" + "endcase", + Style); +} + TEST_F(FormatTestVerilog, Delay) { // Delay by the default unit. verifyFormat("#0;"); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -838,6 +838,21 @@ Tokens = Annotate("extern function [1 : 0] x;"); ASSERT_EQ(Tokens.size(), 10u) << Tokens; EXPECT_TOKEN(Tokens[4], tok::colon, TT_BitFieldColon); + // Test case labels and ternary operators. + Tokens = Annotate("case (x)\n" + " x:\n" + " x;\n" + "endcase\n"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[5], tok::colon, TT_GotoLabelColon); + Tokens = Annotate("case (x)\n" + " x ? x : x:\n" + " x;\n" + "endcase\n"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_TOKEN(Tokens[5], tok::question, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[7], tok::colon, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[9], tok::colon, TT_GotoLabelColon); } } // namespace