llvm-project/clang/unittests/Format/FormatTestVerilog.cpp
sstwcw c88719483c [clang-format] Handle Verilog case statements
These statements are like switch statements in C, but without the 'case'
keyword in labels.

How labels are parsed.  In UnwrappedLineParser, the program tries to
parse a statement every time it sees a colon.  In TokenAnnotator, a
colon that isn't part of an expression is annotated as a label.

The token type `TT_GotoLabelColon` is added.  We did not include Verilog
in the name because we thought we would eventually have to fix the
problem that case labels in C can't contain ternary conditional
expressions and we would use that token type.

The style is like below.  Labels are on separate lines and indented by
default.  The linked style guide also has examples where labels and the
corresponding statements are on the same lines.  They are not supported
for now.

https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md

```
case (state_q)
  StIdle:
    state_d = StA;
  StA: begin
    state_d = StB;
  end
endcase
```

Differential Revision: https://reviews.llvm.org/D128714
2022-07-29 00:38:30 +00:00

571 lines
17 KiB
C++

//===- unittest/Format/FormatTestVerilog.cpp ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "FormatTestUtils.h"
#include "clang/Format/Format.h"
#include "llvm/Support/Debug.h"
#include "gtest/gtest.h"
#define DEBUG_TYPE "format-test"
namespace clang {
namespace format {
class FormatTestVerilog : public ::testing::Test {
protected:
static std::string format(llvm::StringRef Code, unsigned Offset,
unsigned Length, const FormatStyle &Style) {
LLVM_DEBUG(llvm::errs() << "---\n");
LLVM_DEBUG(llvm::errs() << Code << "\n\n");
std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
tooling::Replacements Replaces = reformat(Style, Code, Ranges);
auto Result = applyAllReplacements(Code, Replaces);
EXPECT_TRUE(static_cast<bool>(Result));
LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
return *Result;
}
static std::string
format(llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) {
return format(Code, 0, Code.size(), Style);
}
static void verifyFormat(
llvm::StringRef Code,
const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Verilog)) {
EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
EXPECT_EQ(Code.str(),
format(test::messUp(Code, /*HandleHash=*/false), Style));
}
};
TEST_F(FormatTestVerilog, BasedLiteral) {
verifyFormat("x = '0;");
verifyFormat("x = '1;");
verifyFormat("x = 'X;");
verifyFormat("x = 'x;");
verifyFormat("x = 'Z;");
verifyFormat("x = 'z;");
verifyFormat("x = 659;");
verifyFormat("x = 'h837ff;");
verifyFormat("x = 'o7460;");
verifyFormat("x = 4'b1001;");
verifyFormat("x = 5'D3;");
verifyFormat("x = 3'b01x;");
verifyFormat("x = 12'hx;");
verifyFormat("x = 16'hz;");
verifyFormat("x = -8'd6;");
verifyFormat("x = 4'shf;");
verifyFormat("x = -4'sd15;");
verifyFormat("x = 16'sd?;");
}
TEST_F(FormatTestVerilog, Block) {
verifyFormat("begin\n"
" x = x;\n"
"end");
verifyFormat("begin : x\n"
" x = x;\n"
"end : x");
verifyFormat("begin\n"
" x = x;\n"
" x = x;\n"
"end");
verifyFormat("fork\n"
" x = x;\n"
"join");
verifyFormat("fork\n"
" x = x;\n"
"join_any");
verifyFormat("fork\n"
" x = x;\n"
"join_none");
verifyFormat("generate\n"
" x = x;\n"
"endgenerate");
verifyFormat("generate : x\n"
" x = x;\n"
"endgenerate : x");
// Nested blocks.
verifyFormat("begin\n"
" begin\n"
" end\n"
"end");
verifyFormat("begin : x\n"
" begin\n"
" end\n"
"end : x");
verifyFormat("begin : x\n"
" begin : x\n"
" end : x\n"
"end : x");
verifyFormat("begin\n"
" begin : x\n"
" end : x\n"
"end");
// Test that 'disable fork' and 'rand join' don't get mistaken as blocks.
verifyFormat("disable fork;\n"
"x = x;");
verifyFormat("rand join x x;\n"
"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;");
verifyFormat("#1;");
verifyFormat("#10;");
verifyFormat("#1.5;");
// Explicit unit.
verifyFormat("#1fs;");
verifyFormat("#1.5fs;");
verifyFormat("#1ns;");
verifyFormat("#1.5ns;");
verifyFormat("#1us;");
verifyFormat("#1.5us;");
verifyFormat("#1ms;");
verifyFormat("#1.5ms;");
verifyFormat("#1s;");
verifyFormat("#1.5s;");
// The following expression should be on the same line.
verifyFormat("#1 x = x;");
EXPECT_EQ("#1 x = x;", format("#1\n"
"x = x;"));
}
TEST_F(FormatTestVerilog, Hierarchy) {
verifyFormat("module x;\n"
"endmodule");
// Test that the end label is on the same line as the end keyword.
verifyFormat("module x;\n"
"endmodule : x");
// Test that things inside are indented.
verifyFormat("module x;\n"
" generate\n"
" endgenerate\n"
"endmodule");
verifyFormat("program x;\n"
" generate\n"
" endgenerate\n"
"endprogram");
verifyFormat("interface x;\n"
" generate\n"
" endgenerate\n"
"endinterface");
verifyFormat("task x;\n"
" generate\n"
" endgenerate\n"
"endtask");
verifyFormat("function x;\n"
" generate\n"
" endgenerate\n"
"endfunction");
verifyFormat("class x;\n"
" generate\n"
" endgenerate\n"
"endclass");
// Test that they nest.
verifyFormat("module x;\n"
" program x;\n"
" program x;\n"
" endprogram\n"
" endprogram\n"
"endmodule");
// Test that an extern declaration doesn't change the indentation.
verifyFormat("extern module x;\n"
"x = x;");
// Test complex headers
verifyFormat("extern module x\n"
" import x.x::x::*;\n"
" import x;\n"
" #(parameter x)\n"
" (output x);");
verifyFormat("module x\n"
" import x.x::x::*;\n"
" import x;\n"
" #(parameter x)\n"
" (output x);\n"
" generate\n"
" endgenerate\n"
"endmodule : x");
verifyFormat("virtual class x\n"
" (x)\n"
" extends x(x)\n"
" implements x, x, x;\n"
" generate\n"
" endgenerate\n"
"endclass : x\n");
verifyFormat("function automatic logic [1 : 0] x\n"
" (input x);\n"
" generate\n"
" endgenerate\n"
"endfunction : x");
}
TEST_F(FormatTestVerilog, If) {
verifyFormat("if (x)\n"
" x = x;");
verifyFormat("if (x)\n"
" x = x;\n"
"x = x;");
// Test else
verifyFormat("if (x)\n"
" x = x;\n"
"else if (x)\n"
" x = x;\n"
"else\n"
" x = x;");
verifyFormat("if (x) begin\n"
" x = x;\n"
"end else if (x) begin\n"
" x = x;\n"
"end else begin\n"
" x = x;\n"
"end");
verifyFormat("if (x) begin : x\n"
" x = x;\n"
"end : x else if (x) begin : x\n"
" x = x;\n"
"end : x else begin : x\n"
" x = x;\n"
"end : x");
// Test block keywords.
verifyFormat("if (x) begin\n"
" x = x;\n"
"end");
verifyFormat("if (x) begin : x\n"
" x = x;\n"
"end : x");
verifyFormat("if (x) begin\n"
" x = x;\n"
" x = x;\n"
"end");
verifyFormat("if (x) fork\n"
" x = x;\n"
"join");
verifyFormat("if (x) fork\n"
" x = x;\n"
"join_any");
verifyFormat("if (x) fork\n"
" x = x;\n"
"join_none");
verifyFormat("if (x) generate\n"
" x = x;\n"
"endgenerate");
verifyFormat("if (x) generate : x\n"
" x = x;\n"
"endgenerate : x");
// Test that concatenation braces don't get regarded as blocks.
verifyFormat("if (x)\n"
" {x} = x;");
verifyFormat("if (x)\n"
" x = {x};");
verifyFormat("if (x)\n"
" x = {x};\n"
"else\n"
" {x} = {x};");
}
TEST_F(FormatTestVerilog, Operators) {
// Test that unary operators are not followed by space.
verifyFormat("x = +x;");
verifyFormat("x = -x;");
verifyFormat("x = !x;");
verifyFormat("x = ~x;");
verifyFormat("x = &x;");
verifyFormat("x = ~&x;");
verifyFormat("x = |x;");
verifyFormat("x = ~|x;");
verifyFormat("x = ^x;");
verifyFormat("x = ~^x;");
verifyFormat("x = ^~x;");
verifyFormat("x = ++x;");
verifyFormat("x = --x;");
// Test that operators don't get split.
verifyFormat("x = x++;");
verifyFormat("x = x--;");
verifyFormat("x = x ** x;");
verifyFormat("x = x << x;");
verifyFormat("x = x >> x;");
verifyFormat("x = x <<< x;");
verifyFormat("x = x >>> x;");
verifyFormat("x = x <= x;");
verifyFormat("x = x >= x;");
verifyFormat("x = x == x;");
verifyFormat("x = x != x;");
verifyFormat("x = x === x;");
verifyFormat("x = x !== x;");
verifyFormat("x = x ==? x;");
verifyFormat("x = x !=? x;");
verifyFormat("x = x ~^ x;");
verifyFormat("x = x ^~ x;");
verifyFormat("x = x && x;");
verifyFormat("x = x || x;");
verifyFormat("x = x->x;");
verifyFormat("x = x <-> x;");
verifyFormat("x += x;");
verifyFormat("x -= x;");
verifyFormat("x *= x;");
verifyFormat("x /= x;");
verifyFormat("x %= x;");
verifyFormat("x &= x;");
verifyFormat("x ^= x;");
verifyFormat("x |= x;");
verifyFormat("x <<= x;");
verifyFormat("x >>= x;");
verifyFormat("x <<<= x;");
verifyFormat("x >>>= x;");
verifyFormat("x <= x;");
// Test that space is added between operators.
EXPECT_EQ("x = x < -x;", format("x=x<-x;"));
EXPECT_EQ("x = x << -x;", format("x=x<<-x;"));
EXPECT_EQ("x = x <<< -x;", format("x=x<<<-x;"));
}
TEST_F(FormatTestVerilog, Preprocessor) {
auto Style = getLLVMStyle(FormatStyle::LK_Verilog);
Style.ColumnLimit = 20;
// Macro definitions.
EXPECT_EQ("`define X \\\n"
" if (x) \\\n"
" x = x;",
format("`define X if(x)x=x;", Style));
EXPECT_EQ("`define X(x) \\\n"
" if (x) \\\n"
" x = x;",
format("`define X(x) if(x)x=x;", Style));
EXPECT_EQ("`define X \\\n"
" x = x; \\\n"
" x = x;",
format("`define X x=x;x=x;", Style));
// Macro definitions with invocations inside.
EXPECT_EQ("`define LIST \\\n"
" `ENTRY \\\n"
" `ENTRY",
format("`define LIST \\\n"
"`ENTRY \\\n"
"`ENTRY",
Style));
EXPECT_EQ("`define LIST \\\n"
" `x = `x; \\\n"
" `x = `x;",
format("`define LIST \\\n"
"`x = `x; \\\n"
"`x = `x;",
Style));
EXPECT_EQ("`define LIST \\\n"
" `x = `x; \\\n"
" `x = `x;",
format("`define LIST `x=`x;`x=`x;", Style));
// Macro invocations.
verifyFormat("`x = (`x1 + `x2 + x);");
// Lines starting with a preprocessor directive should not be indented.
std::string Directives[] = {
"begin_keywords",
"celldefine",
"default_nettype",
"define",
"else",
"elsif",
"end_keywords",
"endcelldefine",
"endif",
"ifdef",
"ifndef",
"include",
"line",
"nounconnected_drive",
"pragma",
"resetall",
"timescale",
"unconnected_drive",
"undef",
"undefineall",
};
for (auto &Name : Directives) {
EXPECT_EQ("if (x)\n"
"`" +
Name +
"\n"
" ;",
format("if (x)\n"
"`" +
Name +
"\n"
";",
Style));
}
// Lines starting with a regular macro invocation should be indented as a
// normal line.
EXPECT_EQ("if (x)\n"
" `x = `x;\n"
"`timescale 1ns / 1ps",
format("if (x)\n"
"`x = `x;\n"
"`timescale 1ns / 1ps",
Style));
EXPECT_EQ("if (x)\n"
"`timescale 1ns / 1ps\n"
" `x = `x;",
format("if (x)\n"
"`timescale 1ns / 1ps\n"
"`x = `x;",
Style));
std::string NonDirectives[] = {
// For `__FILE__` and `__LINE__`, although the standard classifies them as
// preprocessor directives, they are used like regular macros.
"__FILE__", "__LINE__", "elif", "foo", "x",
};
for (auto &Name : NonDirectives) {
EXPECT_EQ("if (x)\n"
" `" +
Name + ";",
format("if (x)\n"
"`" +
Name +
"\n"
";",
Style));
}
}
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