Add --class_parameter_space (#2571) Signed-off-by: Wilson Snyder <wsnyder@wsnyder.org>
diff --git a/verible/verilog/formatting/format-style-init.cc b/verible/verilog/formatting/format-style-init.cc index 2dde818..a6d010b 100644 --- a/verible/verilog/formatting/format-style-init.cc +++ b/verible/verilog/formatting/format-style-init.cc
@@ -140,6 +140,13 @@ "Use compact binary expressions inside indexing / bit selection " "operators"); +ABSL_FLAG(bool, class_parameter_space, false, + "If true, keep/insert a space before '#' in a class" + "parameterized typedef, e.g. \"typedef my_class #(.P(P)) " + "my_class_t;\". If false (default), no space is inserted, " + "matching the convention used for IEEE parameterized class " + "instantiations, e.g. \"type#(params...)::method(...)\"."); + ABSL_FLAG(bool, wrap_end_else_clauses, false, "Split end and else keywords into separate lines"); @@ -197,6 +204,7 @@ STYLE_FROM_FLAG(try_wrap_long_lines); STYLE_FROM_FLAG(expand_coverpoints); STYLE_FROM_FLAG(compact_indexing_and_selections); + STYLE_FROM_FLAG(class_parameter_space); STYLE_FROM_FLAG(wrap_end_else_clauses); STYLE_FROM_FLAG(alignment_group_boundary);
diff --git a/verible/verilog/formatting/format-style.h b/verible/verilog/formatting/format-style.h index 2fad329..55347c5 100644 --- a/verible/verilog/formatting/format-style.h +++ b/verible/verilog/formatting/format-style.h
@@ -146,6 +146,9 @@ // Compact binary expressions inside indexing / bit selection operators bool compact_indexing_and_selections = true; + // Keep/insert a space before '#' in a parameterized class typedef + bool class_parameter_space = false; + // Split with a \n end and else clauses bool wrap_end_else_clauses = false;
diff --git a/verible/verilog/formatting/formatter_test.cc b/verible/verilog/formatting/formatter_test.cc index 5205a01..8bd8e72 100644 --- a/verible/verilog/formatting/formatter_test.cc +++ b/verible/verilog/formatting/formatter_test.cc
@@ -4478,19 +4478,30 @@ " .L(L),\n" " .W(W)\n" ") bar_t;\n"}, - // unqualified parameterized type keeps a space before '#' + // By default (class_parameter_space == false), no space before '#' {"typedef dv_base_env_cov #(.CFG_T(tl_agent_env_cfg)) tl_agent_env_cov;\n", - "typedef dv_base_env_cov #(\n" + "typedef dv_base_env_cov#(\n" " .CFG_T(tl_agent_env_cfg)\n" ") tl_agent_env_cov;\n"}, - // ... and is inserted when absent {"typedef dv_base_env_cov#(.CFG_T(tl_agent_env_cfg)) tl_agent_env_cov;\n", - "typedef dv_base_env_cov #(\n" + "typedef dv_base_env_cov#(\n" " .CFG_T(tl_agent_env_cfg)\n" ") tl_agent_env_cov;\n"}, // single short parameter stays on one line {"typedef my_class #(.P(P)) my_class_t;\n", - "typedef my_class #(.P(P)) my_class_t;\n"}, + "typedef my_class#(.P(P)) my_class_t;\n"}, + + // let declarations each stay on their own line + {"module t;\n" + "let OFF = 4;\n" + "let UNIQUE = 32;\n" + "let PP(a) = 30 + a;\n" + "endmodule\n", + "module t;\n" + " let OFF = 4;\n" + " let UNIQUE = 32;\n" + " let PP(a) = 30 + a;\n" + "endmodule\n"}, // package test cases {"package fedex;localparam int www=3 ;endpackage : fedex\n", @@ -18788,6 +18799,50 @@ } } +static constexpr FormatterTestCase + kSpaceBeforeHashInUnqualifiedTypedefTestCases[] = { + // unqualified parameterized type keeps a space before '#' + {"typedef dv_base_env_cov #(.CFG_T(tl_agent_env_cfg)) " + "tl_agent_env_cov;\n", + "typedef dv_base_env_cov #(\n" + " .CFG_T(tl_agent_env_cfg)\n" + ") tl_agent_env_cov;\n"}, + // ... and is inserted when absent + {"typedef dv_base_env_cov#(.CFG_T(tl_agent_env_cfg)) " + "tl_agent_env_cov;\n", + "typedef dv_base_env_cov #(\n" + " .CFG_T(tl_agent_env_cfg)\n" + ") tl_agent_env_cov;\n"}, + // single short parameter stays on one line + {"typedef my_class #(.P(P)) my_class_t;\n", + "typedef my_class #(.P(P)) my_class_t;\n"}, + // package-qualified types are unaffected (no space before '#') + {"typedef foo_pkg::baz_t#(.L(L), .W(W)) bar_t;\n", + "typedef foo_pkg::baz_t#(\n" + " .L(L),\n" + " .W(W)\n" + ") bar_t;\n"}, +}; + +TEST(FormatterEndToEndTest, SpaceBeforeHashInUnqualifiedTypedefTestCases) { + // Use a fixed style. + FormatStyle style; + style.column_limit = 40; + style.indentation_spaces = 2; + style.wrap_spaces = 4; + style.class_parameter_space = true; + + for (const auto &test_case : kSpaceBeforeHashInUnqualifiedTypedefTestCases) { + VLOG(1) << "code-to-format:\n" << test_case.input << "<EOF>"; + std::ostringstream stream; + const auto status = + FormatVerilog(test_case.input, "<filename>", style, stream); + // Require these test cases to be valid. + EXPECT_OK(status) << status.message(); + EXPECT_EQ(stream.str(), test_case.expected) << "code:\n" << test_case.input; + } +} + static constexpr FormatterTestCase kFunctionCallsWithComments[] = { {// no comments "module foo;\n"
diff --git a/verible/verilog/formatting/token-annotator.cc b/verible/verilog/formatting/token-annotator.cc index def1349..ebaeb21 100644 --- a/verible/verilog/formatting/token-annotator.cc +++ b/verible/verilog/formatting/token-annotator.cc
@@ -510,7 +510,8 @@ // This may be controversial or context-dependent, as parameterized // classes often appear with method calls like: // type#(params...)::method(...); - // A parameterized type in a typedef keeps the space before '#': + // If style.class_parameter_space is enabled, a + // parameterized type in a typedef keeps the space before '#': // typedef my_class #(.P(P)) my_class_t; // but a package-qualified type does not, matching the existing // "type#(params...)::method(...)" convention: @@ -518,6 +519,7 @@ // Kept as separate IsInsideFirst() calls because MatchesTagAnyOf() // only unrolls up to four tags. const bool inside_unqualified_typedef = + style.class_parameter_space && left_context.IsInsideFirst({NodeEnum::kTypeDeclaration}, {}) && !left_context.IsInsideFirst({NodeEnum::kQualifiedId}, {});
diff --git a/verible/verilog/formatting/tree-unwrapper.cc b/verible/verilog/formatting/tree-unwrapper.cc index a6601ac..bc1af07 100644 --- a/verible/verilog/formatting/tree-unwrapper.cc +++ b/verible/verilog/formatting/tree-unwrapper.cc
@@ -801,6 +801,7 @@ case NodeEnum::kPreprocessorUndef: case NodeEnum::kTFPortDeclaration: case NodeEnum::kTypeDeclaration: + case NodeEnum::kLetDeclaration: case NodeEnum::kNetTypeDeclaration: case NodeEnum::kForwardDeclaration: case NodeEnum::kInterfaceClassMethod:
diff --git a/verible/verilog/tools/formatter/README.md b/verible/verilog/tools/formatter/README.md index 01b2869..a3ffb45 100644 --- a/verible/verilog/tools/formatter/README.md +++ b/verible/verilog/tools/formatter/README.md
@@ -42,6 +42,11 @@ {align,flush-left,preserve,infer}); default: infer; --class_member_variable_alignment (Format class member variables: {align,flush-left,preserve,infer}); default: infer; + --class_parameter_space (If true, keep/insert a space + before '#' in a class parameterized typedef, e.g. "typedef + my_class #(.P(P)) my_class_t;". If false (default), no space is + inserted, matching the IEEE convention used for parameterized class + instantiations, e.g. "type#(params...)::method(...)".); default: false; --compact_indexing_and_selections (Use compact binary expressions inside indexing / bit selection operators); default: true; --distribution_items_alignment (Align distribution items: