| // Copyright 2017-2020 The Verible Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "verilog/formatting/tree_unwrapper.h" | |
| #include <initializer_list> | |
| #include <iostream> | |
| #include <memory> | |
| #include <sstream> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| #include "absl/memory/memory.h" | |
| #include "absl/status/status.h" | |
| #include "absl/strings/str_join.h" | |
| #include "absl/strings/string_view.h" | |
| #include "common/formatting/basic_format_style.h" | |
| #include "common/formatting/format_token.h" | |
| #include "common/formatting/token_partition_tree.h" | |
| #include "common/formatting/unwrapped_line.h" | |
| #include "common/text/text_structure.h" | |
| #include "common/util/container_iterator_range.h" | |
| #include "common/util/logging.h" | |
| #include "common/util/spacer.h" | |
| #include "common/util/vector_tree.h" | |
| #include "verilog/analysis/verilog_analyzer.h" | |
| #undef EXPECT_OK | |
| #define EXPECT_OK(value) EXPECT_TRUE((value).ok()) | |
| namespace verilog { | |
| namespace formatter { | |
| namespace { | |
| using verible::UnwrappedLine; | |
| // Contains the expected token sequence and indentation for an UnwrappedLine | |
| struct ExpectedUnwrappedLine { | |
| int indentation_spaces; | |
| std::vector<absl::string_view> tokens; // includes comments | |
| explicit ExpectedUnwrappedLine(int s) : indentation_spaces(s), tokens() {} | |
| ExpectedUnwrappedLine( | |
| int s, std::initializer_list<absl::string_view> expected_tokens) | |
| : indentation_spaces(s), tokens(expected_tokens) {} | |
| void ShowUnwrappedLineDifference(std::ostream* stream, | |
| const UnwrappedLine& uwline) const; | |
| bool EqualsUnwrappedLine(std::ostream* stream, | |
| const UnwrappedLine& uwline) const; | |
| }; | |
| // Human readable ExpectedUnwrappedLined which outputs indentation and line. | |
| // Mimic operator << (ostream&, const UnwrappedLine&). | |
| std::ostream& operator<<(std::ostream& stream, | |
| const ExpectedUnwrappedLine& expected_uwline) { | |
| stream << verible::Spacer(expected_uwline.indentation_spaces, | |
| UnwrappedLine::kIndentationMarker) | |
| << '['; | |
| if (expected_uwline.tokens.empty()) { | |
| // Empty really means don't-care -- this is not a leaf level | |
| // UnwrappedLine, but rather, an enclosing level. | |
| stream << "<auto>"; | |
| } else { | |
| stream << absl::StrJoin(expected_uwline.tokens.begin(), | |
| expected_uwline.tokens.end(), " ", | |
| absl::StreamFormatter()); | |
| } | |
| return stream << ']'; | |
| } | |
| // This tree type will be 'diff-ed' against a VectorTree<UnwrappedLine>. | |
| typedef verible::VectorTree<ExpectedUnwrappedLine> ExpectedUnwrappedLineTree; | |
| void ValidateExpectedTreeNode(const ExpectedUnwrappedLineTree& etree) { | |
| // At each tree node, there should either be expected tokens in the node's | |
| // value, or node's children, but not both. | |
| CHECK(etree.Value().tokens.empty() != etree.Children().empty()) | |
| << "Node should not contain both tokens and children @" | |
| << verible::NodePath(etree); | |
| } | |
| // Make sure the expect-tree is well-formed. | |
| void ValidateExpectedTree(const ExpectedUnwrappedLineTree& etree) { | |
| etree.ApplyPreOrder(ValidateExpectedTreeNode); | |
| } | |
| // Outputs the unwrapped line followed by this expected unwrapped line | |
| void ExpectedUnwrappedLine::ShowUnwrappedLineDifference( | |
| std::ostream* stream, const UnwrappedLine& uwline) const { | |
| *stream << std::endl | |
| << "unwrapped line: " << std::endl | |
| << '\"' << uwline << '\"' << std::endl; | |
| *stream << "expected: " << std::endl; | |
| *stream << '\"' << *this << '\"' << std::endl; | |
| } | |
| // Helper method to compare ExpectedUnwrappedLine to UnwrappedLine by checking | |
| // sizes (number of tokens), each token sequentially, and indentation. | |
| // Outputs differences to stream | |
| bool ExpectedUnwrappedLine::EqualsUnwrappedLine( | |
| std::ostream* stream, const UnwrappedLine& uwline) const { | |
| VLOG(4) << __FUNCTION__; | |
| bool equal = true; | |
| // If the expected token array is empty, don't check because tokens | |
| // are expected in children nodes. | |
| if (!tokens.empty()) { | |
| // Check that the size of the UnwrappedLine (number of tokens) is correct. | |
| if (uwline.Size() != tokens.size()) { | |
| *stream << "error: unwrapped line size incorrect" << std::endl; | |
| *stream << "unwrapped line has: " << uwline.Size() << " tokens, "; | |
| *stream << "expected: " << tokens.size() << std::endl; | |
| ShowUnwrappedLineDifference(stream, uwline); | |
| equal = false; | |
| } else { | |
| // Only compare the text of each token, and none of the other TokenInfo | |
| // fields. Stops at first unmatched token | |
| // TODO(fangism): rewrite this using std::mismatch | |
| for (size_t i = 0; i < uwline.Size(); i++) { | |
| absl::string_view uwline_token = uwline.TokensRange()[i].Text(); | |
| absl::string_view expected_token = tokens[i]; | |
| if (uwline_token != expected_token) { | |
| *stream << "error: unwrapped line token #" << i + 1 | |
| << " does not match expected token" << std::endl; | |
| *stream << "unwrapped line token is: \"" << uwline_token << "\"" | |
| << std::endl; | |
| *stream << "expected: \"" << expected_token << "\"" << std::endl; | |
| equal = false; | |
| } | |
| } | |
| } | |
| } | |
| // Check that the indentation spaces of the UnwrappedLine is correct | |
| if (uwline.IndentationSpaces() != indentation_spaces) { | |
| *stream << "error: unwrapped line indentation incorrect" << std::endl; | |
| *stream << "indentation spaces: " << uwline.IndentationSpaces() | |
| << std::endl; | |
| *stream << "expected indentation spaces: " << indentation_spaces | |
| << std::endl; | |
| equal = false; | |
| } | |
| if (!equal) { | |
| ShowUnwrappedLineDifference(stream, uwline); | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Contains test cases for files with the UnwrappedLines that should be | |
| // produced from TreeUnwrapper.Unwrap() | |
| struct TreeUnwrapperTestData { | |
| const char* test_name; | |
| // The source code for testing must be syntactically correct. | |
| absl::string_view source_code; | |
| // The reference values and structure of UnwrappedLines to expect. | |
| ExpectedUnwrappedLineTree expected_unwrapped_lines; | |
| template <typename... Args> | |
| TreeUnwrapperTestData(const char* name, absl::string_view code, | |
| Args&&... nodes) | |
| : test_name(name), | |
| source_code(code), | |
| expected_unwrapped_lines(ExpectedUnwrappedLine{0}, | |
| std::forward<Args>(nodes)...) { | |
| // The root node is always at level 0. | |
| ValidateExpectedTree(expected_unwrapped_lines); | |
| } | |
| }; | |
| // Iterates through UnwrappedLines and expected lines and verifies that they | |
| // are equal | |
| bool VerifyUnwrappedLines(std::ostream* stream, | |
| const verible::VectorTree<UnwrappedLine>& uwlines, | |
| const TreeUnwrapperTestData& test_case) { | |
| std::ostringstream first_diff_stream; | |
| const auto diff = verible::DeepEqual( | |
| uwlines, test_case.expected_unwrapped_lines, | |
| [&first_diff_stream](const UnwrappedLine& actual, | |
| const ExpectedUnwrappedLine& expect) { | |
| return expect.EqualsUnwrappedLine(&first_diff_stream, actual); | |
| }); | |
| if (diff.left != nullptr) { | |
| *stream << "error: test case: " << test_case.test_name << std::endl; | |
| *stream << "first difference at subnode " << verible::NodePath(*diff.left) | |
| << std::endl; | |
| *stream << "expected:\n" << *diff.right << std::endl; | |
| *stream << "but got :\n" | |
| << verible::TokenPartitionTreePrinter(*diff.left) << std::endl; | |
| const auto left_children = diff.left->Children().size(); | |
| const auto right_children = diff.right->Children().size(); | |
| EXPECT_EQ(left_children, right_children) << "code:\n" | |
| << test_case.source_code; | |
| if (first_diff_stream.str().length()) { | |
| // The Value()s at these nodes are different. | |
| *stream << "value difference: " << first_diff_stream.str(); | |
| } | |
| return false; | |
| } | |
| return true; | |
| } | |
| // Test fixture used to handle the VerilogAnalyzer which produces the | |
| // concrete syntax tree and token stream that TreeUnwrapper uses to produce | |
| // UnwrappedLines | |
| class TreeUnwrapperTest : public ::testing::Test { | |
| protected: | |
| TreeUnwrapperTest() { | |
| style_.indentation_spaces = 1; | |
| style_.wrap_spaces = 2; | |
| } | |
| // Takes a string representation of a verilog file and creates a | |
| // VerilogAnalyzer which holds a concrete syntax tree and token stream view | |
| // of the file. | |
| void MakeTree(absl::string_view content) { | |
| analyzer_ = absl::make_unique<VerilogAnalyzer>(content, "TEST_FILE"); | |
| absl::Status status = ABSL_DIE_IF_NULL(analyzer_)->Analyze(); | |
| EXPECT_OK(status) << "Rejected code: " << std::endl << content; | |
| // Since source code is required to be valid, this error-handling is just | |
| // to help debug the test case construction | |
| if (!status.ok()) { | |
| const std::vector<std::string> syntax_error_messages( | |
| analyzer_->LinterTokenErrorMessages()); | |
| for (const auto& message : syntax_error_messages) { | |
| std::cout << message << std::endl; | |
| } | |
| } | |
| } | |
| // Creates a TreeUnwrapper populated with a concrete syntax tree and | |
| // token stream view from the file input | |
| std::unique_ptr<TreeUnwrapper> CreateTreeUnwrapper( | |
| absl::string_view source_code) { | |
| MakeTree(source_code); | |
| const verible::TextStructureView& text_structure_view = analyzer_->Data(); | |
| unwrapper_data_ = | |
| absl::make_unique<UnwrapperData>(text_structure_view.TokenStream()); | |
| return absl::make_unique<TreeUnwrapper>( | |
| text_structure_view, style_, unwrapper_data_->preformatted_tokens); | |
| } | |
| // The VerilogAnalyzer to produce a concrete syntax tree of raw Verilog code | |
| std::unique_ptr<VerilogAnalyzer> analyzer_; | |
| // Support data that needs to outlive the TreeUnwrappers that use it. | |
| std::unique_ptr<UnwrapperData> unwrapper_data_; | |
| // Style configuration. | |
| FormatStyle style_; | |
| }; | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from an empty | |
| // file | |
| TEST_F(TreeUnwrapperTest, UnwrapEmptyFile) { | |
| const absl::string_view source_code = ""; | |
| auto tree_unwrapper = CreateTreeUnwrapper(source_code); | |
| tree_unwrapper->Unwrap(); | |
| const auto lines = tree_unwrapper->FullyPartitionedUnwrappedLines(); | |
| EXPECT_TRUE(lines.empty()) // Blank line removed. | |
| << "Unexpected unwrapped line: " << lines.front(); | |
| } | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from a blank | |
| // line. | |
| TEST_F(TreeUnwrapperTest, UnwrapBlankLineOnly) { | |
| const absl::string_view source_code = "\n"; | |
| auto tree_unwrapper = CreateTreeUnwrapper(source_code); | |
| tree_unwrapper->Unwrap(); | |
| const auto lines = tree_unwrapper->FullyPartitionedUnwrappedLines(); | |
| // TODO(b/140277909): preserve blank lines | |
| EXPECT_TRUE(lines.empty()) // Blank line removed. | |
| << "Unexpected unwrapped line: " << lines.front(); | |
| } | |
| // TODO(korzhacke): Test CollectFilteredTokens directly | |
| // ExpectedUnwrappedLine tree builder functions | |
| // N is for node | |
| template <typename... Args> | |
| ExpectedUnwrappedLineTree N(int spaces, Args&&... nodes) { | |
| return ExpectedUnwrappedLineTree(ExpectedUnwrappedLine(spaces), | |
| std::forward<Args>(nodes)...); | |
| } | |
| // L is for leaf, which is the only type of node that should list tokens | |
| ExpectedUnwrappedLineTree L(int spaces, | |
| std::initializer_list<absl::string_view> tokens) { | |
| return ExpectedUnwrappedLineTree(ExpectedUnwrappedLine(spaces, tokens)); | |
| } | |
| // Node function aliases for readability. | |
| // Can't use const auto& Alias = N; because N is overloaded. | |
| #define ModuleDeclaration N | |
| #define ModuleHeader N | |
| #define ModulePortList N | |
| #define ModuleParameterList N | |
| #define ModuleItemList N | |
| #define MacroArgList N | |
| #define InterfaceDeclaration N | |
| #define Instantiation N | |
| #define DataDeclaration N | |
| #define InstanceList N | |
| #define PortActualList N | |
| #define StatementList N | |
| #define ClassDeclaration N | |
| #define ClassHeader N | |
| #define ClassItemList N | |
| #define ClassParameterList N | |
| #define FunctionDeclaration N | |
| #define FunctionHeader L | |
| #define TaskDeclaration N | |
| #define TaskHeader L | |
| #define TFPortList N | |
| #define PackageDeclaration N | |
| #define PackageItemList N | |
| #define EnumItemList N | |
| #define StructUnionMemberList N | |
| #define PropertyDeclaration N | |
| #define PropertyItemList N | |
| #define VarDeclList N | |
| #define CovergroupDeclaration N | |
| #define CovergroupHeader N | |
| #define CovergroupItemList N | |
| #define CoverpointItemList N | |
| #define CrossItemList N | |
| #define SequenceDeclaration N | |
| #define SequenceItemList N | |
| #define ConstraintDeclaration N | |
| #define ConstraintItemList N | |
| #define ConstraintExpressionList N | |
| #define DistItemList N | |
| #define LoopHeader N | |
| #define ForSpec N | |
| #define CaseItemList N | |
| #define FlowControl N // for loops and conditional whole constructs | |
| #define UdpBody N | |
| #define ParBlock N | |
| #define UDPDeclaration N | |
| // Test data for unwrapping Verilog modules | |
| // Test case format: test name, source code, ExpectedUnwrappedLines | |
| const TreeUnwrapperTestData kUnwrapModuleTestCases[] = { | |
| { | |
| "empty module", | |
| "module foo ();" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "empty module with one port comment", | |
| "module foo (\n" | |
| "//comment\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration(0, | |
| ModuleHeader(0, // | |
| L(0, {"module", "foo", "("}), // | |
| L(2, {"//comment"}), // | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "empty module extra spaces", // verifying space-insensitivity | |
| " module\tfoo (\t) ; " | |
| "endmodule ", | |
| ModuleDeclaration(0, L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "empty module extra newlines", // verifying space-insensitivity | |
| "module foo (\n\n);\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with port declarations", | |
| "module foo (" | |
| "input bar," | |
| "output baz" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "("}), | |
| ModulePortList(2, L(2, {"input", "bar", ","}), | |
| L(2, {"output", "baz"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional port declarations", | |
| "module foo (" | |
| "`ifndef FOO\n" | |
| "input bar," | |
| "`endif\n" | |
| "output baz" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "("}), | |
| ModulePortList(2, L(0, {"`ifndef", "FOO"}), | |
| L(2, {"input", "bar", ","}), L(0, {"`endif"}), | |
| L(2, {"output", "baz"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with `include port declarations", | |
| "module foo (" | |
| "`include \"ports.svh\"\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, // | |
| L(0, {"module", "foo", "("}), | |
| // TODO(b/149503062): un-indent `include | |
| L(2, {"`include", "\"ports.svh\""}), L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters", | |
| "module foo #(" | |
| "parameter bar =1," | |
| "localparam baz =2" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional parameters", | |
| "module foo #(" | |
| "`ifdef FOO\n" | |
| "parameter bar =1," | |
| "`endif\n" | |
| "localparam baz =2" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList(2, L(0, {"`ifdef", "FOO"}), | |
| L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(0, {"`endif"}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters and ports", | |
| "module foo #(" | |
| "parameter bar =1," | |
| "localparam baz =2" | |
| ") (" | |
| "input yar," | |
| "output gar" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", "("}), | |
| ModulePortList(2, L(2, {"input", "yar", ","}), | |
| L(2, {"output", "gar"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters and empty ports", | |
| "module foo #(" | |
| "parameter bar =1," | |
| "localparam baz =2" | |
| ") ();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters and EOL comment before first param", | |
| "module foo #(//comment\n" | |
| "parameter bar =1," | |
| "localparam baz =2" | |
| ") ();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "#", "(", "//comment"}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters and EOL comment after first param", | |
| "module foo #(" | |
| "parameter bar =1,//comment\n" | |
| "localparam baz =2" | |
| ") ();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ",", "//comment"}), | |
| L(2, {"localparam", "baz", "=", "2"})), | |
| L(0, {")", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameters and EOL comment after first param", | |
| "module foo #(" | |
| "parameter bar =1," | |
| "localparam baz =2//comment\n" | |
| ") ();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "#", "("}), | |
| ModuleParameterList( | |
| 2, L(2, {"parameter", "bar", "=", "1", ","}), | |
| L(2, {"localparam", "baz", "=", "2", "//comment"})), | |
| L(0, {")", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "two modules with end-labels", | |
| "module foo ();" | |
| "endmodule : foo " | |
| "module zoo;" | |
| "endmodule : zoo", | |
| ModuleDeclaration(0, L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule", ":", "foo"})), | |
| ModuleDeclaration(0, L(0, {"module", "zoo", ";"}), | |
| L(0, {"endmodule", ":", "zoo"})), | |
| }, | |
| { | |
| "module with K&R-style ports with always/begin/end " | |
| "(kModulePortDeclaration)", | |
| "module addf (a, b, ci, s, co);" | |
| "input a, b, ci;" | |
| "output s, co;" | |
| "always @(a, b, ci) begin" | |
| " s = (a^b^ci);" | |
| " co = (a&b);" | |
| "end " | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "addf", "("}), | |
| N(2, // | |
| L(2, {"a", ","}), // | |
| L(2, {"b", ","}), // | |
| L(2, {"ci", ","}), // | |
| L(2, {"s", ","}), // | |
| L(2, {"co"})), | |
| L(0, {")", ";"})), | |
| ModuleItemList( | |
| 1, L(1, {"input", "a", ",", "b", ",", "ci", ";"}), | |
| L(1, {"output", "s", ",", "co", ";"}), | |
| N(1, | |
| L(1, {"always", "@", "(", "a", ",", "b", ",", "ci", ")", | |
| "begin"}), | |
| StatementList( | |
| 2, | |
| L(2, {"s", "=", "(", "a", "^", "b", "^", "ci", ")", ";"}), | |
| L(2, {"co", "=", "(", "a", "&", "b", ")", ";"})), | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement", | |
| "module m;\n" | |
| "always @(b, c) " | |
| " s = y;" | |
| "endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, conditional", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " if (expr) s = y;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"if", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, conditional with else", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " if (expr) s = y; else t = v;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| N(2, // | |
| L(2, {"if", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| N(2, // | |
| L(2, {"else"}), L(3, {"t", "=", "v", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, if-else-if", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " if (expr) s = y; else if (j) t = v;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| N(2, // | |
| L(2, {"if", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| N(2, // | |
| L(2, {"else", "if", "(", "j", ")"}), | |
| L(3, {"t", "=", "v", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, if-else-if-else", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " if (expr) s = y; else if (j) t = v; else r=0;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| N(2, // | |
| L(2, {"if", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| N(2, // | |
| L(2, {"else", "if", "(", "j", ")"}), | |
| L(3, {"t", "=", "v", ";"})), | |
| N(2, // | |
| L(2, {"else"}), L(3, {"r", "=", "0", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, loop", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " for (;;) s = y;" | |
| "endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| N(2, // | |
| L(2, {"for", "("}), | |
| N(4, L(4, {";"}), L(4, {";"})), L(2, {")"})), | |
| L(3, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, foreach", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " foreach (a[i]) s = y;" | |
| "endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"foreach", "(", "a", "[", "i", "]", ")"}), | |
| L(3, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, repeat", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " repeat (expr) s = y;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"repeat", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, while", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " while (expr) s = y;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"while", "(", "expr", ")"}), L(3, {"s", "=", "y", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, do-while", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " do s = y; while (expr) ;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), L(2, {"do"}), // | |
| L(3, {"s", "=", "y", ";"}), // | |
| L(2, {"while", "(", "expr", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, forever", | |
| "module m;\n" | |
| "always @*" | |
| " forever love(u);" | |
| "endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "*"}), // | |
| L(2, {"forever"}), // | |
| N(3, // | |
| L(3, {"love", "("}), L(5, {"u", ")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with always construct, single statement, case", | |
| "module m;\n" | |
| "always @(b, c)" | |
| " case (e) x: s = y;" | |
| " endcase " | |
| "endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"always", "@", "(", "b", ",", "c", ")"}), | |
| L(2, {"case", "(", "e", ")"}), | |
| N(3, // | |
| L(3, {"x", ":"}), // | |
| L(3, {"s", "=", "y", ";"})), | |
| L(2, {"endcase"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with kModuleItemList and kDataDeclarations", | |
| "module tryme;" | |
| "foo1 a;" | |
| "foo2 b();" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "tryme", ";"}), | |
| ModuleItemList(1, | |
| // fused single instance | |
| L(1, {"foo1", "a", ";"}), | |
| // fused single instance | |
| L(1, {"foo2", "b", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multi-instance () in single declaration", | |
| "module multi_inst;" | |
| "foo aa(), bb();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "multi_inst", ";"}), | |
| Instantiation(1, L(1, {"foo"}), // instantiation type | |
| InstanceList(3, L(3, {"aa", "(", ")", ","}), | |
| L(3, {"bb", "(", ")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multi-variable in single declaration", | |
| "module multi_inst;" | |
| "foo aa, bb;" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "multi_inst", ";"}), | |
| Instantiation(1, L(1, {"foo"}), // instantiation type | |
| InstanceList(3, L(3, {"aa", ","}), | |
| L(3, {"bb", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multi-variable with assignments in single declaration", | |
| "module multi_inst;" | |
| "foo aa = 1, bb = 2;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "multi_inst", ";"}), | |
| Instantiation(1, L(1, {"foo"}), // instantiation type | |
| InstanceList(3, L(3, {"aa", "=", "1", ","}), | |
| L(3, {"bb", "=", "2", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instantiations with parameterized types (positional)", | |
| "module tryme;" | |
| "foo #(1) a;" | |
| "bar #(2, 3) b();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| ModuleItemList( | |
| 1, | |
| // These are both single instances, fused with type partition. | |
| L(1, {"foo", "#", "(", "1", ")", // | |
| "a", ";"}), | |
| L(1, {"bar", "#", "(", "2", ",", "3", ")", // | |
| "b", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instantiations with single-parameterized types (named)", | |
| "module tryme;" | |
| "foo #(.N(1)) a;" | |
| "bar #(.M(2)) b();" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| ModuleItemList(1, | |
| // single instances fused with instantiation type | |
| Instantiation(1, // | |
| L(1, {"foo", "#", "("}), // | |
| L(3, {".", "N", "(", "1", ")"}), // | |
| L(1, {")", "a", ";"})), | |
| Instantiation(1, // | |
| L(1, {"bar", "#", "("}), // | |
| L(3, {".", "M", "(", "2", ")"}), // | |
| L(1, {")", "b", "(", ")", ";"})) // | |
| ), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instantiations with multi-parameterized types (named)", | |
| "module tryme;" | |
| "foo #(.N(1), .M(4)) a;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| // single instances fused with instantiation type | |
| Instantiation(1, L(1, {"foo", "#", "("}), | |
| N(3, // | |
| L(3, {".", "N", "(", "1", ")", ","}), | |
| // note how comma is attached to above partition | |
| L(3, {".", "M", "(", "4", ")"})), | |
| L(1, {")", "a", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameterized instantiations with comment before first " | |
| "param", | |
| "module tryme;" | |
| "foo #(//comment\n.N(5),.M(6)) a;" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "tryme", ";"}), | |
| Instantiation(1, L(1, {"foo", "#", "(", "//comment"}), | |
| N(3, // | |
| L(3, {".", "N", "(", "5", ")", ","}), | |
| L(3, {".", "M", "(", "6", ")"})), | |
| L(1, {")", "a", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameterized instantiations with parameter EOL comment", | |
| "module tryme;" | |
| "foo #(.N(5), //comment\n.M(6)) a;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| Instantiation(1, L(1, {"foo", "#", "("}), | |
| N(3, // | |
| L(3, {".", "N", "(", "5", ")", ",", "//comment"}), | |
| L(3, {".", "M", "(", "6", ")"})), | |
| L(1, {")", "a", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with parameterized instantiations with EOL comment (last " | |
| "param)", | |
| "module tryme;" | |
| "foo #(.N(5),.M(6)//comment\n) a;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| Instantiation(1, L(1, {"foo", "#", "("}), | |
| N(3, // | |
| L(3, {".", "N", "(", "5", ")", ","}), | |
| L(3, {".", "M", "(", "6", ")", "//comment"})), | |
| L(1, {")", "a", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module instance with named parameter interleaved among EOL comments", | |
| "module tryme;" | |
| "foo #(//c1\n//c2\n.N(5), //c3\n//c4\n.M(6)//c5\n//c6\n) a;" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "tryme", ";"}), | |
| Instantiation(1, L(1, {"foo", "#", "(", "//c1"}), | |
| N(3, // | |
| L(3, {"//c2"}), // | |
| L(3, {".", "N", "(", "5", ")", ",", "//c3"}), // | |
| L(3, {"//c4"}), // | |
| L(3, {".", "M", "(", "6", ")", "//c5"}), // | |
| L(3, {"//c6"})), // | |
| L(1, {")", "a", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with single instance and positional port actuals", | |
| "module got_ports;" | |
| "foo c(y, z);" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "got_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "c", "("}), | |
| PortActualList(3, L(3, {"y", ","}), L(3, {"z"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances and various port actuals", | |
| "module got_ports;" | |
| "foo c(x, y, z);" | |
| "foo d(.x(x), .y(y), .w(z));" | |
| "foo e(x, a, .y(y), .w(z));" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "got_ports", ";"}), | |
| ModuleItemList( | |
| 1, | |
| Instantiation(1, L(1, {"foo", "c", "("}), | |
| PortActualList(3, L(3, {"x", ","}), | |
| L(3, {"y", ","}), L(3, {"z"})), | |
| L(1, {")", ";"}) // TODO(fangism): attach to 'z'? | |
| ), | |
| Instantiation( | |
| 1, L(1, {"foo", "d", "("}), | |
| PortActualList(3, L(3, {".", "x", "(", "x", ")", ","}), | |
| L(3, {".", "y", "(", "y", ")", ","}), | |
| L(3, {".", "w", "(", "z", ")"})), | |
| L(1, {")", ";"})), | |
| Instantiation( | |
| 1, L(1, {"foo", "e", "("}), | |
| PortActualList(3, L(3, {"x", ","}), L(3, {"a", ","}), | |
| L(3, {".", "y", "(", "y", ")", ","}), | |
| L(3, {".", "w", "(", "z", ")"})), | |
| L(1, {")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with ifdef in ports", | |
| "module ifdef_ports;" | |
| "foo bar(\n" | |
| "`ifdef BAZ\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "ifdef_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(0, {"`ifdef", "BAZ"}), | |
| L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with ifdef-else in ports", | |
| "module ifdef_else_ports;" | |
| "foo bar(\n" | |
| "`ifdef BAZ\n" | |
| "`else\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "ifdef_else_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(0, {"`ifdef", "BAZ"}), | |
| L(0, {"`else"}), L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with ifndef in ports", | |
| "module ifndef_ports;" | |
| "foo bar(\n" | |
| "`ifndef BAZ\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "ifndef_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(0, {"`ifndef", "BAZ"}), | |
| L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with actuals and ifdef in ports", | |
| "module ifdef_ports;" | |
| "foo bar(\n" | |
| ".a(a),\n" // with comma | |
| "`ifdef BAZ\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "ifdef_ports", ";"}), | |
| Instantiation( | |
| 1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(3, {".", "a", "(", "a", ")", ","}), | |
| L(0, {"`ifdef", "BAZ"}), L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with actuals and ifdef in ports (no comma)", | |
| "module ifdef_ports;" | |
| "foo bar(\n" | |
| ".a(a)\n" // no comma | |
| "`ifdef BAZ\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "ifdef_ports", ";"}), | |
| Instantiation( | |
| 1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(3, {".", "a", "(", "a", ")"}), | |
| L(0, {"`ifdef", "BAZ"}), L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with ifdef and actuals in ports", | |
| "module ifdef_ports;" | |
| "foo bar(\n" | |
| "`ifdef BAZ\n" | |
| "`endif\n" | |
| ".a(a)\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "ifdef_ports", ";"}), | |
| Instantiation( | |
| 1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(0, {"`ifdef", "BAZ"}), L(0, {"`endif"}), | |
| L(3, {".", "a", "(", "a", ")"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with ifdef conditional port", | |
| "module ifdef_ports;" | |
| "foo bar(\n" | |
| "`ifdef BAZ\n" | |
| ".a(a)\n" | |
| "`endif\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "ifdef_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(0, {"`ifdef", "BAZ"}), | |
| L(3, {".", "a", "(", "a", ")"}), | |
| L(0, {"`endif"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with instances with commented named ports", | |
| "module named_ports;" | |
| "foo bar(\n" | |
| ".a(a),\n" | |
| "//.aa(aa),\n" | |
| ".aaa(aaa)\n" | |
| ");" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "named_ports", ";"}), | |
| Instantiation(1, L(1, {"foo", "bar", "("}), | |
| PortActualList(3, // | |
| L(3, {".", "a", "(", "a", ")", ","}), | |
| L(3, {"//.aa(aa),"}), | |
| L(3, {".", "aaa", "(", "aaa", ")"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module interface ports", | |
| "module foo (" | |
| "interface bar_if, interface baz_if);" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "("}), | |
| ModulePortList(2, L(2, {"interface", "bar_if", ","}), | |
| L(2, {"interface", "baz_if"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module cast with constant functions", | |
| "module cast_with_constant_functions;" | |
| "foo dut(" | |
| ".bus_in({brn::Num_blocks{$bits(dbg::bus_t)'(0)}})," | |
| ".bus_mid({brn::Num_bits{$clog2(dbg::bus_t)'(1)}})," | |
| ".bus_out(out));" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "cast_with_constant_functions", ";"}), | |
| Instantiation( | |
| 1, // | |
| L(1, {"foo", "dut", "("}), | |
| PortActualList( | |
| 3, // | |
| N(3, | |
| L(3, {".", "bus_in", "(", "{", "brn", "::", "Num_blocks", | |
| "{", "$bits", "("}), | |
| L(5, {"dbg", "::", "bus_t"}), | |
| L(3, {")", "'", "(", "0", ")", "}", "}", ")", ","})), | |
| N(3, | |
| L(3, {".", "bus_mid", "(", "{", "brn", "::", "Num_bits", | |
| "{", "$clog2", "("}), | |
| L(5, {"dbg", "::", "bus_t"}), | |
| L(3, {")", "'", "(", "1", ")", "}", "}", ")", ","})), | |
| L(3, {".", "bus_out", "(", "out", ")"})), | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module direct assignment", | |
| "module addf (\n" | |
| "input a, input b, input ci,\n" | |
| "output s, output co);\n" | |
| "assign s = (a^b^ci);\n" | |
| "assign co = (a&b)|(a&ci)|(b&ci);\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "addf", "("}), | |
| ModulePortList(2, L(2, {"input", "a", ","}), | |
| L(2, {"input", "b", ","}), | |
| L(2, {"input", "ci", ","}), | |
| L(2, {"output", "s", ","}), | |
| L(2, {"output", "co"})), | |
| L(0, {")", ";"})), | |
| ModuleItemList(1, | |
| L(1, {"assign", "s", "=", "(", "a", "^", "b", "^", | |
| "ci", ")", ";"}), | |
| L(1, {"assign", "co", "=", "(", "a", "&", "b", | |
| ")", "|", "(", "a", "&", "ci", ")", | |
| "|", "(", "b", "&", "ci", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple assignments", | |
| "module foob;\n" | |
| "assign s = a, y[0] = b[1], z.z = c -jkl;\n" // multiple assignments | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foob", ";"}), | |
| // TODO(fangism): subpartition multiple assignments. | |
| N(1, L(1, {"assign", "s", "=", "a", ","}), | |
| // TODO(fangism): wrap-indent subsequent assignments. | |
| L(1, {"y", "[", "0", "]", "=", "b", "[", "1", "]", ","}), | |
| L(1, {"z", ".", "z", "=", "c", "-", "jkl", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple assignments as module item", | |
| "module foob;\n" | |
| "assign `BIT_ASSIGN_MACRO(l1, r1)\n" // as module item | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foob", ";"}), | |
| N(1, L(1, {"assign", "`BIT_ASSIGN_MACRO", "("}), | |
| MacroArgList(3, L(3, {"l1", ","}), L(3, {"r1", ")"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple assignments as module item with semicolon", | |
| "module foob;\n" | |
| "assign `BIT_ASSIGN_MACRO(l1, r1);\n" // as module item | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foob", ";"}), | |
| N(1, L(1, {"assign", "`BIT_ASSIGN_MACRO", "("}), | |
| MacroArgList(3, L(3, {"l1", ","}), L(3, {"r1", ")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple assignments as module item II", | |
| "module foob;\n" | |
| "initial begin\n" | |
| "assign `BIT_ASSIGN_MACRO(l1, r1)\n" // as statement item | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foob", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"initial", "begin"}), | |
| StatementList( | |
| 2, L(2, {"assign", "`BIT_ASSIGN_MACRO", "("}), | |
| MacroArgList(4, L(4, {"l1", ","}), L(4, {"r1", ")"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple assignments with macro-call rvalue", | |
| "module foob;\n" | |
| "initial begin\n" | |
| "assign z1 = `RVALUE(l1, r1);\n" // as statement item | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foob", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"initial", "begin"}), | |
| N(2, L(2, {"assign", "z1", "=", "`RVALUE", "("}), | |
| MacroArgList(4, L(4, {"l1", ","}), L(4, {"r1", ")", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with labeled statements", | |
| "module labeled_statements;\n" | |
| "initial begin\n" | |
| " a = 0;\n" | |
| " foo: b = 0;\n" // with label | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "labeled_statements", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| StatementList(2, L(2, {"a", "=", "0", ";"}), | |
| N(2, L(2, {"foo", ":"}), | |
| L(2, {"b", "=", "0", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with labeled statement block", | |
| "module labeled_block;\n" | |
| "initial begin\n" | |
| " a = 0;\n" | |
| " foo: begin\n" // labeled begin-end block | |
| " b = 9;\n" | |
| " end\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "labeled_block", ";"}), | |
| ModuleItemList( | |
| 1, // | |
| L(1, {"initial", "begin"}), | |
| StatementList(2, // | |
| L(2, {"a", "=", "0", ";"}), | |
| N(2, // | |
| L(2, {"foo", ":", "begin"}), | |
| L(3, {"b", "=", "9", ";"}), L(2, {"end"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with static variable", | |
| "module static_variable;\n" | |
| "initial begin\n" | |
| " static int a = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "static_variable", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, L(2, {"static"}), L(2, {"int"}), | |
| L(2, {"a", "=", "0", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with static and automatic variables", | |
| "module static_automatic;\n" | |
| "initial begin\n" | |
| " static int a = 0;\n" | |
| " automatic byte b = 1;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "static_automatic", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"initial", "begin"}), | |
| StatementList(2, | |
| N(2, L(2, {"static"}), L(2, {"int"}), | |
| L(2, {"a", "=", "0", ";"})), | |
| N(2, L(2, {"automatic"}), L(2, {"byte"}), | |
| L(2, {"b", "=", "1", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multiple static variables in one declaration", | |
| "module multi_static;\n" | |
| "initial begin\n" | |
| " static int a, b, c = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "multi_static", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, // | |
| L(2, {"static"}), // | |
| L(2, {"int"}), // | |
| N(4, // | |
| L(4, {"a", ","}), // | |
| L(4, {"b", ","}), // | |
| L(4, {"c", "=", "0", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multiple initialized static variables", | |
| "module multi_static;\n" | |
| "initial begin\n" | |
| " static int a = 1, b = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "multi_static", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, // | |
| L(2, {"static"}), // | |
| L(2, {"int"}), // | |
| N(4, L(4, {"a", "=", "1", ","}), | |
| L(4, {"b", "=", "0", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with const variable", | |
| "module const_variable;\n" | |
| "initial begin\n" | |
| " const int a = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "const_variable", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, // | |
| // TODO(fangism): merge qualifiers with type. | |
| L(2, {"const"}), // | |
| L(2, {"int"}), // | |
| L(2, {"a", "=", "0", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with const automatic variable", | |
| "module const_variable;\n" | |
| "initial begin\n" | |
| " automatic const int a = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "const_variable", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, | |
| // TODO(fangism): merge qualifiers with type. | |
| L(2, {"automatic", "const"}), // | |
| L(2, {"int"}), // | |
| L(2, {"a", "=", "0", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with variable using multiple qualifiers", | |
| "module qualified;\n" | |
| "initial begin\n" | |
| " const var automatic int a = 0;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "qualified", ";"}), | |
| ModuleItemList(1, L(1, {"initial", "begin"}), | |
| N(2, // | |
| L(2, {"const", "var", "automatic"}), // | |
| L(2, {"int"}), // | |
| L(2, {"a", "=", "0", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with block generate statements", | |
| "module block_generate;\n" | |
| "generate\n" | |
| "endgenerate\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "block_generate", ";"}), | |
| ModuleItemList(1, L(1, {"generate"}), L(1, {"endgenerate"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with block generate statements and macro call item", | |
| "module block_generate;\n" | |
| "`ASSERT(blah)\n" | |
| "generate\n" | |
| "endgenerate\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "block_generate", ";"}), | |
| ModuleItemList(1, | |
| N(1, // | |
| L(1, {"`ASSERT", "("}), L(3, {"blah", ")"})), | |
| N(1, // | |
| L(1, {"generate"}), L(1, {"endgenerate"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional generate blocks, null statements", | |
| "module conditionals;\n" | |
| "if (foo) ;\n" | |
| "if (bar) ;\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "conditionals", ";"}), | |
| ModuleItemList(1, L(1, {"if", "(", "foo", ")", ";"}), | |
| L(1, {"if", "(", "bar", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional generate statement blocks", | |
| "module conditionals;\n" | |
| "if (foo) begin\n" | |
| " a aa;\n" | |
| "end\n" | |
| "if (bar) begin\n" | |
| " b bb;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "conditionals", ";"}), | |
| ModuleItemList( | |
| 1, | |
| FlowControl(1, L(1, {"if", "(", "foo", ")", "begin"}), | |
| L(2, {"a", "aa", ";"}), // | |
| L(1, {"end"})), // | |
| FlowControl(1, L(1, {"if", "(", "bar", ")", "begin"}), | |
| L(2, {"b", "bb", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional generate statement blocks with labels", | |
| "module zv;\n" | |
| "if (x) begin\n" | |
| "end : l1\n" | |
| "else begin\n" | |
| "end\n" | |
| "endmodule;\n", | |
| ModuleDeclaration(0, L(0, {"module", "zv", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "x", ")", "begin"}), | |
| L(1, {"end", ":", "l1"})), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional generate statement blocks", | |
| "module zw;\n" | |
| "if (x) begin\n" | |
| "end\n" | |
| "else begin\n" | |
| "end\n" | |
| "endmodule;\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "zw", ";"}), | |
| FlowControl(1, L(1, {"if", "(", "x", ")", "begin"}), | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional generate single-statements", | |
| "module zx;\n" | |
| "if (x) assign z=y;\n" | |
| "else assign x=y;\n" | |
| "endmodule;\n", | |
| ModuleDeclaration(0, L(0, {"module", "zx", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "x", ")"}), // | |
| L(2, {"assign", "z", "=", "y", ";"})), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"assign", "x", "=", "y", ";"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional generate chained else-if, single-statements", | |
| "module zx;\n" | |
| "if (x) assign z=y;\n" | |
| "else if (r) assign z=w;\n" | |
| "else assign x=y;\n" | |
| "endmodule;\n", | |
| ModuleDeclaration(0, L(0, {"module", "zx", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "x", ")"}), // | |
| L(2, {"assign", "z", "=", "y", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "r", ")"}), // | |
| L(2, {"assign", "z", "=", "w", ";"})), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"assign", "x", "=", "y", ";"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional-else generate statement blocks with labels", | |
| "module zy;\n" | |
| "if (x) begin:z1\n" | |
| "assign x=y;\n" | |
| "end\n" | |
| "else\n" | |
| "if (y) begin:z2\n" | |
| "assign z=y;\n" | |
| "end\n" | |
| "endmodule;\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "zy", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "x", ")", "begin", ":", "z1"}), // | |
| L(2, {"assign", "x", "=", "y", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "if", "(", "y", ")", "begin", | |
| ":", "z2"}), | |
| L(2, {"assign", "z", "=", "y", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional generate statement blocks with labels", | |
| "module zz;\n" | |
| "if (x) begin:z1\n" | |
| "assign x=y;\n" | |
| "end\n" | |
| "if (y) begin:z2\n" | |
| "assign z=y;\n" | |
| "end\n" | |
| "endmodule;\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "zz", ";"}), | |
| ModuleItemList( | |
| 1, | |
| FlowControl(1, // | |
| L(1, {"if", "(", "x", ")", "begin", ":", "z1"}), | |
| L(2, {"assign", "x", "=", "y", ";"}), // | |
| L(1, {"end"})), | |
| FlowControl(1, // | |
| L(1, {"if", "(", "y", ")", "begin", ":", "z2"}), | |
| L(2, {"assign", "z", "=", "y", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| L(0, {";"}), | |
| }, | |
| { | |
| "module with conditional generate block and macro call item", | |
| "module conditional_generate_macros;\n" | |
| "if (foo) begin\n" | |
| "`COVER()\n" | |
| "`ASSERT()\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "conditional_generate_macros", ";"}), | |
| FlowControl(1, L(1, {"if", "(", "foo", ")", "begin"}), | |
| ModuleItemList(2, L(2, {"`COVER", "(", ")"}), | |
| L(2, {"`ASSERT", "(", ")"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with conditional generate block and comments", | |
| "module conditional_generate_comments;\n" | |
| "if (foo) begin\n" | |
| "// comment1\n" | |
| "// comment2\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "conditional_generate_comments", ";"}), | |
| FlowControl( | |
| 1, L(1, {"if", "(", "foo", ")", "begin"}), | |
| ModuleItemList(2, L(2, {"// comment1"}), L(2, {"// comment2"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| /* TODO(fangism): Adding another level of non-indented nesting may be needed | |
| * to handle the following single-statement conditional form gracefully. | |
| { | |
| "module with conditional generate single statements", | |
| "module conditionals;\n" | |
| "if (foo) a aa;\n" | |
| "if (bar) b bb;\n" | |
| "endmodule", | |
| }, | |
| */ | |
| { | |
| "module with single loop generate with null statement body", | |
| "module loop_generate;\n" | |
| "for (genvar x=1;x<N;++x)\n" | |
| " ;\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_generate", ";"}), | |
| FlowControl( | |
| 1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, // | |
| L(3, {"genvar", "x", "=", "1", ";"}), // | |
| L(3, {"x", "<", "N", ";"}), // | |
| L(3, {"++", "x"})), | |
| L(1, {")"})), | |
| L(2, {";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with single loop generate statement", | |
| "module loop_generate;\n" | |
| "for (genvar x=1;x<N;++x) begin\n" | |
| " a aa;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_generate", ";"}), | |
| ModuleItemList( | |
| 1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, // | |
| L(3, {"genvar", "x", "=", "1", ";"}), // | |
| L(3, {"x", "<", "N", ";"}), // | |
| L(3, {"++", "x"})), | |
| L(1, {")", "begin"})), | |
| L(2, {"a", "aa", ";"}), L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with loop generate continuous assignments", | |
| "module loop_generate_assign;\n" | |
| "for (genvar x=1;x<N;++x) begin" | |
| " assign x = y;assign y = z;" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_generate_assign", ";"}), | |
| ModuleItemList( | |
| 1, | |
| LoopHeader( | |
| 1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"genvar", "x", "=", "1", ";"}), | |
| L(3, {"x", "<", "N", ";"}), L(3, {"++", "x"})), | |
| L(1, {")", "begin"})), | |
| ModuleItemList(2, // | |
| L(2, {"assign", "x", "=", "y", ";"}), | |
| L(2, {"assign", "y", "=", "z", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with standalone genvar statement", | |
| "module loop_standalone_genvar;\n" | |
| "genvar i;" | |
| "for (i=1;i<N;++i) begin\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_standalone_genvar", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"genvar", "i", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"i", "=", "1", ";"}), | |
| L(3, {"i", "<", "N", ";"}), | |
| L(3, {"++", "i"})), | |
| L(1, {")", "begin"})), | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multiple arguments to genvar statement", | |
| "module loop_multiarg_genvar;\n" | |
| "genvar i,j;" | |
| "for (i=1;i<N;++i) begin\n" | |
| "end\n" | |
| "for (j=N;j>0;--j) begin\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_multiarg_genvar", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"genvar", "i", ",", "j", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"i", "=", "1", ";"}), | |
| L(3, {"i", "<", "N", ";"}), | |
| L(3, {"++", "i"})), | |
| L(1, {")", "begin"})), | |
| L(1, {"end"})), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"j", "=", "N", ";"}), | |
| L(3, {"j", ">", "0", ";"}), | |
| L(3, {"--", "j"})), | |
| L(1, {")", "begin"})), | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multiple genvar statements", | |
| "module loop_multi_genvar;\n" | |
| "genvar i;" | |
| "genvar j;" | |
| "for (i=1;i<N;++i) begin\n" | |
| "end\n" | |
| "for (j=N;j>0;--j) begin\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_multi_genvar", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"genvar", "i", ";"}), L(1, {"genvar", "j", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"i", "=", "1", ";"}), | |
| L(3, {"i", "<", "N", ";"}), | |
| L(3, {"++", "i"})), | |
| L(1, {")", "begin"})), | |
| L(1, {"end"})), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"j", "=", "N", ";"}), | |
| L(3, {"j", ">", "0", ";"}), | |
| L(3, {"--", "j"})), | |
| L(1, {")", "begin"})), | |
| L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with multiple loop generate statements", | |
| "module loop_generates;\n" | |
| "for (x=1;;) begin\n" | |
| " a aa;\n" | |
| "end\n" | |
| "for (y=0;;) begin\n" | |
| " b bb;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "loop_generates", ";"}), | |
| ModuleItemList( | |
| 1, | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"x", "=", "1", ";"}), | |
| L(3, {";"})), | |
| L(1, {")", "begin"})), | |
| L(2, {"a", "aa", ";"}), L(1, {"end"})), // | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"y", "=", "0", ";"}), | |
| L(3, {";"})), | |
| L(1, {")", "begin"})), | |
| L(2, {"b", "bb", ";"}), L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with case generate statements", | |
| "module multi_cases;\n" | |
| "case (foo)\n" | |
| " A: a aa;\n" | |
| "endcase\n" | |
| "case (bar)\n" | |
| " B: b bb;\n" | |
| "endcase\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "multi_cases", ";"}), | |
| ModuleItemList(1, | |
| FlowControl(1, L(1, {"case", "(", "foo", ")"}), | |
| N(2, L(2, {"A", ":"}), // | |
| L(2, {"a", "aa", ";"})), | |
| L(1, {"endcase"})), | |
| FlowControl(1, L(1, {"case", "(", "bar", ")"}), | |
| N(2, L(2, {"B", ":"}), // | |
| L(2, {"b", "bb", ";"})), | |
| L(1, {"endcase"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with case generate block statements", | |
| "module case_block;\n" | |
| "case (foo)\n" | |
| " A: begin\n" | |
| " a aa;\n" | |
| " end\n" | |
| "endcase\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "case_block", ";"}), | |
| FlowControl(1, L(1, {"case", "(", "foo", ")"}), | |
| N(2, // | |
| L(2, {"A", ":", "begin"}), // | |
| L(3, {"a", "aa", ";"}), // | |
| L(2, {"end"})), | |
| L(1, {"endcase"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module case statements", | |
| "module case_statements;\n" // case statements | |
| "always_comb begin\n" | |
| " case (blah.blah)\n" | |
| " aaa,bbb: x = y;\n" | |
| " ccc,ddd: w = z;\n" | |
| " endcase\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "case_statements", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"always_comb", "begin"}), | |
| FlowControl( | |
| 2, L(2, {"case", "(", "blah", ".", "blah", ")"}), | |
| CaseItemList( | |
| 3, // | |
| // TODO(fangism): may want to wrap case item statements | |
| N(3, L(3, {"aaa", ",", "bbb", ":"}), // | |
| L(3, {"x", "=", "y", ";"})), // | |
| N(3, L(3, {"ccc", ",", "ddd", ":"}), // | |
| L(3, {"w", "=", "z", ";"})) // | |
| ), | |
| L(2, {"endcase"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module case/default statements with macro call rvalue", | |
| "module case_statements;\n" // case statements | |
| "initial begin\n" | |
| " case (blah.blah)\n" | |
| " aaa,bbb: x = `YYY();\n" | |
| " default: w = `ZZZ();\n" | |
| " endcase\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "case_statements", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"initial", "begin"}), | |
| FlowControl( | |
| 2, L(2, {"case", "(", "blah", ".", "blah", ")"}), | |
| CaseItemList(3, | |
| N(3, L(3, {"aaa", ",", "bbb", ":"}), | |
| L(3, {"x", "=", "`YYY", "(", ")", ";"})), | |
| N(3, L(3, {"default", ":"}), | |
| L(3, {"w", "=", "`ZZZ", "(", ")", ";"}))), | |
| L(2, {"endcase"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module case/default statements with begin-end blocks", | |
| "module case_statements;\n" // case statements | |
| "initial begin\n" | |
| " case (blah.blah)\n" | |
| " aaa,bbb: begin x = Y; end\n" | |
| " default: begin w = Z; end\n" | |
| " endcase\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "case_statements", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"initial", "begin"}), | |
| FlowControl( | |
| 2, L(2, {"case", "(", "blah", ".", "blah", ")"}), | |
| CaseItemList(3, | |
| N(3, // | |
| L(3, {"aaa", ",", "bbb", ":", "begin"}), | |
| L(4, {"x", "=", "Y", ";"}), L(3, {"end"})), | |
| N(3, // | |
| L(3, {"default", ":", "begin"}), | |
| L(4, {"w", "=", "Z", ";"}), L(3, {"end"}))), | |
| L(2, {"endcase"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple case statements", | |
| "module multiple_case_statements;\n" | |
| "always_comb begin\n" | |
| " case (blah.blah)\n" | |
| " aaa,bbb: x = y;\n" | |
| " endcase\n" | |
| " case (blah.blah)\n" | |
| " ccc,ddd: w = z;\n" | |
| " endcase\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "multiple_case_statements", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"always_comb", "begin"}), | |
| StatementList( | |
| 2, | |
| FlowControl(2, | |
| L(2, {"case", "(", "blah", ".", "blah", ")"}), | |
| N(3, L(3, {"aaa", ",", "bbb", ":"}), | |
| L(3, {"x", "=", "y", ";"})), | |
| L(2, {"endcase"})), | |
| FlowControl(2, | |
| L(2, {"case", "(", "blah", ".", "blah", ")"}), | |
| N(3, L(3, {"ccc", ",", "ddd", ":"}), | |
| L(3, {"w", "=", "z", ";"})), | |
| L(2, {"endcase"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module multiple initial/final statements", | |
| "module multiple_initial_final_statements;\n" | |
| "begin end\n" | |
| "initial begin\n" | |
| "end\n" | |
| "final begin\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "multiple_initial_final_statements", ";"}), | |
| ModuleItemList(1, L(1, {"begin"}), L(1, {"end"}), | |
| N(1, L(1, {"initial", "begin"}), L(1, {"end"})), | |
| N(1, L(1, {"final", "begin"}), L(1, {"end"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with two consecutive clocking declarations", | |
| "module mcd;\n" | |
| " clocking cb @(posedge clk);\n" | |
| " endclocking\n" | |
| " clocking cb2 @(posedge clk);\n" | |
| " endclocking\n" | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "mcd", ";"}), | |
| ModuleItemList(1, // | |
| N(1, // | |
| L(1, {"clocking", "cb", "@", "(", | |
| "posedge", "clk", ")", ";"}), | |
| L(1, {"endclocking"})), | |
| N(1, // | |
| L(1, {"clocking", "cb2", "@", "(", | |
| "posedge", "clk", ")", ";"}), | |
| L(1, {"endclocking"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module containing clocking declaration with ports", | |
| "module mcd;\n" | |
| " clocking cb @(posedge clk);\n" | |
| " input a;\n" | |
| " output b;\n" | |
| " endclocking\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "mcd", ";"}), | |
| N(1, // | |
| L(1, {"clocking", "cb", "@", "(", "posedge", "clk", ")", ";"}), | |
| TFPortList(2, // | |
| L(2, {"input", "a", ";"}), L(2, {"output", "b", ";"})), | |
| L(1, {"endclocking"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with DPI import declarations", | |
| "module mdi;" | |
| "import \"DPI-C\" function int add();" | |
| "import \"DPI-C\" function int sleep( input int secs );" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "mdi", ";"}), | |
| ModuleItemList(1, // | |
| L(1, {"import", "\"DPI-C\"", "function", "int", | |
| "add", "(", ")", ";"}), | |
| N(1, // | |
| L(1, {"import", "\"DPI-C\"", "function", "int", | |
| "sleep", "("}), | |
| L(3, {"input", "int", "secs", ")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with pair of procedural continuous assignment statements", | |
| "module proc_cont_assigner;\n" | |
| "always begin\n" | |
| "assign x1 = y1;\n" | |
| "assign x2 = y2;\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "proc_cont_assigner", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"assign", "x1", "=", "y1", ";"}), | |
| L(2, {"assign", "x2", "=", "y2", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with pair of procedural continuous force statements", | |
| "module proc_cont_forcer;\n" | |
| "always begin\n" | |
| "force x1 = y1;\n" | |
| "force x2 = y2;\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "proc_cont_forcer", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"force", "x1", "=", "y1", ";"}), | |
| L(2, {"force", "x2", "=", "y2", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module procedural continuous force statements, macro rvalues", | |
| "module proc_cont_forcer;\n" | |
| "always begin\n" | |
| "force x1 = `y1();\n" | |
| "force x2 = `y2(f, g);\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "proc_cont_forcer", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"force", "x1", "=", "`y1", "(", ")", ";"}), | |
| N(2, L(2, {"force", "x2", "=", "`y2", "("}), | |
| N(4, L(4, {"f", ","}), L(4, {"g", ")", ";"})))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with pair of procedural continuous de-assignment statements", | |
| "module proc_cont_deassigner;\n" | |
| "always begin\n" | |
| "deassign x1 ;\n" | |
| "deassign x2 ;\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "proc_cont_deassigner", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"deassign", "x1", ";"}), | |
| L(2, {"deassign", "x2", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with pair of procedural continuous release statements", | |
| "module proc_cont_releaser;\n" | |
| "always begin\n" | |
| "release x1 ;\n" | |
| "release x2 ;\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "proc_cont_releaser", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"release", "x1", ";"}), L(2, {"release", "x2", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with various procedural continuous assignment statements", | |
| "module proc_cont_assigner;\n" | |
| "always begin\n" | |
| "assign x1 = y1;\n" | |
| "deassign x2;\n" | |
| "force x3 = y3;\n" | |
| "release x4;\n" | |
| "end\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "proc_cont_assigner", ";"}), | |
| N(1, L(1, {"always", "begin"}), | |
| N(2, L(2, {"assign", "x1", "=", "y1", ";"}), | |
| L(2, {"deassign", "x2", ";"}), | |
| L(2, {"force", "x3", "=", "y3", ";"}), | |
| L(2, {"release", "x4", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module using disable statements labelled begin.", | |
| "module disable_self;\n" | |
| " always begin : block\n" | |
| " disable disable_self.block;\n" | |
| " end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "disable_self", ";"}), | |
| ModuleItemList(1, L(1, {"always", "begin", ":", "block"}), | |
| L(2, {"disable", "disable_self", ".", "block", ";"}), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module using disable statements", | |
| "module disable_other;\n" | |
| " always begin\n" | |
| " disable disable_other.block;\n" | |
| " end\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "disable_other", ";"}), | |
| ModuleItemList(1, L(1, {"always", "begin"}), | |
| L(2, {"disable", "disable_other", ".", | |
| "block", ";"}), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with simple immediate assertion statement, inside initial", | |
| "module m_assert; initial assert (x); endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"initial"}), // | |
| L(2, {"assert", "(", "x", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with simple immediate assertion statement, inside final", | |
| "module m_assert; final assert (z); endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"final"}), // | |
| L(2, {"assert", "(", "z", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with simple immediate assertion statement, inside always", | |
| "module m_assert; always_comb assert (y); endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"always_comb"}), // | |
| L(2, {"assert", "(", "y", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: simple immediate assertion statement, inside initial block", | |
| "module m_assert; initial begin assert (x); end endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"initial", "begin"}), // | |
| L(2, {"assert", "(", "x", ")", ";"}), // | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: simple immediate assertion statement, inside final block", | |
| "module m_assert; final begin assert (x); end endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"final", "begin"}), // | |
| L(2, {"assert", "(", "x", ")", ";"}), // | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: simple immediate assertion statement, inside always block", | |
| "module m_assert; always_comb begin assert (x); end endmodule", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "m_assert", ";"}), | |
| N(1, // | |
| L(1, {"always_comb", "begin"}), // | |
| L(2, {"assert", "(", "x", ")", ";"}), // | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: simple initial statement with function call", | |
| "module m;initial aa(bb,cc,dd,ee);endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"aa", "("}), | |
| N(4, L(4, {"bb", ","}), L(4, {"cc", ","}), | |
| L(4, {"dd", ","}), L(4, {"ee", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: expressions and function calls inside if-statement headers", | |
| "module m;" | |
| "initial begin " | |
| "if (aa(bb) == cc(dd)) a = b;" | |
| "if (xx()) b = a;" | |
| "end " | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial", "begin"}), | |
| N(2, | |
| N(2, | |
| N(2, L(2, {"if", "(", "aa", "("}), L(6, {"bb"}), | |
| L(4, {")", "==", "cc", "("}), L(6, {"dd"}), | |
| L(4, {")", ")"})), | |
| L(3, {"a", "=", "b", ";"})), | |
| N(2, L(2, {"if", "(", "xx", "(", ")", ")"}), | |
| L(3, {"b", "=", "a", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: fuction with two arguments inside if-statement headers", | |
| "module m;" | |
| "initial begin " | |
| "if (aa(bb, cc)) x = y;" | |
| "end " | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial", "begin"}), | |
| N(2, | |
| N(2, L(2, {"if", "(", "aa", "("}), | |
| N(6, L(6, {"bb", ","}), L(6, {"cc"})), L(4, {")", ")"})), | |
| L(3, {"x", "=", "y", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: kMethodCallExtension inside if-statement headers", | |
| "module m;" | |
| "initial begin " | |
| "if (aa.bb(cc)) x = y;" | |
| "end " | |
| "endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial", "begin"}), | |
| N(2, | |
| N(2, L(2, {"if", "(", "aa", ".", "bb", "("}), | |
| L(6, {"cc"}), L(4, {")", ")"})), | |
| L(3, {"x", "=", "y", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: initial statement with object method call", | |
| "module m; initial a.b(a,b,c); endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"a", ".", "b", "("}), | |
| N(4, L(4, {"a", ","}), L(4, {"b", ","}), | |
| L(4, {"c", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: initial statement with method call on indexed object", | |
| "module m; initial a[i].b(a,b,c); endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"a", "[", "i", "]", ".", "b", "("}), | |
| N(4, L(4, {"a", ","}), L(4, {"b", ","}), | |
| L(4, {"c", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: initial statement with method call on function returned " | |
| "object", | |
| "module m; initial a(d,e,f).b(a,b,c); endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"a", "("}), | |
| N(4, L(4, {"d", ","}), L(4, {"e", ","}), L(4, {"f"})), | |
| L(2, {")", ".", "b", "("}), | |
| N(4, L(4, {"a", ","}), L(4, {"b", ","}), | |
| L(4, {"c", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: initial statement with indexed access to function returned " | |
| "object", | |
| "module m; initial a(a,b,c)[i]; endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"a", "("}), | |
| N(4, L(4, {"a", ","}), L(4, {"b", ","}), L(4, {"c"})), | |
| L(2, {")", "[", "i", "]", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: method call with no arguments on an object", | |
| "module m; initial foo.bar();endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), L(2, {"foo", ".", "bar", "(", ")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: method call with one argument on an object", | |
| "module m; initial foo.bar(aa);endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"foo", ".", "bar", "("}), L(4, {"aa", ")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: method call with two arguments on an object", | |
| "module m; initial foo.bar(aa,bb);endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"foo", ".", "bar", "("}), | |
| N(4, L(4, {"aa", ","}), L(4, {"bb", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module: method call with three arguments on an object", | |
| "module m; initial foo.bar(aa,bb,cc);endmodule", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, L(1, {"initial"}), | |
| N(2, L(2, {"foo", ".", "bar", "("}), | |
| N(4, L(4, {"aa", ","}), L(4, {"bb", ","}), | |
| L(4, {"cc", ")", ";"})))), | |
| L(0, {"endmodule"})), | |
| }, | |
| // specify block tests | |
| { | |
| "module with empty specify block", | |
| "module specify_m;\n" | |
| " specify\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with empty specify block with comment", | |
| "module specify_m;\n" | |
| " specify\n" | |
| "//comment\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| L(2, {"//comment"}), // | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with empty specify block with comments", | |
| "module specify_m;\n" | |
| " specify\n" | |
| "//comment 1\n" | |
| "//comment 2\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| N(2, // | |
| L(2, {"//comment 1"}), // | |
| L(2, {"//comment 2"})), // | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with empty specify block with one timing spec", | |
| "module specify_m;\n" | |
| " specify\n" | |
| "$setup(posedge x, posedge y, tt);\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| L(2, {"$setup", "(", "posedge", "x", ",", "posedge", | |
| "y", ",", "tt", ")", ";"}), | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with empty specify block with two timing specs", | |
| "module specify_m;\n" | |
| " specify\n" | |
| "$setup(posedge x, posedge y, tt);\n" | |
| "$hold(posedge y, posedge x, tw);\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| N(2, // | |
| L(2, {"$setup", "(", "posedge", "x", ",", | |
| "posedge", "y", ",", "tt", ")", ";"}), | |
| L(2, {"$hold", "(", "posedge", "y", ",", | |
| "posedge", "x", ",", "tw", ")", ";"})), | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with empty specify block with conditional timing specs", | |
| "module specify_m;\n" | |
| " specify\n" | |
| "`ifdef FOO\n" | |
| "$setup(posedge x, posedge y, tt);\n" | |
| "`else\n" | |
| "$hold(posedge y, posedge x, tw);\n" | |
| "`endif\n" | |
| " endspecify\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "specify_m", ";"}), // | |
| N(1, // | |
| L(1, {"specify"}), // | |
| N(2, // | |
| L(0, {"`ifdef", "FOO"}), // | |
| L(2, {"$setup", "(", "posedge", "x", ",", | |
| "posedge", "y", ",", "tt", ")", ";"}), | |
| L(0, {"`else"}), // | |
| L(2, {"$hold", "(", "posedge", "y", ",", | |
| "posedge", "x", ",", "tw", ")", ";"}), | |
| L(0, {"`endif"})), // | |
| L(1, {"endspecify"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from module tests | |
| TEST_F(TreeUnwrapperTest, UnwrapModuleTests) { | |
| for (const auto& test_case : kUnwrapModuleTestCases) { | |
| VLOG(1) << "Test: " << test_case.test_name; | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| // Test data for unwrapping Verilog code with comments. | |
| // Test case format: test name, source code, ExpectedUnwrappedLines | |
| const TreeUnwrapperTestData kUnwrapCommentsTestCases[] = { | |
| // The UnwrappedLine keeps all of these comments, but mark them as | |
| // must-break | |
| { | |
| "single end of line comment test", | |
| "// comment\n", | |
| L(0, {"// comment"}), | |
| }, | |
| { | |
| "single block comment test, no newline", | |
| "/* comment */", // no newline | |
| L(0, {"/* comment */"}), | |
| }, | |
| { | |
| "single block comment test, with newline", | |
| "/* comment */ \n", // no newline | |
| L(0, {"/* comment */"}), | |
| }, | |
| { | |
| "Indented offset first comment", | |
| "\n\n\n\n /* comment */", | |
| L(0, {"/* comment */"}), | |
| }, | |
| { | |
| "Indented offset multiple comments", | |
| "\n\n\n\n /* comment */" | |
| "\n\n\n\n\n\n // last comment\n", | |
| L(0, {"/* comment */"}), | |
| L(0, {"// last comment"}), | |
| }, | |
| { | |
| "multiple comments", | |
| "// comment0\n" | |
| "/* comment1 *//*comment2*/ /*comment3*/ // comment4\n", | |
| L(0, {"// comment0"}), | |
| L(0, {"/* comment1 */", "/*comment2*/", "/*comment3*/", "// comment4"}), | |
| }, | |
| { | |
| "simple module comments", | |
| "// start comment\n" | |
| "module foo (); endmodule\n" | |
| "// end comment\n", | |
| L(0, {"// start comment"}), | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), // | |
| L(0, {"// end comment"}), // comment on own line | |
| }, | |
| { | |
| "two modules surrounded by comments", | |
| "// comment1\n" | |
| "module foo (); endmodule\n" | |
| "// comment2\n\n" | |
| "// comment3\n" | |
| "module bar (); endmodule\n" | |
| "// comment4\n", | |
| L(0, {"// comment1"}), | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), // | |
| L(0, {"// comment2"}), // comment on own line | |
| L(0, {"// comment3"}), // | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "bar", "(", ")", ";"}), | |
| L(0, {"endmodule"})), // | |
| L(0, {"// comment4"}), // comment on own line | |
| }, | |
| { | |
| "module item comments only", | |
| "module foo ();\n" | |
| "// item comment 1\n" | |
| "// item comment 2\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, // | |
| L(0, {"module", "foo", "(", ")", ";"}), | |
| ModuleItemList(1, L(1, {"// item comment 1"}), // | |
| L(1, {"// item comment 2"}) // | |
| ), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module item and ports comments only", | |
| " // humble module\n" | |
| " module foo ( // non-port comment\n" | |
| "// port comment 1\n" | |
| "// port comment 2\n" | |
| "); // header trailing comment\n" | |
| "// item comment 1\n" | |
| "// item comment 2\n" | |
| "endmodule\n", | |
| L(0, {"// humble module"}), | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader(0, L(0, {"module", "foo", "(", "// non-port comment"}), | |
| ModulePortList(2, L(2, {"// port comment 1"}), | |
| L(2, {"// port comment 2"})), | |
| L(0, {")", ";", "// header trailing comment"})), | |
| ModuleItemList(1, L(1, {"// item comment 1"}), // | |
| L(1, {"// item comment 2"}) // | |
| ), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "offset tokens with comments", | |
| "// start comment\n" | |
| "module \n\n" | |
| "foo \n\n\n\n" | |
| "()\n\n\n\n" | |
| "; // comment at end of module\n" | |
| "endmodule\n" | |
| "// end comment\n", | |
| L(0, {"// start comment"}), | |
| ModuleDeclaration( | |
| 0, // | |
| L(0, | |
| {"module", "foo", "(", ")", ";", "// comment at end of module"}), | |
| L(0, {"endmodule"})), // comment separated to next line | |
| L(0, {"// end comment"}), | |
| }, | |
| { | |
| "multiple starting comments split", | |
| "// comment 1\n" | |
| "\n" | |
| "// comment 2\n" | |
| "module foo();" | |
| "endmodule", | |
| L(0, {"// comment 1"}), // | |
| L(0, {"// comment 2"}), | |
| ModuleDeclaration(0, L(0, {"module", "foo", "(", ")", ";"}), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module with end of line comments in empty ports", | |
| "module foo ( // comment1\n" | |
| "// comment2\n" | |
| "// comment3\n" | |
| "); // comment4\n" | |
| "endmodule // endmodule comment\n", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "(", "// comment1"}), | |
| ModulePortList(2, L(2, {"// comment2"}), L(2, {"// comment3"})), | |
| L(0, {")", ";", "// comment4"})), | |
| L(0, {"endmodule", "// endmodule comment"})), | |
| }, | |
| { | |
| "module with end of line comments", | |
| "module foo ( // module foo ( comment!\n" | |
| "input bar, // input bar, comment\n" | |
| "output baz // output baz comment\n" | |
| "); // ); comment\n" | |
| "endmodule // endmodule comment\n", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "(", "// module foo ( comment!"}), | |
| ModulePortList( | |
| 2, L(2, {"input", "bar", ",", "// input bar, comment"}), | |
| L(2, {"output", "baz", "// output baz comment"})), | |
| L(0, {")", ";", "// ); comment"})), | |
| L(0, {"endmodule", "// endmodule comment"})), | |
| }, | |
| // If there exists a newline between two comments, start the comment on | |
| // its own UnwrappedLine | |
| { | |
| "class with end of line comments spanning multiple lines", | |
| "class foo; // class foo; comment\n" | |
| "// comment on its own line\n" | |
| "// one more comment\n" | |
| "// and one last comment\n" | |
| " import fedex_pkg::box;\n" | |
| "// new comment for fun\n" | |
| " import fedex_pkg::*;\n" | |
| "endclass // endclass comment\n", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "foo", ";", "// class foo; comment"}), | |
| ClassItemList(1, L(1, {"// comment on its own line"}), | |
| L(1, {"// one more comment"}), | |
| L(1, {"// and one last comment"}), | |
| L(1, {"import", "fedex_pkg", "::", "box", ";"}), | |
| L(1, {"// new comment for fun"}), | |
| L(1, {"import", "fedex_pkg", "::", "*", ";"})), | |
| L(0, {"endclass", "// endclass comment"})), | |
| }, | |
| // The UnwrappedLine keeps all of these comments but does not mark them | |
| // as must-break | |
| { | |
| "module with in-line comments", | |
| "module foo ( /* comment1 */" | |
| " input /* comment2 */ bar," | |
| "/*comment3 */ output /* comment4 */ baz" | |
| ") /* comment5 */;\n" | |
| "/* comment6 */endmodule\n", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, L(0, {"module", "foo", "(", "/* comment1 */"}), | |
| ModulePortList(2, | |
| L(2, {"input", "/* comment2 */", "bar", ",", | |
| "/*comment3 */"}), | |
| L(2, {"output", "/* comment4 */", "baz"})), | |
| L(0, {")", "/* comment5 */", ";"})), | |
| L(0, {"/* comment6 */"}), L(0, {"endmodule"})), | |
| }, | |
| // This test case mixes types of comments to ensure they are in the | |
| // correct UnwrappedLines | |
| { | |
| "module with end of line and in-line comments", | |
| "module /* comment1 */ foo ( // comment2\n" | |
| "input bar,/* comment3 */ // comment4\n" | |
| "output baz // comment5\n" | |
| "); // comment6\n" | |
| "/* comment7 */ endmodule //comment8\n", | |
| ModuleDeclaration( | |
| 0, | |
| ModuleHeader( | |
| 0, | |
| L(0, {"module", "/* comment1 */", "foo", "(", "// comment2"}), | |
| ModulePortList(2, | |
| L(2, {"input", "bar", ",", "/* comment3 */", | |
| "// comment4"}), | |
| L(2, {"output", "baz", "// comment5"})), | |
| L(0, {")", ";", "// comment6"})), | |
| L(0, {"/* comment7 */"}), L(0, {"endmodule", "//comment8"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from code with | |
| // comments | |
| TEST_F(TreeUnwrapperTest, UnwrapCommentsTests) { | |
| for (const auto& test_case : kUnwrapCommentsTestCases) { | |
| VLOG(1) << "Test: " << test_case.test_name; | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)) | |
| << "code:\n" | |
| << test_case.source_code; | |
| } | |
| } | |
| // Test data for unwrapping Verilog `uvm.* macros | |
| // Test case format: test name, source code, ExpectedUnwrappedLines | |
| const TreeUnwrapperTestData kUnwrapUvmTestCases[] = { | |
| { | |
| "simple uvm test case", | |
| "`uvm_object_utils_begin(l0)\n" | |
| "`uvm_field_int(l1a, UVM_DEFAULT)\n" | |
| "`uvm_field_int(l1b, UVM_DEFAULT)\n" | |
| "`uvm_object_utils_end\n", | |
| N(0, L(0, {"`uvm_object_utils_begin", "("}), L(2, {"l0", ")"})), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1a", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1b", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| L(0, {"`uvm_object_utils_end"}), | |
| }, | |
| { | |
| "simple uvm field utils test case", | |
| "`uvm_field_utils_begin(l0)\n" | |
| "`uvm_field_int(l1a, UVM_DEFAULT)\n" | |
| "`uvm_field_int(l1b, UVM_DEFAULT)\n" | |
| "`uvm_field_utils_end\n", | |
| N(0, L(0, {"`uvm_field_utils_begin", "("}), L(2, {"l0", ")"})), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1a", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1b", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| L(0, {"`uvm_field_utils_end"}), | |
| }, | |
| { | |
| "nested uvm test case", | |
| "`uvm_object_utils_begin(l0)\n" | |
| "`uvm_field_int(l1a, UVM_DEFAULT)\n" | |
| "`uvm_object_utils_begin(l1)\n" | |
| "`uvm_field_int(l2a, UVM_DEFAULT)\n" | |
| "`uvm_object_utils_begin(l2)\n" | |
| "`uvm_field_int(l3a, UVM_DEFAULT)\n" | |
| "`uvm_object_utils_end\n" | |
| "`uvm_object_utils_end\n" | |
| "`uvm_field_int(l1b, UVM_DEFAULT)\n" | |
| "`uvm_object_utils_end\n", | |
| N(0, L(0, {"`uvm_object_utils_begin", "("}), L(2, {"l0", ")"})), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1a", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| N(1, L(1, {"`uvm_object_utils_begin", "("}), L(3, {"l1", ")"})), | |
| N(2, L(2, {"`uvm_field_int", "("}), | |
| N(4, L(4, {"l2a", ","}), L(4, {"UVM_DEFAULT", ")"}))), | |
| N(2, L(2, {"`uvm_object_utils_begin", "("}), L(4, {"l2", ")"})), | |
| N(3, L(3, {"`uvm_field_int", "("}), | |
| N(5, L(5, {"l3a", ","}), L(5, {"UVM_DEFAULT", ")"}))), | |
| L(2, {"`uvm_object_utils_end"}), | |
| L(1, {"`uvm_object_utils_end"}), | |
| N(1, L(1, {"`uvm_field_int", "("}), | |
| N(3, L(3, {"l1b", ","}), L(3, {"UVM_DEFAULT", ")"}))), | |
| L(0, {"`uvm_object_utils_end"}), | |
| }, | |
| { | |
| "missing uvm.*end macro test case", | |
| "`uvm_field_utils_begin(l0)\n" | |
| "`uvm_field_int(l1a, UVM_DEFAULT)\n" | |
| "`uvm_field_int(l1b, UVM_DEFAULT)\n", | |
| N(0, L(0, {"`uvm_field_utils_begin", "("}), L(2, {"l0", ")"})), | |
| N(0, L(0, {"`uvm_field_int", "("}), | |
| N(2, L(2, {"l1a", ","}), L(2, {"UVM_DEFAULT", ")"}))), | |
| N(0, L(0, {"`uvm_field_int", "("}), | |
| N(2, L(2, {"l1b", ","}), L(2, {"UVM_DEFAULT", ")"}))), | |
| }, | |
| { | |
| "missing uvm.*begin macro test case", | |
| "`uvm_field_int(l1a, UVM_DEFAULT)\n" | |
| "`uvm_field_int(l1b, UVM_DEFAULT)\n" | |
| "`uvm_field_utils_end\n", | |
| N(0, L(0, {"`uvm_field_int", "("}), | |
| N(2, L(2, {"l1a", ","}), L(2, {"UVM_DEFAULT", ")"}))), | |
| N(0, L(0, {"`uvm_field_int", "("}), | |
| N(2, L(2, {"l1b", ","}), L(2, {"UVM_DEFAULT", ")"}))), | |
| L(0, {"`uvm_field_utils_end"}), | |
| }, | |
| { | |
| "uvm macro statement test, with semicolon on same line", | |
| "task t;\n" | |
| "`uvm_error(foo, bar);\n" | |
| "endtask\n", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| N(1, // | |
| L(1, {"`uvm_error", "("}), // | |
| N(3, // | |
| L(3, {"foo", ","}), // | |
| L(3, {"bar", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "uvm macro statement test, detached null statement semicolon", | |
| "task t;\n" | |
| "`uvm_error(foo, bar)\n" | |
| ";\n" | |
| "endtask\n", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, | |
| N(1, // | |
| L(1, {"`uvm_error", "("}), // | |
| N(3, // | |
| L(3, {"foo", ","}), // | |
| L(3, {"bar", ")"}))), // | |
| L(1, {";"}) // null statement stays detached | |
| ), | |
| L(0, {"endtask"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from code with | |
| // uvm macros | |
| TEST_F(TreeUnwrapperTest, UnwrapUvmTests) { | |
| for (const auto& test_case : kUnwrapUvmTestCases) { | |
| VLOG(1) << "Test: " << test_case.test_name; | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)) | |
| << "code:\n" | |
| << test_case.source_code; | |
| } | |
| } | |
| // Test data for unwrapping Verilog classes | |
| // Test case format: test name, source code, ExpectedUnwrappedLine | |
| const TreeUnwrapperTestData kClassTestCases[] = { | |
| { | |
| "empty class", | |
| "class Foo; endclass", | |
| ClassDeclaration(0, L(0, {"class", "Foo", ";"}), L(0, {"endclass"})), | |
| }, | |
| { | |
| "virtual class", | |
| "virtual class automatic Foo; endclass", | |
| ClassDeclaration(0, L(0, {"virtual", "class", "automatic", "Foo", ";"}), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "extends class", | |
| "class Foo extends Bar #(x,y,z); endclass", | |
| ClassDeclaration(0, | |
| L(0, {"class", "Foo", "extends", "Bar", "#", "(", "x", | |
| ",", "y", ",", "z", ")", ";"}), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "extends class with type parameters", | |
| "class Foo extends Bar #(.x(x),.y(y)); endclass", | |
| ClassDeclaration( | |
| 0, | |
| ClassHeader(0, // | |
| L(0, {"class", "Foo", "extends", "Bar", "#", "("}), | |
| N(2, // | |
| L(2, {".", "x", "(", "x", ")", ","}), | |
| L(2, {".", "y", "(", "y", ")"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with function and task", | |
| "class Foo;\n" | |
| "integer sizer;\n" | |
| "function new (integer size);\n" | |
| " begin\n" | |
| " this.size = size;\n" | |
| " end\n" | |
| "endfunction\n" | |
| "task print();\n" | |
| " begin\n" | |
| " $write(\"Hello, world!\");\n" | |
| " end\n" | |
| "endtask\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ClassItemList( | |
| 1, L(1, {"integer", "sizer", ";"}), | |
| FunctionDeclaration( | |
| 1, | |
| N(1, L(1, {"function", "new", "("}), | |
| L(3, {"integer", "size", ")", ";"})), | |
| StatementList(2, L(2, {"begin"}), | |
| L(3, {"this", ".", "size", "=", "size", ";"}), | |
| L(2, {"end"})), | |
| L(1, {"endfunction"})), | |
| TaskDeclaration( | |
| 1, TaskHeader(1, {"task", "print", "(", ")", ";"}), | |
| StatementList(2, L(2, {"begin"}), | |
| N(3, L(3, {"$write", "("}), | |
| L(5, {"\"Hello, world!\"", ")", ";"})), | |
| L(2, {"end"})), | |
| L(1, {"endtask"}))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with function and task and comments", | |
| "class c; // c is for cookie\n" | |
| "// f is for false\n" | |
| "function f (integer size);\n" | |
| "endfunction\n" | |
| "// t is for true\n" | |
| "task t();\n" | |
| "endtask\n" | |
| "// class is about to end\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";", "// c is for cookie"}), | |
| ClassItemList( | |
| 1, L(1, {"// f is for false"}), | |
| FunctionDeclaration( | |
| 1, | |
| N(1, L(1, {"function", "f", "("}), | |
| L(3, {"integer", "size", ")", ";"})), | |
| L(1, {"endfunction"})), // | |
| L(1, {"// t is for true"}), | |
| TaskDeclaration(1, | |
| TaskHeader(1, {"task", "t", "(", ")", ";"}), // | |
| L(1, {"endtask"})), | |
| L(1, {"// class is about to end"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class import declarations", | |
| "class foo;\n" | |
| " import fedex_pkg::box;\n" | |
| " import fedex_pkg::*;\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "foo", ";"}), | |
| ClassItemList(1, L(1, {"import", "fedex_pkg", "::", "box", ";"}), | |
| L(1, {"import", "fedex_pkg", "::", "*", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class macros as class item", | |
| "class macros_as_class_item;\n" | |
| " `uvm_warning()\n" | |
| " `uvm_error( )\n" | |
| " `uvm_func_new(\n)\n" | |
| "endclass", | |
| ClassDeclaration(0, L(0, {"class", "macros_as_class_item", ";"}), | |
| ClassItemList(1, L(1, {"`uvm_warning", "(", ")"}), | |
| L(1, {"`uvm_error", "(", ")"}), | |
| L(1, {"`uvm_func_new", "(", ")"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class macro unwrapping", | |
| "class macro_unwrapping;\n" | |
| " `MACRO_CALL(\n" | |
| " // verilog_syntax: parse-as-statements\n" | |
| " int count;\n" | |
| " if(cfg) begin\n" | |
| " count = 1;\n" | |
| " end)\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "macro_unwrapping", ";"}), | |
| N(1, L(1, {"`MACRO_CALL", "("}), | |
| N(3, L(3, {"// verilog_syntax: parse-as-statements"}), | |
| L(3, {"int", "count", ";"}), | |
| FlowControl(3, L(3, {"if", "(", "cfg", ")", "begin"}), | |
| L(4, {"count", "=", "1", ";"}), | |
| L(3, {"end", ")"})))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class macro unwrapping with comment", | |
| "class macro_unwrapping_with_comment;\n" | |
| " `MACRO_CALL(\n" | |
| " // verilog_syntax: parse-as-statements\n" | |
| " int count;\n" | |
| " if(cfg) begin\n" | |
| " // parsed comment\n" | |
| " count = 1;\n" | |
| " end)\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "macro_unwrapping_with_comment", ";"}), | |
| N(1, L(1, {"`MACRO_CALL", "("}), | |
| N(3, L(3, {"// verilog_syntax: parse-as-statements"}), | |
| L(3, {"int", "count", ";"}), | |
| FlowControl(3, L(3, {"if", "(", "cfg", ")", "begin"}), | |
| N(4, L(4, {"// parsed comment"}), | |
| L(4, {"count", "=", "1", ";"})), | |
| L(3, {"end", ")"})))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with parameters as class items", | |
| "class params_as_class_item;\n" | |
| " parameter N = 2;\n" | |
| " parameter reg P = '1;\n" | |
| " localparam M = f(glb::arr[N]) + 1;\n" | |
| " localparam M = $f(glb::arr[N]) + 1;\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "params_as_class_item", ";"}), | |
| ClassItemList(1, L(1, {"parameter", "N", "=", "2", ";"}), | |
| L(1, {"parameter", "reg", "P", "=", "'1", ";"}), | |
| N(1, L(1, {"localparam", "M", "=", "f", "("}), | |
| L(3, {"glb", "::", "arr", "[", "N", "]"}), | |
| L(1, {")", "+", "1", ";"})), | |
| N(1, L(1, {"localparam", "M", "=", "$f", "("}), | |
| L(3, {"glb", "::", "arr", "[", "N", "]"}), | |
| L(1, {")", "+", "1", ";"}))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with events", | |
| "class event_calendar;\n" | |
| " event birthday;\n" | |
| " event first_date, anniversary;\n" | |
| " event revolution[4:0], independence[2:0];\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "event_calendar", ";"}), | |
| ClassItemList( | |
| 1, L(1, {"event", "birthday", ";"}), | |
| DataDeclaration(1, L(1, {"event"}), | |
| InstanceList(3, // | |
| L(3, {"first_date", ","}), | |
| L(3, {"anniversary", ";"}))), | |
| DataDeclaration( | |
| 1, L(1, {"event"}), | |
| InstanceList( | |
| 3, // | |
| L(3, {"revolution", "[", "4", ":", "0", "]", ","}), | |
| L(3, {"independence", "[", "2", ":", "0", "]", ";"})))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with associative array declaration", | |
| "class Driver;\n" | |
| " Packet pNP [*];\n" | |
| " Packet pNP1 [*];\n" | |
| "endclass", | |
| ClassDeclaration(0, L(0, {"class", "Driver", ";"}), | |
| ClassItemList(1, L(1, {"Packet", "pNP", "[*]", ";"}), | |
| L(1, {"Packet", "pNP1", "[*]", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class member declarations", | |
| "class fields_with_modifiers;\n" | |
| " const data_type_or_module_type foo1 = 4'hf;\n" | |
| " static data_type_or_module_type foo3, foo4;\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "fields_with_modifiers", ";"}), | |
| ClassItemList( | |
| 1, | |
| DataDeclaration( | |
| 1, // | |
| // TODO(b/149343440): merge qualifiers and type | |
| // partitions together. | |
| L(1, {"const"}), L(1, {"data_type_or_module_type"}), | |
| L(1, // TODO(b/149344110): should indent to level 3 | |
| {"foo1", "=", "4", "'h", "f", ";"})), | |
| DataDeclaration( | |
| 1, | |
| // TODO(b/149343440): merge qualifiers and type | |
| // partitions together. | |
| L(1, {"static"}), L(1, {"data_type_or_module_type"}), | |
| InstanceList(3, // | |
| L(3, {"foo3", ","}), L(3, {"foo4", ";"})))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with preprocessing", | |
| "class pp_class;\n" | |
| "`ifdef DEBUGGER\n" | |
| "`ifdef VERBOSE\n" // nested, empty | |
| "`endif\n" | |
| "`endif\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "pp_class", ";"}), | |
| ClassItemList(1, L(0, {"`ifdef", "DEBUGGER"}), | |
| N(1, // nested ifdef | |
| L(0, {"`ifdef", "VERBOSE"}), L(0, {"`endif"})), | |
| L(0, {"`endif"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "consecutive `define's", | |
| "class pp_class;\n" | |
| "`define FOO BAR\n" | |
| "`define BAR FOO+1\n" | |
| "endclass", | |
| ClassDeclaration(0, L(0, {"class", "pp_class", ";"}), | |
| ClassItemList(1, L(1, {"`define", "FOO", "BAR"}), | |
| L(1, {"`define", "BAR", "FOO+1"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class pure virtual tasks", | |
| "class myclass;\n" | |
| "pure virtual task pure_task1;\n" | |
| "pure virtual task pure_task2(arg_type arg);\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "myclass", ";"}), | |
| ClassItemList( | |
| 1, // | |
| L(1, {"pure", "virtual", "task", "pure_task1", ";"}), | |
| N(1, // | |
| L(1, {"pure", "virtual", "task", "pure_task2", "("}), | |
| L(3, {"arg_type", "arg", ")", ";"}))), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "nested classes", | |
| "class outerclass;\n" | |
| " class innerclass;\n" | |
| " class reallyinnerclass;\n" | |
| " task subtask;\n" | |
| " endtask\n" | |
| " endclass\n" | |
| " endclass\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "outerclass", ";"}), | |
| ClassDeclaration( | |
| 1, L(1, {"class", "innerclass", ";"}), | |
| ClassDeclaration( | |
| 2, L(2, {"class", "reallyinnerclass", ";"}), | |
| TaskDeclaration(3, TaskHeader(3, {"task", "subtask", ";"}), | |
| L(3, {"endtask"})), | |
| L(2, {"endclass"})), | |
| L(1, {"endclass"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with protected members", | |
| "class protected_stuff;\n" | |
| " protected int count;\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "protected_stuff", ";"}), | |
| DataDeclaration(1, | |
| // TODO(b/149343440): merge qualifiers and type | |
| // partitions together. | |
| L(1, {"protected"}), L(1, {"int"}), | |
| // TODO(b/149344110): indent variable to level 3 | |
| L(1, {"count", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with virtual function", | |
| "class myclass;\n" | |
| "virtual function integer subroutine;\n" | |
| " input a;\n" | |
| " subroutine = a+42;\n" | |
| "endfunction\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "myclass", ";"}), | |
| FunctionDeclaration( | |
| 1, L(1, {"virtual", "function", "integer", "subroutine", ";"}), | |
| L(2, {"input", "a", ";"}), | |
| L(2, {"subroutine", "=", "a", "+", "42", ";"}), | |
| L(1, {"endfunction"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class constructor", | |
| "class constructible;\n" | |
| "function new ();\n" | |
| "endfunction\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "constructible", ";"}), | |
| FunctionDeclaration( | |
| 1, FunctionHeader(1, {"function", "new", "(", ")", ";"}), | |
| L(1, {"endfunction"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class foreach", | |
| "class myclass;\n" | |
| "function apkg::num_t apply_all();\n" | |
| " foreach (this.foo[i]) begin\n" | |
| " y = {y, this.foo[i]};\n" | |
| " z = {z, super.bar[i]};\n" | |
| " end\n" | |
| " foreach (this.foo[i]) begin\n" | |
| " y = {y, this.foo[i]};\n" | |
| " z = {z, super.bar[i]};\n" | |
| " end\n" | |
| "endfunction\n" | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "myclass", ";"}), | |
| FunctionDeclaration( | |
| 1, | |
| L(1, {"function", "apkg", "::", "num_t", "apply_all", "(", ")", | |
| ";"}), | |
| StatementList( | |
| 2, | |
| FlowControl( | |
| 2, | |
| L(2, {"foreach", "(", "this", ".", "foo", "[", "i", "]", | |
| ")", "begin"}), | |
| StatementList( | |
| 3, | |
| N(3, L(3, {"y", "=", "{"}), | |
| N(4, L(4, {"y", ","}), | |
| L(4, {"this", ".", "foo", "[", "i", "]"})), | |
| L(3, {"}", ";"})), | |
| N(3, L(3, {"z", "=", "{"}), | |
| N(4, L(4, {"z", ","}), | |
| L(4, {"super", ".", "bar", "[", "i", "]"})), | |
| L(3, {"}", ";"}))), | |
| L(2, {"end"})), | |
| FlowControl( | |
| 2, | |
| L(2, {"foreach", "(", "this", ".", "foo", "[", "i", "]", | |
| ")", "begin"}), | |
| StatementList( | |
| 3, | |
| N(3, L(3, {"y", "=", "{"}), | |
| N(4, L(4, {"y", ","}), | |
| L(4, {"this", ".", "foo", "[", "i", "]"})), | |
| L(3, {"}", ";"})), | |
| N(3, L(3, {"z", "=", "{"}), | |
| N(4, L(4, {"z", ","}), | |
| L(4, {"super", ".", "bar", "[", "i", "]"})), | |
| L(3, {"}", ";"}))), | |
| L(2, {"end"}))), | |
| L(1, {"endfunction"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with empty constraint", | |
| "class Foo; constraint empty_c { } endclass", | |
| ClassDeclaration(0, L(0, {"class", "Foo", ";"}), | |
| L(1, {"constraint", "empty_c", "{", "}"}), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with constraint, simple expression", | |
| "class Foo; constraint empty_c { c < d; } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration(1, L(1, {"constraint", "empty_c", "{"}), | |
| L(2, {"c", "<", "d", ";"}), L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with empty constraint, only comments", | |
| "class Foo; constraint empty_c { //c1\n" | |
| "//c2\n" | |
| "} endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "empty_c", "{", "//c1"}), // | |
| L(2, {"//c2"}), // | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with multiple constraint declarations", | |
| "class Foo; constraint empty1_c { } constraint empty2_c {} endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ClassItemList(1, L(1, {"constraint", "empty1_c", "{", "}"}), | |
| L(1, {"constraint", "empty2_c", "{", "}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with constraints", | |
| "class Foo; constraint bar_c { unique {baz}; } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration(1, L(1, {"constraint", "bar_c", "{"}), | |
| L(2, {"unique", "{", "baz", "}", ";"}), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with constraints, multiple constraint expressions", | |
| "class Foo; constraint bar_c { soft z == y; unique {baz}; } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "bar_c", "{"}), | |
| ConstraintItemList(2, L(2, {"soft", "z", "==", "y", ";"}), | |
| L(2, {"unique", "{", "baz", "}", ";"})), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with conditional constraint set, constraint expression list", | |
| "class Foo; constraint if_c { if (z) { soft x == y; } } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration(1, L(1, {"constraint", "if_c", "{"}), | |
| N(2, L(2, {"if", "(", "z", ")", "{"}), // | |
| L(3, {"soft", "x", "==", "y", ";"}), // | |
| L(2, {"}"})), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with conditional constraint set, constraint exprs and comments", | |
| "class Foo; constraint if_c { if (z) { //comment-w\n" | |
| "//comment-x\n" | |
| "soft x == y; //comment-y\n" | |
| "//comment-z\n" | |
| "} } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "if_c", "{"}), | |
| N(2, L(2, {"if", "(", "z", ")", "{", "//comment-w"}), // | |
| N(3, L(3, {"//comment-x"}), // | |
| L(3, {"soft", "x", "==", "y", ";", "//comment-y"}), // | |
| L(3, {"//comment-z"})), | |
| L(2, {"}"})), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with nested conditional constraint set", | |
| "class Foo; constraint if_c { " | |
| "if (z) { if (p) { soft x == y; }} " | |
| "} endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "if_c", "{"}), | |
| ConstraintItemList( | |
| 2, L(2, {"if", "(", "z", ")", "{"}), | |
| ConstraintExpressionList( | |
| 3, L(3, {"if", "(", "p", ")", "{"}), | |
| L(4, {"soft", "x", "==", "y", ";"}), L(3, {"}"})), | |
| L(2, {"}"})), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with foreach constraint sets", | |
| "class Foo; constraint if_c { " | |
| "foreach (z) { soft x == y; } " | |
| "foreach (w) { soft y == z; } " | |
| "} endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "if_c", "{"}), | |
| ConstraintItemList( | |
| 2, | |
| N(2, // | |
| L(2, {"foreach", "(", "z", ")", "{"}), | |
| L(3, {"soft", "x", "==", "y", ";"}), L(2, {"}"})), | |
| N(2, // | |
| L(2, {"foreach", "(", "w", ")", "{"}), | |
| L(3, {"soft", "y", "==", "z", ";"}), L(2, {"}"}))), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with constraints, implication constraint expressions", | |
| "class Foo; constraint bar_c { " | |
| " z < y -> { unique {baz}; }" | |
| " a > b -> { soft p == q; }" | |
| " } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ConstraintDeclaration( | |
| 1, L(1, {"constraint", "bar_c", "{"}), | |
| ConstraintItemList( | |
| 2, | |
| N(2, // | |
| L(2, {"z", "<", "y", "->", "{"}), | |
| L(3, {"unique", "{", "baz", "}", ";"}), L(2, {"}"})), | |
| N(2, // | |
| L(2, {"a", ">", "b", "->", "{"}), | |
| L(3, {"soft", "p", "==", "q", ";"}), L(2, {"}"}))), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with constraints, distribution list", | |
| "class Foo; constraint bar_c { " | |
| " timer_enable dist { [0:9] :/ 20, 10 :/ 80 };" | |
| " } endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "Foo", ";"}), | |
| ClassItemList( | |
| 1, L(1, {"constraint", "bar_c", "{"}), | |
| ConstraintItemList( | |
| 2, L(2, {"timer_enable", "dist", "{"}), | |
| DistItemList( | |
| 3, L(3, {"[", "0", ":", "9", "]", ":/", "20", ","}), | |
| L(3, {"10", ":/", "80"})), | |
| L(2, {"}", ";"})), | |
| L(1, {"}"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with empty parameter list", | |
| "class Foo #(); endclass", | |
| ClassDeclaration(0, L(0, {"class", "Foo", "#", "(", ")", ";"}), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with one parameter list", | |
| "class Foo #(type a = b); endclass", | |
| ClassDeclaration( | |
| 0, | |
| ClassHeader(0, L(0, {"class", "Foo", "#", "("}), | |
| L(2, {"type", "a", "=", "b"}), L(0, {")", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "class with multiple parameter list", | |
| "class Foo #(type a = b, type c = d, type e = f); endclass", | |
| ClassDeclaration(0, | |
| ClassHeader(0, L(0, {"class", "Foo", "#", "("}), | |
| ClassParameterList( | |
| 2, L(2, {"type", "a", "=", "b", ","}), | |
| L(2, {"type", "c", "=", "d", ","}), | |
| L(2, {"type", "e", "=", "f"})), | |
| L(0, {")", ";"})), | |
| L(0, {"endclass"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces the correct UnwrappedLines from class tests | |
| TEST_F(TreeUnwrapperTest, UnwrapClassTests) { | |
| for (const auto& test_case : kClassTestCases) { | |
| VLOG(1) << "Test: " << test_case.test_name; | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapPackageTestCases[] = { | |
| { | |
| "empty package", | |
| "package foo_pkg;" | |
| "endpackage", | |
| PackageDeclaration(0, L(0, {"package", "foo_pkg", ";"}), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "empty packages with end-labels", | |
| "package foo_pkg;" | |
| "endpackage : foo_pkg " | |
| "package bar_pkg;" | |
| "endpackage : bar_pkg", | |
| PackageDeclaration(0, L(0, {"package", "foo_pkg", ";"}), | |
| L(0, {"endpackage", ":", "foo_pkg"})), | |
| PackageDeclaration(0, L(0, {"package", "bar_pkg", ";"}), | |
| L(0, {"endpackage", ":", "bar_pkg"})), | |
| }, | |
| { | |
| "in package, implicit-type data declaration, singleton", | |
| "package p ;a;endpackage", | |
| PackageDeclaration(0, L(0, {"package", "p", ";"}), | |
| L(1, {"a", ";"}), // implicit type | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "in package, two implicit-type data declaration", | |
| "package p;a;b;endpackage", | |
| PackageDeclaration(0, L(0, {"package", "p", ";"}), | |
| PackageItemList(1, // | |
| L(1, {"a", ";"}), // | |
| L(1, {"b", ";"})), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "in package, implicit-type data declaration, two variables", | |
| "package p;a,b;\tendpackage", | |
| PackageDeclaration(0, L(0, {"package", "p", ";"}), | |
| DataDeclaration(1, // | |
| L(1, {"a", ","}), // | |
| L(1, {"b", ";"})), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with one parameter declaration", | |
| "package foo_pkg;" | |
| "parameter size=4;" | |
| "endpackage", | |
| PackageDeclaration(0, L(0, {"package", "foo_pkg", ";"}), | |
| L(1, {"parameter", "size", "=", "4", ";"}), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with one localparam declaration", | |
| "package foo_pkg;" | |
| "localparam size=2;" | |
| "endpackage", | |
| PackageDeclaration(0, L(0, {"package", "foo_pkg", ";"}), | |
| L(1, {"localparam", "size", "=", "2", ";"}), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with two type declarations", | |
| "package foo_pkg;" | |
| "typedef enum {X=0,Y=1} bar_t;" | |
| "typedef enum {A=0,B=1} foo_t;" | |
| "endpackage", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "foo_pkg", ";"}), | |
| PackageItemList(1, | |
| N(1, // | |
| L(1, {"typedef", "enum", "{"}), | |
| EnumItemList(2, L(2, {"X", "=", "0", ","}), | |
| L(2, {"Y", "=", "1"})), | |
| L(1, {"}", "bar_t", ";"})), // | |
| N(1, // | |
| L(1, {"typedef", "enum", "{"}), | |
| EnumItemList(2, L(2, {"A", "=", "0", ","}), | |
| L(2, {"B", "=", "1"})), | |
| L(1, {"}", "foo_t", ";"}))), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with typedef declaration on type with named parameters", | |
| "package foo_pkg;" | |
| "typedef goo_pkg::baz_t #(.X(X),.Y(Y)) bar_t;" | |
| "endpackage", | |
| PackageDeclaration( | |
| 0, // | |
| L(0, {"package", "foo_pkg", ";"}), | |
| N(1, // | |
| L(1, {"typedef", "goo_pkg", "::", "baz_t", "#", "("}), | |
| N(3, // | |
| L(3, {".", "X", "(", "X", ")", ","}), // | |
| L(3, {".", "Y", "(", "Y", ")"})), | |
| L(1, {")", "bar_t", ";"})), // | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with function declaration, commented", | |
| "package foo_pkg; \n" | |
| "// function description\n" | |
| "function automatic void bar();" | |
| "endfunction " | |
| " endpackage\n", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "foo_pkg", ";"}), | |
| PackageItemList( | |
| 1, L(1, {"// function description"}), | |
| FunctionDeclaration(1, | |
| L(1, {"function", "automatic", "void", | |
| "bar", "(", ")", ";"}), | |
| L(1, {"endfunction"}))), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with class declaration, commented", | |
| "package foo_pkg; \n" | |
| "// class description\n" | |
| "class classy;" | |
| "endclass " | |
| " endpackage\n", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "foo_pkg", ";"}), | |
| PackageItemList(1, L(1, {"// class description"}), | |
| ClassDeclaration(1, L(1, {"class", "classy", ";"}), | |
| L(1, {"endclass"}))), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "package with class and function declaration, commented", | |
| "package foo_pkg; \n" | |
| "// class description\n" | |
| "class classy;\n" | |
| "// function description\n" | |
| "function automatic void bar();" | |
| "endfunction " | |
| "endclass " | |
| " endpackage\n", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "foo_pkg", ";"}), | |
| PackageItemList( | |
| 1, L(1, {"// class description"}), | |
| ClassDeclaration( | |
| 1, L(1, {"class", "classy", ";"}), | |
| ClassItemList(2, L(2, {"// function description"}), | |
| FunctionDeclaration( | |
| 2, | |
| L(2, {"function", "automatic", "void", | |
| "bar", "(", ")", ";"}), | |
| L(2, {"endfunction"}))), | |
| L(1, {"endclass"}))), | |
| L(0, {"endpackage"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from package tests | |
| TEST_F(TreeUnwrapperTest, UnwrapPackageTests) { | |
| for (const auto& test_case : kUnwrapPackageTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kDescriptionTestCases[] = { | |
| { | |
| "implicit-type data declaration, singleton", | |
| "a;", | |
| L(0, {"a", ";"}), | |
| }, | |
| { | |
| "implicit-type data declaration, singleton, with var keyword", | |
| "\t var a;", | |
| L(0, {"var", "a", ";"}), | |
| }, | |
| { | |
| "two implicit-type data declaration", | |
| "a;b;", | |
| L(0, {"a", ";"}), | |
| L(0, {"b", ";"}), | |
| }, | |
| { | |
| "implicit-type data declaration, two variables", | |
| "a,b;", | |
| DataDeclaration(0, // | |
| L(0, {"a", ","}), // | |
| L(0, {"b", ";"})), | |
| }, | |
| { | |
| "implicit-type data declaration, two variables, with var keyword", | |
| "var a,b;", | |
| DataDeclaration(0, // | |
| L(0, {"var"}), // | |
| N(2, // | |
| L(2, {"a", ","}), // | |
| L(2, {"b", ";"}))), | |
| }, | |
| { | |
| "one bind declaration", | |
| "bind foo bar#(.x(y)) baz(.clk(clk));", | |
| N(0, // kBindDeclaration | |
| L(0, {"bind", "foo", "bar", "#", "("}), | |
| L(2, {".", "x", "(", "y", ")"}), | |
| N(0, L(0, {")", "baz", "("}), // | |
| L(2, {".", "clk", "(", "clk", ")"}), // | |
| L(0, {")", ";"})) // ';' is attached to end of bind directive | |
| ), | |
| }, | |
| {"multiple bind declarations", | |
| "bind foo bar baz();" | |
| "bind goo car caz();", | |
| L(0, {"bind", "foo", "bar", "baz", "(", ")", ";"}), | |
| L(0, {"bind", "goo", "car", "caz", "(", ")", ";"})}, | |
| { | |
| "multi-instance bind declaration", | |
| "bind foo bar baz1(), baz2();", | |
| N(0, // kBindDeclaration | |
| L(0, {"bind", "foo", "bar", "baz1", "(", ")", ","}), // | |
| L(0, {"baz2", "(", ")", | |
| ";"}) // TODO(fangism): what should be this indentation? | |
| ), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from package tests | |
| TEST_F(TreeUnwrapperTest, DescriptionTests) { | |
| for (const auto& test_case : kDescriptionTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapPreprocessorTestCases[] = { | |
| { | |
| "consecutive `include's", | |
| "`include \"header1.vh\"\n" | |
| "`include \"path/header2.svh\"\n", | |
| L(0, {"`include", "\"header1.vh\""}), | |
| L(0, {"`include", "\"path/header2.svh\""}), | |
| }, | |
| { | |
| "consecutive `define's", | |
| "`define FOO BAR\n" | |
| "`define BAR FOO+1\n", | |
| L(0, {"`define", "FOO", "BAR"}), | |
| L(0, {"`define", "BAR", "FOO+1"}), | |
| }, | |
| { | |
| "consecutive `define's multiline", | |
| "`define FOO BAR \\\n" | |
| " NONE\n" | |
| "`define BAR FOO+1 \\\n" | |
| " -1\n", | |
| L(0, {"`define", "FOO", "BAR \\\n NONE"}), | |
| L(0, {"`define", "BAR", "FOO+1 \\\n -1"}), | |
| }, | |
| { | |
| "`define's followed by top-level macro call", | |
| "`define FOO BAR\n" | |
| "`FOO(baz)\n", | |
| L(0, {"`define", "FOO", "BAR"}), | |
| N(0, L(0, {"`FOO", "("}), L(2, {"baz", ")"})), | |
| }, | |
| { | |
| "consecutive `undef's", | |
| "`undef FOO\n" | |
| "`undef BAR\n", | |
| L(0, {"`undef", "FOO"}), | |
| L(0, {"`undef", "BAR"}), | |
| }, | |
| { | |
| "preprocessor conditionals `ifdef's", | |
| "`ifdef BAR\n" | |
| "`else\n" | |
| "`endif\n" | |
| "`ifdef FOO\n" | |
| "`elsif XYZ\n" | |
| "`endif\n", | |
| L(0, {"`ifdef", "BAR"}), | |
| L(0, {"`else"}), | |
| L(0, {"`endif"}), | |
| L(0, {"`ifdef", "FOO"}), | |
| L(0, {"`elsif", "XYZ"}), | |
| L(0, {"`endif"}), | |
| }, | |
| { | |
| "`define's surrounded by comments", | |
| "// leading comment\n" | |
| "`define FOO BAR\n" | |
| "`define BAR FOO+1\n" | |
| "// trailing comment\n", | |
| L(0, {"// leading comment"}), | |
| L(0, {"`define", "FOO", "BAR"}), | |
| L(0, {"`define", "BAR", "FOO+1"}), | |
| L(0, {"// trailing comment"}), | |
| }, | |
| { | |
| "preprocessor conditionals `ifndef's", | |
| "`ifndef BAR\n" | |
| "`else\n" | |
| "`endif\n" | |
| "`ifndef FOO\n" | |
| "`elsif XYZ\n" | |
| "`endif\n", | |
| L(0, {"`ifndef", "BAR"}), | |
| L(0, {"`else"}), | |
| L(0, {"`endif"}), | |
| L(0, {"`ifndef", "FOO"}), | |
| L(0, {"`elsif", "XYZ"}), | |
| L(0, {"`endif"}), | |
| }, | |
| { | |
| "`include's inside package should be indented as package items", | |
| "package includer;\n" | |
| "`include \"header1.vh\"\n" | |
| "`include \"path/header2.svh\"\n" | |
| "endpackage : includer\n", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "includer", ";"}), | |
| PackageItemList(1, L(1, {"`include", "\"header1.vh\""}), | |
| L(1, {"`include", "\"path/header2.svh\""})), | |
| L(0, {"endpackage", ":", "includer"})), | |
| }, | |
| { | |
| "`defines's inside package should be indented as package items", | |
| "package definer;\n" | |
| "`define BAR\n" | |
| "`undef BAR\n" | |
| "endpackage : definer\n", | |
| PackageDeclaration(0, L(0, {"package", "definer", ";"}), | |
| PackageItemList(1, L(1, {"`define", "BAR", ""}), | |
| L(1, {"`undef", "BAR"})), | |
| L(0, {"endpackage", ":", "definer"})), | |
| }, | |
| { | |
| "`ifdefs's inside package should be flushed left, but not items", | |
| "package ifdeffer;\n" | |
| "parameter three=3;" | |
| "`ifdef FOUR\n" | |
| "parameter size=4;" | |
| "`elsif FIVE\n" | |
| "parameter size=5;" | |
| "`else\n" | |
| "parameter size=6;" | |
| "`endif\n" | |
| "parameter foo=7;" | |
| "endpackage : ifdeffer\n", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "ifdeffer", ";"}), | |
| PackageItemList( | |
| 1, L(1, {"parameter", "three", "=", "3", ";"}), | |
| L(0, {"`ifdef", "FOUR"}), | |
| L(1, {"parameter", "size", "=", "4", ";"}), | |
| L(0, {"`elsif", "FIVE"}), | |
| L(1, {"parameter", "size", "=", "5", ";"}), L(0, {"`else"}), | |
| L(1, {"parameter", "size", "=", "6", ";"}), L(0, {"`endif"}), | |
| L(1, {"parameter", "foo", "=", "7", ";"})), | |
| L(0, {"endpackage", ":", "ifdeffer"})), | |
| }, | |
| { | |
| "new partition after `else", | |
| "`ifdef FOO\n" | |
| "`fine\n" | |
| "`else\n" | |
| "`error\n" | |
| "`endif\n", | |
| L(0, {"`ifdef", "FOO"}), | |
| L(0, {"`fine"}), | |
| L(0, {"`else"}), | |
| L(0, {"`error"}), | |
| L(0, {"`endif"}), | |
| }, | |
| { | |
| "new partition after `else with EOL comment", | |
| "`ifdef FOO\n" | |
| "`fine\n" | |
| "`else // not good\n" | |
| "`error\n" | |
| "`endif\n", | |
| L(0, {"`ifdef", "FOO"}), | |
| L(0, {"`fine"}), | |
| L(0, {"`else", "// not good"}), | |
| L(0, {"`error"}), | |
| L(0, {"`endif"}), | |
| }, | |
| { | |
| "new partition after `else with block comment", | |
| "`ifdef FOO\n" | |
| "`fine\n" | |
| "`else /* not good */\n" | |
| "`error\n" | |
| "`endif\n", | |
| L(0, {"`ifdef", "FOO"}), | |
| L(0, {"`fine"}), | |
| L(0, {"`else", "/* not good */"}), | |
| L(0, {"`error"}), | |
| L(0, {"`endif"}), | |
| }, | |
| { | |
| "lone macro call, no semicolon", | |
| "`FOO()\n", | |
| L(0, {"`FOO", "(", ")"}), | |
| }, | |
| { | |
| "lone macro call, with semicolon", | |
| "`FOO();\n", | |
| L(0, {"`FOO", "(", ")", ";"}), | |
| }, | |
| { | |
| "lone macro call, with space before semicolon", | |
| "`FOO() ;\n", | |
| L(0, {"`FOO", "(", ")", ";"}), | |
| }, | |
| { | |
| "macro call with one argument and with semicolon", | |
| "`FOO(arg);\n", | |
| N(0, L(0, {"`FOO", "("}), L(2, {"arg", ")", ";"})), | |
| }, | |
| { | |
| "macro call with one argument and with space before semicolon", | |
| "`FOO(arg) ;\n", | |
| N(0, L(0, {"`FOO", "("}), L(2, {"arg", ")", ";"})), | |
| }, | |
| { | |
| "macro call with comments in argument list", | |
| "`FOO(aa, //aa\nbb , // bb\ncc)\n", | |
| N(0, L(0, {"`FOO", "("}), | |
| N(2, // | |
| L(2, {"aa", ",", "//aa"}), // | |
| L(2, {"bb", ",", "// bb"}), // | |
| L(2, {"cc", ")"}))), | |
| }, | |
| { | |
| "macro call with comment before first argument", | |
| "`FOO(// aa\naa, // bb\nbb, // cc\ncc)\n", | |
| N(0, L(0, {"`FOO", "(", "// aa"}), | |
| N(2, // | |
| L(2, {"aa", ",", "// bb"}), // | |
| L(2, {"bb", ",", "// cc"}), // | |
| L(2, {"cc", ")"}))), | |
| }, | |
| { | |
| "macro call with argument including comment", | |
| "`FOO(aa, bb,\n// cc\ndd)\n", | |
| N(0, L(0, {"`FOO", "("}), | |
| N(2, // | |
| L(2, {"aa", ","}), // | |
| L(2, {"bb", ","}), // | |
| L(2, {"// cc"}), // indented to same level as surrounding args | |
| L(2, {"dd", ")"}))), | |
| }, | |
| { | |
| "macro call with argument including trailing EOL comment", | |
| "`FOO(aa, bb, // cc\ndd)\n", | |
| N(0, L(0, {"`FOO", "("}), | |
| N(2, // | |
| L(2, {"aa", ","}), // | |
| L(2, {"bb", ",", {"// cc"}}), // | |
| L(2, {"dd", ")"}))), | |
| }, | |
| { | |
| "lone macro item", | |
| "`FOO\n", | |
| L(0, {"`FOO"}), | |
| }, | |
| { | |
| "two macro items", | |
| "`FOO\n" | |
| "`BAR\n", | |
| L(0, {"`FOO"}), | |
| L(0, {"`BAR"}), | |
| }, | |
| { | |
| "top-level assert macro with property_spec inside argument list", | |
| "`ASSERT(" | |
| " MioWarl_A," | |
| " padctrl.reg2hw.mio_pads[mio_sel].qe |=>" | |
| " !(|padctrl.mio_attr_q[mio_sel][padctrl_reg_pkg::AttrDw-1:2])," | |
| " clk_i, !rst_ni)\n", | |
| N(0, // | |
| L(0, {"`ASSERT", "("}), | |
| N(2, // | |
| L(2, {"MioWarl_A", ","}), L(2, {"padctrl", ".", | |
| "reg2hw", ".", | |
| "mio_pads", "[", | |
| "mio_sel", "]", | |
| ".", "qe", | |
| "|=>", "!", | |
| "(", "|", | |
| "padctrl", ".", | |
| "mio_attr_q", "[", | |
| "mio_sel", "]", | |
| "[", "padctrl_reg_pkg", | |
| "::", "AttrDw", | |
| "-", "1", | |
| ":", "2", | |
| "]", ")", | |
| ","}), | |
| L(2, {"clk_i", ","}), L(2, {"!", "rst_ni", ")"}))), | |
| }, | |
| { | |
| "assert macro embedded in module with property_spec inside arugment " | |
| "list", | |
| "module foo;" | |
| " `ASSERT(" | |
| " MioWarl_A," | |
| " padctrl.reg2hw.mio_pads[mio_sel].qe |=>" | |
| " " | |
| "!(|padctrl.mio_attr_q[mio_sel][padctrl_reg_pkg::AttrDw-1:2])," | |
| " clk_i, !rst_ni)\n" | |
| "endmodule\n", | |
| ModuleDeclaration( // | |
| 0, // | |
| L(0, {"module", "foo", ";"}), | |
| N(1, // | |
| L(1, {"`ASSERT", "("}), | |
| N(3, // | |
| L(3, {"MioWarl_A", ","}), // | |
| L(3, {"padctrl", ".", | |
| "reg2hw", ".", | |
| "mio_pads", "[", | |
| "mio_sel", "]", | |
| ".", "qe", | |
| "|=>", "!", | |
| "(", "|", | |
| "padctrl", ".", | |
| "mio_attr_q", "[", | |
| "mio_sel", "]", | |
| "[", "padctrl_reg_pkg", | |
| "::", "AttrDw", | |
| "-", "1", | |
| ":", "2", | |
| "]", ")", | |
| ","}), | |
| L(3, {"clk_i", ","}), L(3, {"!", "rst_ni", ")"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "assert macro embedded in initial block with property_spec inside " | |
| "argument list", | |
| "module foo;" | |
| " initial begin" | |
| " `ASSERT(" | |
| " MioWarl_A," | |
| " padctrl.reg2hw.mio_pads[mio_sel].qe |=>" | |
| " " | |
| "!(|padctrl.mio_attr_q[mio_sel][padctrl_reg_pkg::AttrDw-1:2])," | |
| " clk_i, !rst_ni)\n" | |
| " end\n" | |
| "endmodule\n", | |
| ModuleDeclaration( // | |
| 0, // | |
| L(0, {"module", "foo", ";"}), | |
| N(1, // | |
| L(1, {"initial", "begin"}), | |
| N(2, // | |
| L(2, {"`ASSERT", "("}), | |
| N(4, // | |
| L(4, {"MioWarl_A", ","}), | |
| L(4, {"padctrl", ".", | |
| "reg2hw", ".", | |
| "mio_pads", "[", | |
| "mio_sel", "]", | |
| ".", "qe", | |
| "|=>", "!", | |
| "(", "|", | |
| "padctrl", ".", | |
| "mio_attr_q", "[", | |
| "mio_sel", "]", | |
| "[", "padctrl_reg_pkg", | |
| "::", "AttrDw", | |
| "-", "1", | |
| ":", "2", | |
| "]", ")", | |
| ","}), | |
| L(4, {"clk_i", ","}), L(4, {"!", "rst_ni", ")"}))), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "`include's inside module should be flushed left", | |
| "module includer;\n" | |
| "`include \"header1.vh\"\n" | |
| "`include \"path/header2.svh\"\n" | |
| "endmodule : includer\n", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "includer", ";"}), | |
| ModuleItemList(1, L(1, {"`include", "\"header1.vh\""}), | |
| L(1, {"`include", "\"path/header2.svh\""})), | |
| L(0, {"endmodule", ":", "includer"})), | |
| }, | |
| { | |
| "`defines's inside module should be flushed left", | |
| "module definer;\n" | |
| "`define BAR\n" | |
| "`undef BAR\n" | |
| "endmodule : definer\n", | |
| ModuleDeclaration(0, L(0, {"module", "definer", ";"}), | |
| ModuleItemList(1, L(1, {"`define", "BAR", ""}), | |
| L(1, {"`undef", "BAR"})), | |
| L(0, {"endmodule", ":", "definer"})), | |
| }, | |
| { | |
| "`ifdefs's inside module should be flushed left, but not items", | |
| "module foo;\n" | |
| "always_comb begin\n" | |
| " x = y;\n" | |
| "`ifdef FOO\n" | |
| " z = 0;\n" | |
| "`endif\n" | |
| " w = z;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList(1, L(1, {"always_comb", "begin"}), | |
| StatementList(2, // | |
| L(2, {"x", "=", "y", ";"}), // | |
| L(0, {"`ifdef", "FOO"}), // | |
| L(2, {"z", "=", "0", ";"}), // | |
| L(0, {"`endif"}), // | |
| L(2, {"w", "=", "z", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "new partition after `else in module", | |
| "module foo;\n" | |
| "always_comb begin\n" | |
| " x = y;\n" | |
| "`ifdef FOO\n" | |
| " z = 0;\n" | |
| "`else\n" | |
| " x = z;\n" | |
| "`endif\n" | |
| " w = z;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList(1, L(1, {"always_comb", "begin"}), | |
| StatementList(2, // | |
| L(2, {"x", "=", "y", ";"}), // | |
| L(0, {"`ifdef", "FOO"}), // | |
| L(2, {"z", "=", "0", ";"}), // | |
| L(0, {"`else"}), // | |
| L(2, {"x", "=", "z", ";"}), // | |
| L(0, {"`endif"}), // | |
| L(2, {"w", "=", "z", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "new partition after `else with EOL comment in module", | |
| "module foo;\n" | |
| "always_comb begin\n" | |
| " x = y;\n" | |
| "`ifdef FOO\n" | |
| " z = 0;\n" | |
| "`else // FOO not defined\n" | |
| " x = z;\n" | |
| "`endif\n" | |
| " w = z;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"always_comb", "begin"}), | |
| StatementList(2, // | |
| L(2, {"x", "=", "y", ";"}), // | |
| L(0, {"`ifdef", "FOO"}), // | |
| L(2, {"z", "=", "0", ";"}), // | |
| L(0, {"`else", "// FOO not defined"}), // | |
| L(2, {"x", "=", "z", ";"}), // | |
| L(0, {"`endif"}), // | |
| L(2, {"w", "=", "z", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "new partition after `else with block comment in module", | |
| "module foo;\n" | |
| "always_comb begin\n" | |
| " x = y;\n" | |
| "`ifdef FOO\n" | |
| " z = 0;\n" | |
| "`else /* z is available */\n" | |
| " x = z;\n" | |
| "`endif\n" | |
| " w = z;\n" | |
| "end\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList( | |
| 1, L(1, {"always_comb", "begin"}), | |
| StatementList(2, // | |
| L(2, {"x", "=", "y", ";"}), // | |
| L(0, {"`ifdef", "FOO"}), // | |
| L(2, {"z", "=", "0", ";"}), // | |
| L(0, {"`else", "/* z is available */"}), // | |
| L(2, {"x", "=", "z", ";"}), // | |
| L(0, {"`endif"}), // | |
| L(2, {"w", "=", "z", ";"})), // | |
| L(1, {"end"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "`ifdefs's inside module should flush left, even with leading comment", | |
| "module foo;\n" | |
| "// comment\n" | |
| "`ifdef SIM\n" | |
| " wire w;\n" | |
| "`endif\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList(1, L(1, {"// comment"}), L(0, {"`ifdef", "SIM"}), | |
| L(1, {"wire", "w", ";"}), L(0, {"`endif"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "`ifndefs's inside module should flush left, even with leading comment", | |
| "module foo;\n" | |
| "// comment\n" | |
| "`ifndef SIM\n" | |
| "`endif\n" | |
| " wire w;\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList(1, L(1, {"// comment"}), L(0, {"`ifndef", "SIM"}), | |
| L(0, {"`endif"}), L(1, {"wire", "w", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "module items with preprocessor conditionals and comments", | |
| "module foo;\n" | |
| "// comment1\n" | |
| "`ifdef SIM\n" | |
| "// comment2\n" | |
| "`elsif SYN\n" | |
| "// comment3\n" | |
| "`else\n" | |
| "// comment4\n" | |
| "`endif\n" | |
| "// comment5\n" | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "foo", ";"}), | |
| ModuleItemList(1, L(1, {"// comment1"}), L(0, {"`ifdef", "SIM"}), | |
| L(1, {"// comment2"}), L(0, {"`elsif", "SYN"}), | |
| L(1, {"// comment3"}), L(0, {"`else"}), | |
| L(1, {"// comment4"}), L(0, {"`endif"}), | |
| L(1, {"// comment5"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "Partitioning formal argument `define", | |
| "`define FOO(BAR)\n", | |
| N(0, L(0, {"`define", "FOO", "("}), L(2, {"BAR", ")", ""})), | |
| }, | |
| { | |
| "Partitioning formal argument `define with body definition", | |
| "`define FOO(BAR) body_def\n", | |
| N(0, L(0, {"`define", "FOO", "("}), L(2, {"BAR", ")", "body_def"})), | |
| }, | |
| { | |
| "Partitioning formal arguments in `define", | |
| "`define FOO(BAR1, BAR2, BAR3)\n", | |
| N(0, L(0, {"`define", "FOO", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", ""}))), | |
| }, | |
| { | |
| "Partitioning formal arguments in `define with body definition", | |
| "`define FOO(BAR1, BAR2, BAR3) definition_body\n", | |
| N(0, L(0, {"`define", "FOO", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", "definition_body"}))), | |
| }, | |
| { | |
| "Partitioning formal arguments in consecutive `define's", | |
| "`define FOO1(BAR1, BAR2, BAR3)\n" | |
| "`define FOO2(BAR1, BAR2, BAR3)\n", | |
| N(0, L(0, {"`define", "FOO1", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", ""}))), | |
| N(0, L(0, {"`define", "FOO2", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", ""}))), | |
| }, | |
| { | |
| "Partitioning formal arguments in consecutive `define's with body def", | |
| "`define FOO1(BAR1, BAR2, BAR3) definition_body\n" | |
| "`define FOO2(BAR1, BAR2, BAR3)\n", | |
| N(0, L(0, {"`define", "FOO1", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", "definition_body"}))), | |
| N(0, L(0, {"`define", "FOO2", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", ""}))), | |
| }, | |
| { | |
| "Partitioning formal arguments in consecutive `define's with body def", | |
| "`define FOO1(BAR1, BAR2, BAR3)\n" | |
| "`define FOO2(BAR1, BAR2, BAR3) definition_body\n", | |
| N(0, L(0, {"`define", "FOO1", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", ""}))), | |
| N(0, L(0, {"`define", "FOO2", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", "definition_body"}))), | |
| }, | |
| { | |
| "Partitioning formal arguments in consecutive `define's with body def", | |
| "`define FOO1(BAR1, BAR2, BAR3) definition_body1\n" | |
| "`define FOO2(BAR1, BAR2, BAR3) definition_body2\n", | |
| N(0, L(0, {"`define", "FOO1", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", "definition_body1"}))), | |
| N(0, L(0, {"`define", "FOO2", "("}), | |
| N(2, L(2, {"BAR1", ","}), L(2, {"BAR2", ","}), | |
| L(2, {"BAR3", ")", "definition_body2"}))), | |
| }, | |
| { | |
| "Partitioning formal argument with default value in `define", | |
| "`define FOO(BAR1=default_val)\n", | |
| N(0, L(0, {"`define", "FOO", "("}), | |
| L(2, {"BAR1", "=", "default_val", ")", ""})), | |
| }, | |
| { | |
| "Partitioning formal arguments with default value in `define with " | |
| "body definition", | |
| "`define FOO(BAR1, BAR2=default_val) definition_body\n", | |
| N(0, L(0, {"`define", "FOO", "("}), | |
| N(2, L(2, {"BAR1", ","}), | |
| L(2, {"BAR2", "=", "default_val", ")", "definition_body"}))), | |
| }, | |
| // TODO(fangism): decide/test/support indenting preprocessor directives | |
| // nested inside `ifdefs. Should `define inside `ifdef be indented? | |
| }; | |
| // Test for correct UnwrappedLines for preprocessor directives. | |
| TEST_F(TreeUnwrapperTest, UnwrapPreprocessorTests) { | |
| for (const auto& test_case : kUnwrapPreprocessorTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| // Interface declarations are structured just like module declarations. | |
| const TreeUnwrapperTestData kUnwrapInterfaceTestCases[] = { | |
| { | |
| "empty interface", | |
| "interface foo_if;" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interface, empty params", | |
| "interface foo_if#( );" | |
| "endinterface", | |
| InterfaceDeclaration(0, | |
| L(0, {"interface", "foo_if", "#", "(", ")", ";"}), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interface, empty params, with comment", | |
| "interface foo_if#(\n" | |
| "//comment\n" | |
| ");" | |
| "endinterface", | |
| InterfaceDeclaration(0, // | |
| N(0, // | |
| L(0, {"interface", "foo_if", "#", "("}), // | |
| L(2, {"//comment"}), L(0, {")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interface, empty ports", | |
| "interface foo_if( );" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", "(", ")", ";"}), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interface, empty params with comment, empty ports", | |
| "interface foo_if#(\n" | |
| "//comment\n" | |
| ")( );" | |
| "endinterface", | |
| InterfaceDeclaration(0, // | |
| N(0, // | |
| L(0, {"interface", "foo_if", "#", "("}), // | |
| L(2, {"//comment"}), L(0, {")", "(", ")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interface, one param type, empty ports", | |
| "interface foo_if#(\n" | |
| "parameter type T = bit\n" | |
| ")( );" | |
| "endinterface", | |
| InterfaceDeclaration(0, // | |
| N(0, // | |
| L(0, {"interface", "foo_if", "#", "("}), // | |
| L(2, {"parameter", "type", "T", "=", "bit"}), | |
| L(0, {")", "(", ")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "empty interfaces with end-labels", | |
| "interface foo_if;" | |
| "endinterface : foo_if " | |
| "interface bar_if;" | |
| "endinterface : bar_if", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| L(0, {"endinterface", ":", "foo_if"})), | |
| InterfaceDeclaration(0, L(0, {"interface", "bar_if", ";"}), | |
| L(0, {"endinterface", ":", "bar_if"})), | |
| }, | |
| { | |
| "interface with one parameter declaration", | |
| "interface foo_if;" | |
| "parameter size=4;" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| L(1, {"parameter", "size", "=", "4", ";"}), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "interface with one localparam declaration", | |
| "interface foo_if;" | |
| "localparam size=2;" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| L(1, {"localparam", "size", "=", "2", ";"}), | |
| L(0, {"endinterface"})), | |
| }, | |
| // modport declarations | |
| { | |
| "interface with modport declarations", | |
| "interface foo_if;" | |
| "modport mp1 (output a, input b);" | |
| "modport mp2 (output c, input d);" | |
| "endinterface", | |
| InterfaceDeclaration( | |
| 0, L(0, {"interface", "foo_if", ";"}), | |
| ModuleItemList( | |
| 1, // | |
| N(1, L(1, {"modport", "mp1", "("}), L(3, {"output", "a", ","}), | |
| L(3, {"input", "b"}), // | |
| L(1, {")", ";"})), | |
| N(1, L(1, {"modport", "mp2", "("}), L(3, {"output", "c", ","}), | |
| L(3, {"input", "d"}), // | |
| L(1, {")", ";"}))), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "interface with modport TF ports", | |
| "interface foo_if;" | |
| "modport mp1 (output a, input b, import c);" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| N(1, L(1, {"modport", "mp1", "("}), // | |
| L(3, {"output", "a", ","}), // | |
| L(3, {"input", "b", ","}), // | |
| L(3, {"import", "c"}), // | |
| L(1, {")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "interface with more modport ports", | |
| "interface foo_if;" | |
| "modport mp1 (output a1, a2, input b1, b2, import c1, c2);" | |
| "endinterface", | |
| InterfaceDeclaration(0, L(0, {"interface", "foo_if", ";"}), | |
| N(1, L(1, {"modport", "mp1", "("}), | |
| L(3, {"output", "a1", ",", "a2", ","}), | |
| L(3, {"input", "b1", ",", "b2", ","}), | |
| L(3, {"import", "c1", ",", "c2"}), // | |
| L(1, {")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| { | |
| "interface with modport and comments between ports", | |
| "interface foo_if;" | |
| " modport mp1(\n" | |
| " // Our output\n" | |
| " output a,\n" | |
| " /* Inputs */\n" | |
| " input b1, b_f /*last*/," | |
| " import c\n" | |
| " );\n" | |
| "endinterface", | |
| InterfaceDeclaration( | |
| 0, L(0, {"interface", "foo_if", ";"}), | |
| N(1, L(1, {"modport", "mp1", "("}), | |
| N(3, L(3, {"// Our output"}), L(3, {"output", "a", ","})), | |
| N(3, L(3, {"/* Inputs */"}), | |
| L(3, {"input", "b1", ",", "b_f", "/*last*/", ","})), | |
| L(3, {"import", "c"}), // | |
| L(1, {")", ";"})), | |
| L(0, {"endinterface"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from interface tests | |
| TEST_F(TreeUnwrapperTest, UnwrapInterfaceTests) { | |
| for (const auto& test_case : kUnwrapInterfaceTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapTaskTestCases[] = { | |
| { | |
| "empty task", | |
| "task foo;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "two empty tasks", | |
| "task foo;" | |
| "endtask " | |
| "task bar;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| L(0, {"endtask"})), | |
| TaskDeclaration(0, TaskHeader(0, {"task", "bar", ";"}), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "empty task, statement comment", | |
| "task foo;\n" | |
| "// statement comment\n" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| L(1, {"// statement comment"}), L(0, {"endtask"})), | |
| }, | |
| { | |
| "empty task, empty ports, statement comment", | |
| "task foo();\n" | |
| "// statement comment\n" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", "(", ")", ";"}), | |
| L(1, {"// statement comment"}), L(0, {"endtask"})), | |
| }, | |
| { | |
| "empty task with qualifier", | |
| "task automatic foo;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "automatic", "foo", ";"}), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with empty formal arguments", | |
| "task foo();" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", "(", ")", ";"}), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with formal argument", | |
| "task foo(string name);" | |
| "endtask", | |
| TaskDeclaration(0, | |
| N(0, L(0, {"task", "foo", "("}), | |
| L(2, {"string", "name", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with multiple formal arguments", | |
| "task foo(string name, int a);" | |
| "endtask", | |
| TaskDeclaration(0, | |
| N(0, L(0, {"task", "foo", "("}), | |
| TFPortList(2, // | |
| L(2, {"string", "name", ","}), // | |
| L(2, {"int", "a", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with local variable", | |
| "task foo;" | |
| "int return_value;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| L(1, {"int", "return_value", ";"}), L(0, {"endtask"})), | |
| }, | |
| { | |
| "in task, implicit-type data declaration, singleton", | |
| "task t ;a;endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), L(1, {"a", ";"}), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "in task, two implicit-type data declaration", | |
| "task t;a;b;endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"a", ";"}), // | |
| L(1, {"b", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with multiple local variables in single declaration", | |
| "task foo;" | |
| "int r1, r2;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| DataDeclaration(1, L(1, {"int"}), // | |
| N(3, // | |
| L(3, {"r1", ","}), // | |
| L(3, {"r2", ";"}) // | |
| )), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with local variable and qualifier", | |
| "task foo;" | |
| "static int return_value;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| DataDeclaration(1, L(1, {"static"}), L(1, {"int"}), | |
| L(1, {"return_value", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with subtask call", | |
| "task foo;" | |
| "$makeitso(x);" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| N(1, L(1, {"$makeitso", "("}), L(3, {"x", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assignment to call expression", | |
| "task foo;" | |
| "y = makeitso(x);" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| N(1, L(1, {"y", "=", "makeitso", "("}), L(3, {"x"}), | |
| L(1, {")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with system call inside if header", | |
| "task t;" | |
| "if (!$cast(ssssssssssssssss, vvvvvvvvvv, gggggggg)) begin " | |
| "end " | |
| "endtask : t", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| N(1, | |
| N(1, L(1, {"if", "(", "!", "$cast", "("}), | |
| N(5, L(5, {"ssssssssssssssss", ","}), | |
| L(5, {"vvvvvvvvvv", ","}), L(5, {"gggggggg"})), | |
| L(3, {")", ")", "begin"})), | |
| L(1, {"end"})), | |
| L(0, {"endtask", ":", "t"})), | |
| }, | |
| { | |
| "task with nested subtask call and arguments passed by name", | |
| "task t;" | |
| "if (!$cast(ssssssssssssssss, vvvvvvvvvv.gggggggg(" | |
| ".ppppppp(ppppppp)," | |
| ".yyyyy(\"xxxxxxxxxxxxx\")" | |
| "))) begin " | |
| "end " | |
| "endtask : t", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "t", ";"}), | |
| N(1, | |
| N(1, L(1, {"if", "(", "!", "$cast", "("}), | |
| N(5, L(5, {"ssssssssssssssss", ","}), | |
| L(5, {"vvvvvvvvvv", ".", "gggggggg", "("}), | |
| N(7, L(7, {".", "ppppppp", "(", "ppppppp", ")", ","}), | |
| L(7, {".", "yyyyy", "(", "\"xxxxxxxxxxxxx\"", ")"})), | |
| L(5, {")"})), | |
| L(3, {")", ")", "begin"})), | |
| L(1, {"end"})), | |
| L(0, {"endtask", ":", "t"})), | |
| }, | |
| { | |
| "task with delayed assignment", | |
| "task foo;" | |
| "#100 " | |
| "bar = 13;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| N(1, // delayed assignment | |
| L(1, {"#", "100"}), L(2, {"bar", "=", "13", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with multiple nonblocking assignments", | |
| "task t; a<=b; c<=d; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "<=", "b", ";"}), | |
| L(1, {"c", "<=", "d", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with arithmetic assignment operators", | |
| "task t; a=b; c+=d; e-=f; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "=", "b", ";"}), | |
| L(1, {"c", "+=", "d", ";"}), | |
| L(1, {"e", "-=", "f", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with arithmetic assignment operators", | |
| "task t; a*=b; c=d; e/=f; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "*=", "b", ";"}), | |
| L(1, {"c", "=", "d", ";"}), | |
| L(1, {"e", "/=", "f", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with modulus assignment operator", | |
| "task t; a%=b; c=d; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "%=", "b", ";"}), | |
| L(1, {"c", "=", "d", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with bitwise assignment operators", | |
| "task t; a&=b; c|=d; e^=f; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "&=", "b", ";"}), | |
| L(1, {"c", "|=", "d", ";"}), | |
| L(1, {"e", "^=", "f", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with logical shift assignment operators", | |
| "task t; a<<=b; c>>=d; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "<<=", "b", ";"}), | |
| L(1, {"c", ">>=", "d", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with arithmetic shift assignment operators", | |
| "task t; a<<<=b; c>>>=d; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, L(1, {"a", "<<<=", "b", ";"}), | |
| L(1, {"c", ">>>=", "d", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with empty fork-join pairs", | |
| "task forkit;" | |
| "fork join fork join " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "forkit", ";"}), | |
| StatementList(1, ParBlock(1, L(1, {"fork"}), L(1, {"join"})), | |
| ParBlock(1, L(1, {"fork"}), L(1, {"join"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with empty fork-join pairs, labeled", | |
| "task forkit;" | |
| "fork:a join:a fork:b join:b " | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "forkit", ";"}), | |
| StatementList(1, | |
| ParBlock(1, L(1, {"fork", ":", "a"}), | |
| L(1, {"join", ":", "a"})), | |
| ParBlock(1, L(1, {"fork", ":", "b"}), | |
| L(1, {"join", ":", "b"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with fork-join around comments", | |
| "task forkit;" | |
| "fork\n" | |
| "// comment1\n" | |
| "join\n" | |
| "fork\n" | |
| "// comment2\n" | |
| "join " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "forkit", ";"}), | |
| StatementList(1, | |
| ParBlock(1, L(1, {"fork"}), L(2, {"// comment1"}), // | |
| L(1, {"join"})), // | |
| ParBlock(1, L(1, {"fork"}), // | |
| L(2, {"// comment2"}), // | |
| L(1, {"join"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with fork-join", | |
| "task foo;" | |
| "fork " | |
| "int value;" | |
| "join " | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| ParBlock(1, L(1, {"fork"}), L(2, {"int", "value", ";"}), | |
| L(1, {"join"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with fork-join-disable", | |
| "task foo;" | |
| "fork " | |
| "int value;" | |
| "join " | |
| "disable fork;" | |
| "endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "foo", ";"}), | |
| StatementList(1, | |
| ParBlock(1, L(1, {"fork"}), | |
| L(2, {"int", "value", ";"}), L(1, {"join"})), | |
| L(1, {"disable", "fork", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with fork-join_any-disable", | |
| "task foo;" | |
| "fork " | |
| "join_any " | |
| "disable fork;" | |
| "endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "foo", ";"}), | |
| StatementList(1, ParBlock(1, L(1, {"fork"}), L(1, {"join_any"})), | |
| L(1, {"disable", "fork", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with disable", | |
| "task foo;" | |
| "disable other;" | |
| "endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "foo", ";"}), | |
| L(1, {"disable", "other", ";"}), L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with sequential-block inside parallel-block", | |
| "task fj; fork foo(); begin end join endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "fj", ";"}), | |
| ParBlock(1, L(1, {"fork"}), | |
| StatementList(2, // | |
| L(2, {"foo", "(", ")", ";"}), // | |
| N(2, L(2, {"begin"}), // | |
| L(2, {"end"}))), | |
| L(1, {"join"})), | |
| L(0, {"endtask"})), | |
| }, | |
| // TODO(fangism): "task with while loop and single statement" | |
| { | |
| "task with while loop and block statement", | |
| "task foo;" | |
| "while (1) begin " | |
| "$makeitso(x);" | |
| "end " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "foo", ";"}), | |
| FlowControl(1, L(1, {"while", "(", "1", ")", "begin"}), | |
| N(2, L(2, {"$makeitso", "("}), L(4, {"x", ")", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with formal parameters declared in-body", | |
| "task automatic clean_up;" | |
| "input logic addr;" | |
| "input logic mask;" | |
| "endtask", | |
| TaskDeclaration(0, | |
| TaskHeader(0, {"task", "automatic", "clean_up", ";"}), | |
| StatementList(1, L(1, {"input", "logic", "addr", ";"}), | |
| L(1, {"input", "logic", "mask", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task inside class with delayed assignment", | |
| "class c; task automatic waiter;" | |
| "#0 z = v; endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration(1, L(1, {"task", "automatic", "waiter", ";"}), | |
| N(2, // delayed assignment | |
| L(2, {"#", "0"}), L(3, {"z", "=", "v", ";"})), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task inside class with labeled assignment", | |
| "class c; task automatic waiter;" | |
| "foo: z = v; endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration(1, L(1, {"task", "automatic", "waiter", ";"}), | |
| N(2, // labeled assignment | |
| L(2, {"foo", ":"}), L(2, {"z", "=", "v", ";"})), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task inside class with labeled and delayed assignment", | |
| "class c; task automatic waiter;" | |
| "foo: #1 z = v; endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration( | |
| 1, L(1, {"task", "automatic", "waiter", ";"}), | |
| N(2, // labeled and delayed assignment | |
| L(2, {"foo", ":"}), // | |
| N(2, L(2, {"#", "1"}), L(3, {"z", "=", "v", ";"}))), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task inside class with procedural timing control statement " | |
| "and null-statement", | |
| "class c; task automatic waiter;" | |
| "#0; return; endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration( | |
| 1, L(1, {"task", "automatic", "waiter", ";"}), | |
| StatementList(2, // | |
| L(2, {"#", "0", ";"}), // timing control | |
| L(2, {"return", ";"})), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with simple event control statement and null-statement", | |
| "class c; task automatic clocker;" | |
| "@(posedge clk); endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration( | |
| 1, L(1, {"task", "automatic", "clocker", ";"}), | |
| L(2, {"@", "(", "posedge", "clk", ")", ";"}), // event control | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with multiple event control statements", | |
| "class c; task automatic clocker;" | |
| "@(posedge clk); @(negedge clk); endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration( | |
| 1, L(1, {"task", "automatic", "clocker", ";"}), | |
| StatementList(2, // | |
| L(2, {"@", "(", "posedge", "clk", ")", ";"}), | |
| L(2, {"@", "(", "negedge", "clk", ")", ";"})), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with repeated event control statement and null-statement", | |
| "class c; task automatic clocker;" | |
| "repeat (2) @(posedge clk); endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration(1, L(1, {"task", "automatic", "clocker", ";"}), | |
| FlowControl(2, // | |
| L(2, {"repeat", "(", "2", ")"}), | |
| L(3, {"@", "(", "posedge", "clk", ")", | |
| ";"}) // event control | |
| ), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with multiple repeat event control statements", | |
| "class c; task automatic clocker;" | |
| "repeat (2) @(posedge clk);" | |
| "repeat (4) @(negedge clk); endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration( | |
| 1, L(1, {"task", "automatic", "clocker", ";"}), | |
| StatementList( | |
| 2, // | |
| FlowControl(2, // | |
| L(2, {"repeat", "(", "2", ")"}), | |
| L(3, {"@", "(", "posedge", "clk", ")", ";"})), | |
| FlowControl(2, // | |
| L(2, {"repeat", "(", "4", ")"}), | |
| L(3, {"@", "(", "negedge", "clk", ")", ";"}))), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with nested repeated event control statements", | |
| "class c; task automatic clocker;" | |
| "repeat (n) repeat (m) @(posedge clk); endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration(1, L(1, {"task", "automatic", "clocker", ";"}), | |
| FlowControl(2, // | |
| L(2, {"repeat", "(", "n", ")"}), | |
| N(3, // | |
| L(3, {"repeat", "(", "m", ")"}), | |
| L(4, {"@", "(", "posedge", "clk", ")", | |
| ";"}) // single null-statement | |
| )), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with nested if statements, single-statement body", | |
| "class c; task automatic iffer;" | |
| "if (n) if (m) y = x; endtask endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "c", ";"}), | |
| TaskDeclaration(1, L(1, {"task", "automatic", "iffer", ";"}), | |
| FlowControl(2, // | |
| L(2, {"if", "(", "n", ")"}), | |
| N(3, // | |
| L(3, {"if", "(", "m", ")"}), | |
| L(4, {"y", "=", "x", | |
| ";"}) // single statement body | |
| )), | |
| L(1, {"endtask"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "task with assert statements, null action", | |
| "task t; Fire(); assert (x); assert(y); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| L(1, {"assert", "(", "x", ")", ";"}), | |
| L(1, {"assert", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert statements, non-null action", | |
| "task t; Fire(); assert (x) g(); assert(y) h(); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| N(1, // | |
| L(1, {"assert", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"assert", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else statements, empty assert body, with else action", | |
| "task t; assert (x) else g(); assert(y) else h(); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"g", "(", ")", ";"}))), | |
| N(1, // | |
| L(1, {"assert", "(", "y", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else statements, with body/else action block", | |
| "task t; assert (x) else begin g(); end " | |
| "assert(y) begin jk(); end else h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else statement, with action blocks in both clauses", | |
| "task t; assert(y) begin jk(); end else begin h(); end endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume statements, null action", | |
| "task t; Fire(); assume (x); assume(y); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| L(1, {"assume", "(", "x", ")", ";"}), | |
| L(1, {"assume", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume statements, non-null action", | |
| "task t; Fire(); assume (x) g(); assume(y) h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList( | |
| 1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| N(1, // | |
| L(1, {"assume", "(", "x", ")"}), L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"assume", "(", "y", ")"}), L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else statements, empty assume body, with else action", | |
| "task t; assume (x) else g(); assume(y) else h(); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"g", "(", ")", ";"}))), | |
| N(1, // | |
| L(1, {"assume", "(", "y", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else statements, with body/else action block", | |
| "task t; assume (x) else begin g(); end " | |
| "assume(y) begin jk(); end else h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else statement, with action blocks in both clauses", | |
| "task t; assume(y) begin jk(); end else begin h(); end endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover statements, null action", | |
| "task t; Fire(); cover (x); cover(y); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| L(1, {"cover", "(", "x", ")", ";"}), | |
| L(1, {"cover", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover statements, non-null action", | |
| "task t; Fire(); cover (x) g(); cover(y) h(); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| N(1, // | |
| L(1, {"cover", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"cover", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover statements, action block", | |
| "task t; Fire(); cover (x) begin g();end " | |
| "cover(y) begin h(); end endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"Fire", "(", ")", ";"}), | |
| N(1, // | |
| L(1, {"cover", "(", "x", ")", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"})), | |
| N(1, // | |
| L(1, {"cover", "(", "y", ")", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with wait statements, null action", | |
| "task t; wait (a==b); wait(c<d); endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"wait", "(", "a", "==", "b", ")", ";"}), | |
| L(1, {"wait", "(", "c", "<", "d", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with wait statements, non-null action", | |
| "task t; wait (a==b) run(); wait(c<d) walk(); endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"wait", "(", "a", "==", "b", ")"}), | |
| L(2, {"run", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"wait", "(", "c", "<", "d", ")"}), | |
| L(2, {"walk", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with wait statements, action block", | |
| "task t; wait (a==b) begin run(); end " | |
| "wait(c<d) begin walk(); end endtask", | |
| TaskDeclaration( | |
| 0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"wait", "(", "a", "==", "b", ")", "begin"}), | |
| L(2, {"run", "(", ")", ";"}), // | |
| L(1, {"end"})), | |
| N(1, // | |
| L(1, {"wait", "(", "c", "<", "d", ")", "begin"}), | |
| L(2, {"walk", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with wait fork statements", | |
| "task t; wait fork ; wait fork; endtask", | |
| TaskDeclaration(0, TaskHeader(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"wait", "fork", ";"}), | |
| L(1, {"wait", "fork", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert property statements, null action", | |
| "task t; assert property (x); assert property(y); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"assert", "property", "(", "x", ")", ";"}), | |
| L(1, {"assert", "property", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert property statements, non-null action", | |
| "task t; assert property (x) g(); assert property(y) h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assert", "property", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"assert", "property", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else property statements, empty assert body, with " | |
| "else action", | |
| "task t; assert property (x) else g(); assert property(y) else h(); " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assert", "property", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"g", "(", ")", ";"}))), | |
| N(1, // | |
| L(1, {"assert", "property", "(", "y", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else property statements, with body/else action " | |
| "block", | |
| "task t; assert property (x) else begin g(); end " | |
| "assert property(y) begin jk(); end else h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList( | |
| 1, // | |
| N(1, // | |
| L(1, {"assert", "property", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assert", "property", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assert-else property statement, with action blocks in both " | |
| "clauses", | |
| "task t; assert property (y) begin jk(); end else begin h(); end " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assert", "property", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume property statements, null action", | |
| "task t; assume property (x); assume property(y); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"assume", "property", "(", "x", ")", ";"}), | |
| L(1, {"assume", "property", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume property statements, non-null action", | |
| "task t; assume property (x) g(); assume property(y) h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assume", "property", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"assume", "property", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else property statements, empty assume body, with " | |
| "else action", | |
| "task t; assume property (x) else g(); assume property(y) else h(); " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"assume", "property", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"g", "(", ")", ";"}))), | |
| N(1, // | |
| L(1, {"assume", "property", "(", "y", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else property statements, with body/else action " | |
| "block", | |
| "task t; assume property (x) else begin g(); end " | |
| "assume property(y) begin jk(); end else h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList( | |
| 1, // | |
| N(1, // | |
| L(1, {"assume", "property", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assume", "property", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with assume-else property statement, with action blocks in both " | |
| "clauses", | |
| "task t; assume property (y) begin jk(); end else begin h(); end " | |
| "endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| N(1, // | |
| N(1, // | |
| L(1, {"assume", "property", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with expect property statements, null action", | |
| "task t; expect (x); expect (y); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"expect", "(", "x", ")", ";"}), | |
| L(1, {"expect", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with expect property statements, non-null action", | |
| "task t; expect (x) g(); expect (y) h(); endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"expect", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"expect", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with expect-else property statements, empty expect body, with " | |
| "else action", | |
| "task t; expect (x) else g(); expect (y) else h(); " | |
| "endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"expect", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"g", "(", ")", ";"}))), | |
| N(1, // | |
| L(1, {"expect", "(", "y", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with expect-else property statements, with body/else action " | |
| "block", | |
| "task t; expect (x) else begin g(); end " | |
| "expect (y) begin jk(); end else h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"expect", "(", "x", ")"}), | |
| N(1, // | |
| L(1, {"else", "begin"}), // | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| N(1, // | |
| N(1, // | |
| L(1, {"expect", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else"}), // | |
| L(2, {"h", "(", ")", ";"})))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with expect-else property statement, with action blocks in both " | |
| "clauses", | |
| "task t; expect (y) begin jk(); end else begin h(); end " | |
| "endtask", | |
| TaskDeclaration(0, L(0, {"task", "t", ";"}), | |
| N(1, // | |
| N(1, // | |
| L(1, {"expect", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"h", "(", ")", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover property statements, null action", | |
| "task t; cover property (x); cover property(y); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"cover", "property", "(", "x", ")", ";"}), | |
| L(1, {"cover", "property", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover property statements, non-null action", | |
| "task t; cover property (x) g(); cover property(y) h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"cover", "property", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"cover", "property", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover property statements, with block action " | |
| "block", | |
| "task t; cover property (x) begin g(); end " | |
| "cover property(y) begin jk(); end endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"cover", "property", "(", "x", ")", "begin"}), | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"})), | |
| N(1, // | |
| L(1, {"cover", "property", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"}), // | |
| L(1, {"end"}))), // | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover sequence statements, null action", | |
| "task t; cover sequence (x); cover sequence(y); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| L(1, {"cover", "sequence", "(", "x", ")", ";"}), | |
| L(1, {"cover", "sequence", "(", "y", ")", ";"})), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover sequence statements, non-null action", | |
| "task t; cover sequence (x) g(); cover sequence(y) h(); endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"cover", "sequence", "(", "x", ")"}), // | |
| L(2, {"g", "(", ")", ";"})), | |
| N(1, // | |
| L(1, {"cover", "sequence", "(", "y", ")"}), // | |
| L(2, {"h", "(", ")", ";"}))), | |
| L(0, {"endtask"})), | |
| }, | |
| { | |
| "task with cover sequence statements, with block action " | |
| "block", | |
| "task t; cover sequence (x) begin g(); end " | |
| "cover sequence(y) begin jk(); end endtask", | |
| TaskDeclaration( | |
| 0, L(0, {"task", "t", ";"}), | |
| StatementList(1, // | |
| N(1, // | |
| L(1, {"cover", "sequence", "(", "x", ")", "begin"}), | |
| L(2, {"g", "(", ")", ";"}), // | |
| L(1, {"end"})), | |
| N(1, // | |
| L(1, {"cover", "sequence", "(", "y", ")", "begin"}), | |
| L(2, {"jk", "(", ")", ";"}), // | |
| L(1, {"end"}))), // | |
| L(0, {"endtask"})), | |
| }, | |
| // TODO(fangism): test calls to UVM macros | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from task tests | |
| TEST_F(TreeUnwrapperTest, UnwrapTaskTests) { | |
| for (const auto& test_case : kUnwrapTaskTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapFunctionTestCases[] = { | |
| { | |
| "empty function", | |
| "function foo;" | |
| "endfunction : foo", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| L(0, {"endfunction", ":", "foo"})), | |
| }, | |
| { | |
| "empty function, comment statement", | |
| "function foo;// foo does x\n" | |
| "// statement comment\n" | |
| "endfunction : foo", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";", "// foo does x"}), | |
| L(1, {"// statement comment"}), L(0, {"endfunction", ":", "foo"})), | |
| }, | |
| { | |
| "two empty functions", | |
| "function funk;" | |
| "endfunction : funk " | |
| "function foo;" | |
| "endfunction : foo", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "funk", ";"}), | |
| L(0, {"endfunction", ":", "funk"})), | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| L(0, {"endfunction", ":", "foo"})), | |
| }, | |
| { | |
| "empty function, empty ports, comment statement", | |
| "function foo();// foo\n" | |
| "// statement comment\n" | |
| "endfunction : foo", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", "(", ")", ";", "// foo"}), | |
| L(1, {"// statement comment"}), L(0, {"endfunction", ":", "foo"})), | |
| }, | |
| { | |
| "function with empty formal arguments", | |
| "function void foo();" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "void", "foo", "(", ")", ";"}), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with formal argument", | |
| "function foo(string name);" | |
| "endfunction : foo", | |
| FunctionDeclaration(0, | |
| N(0, L(0, {"function", "foo", "("}), | |
| L(2, {"string", "name", ")", ";"})), | |
| L(0, {"endfunction", ":", "foo"})), | |
| }, | |
| { | |
| "function with multiple formal arguments", | |
| "function foo(string name, int a);" | |
| "endfunction", | |
| FunctionDeclaration(0, | |
| N(0, L(0, {"function", "foo", "("}), | |
| TFPortList(2, // | |
| L(2, {"string", "name", ","}), // | |
| L(2, {"int", "a", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with local variable", | |
| "function foo;" | |
| "int value;" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| L(1, {"int", "value", ";"}), L(0, {"endfunction"})), | |
| }, | |
| { | |
| "in function, implicit-type data declaration, singleton", | |
| "function f ;a;endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "f", ";"}), | |
| L(1, {"a", ";"}), L(0, {"endfunction"})), | |
| }, | |
| { | |
| "in function, two implicit-type data declaration", | |
| "function f;a;b;endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "f", ";"}), | |
| StatementList(1, // | |
| L(1, {"a", ";"}), // | |
| L(1, {"b", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assignment to call expression", | |
| "function foo;" | |
| "y = twister(x, 1);" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, L(1, {"y", "=", "twister", "("}), | |
| N(3, L(3, {"x", ","}), L(3, {"1"})), L(1, {")", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with multiple statements", | |
| "function foo;" | |
| "y = twister(x, 1);" | |
| "z = twister(x, 2);" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList( | |
| 1, | |
| N(1, L(1, {"y", "=", "twister", "("}), | |
| N(3, L(3, {"x", ","}), L(3, {"1"})), L(1, {")", ";"})), | |
| N(1, L(1, {"z", "=", "twister", "("}), | |
| N(3, L(3, {"x", ","}), L(3, {"2"})), L(1, {")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with foreach block with multiple statements", | |
| "function foo;" | |
| "foreach (x[i]) begin " | |
| "y = twister(x[i], 1);" | |
| "z = twister(x[i], 2);" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl( | |
| 1, L(1, {"foreach", "(", "x", "[", "i", "]", ")", "begin"}), | |
| StatementList( | |
| 2, | |
| N(2, L(2, {"y", "=", "twister", "("}), | |
| N(4, L(4, {"x", "[", "i", "]", ","}), L(4, {"1"})), | |
| L(2, {")", ";"})), | |
| N(2, L(2, {"z", "=", "twister", "("}), | |
| N(4, L(4, {"x", "[", "i", "]", ","}), L(4, {"2"})), | |
| L(2, {")", ";"}))), | |
| L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with foreach block with single statements", | |
| "function foo;" | |
| "foreach (x[i]) y = twister(x[i], 1);" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"foreach", "(", "x", "[", "i", "]", ")"}), | |
| N(2, L(2, {"y", "=", "twister", "("}), | |
| N(4, L(4, {"x", "[", "i", "]", ","}), L(4, {"1"})), | |
| L(2, {")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with nested foreach block with single statements", | |
| "function foo;" | |
| "foreach (x[i]) foreach(j[k]) y = x;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"foreach", "(", "x", "[", "i", "]", ")"}), // | |
| N(2, // | |
| L(2, {"foreach", "(", "j", "[", "k", "]", ")"}), // | |
| L(3, {"y", "=", "x", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assignment to macro call", | |
| "function foo;" | |
| "y = `TWISTER(x, y);" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, L(1, {"y", "=", "`TWISTER", "("}), | |
| MacroArgList(3, L(3, {"x", ","}), L(3, {"y", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with array formal parameters and return statement", | |
| "function automatic logic checkit (" | |
| "input logic [4:0] a," | |
| "input logic [4:0] b);" | |
| "return a ^ b;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, | |
| N(0, // | |
| L(0, {"function", "automatic", "logic", "checkit", "("}), | |
| TFPortList( | |
| 2, | |
| L(2, {"input", "logic", "[", "4", ":", "0", "]", "a", ","}), | |
| L(2, {"input", "logic", "[", "4", ":", "0", "]", "b", ")", | |
| ";"}))), | |
| L(1, {"return", "a", "^", "b", ";"}), L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with formal parameters declared in-body", | |
| "function automatic index_t make_index;" | |
| "input logic [1:0] addr;" | |
| "input mode_t mode;" | |
| "input logic [2:0] hash_mask;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, | |
| FunctionHeader( | |
| 0, {"function", "automatic", "index_t", "make_index", ";"}), | |
| StatementList( | |
| 1, | |
| L(1, {"input", "logic", "[", "1", ":", "0", "]", "addr", ";"}), | |
| L(1, {"input", "mode_t", "mode", ";"}), | |
| L(1, {"input", "logic", "[", "2", ":", "0", "]", "hash_mask", | |
| ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with back-to-back if statements", | |
| "function foo;" | |
| "if (zz) begin " | |
| "return 0;" | |
| "end " | |
| "if (yy) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList(1, | |
| FlowControl(1, // | |
| L(1, {"if", "(", "zz", ")", "begin"}), | |
| L(2, {"return", "0", ";"}), // | |
| L(1, {"end"})), // | |
| FlowControl(1, L(1, {"if", "(", "yy", ")", "begin"}), | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with back-to-back if statements, single-statement body", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "if (yy) " | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList(1, | |
| FlowControl(1, // | |
| L(1, {"if", "(", "zz", ")"}), | |
| L(2, {"return", "0", ";"})), | |
| FlowControl(1, // | |
| L(1, {"if", "(", "yy", ")"}), | |
| L(2, {"return", "1", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with back-to-back if statements, null body", | |
| "function foo;" | |
| "if (zz);" | |
| "if (yy);" | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList(1, L(1, {"if", "(", "zz", ")", ";"}), | |
| L(1, {"if", "(", "yy", ")", ";"}), | |
| L(1, {"return", "1", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with back-to-back if-else statements, null bodies", | |
| "function foo;" | |
| "if (zz); else ;" // yes, this is syntactically legal | |
| "if (yy); else ;" | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList(1, | |
| FlowControl(1, // | |
| L(1, {"if", "(", "zz", ")", ";"}), // | |
| L(1, {"else", ";"})), | |
| FlowControl(1, // | |
| L(1, {"if", "(", "yy", ")", ";"}), // | |
| L(1, {"else", ";"})), | |
| L(1, {"return", "1", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with if-else branches in begin/end", | |
| "function foo;" | |
| "if (zz) begin " | |
| "return 0;" | |
| "end else begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")", "begin"}), // | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with if-else branches, single-statements", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "else " | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"return", "1", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with else-if branches in begin/end", | |
| "function foo;" | |
| "if (zz) begin " | |
| "return 0;" | |
| "end else if (yy) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")", "begin"}), | |
| L(2, {"return", "0", ";"})), | |
| N(1, // | |
| L(1, {"end", "else", "if", "(", "yy", ")", "begin"}), | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with else-if branches, single-statements", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "else if (yy) " | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")"}), // same level | |
| L(2, {"return", "1", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with two else-if branches, single-statements", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "else if (yy) " | |
| "return 1;" | |
| "else if (xx) " | |
| "return 2;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")"}), // same level | |
| L(2, {"return", "1", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "xx", ")"}), // same level | |
| L(2, {"return", "2", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with else-if branches, trailing else branch, " | |
| "single-statements", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "else if (yy) " | |
| "return 1;" | |
| "else " | |
| "return 2;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")"}), // same level | |
| L(2, {"return", "1", ";"})), // | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"return", "2", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with many else-if branches, single-statements", | |
| "function foo;" | |
| "if (zz) " | |
| "return 0;" | |
| "else if (yy) " | |
| "return 1;" | |
| "else if (xx) " | |
| "return 2;" | |
| "else if (ww) " | |
| "return 3;" | |
| "else if (vv) " | |
| "return 4;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")"}), // same level | |
| L(2, {"return", "1", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "xx", ")"}), // same level | |
| L(2, {"return", "2", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "ww", ")"}), // same level | |
| L(2, {"return", "3", ";"})), | |
| N(1, // | |
| L(1, {"else", "if", "(", "vv", ")"}), // same level | |
| L(2, {"return", "4", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with else-if branches, labeled begin and end", | |
| "function foo;" | |
| "if (zz) begin : label1 " | |
| "return 0;" | |
| "end : label1 " | |
| "else if (yy) begin : label2 " | |
| "return 1;" | |
| "end : label2 " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl( | |
| 1, | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")", "begin", ":", "label1"}), | |
| L(2, {"return", "0", ";"}), // | |
| L(1, {"end", ":", "label1"})), // | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")", "begin", ":", "label2"}), | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end", ":", "label2"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with else-if-else branches, labeled begin and end", | |
| "function foo;" | |
| "if (zz) begin : label1 " | |
| "return 0;" | |
| "end : label1 " | |
| "else if (yy) begin : label2 " | |
| "return 1;" | |
| "end : label2 " | |
| "else begin : label3 " | |
| "return 2;" | |
| "end : label3 " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl( | |
| 1, | |
| N(1, // | |
| L(1, {"if", "(", "zz", ")", "begin", ":", "label1"}), | |
| L(2, {"return", "0", ";"}), // | |
| L(1, {"end", ":", "label1"})), // | |
| N(1, // | |
| L(1, {"else", "if", "(", "yy", ")", "begin", ":", "label2"}), | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end", ":", "label2"})), // | |
| N(1, // | |
| L(1, {"else", "begin", ":", "label3"}), // | |
| L(2, {"return", "2", ";"}), // | |
| L(1, {"end", ":", "label3"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assertion statements, null-statements", | |
| "function foo;" | |
| "assert (b); " | |
| "assert (c); " | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, // | |
| L(1, {"assert", "(", "b", ")", ";"}), // | |
| L(1, {"assert", "(", "c", ")", ";"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with deferred assertion statements, null-statements", | |
| "function foo;" | |
| "assert final(b); " | |
| "assert #0(c); " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, // | |
| L(1, {"assert", "final", "(", "b", ")", ";"}), // | |
| L(1, {"assert", "#", "0", "(", "c", ")", ";"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assert-else branches in begin/end", | |
| "function foo;" | |
| "assert (zz) begin " | |
| "return 0;" | |
| "end else begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "zz", ")", "begin"}), // | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assert-else branches, null assert-clause-body", | |
| "function foo;" | |
| "assert (zz) " | |
| "else " | |
| "foo();" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"assert", "(", "zz", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"foo", "(", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assert-else branches, single-statements", | |
| "function foo;" | |
| "assert (zz) " | |
| "return 0;" | |
| "else " | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"assert", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"return", "1", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assume statements, null-statements", | |
| "function foo;" | |
| "assume (b); " | |
| "assume (c); " | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, // | |
| L(1, {"assume", "(", "b", ")", ";"}), // | |
| L(1, {"assume", "(", "c", ")", ";"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with deferred assume statements, null-statements", | |
| "function foo;" | |
| "assume final(b); " | |
| "assume #0(c); " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| N(1, // | |
| L(1, {"assume", "final", "(", "b", ")", ";"}), // | |
| L(1, {"assume", "#", "0", "(", "c", ")", ";"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assume-else branches in begin/end", | |
| "function foo;" | |
| "assume (zz) begin " | |
| "return 0;" | |
| "end else begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "zz", ")", "begin"}), // | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"end", "else", "begin"}), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assume-else branches, null assume-clause-body", | |
| "function foo;" | |
| "assume (zz) " | |
| "else " | |
| "foo();" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"assume", "(", "zz", ")"}), | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"foo", "(", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with assume-else branches, single-statements", | |
| "function foo;" | |
| "assume (zz) " | |
| "return 0;" | |
| "else " | |
| "return 1;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| N(1, // | |
| L(1, {"assume", "(", "zz", ")"}), // same level | |
| L(2, {"return", "0", ";"})), // | |
| N(1, // | |
| L(1, {"else"}), // same level | |
| L(2, {"return", "1", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with for loop", | |
| "function foo;" | |
| "for (x=0;x<N;++x) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"x", "=", "0", ";"}), | |
| L(3, {"x", "<", "N", ";"}), | |
| L(3, {"++", "x"})), | |
| L(1, {")", "begin"})), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with for loop, null-statements", | |
| "function foo;" | |
| "for (;;); " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {";"}), L(3, {";"})), | |
| L(1, {")"})), // | |
| L(2, {";"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with for loop, single-statement body", | |
| "function foo;" | |
| "for (x=0;x<N;++x) y=x;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"x", "=", "0", ";"}), | |
| L(3, {"x", "<", "N", ";"}), | |
| L(3, {"++", "x"})), | |
| L(1, {")"})), | |
| L(2, {"y", "=", "x", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with for loop, labeled begin and end", | |
| "function foo;" | |
| "for (x=0;x<N;++x) begin:yyy " | |
| "return 1;" | |
| "end:yyy " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {"x", "=", "0", ";"}), | |
| L(3, {"x", "<", "N", ";"}), | |
| L(3, {"++", "x"})), | |
| L(1, {")", "begin", ":", "yyy"})), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end", ":", "yyy"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with forever loop, block statement body", | |
| "function foo;" | |
| "forever begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, L(1, {"forever", "begin"}), | |
| L(2, {"return", "1", ";"}), L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with forever loop, single-statement body", | |
| "function foo;" | |
| "forever break; " | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"forever"}), // | |
| L(2, {"break", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with repeat loop, block statement body", | |
| "function foo;" | |
| "repeat (2) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"repeat", "(", "2", ")", "begin"}), | |
| L(2, {"return", "1", ";"}), L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with repeat loop, single-statement body", | |
| "function foo;" | |
| "repeat (2) continue; " | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"repeat", "(", "2", ")"}), // | |
| L(2, {"continue", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with while loop, block statement body", | |
| "function foo;" | |
| "while (x) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, L(1, {"while", "(", "x", ")", "begin"}), | |
| L(2, {"return", "1", ";"}), L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with while loop, single-statement body", | |
| "function foo;" | |
| "while (e) coyote(sooper_genius); " | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, L(1, {"while", "(", "e", ")"}), | |
| N(2, L(2, {"coyote", "("}), | |
| L(4, {"sooper_genius", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with nested while loop, single-statement body", | |
| "function foo;" | |
| "while (e) while (e) coyote(sooper_genius); " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"while", "(", "e", ")"}), | |
| N(2, // | |
| L(2, {"while", "(", "e", ")"}), | |
| N(3, L(3, {"coyote", "("}), | |
| L(5, {"sooper_genius", ")", ";"})))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with do-while loop, null-statement", | |
| "function foo;" | |
| "do;" | |
| "while (y);" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"do"}), // | |
| L(2, {";"}), // | |
| L(1, {"while", "(", "y", ")", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with do-while loop", | |
| "function foo;" | |
| "do begin " | |
| "return 1;" | |
| "end while (y);" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, L(1, {"do", "begin"}), L(2, {"return", "1", ";"}), | |
| L(1, {"end", "while", "(", "y", ")", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with do-while loop, single-statement", | |
| "function foo;" | |
| "do --y;" | |
| "while (y);" | |
| "endfunction", | |
| FunctionDeclaration(0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl(1, // | |
| L(1, {"do"}), // | |
| L(2, {"--", "y", ";"}), // | |
| L(1, {"while", "(", "y", ")", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with foreach loop", | |
| "function foo;" | |
| "foreach (x[k]) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| FlowControl( | |
| 1, L(1, {"foreach", "(", "x", "[", "k", "]", ")", "begin"}), | |
| L(2, {"return", "1", ";"}), L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with loops", | |
| "function foo;" | |
| "for (;;) begin " | |
| "return 0;" | |
| "end " | |
| "for (;;) begin " | |
| "return 1;" | |
| "end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo", ";"}), | |
| StatementList( | |
| 1, | |
| FlowControl(1, // | |
| LoopHeader(1, // | |
| L(1, {"for", "("}), | |
| ForSpec(3, L(3, {";"}), L(3, {";"})), | |
| L(1, {")", "begin"})), // | |
| L(2, {"return", "0", ";"}), // | |
| L(1, {"end"}) // | |
| ), | |
| FlowControl(1, // | |
| LoopHeader(1, L(1, {"for", "("}), | |
| ForSpec(3, L(3, {";"}), L(3, {";"})), | |
| L(1, {")", "begin"})), // | |
| L(2, {"return", "1", ";"}), // | |
| L(1, {"end"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case statements", | |
| "function foo_case;" | |
| "case (y) " | |
| "k1: return 0;" | |
| "k2: return 1;" | |
| "endcase " | |
| "case (z) " | |
| "k3: return 0;" | |
| "k4: return 1;" | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case", ";"}), | |
| StatementList( | |
| 1, | |
| FlowControl(1, L(1, {"case", "(", "y", ")"}), | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k1", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k2", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"})), // | |
| FlowControl(1, L(1, {"case", "(", "z", ")"}), // | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k3", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k4", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case block statements", | |
| "function foo_case_block;" | |
| "case (y) " | |
| "k1: begin return 0; end " | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case_block", ";"}), | |
| FlowControl(1, L(1, {"case", "(", "y", ")"}), | |
| N(2, // | |
| L(2, {"k1", ":", "begin"}), // | |
| L(3, {"return", "0", ";"}), L(2, {"end"})), | |
| L(1, {"endcase"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case inside statements", | |
| "function foo_case_inside;" | |
| "case (y) inside " | |
| "k1: return 0;" | |
| "k2: return 1;" | |
| "endcase " | |
| "case (z) inside " | |
| "k3: return 0;" | |
| "k4: return 1;" | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case_inside", ";"}), | |
| StatementList( | |
| 1, | |
| FlowControl(1, L(1, {"case", "(", "y", ")", "inside"}), | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k1", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k2", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"})), // | |
| FlowControl(1, // | |
| L(1, {"case", "(", "z", ")", "inside"}), // | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k3", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k4", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case inside blocks", | |
| "function foo_case_inside_block;" | |
| "case (y) inside " | |
| "k2: begin return 1; end " | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case_inside_block", ";"}), | |
| FlowControl(1, L(1, {"case", "(", "y", ")", "inside"}), | |
| N(2, // | |
| L(2, {"k2", ":", "begin"}), // | |
| L(3, {"return", "1", ";"}), // | |
| L(2, {"end"})), | |
| L(1, {"endcase"})), // | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case pattern statements", | |
| "function foo_case_pattern;" | |
| "case (y) matches " | |
| ".foo: return 0;" | |
| ".*: return 1;" | |
| "endcase " | |
| "case (z) matches " | |
| ".foo: return 0;" | |
| ".*: return 1;" | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case_pattern", ";"}), | |
| StatementList( | |
| 1, | |
| FlowControl(1, L(1, {"case", "(", "y", ")", "matches"}), | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {".", "foo", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {".*", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"})), // | |
| FlowControl(1, // | |
| L(1, {"case", "(", "z", ")", "matches"}), // | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {".", "foo", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {".*", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with case pattern blocks", | |
| "function foo_case_pattern_block;" | |
| "case (y) matches " | |
| ".foo: begin return 0; end " | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_case_pattern_block", ";"}), | |
| FlowControl(1, L(1, {"case", "(", "y", ")", "matches"}), | |
| N(2, // | |
| L(2, {".", "foo", ":", "begin"}), // | |
| L(3, {"return", "0", ";"}), // | |
| L(2, {"end"})), // | |
| L(1, {"endcase"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with randcase statements", | |
| "function foo_randcase;" | |
| "randcase " | |
| "k1: return 0;" | |
| "k2: return 1;" | |
| "endcase " | |
| "randcase " | |
| "k3: return 0;" | |
| "k4: return 1;" | |
| "endcase " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, FunctionHeader(0, {"function", "foo_randcase", ";"}), | |
| StatementList( | |
| 1, | |
| FlowControl(1, L(1, {"randcase"}), | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k1", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k2", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"})), // | |
| FlowControl(1, L(1, {"randcase"}), // | |
| CaseItemList(2, // | |
| N(2, // | |
| L(2, {"k3", ":"}), // | |
| L(2, {"return", "0", ";"})), | |
| N(2, // | |
| L(2, {"k4", ":"}), // | |
| L(2, {"return", "1", ";"}))), | |
| L(1, {"endcase"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with array formal parameters and return statement", | |
| "function automatic logic checkit (" | |
| "input logic [4:0] a," | |
| "input logic [4:0] b);" | |
| "return a ^ b;" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, | |
| N(0, // | |
| L(0, {"function", "automatic", "logic", "checkit", "("}), | |
| TFPortList( | |
| 2, | |
| L(2, {"input", "logic", "[", "4", ":", "0", "]", "a", ","}), | |
| L(2, {"input", "logic", "[", "4", ":", "0", "]", "b", ")", | |
| ";"}))), | |
| L(1, {"return", "a", "^", "b", ";"}), L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function (class method) constructor with foreach", | |
| "class foo;" | |
| "function new(string name);" | |
| "super.new(name);" | |
| "foreach (bar[j]) begin " | |
| "bar[j] = new();" | |
| "bar[j].x = new();" | |
| "end " | |
| "endfunction " | |
| "endclass", | |
| ClassDeclaration( | |
| 0, L(0, {"class", "foo", ";"}), | |
| FunctionDeclaration( | |
| 1, | |
| N(1, // | |
| L(1, {"function", "new", "("}), // | |
| L(3, {"string", "name", ")", ";"})), | |
| StatementList( | |
| 2, | |
| N(2, L(2, {"super", ".", "new", "("}), | |
| L(4, {"name", ")", ";"})), | |
| FlowControl( | |
| 2, | |
| L(2, | |
| {"foreach", "(", "bar", "[", "j", "]", ")", "begin"}), | |
| StatementList(3, | |
| L(3, {"bar", "[", "j", "]", "=", "new", | |
| "(", ")", ";"}), | |
| L(3, {"bar", "[", "j", "]", ".", "x", "=", | |
| "new", "(", ")", ";"})), | |
| L(2, {"end"}))), | |
| L(1, {"endfunction"})), | |
| L(0, {"endclass"})), | |
| }, | |
| { | |
| "function with randomize-with call with comments", | |
| "function f;\n" | |
| "s = std::randomize() with {\n" | |
| "// comment1\n" | |
| "a == e;\n" | |
| "// comment2\n" | |
| "}; \n" | |
| "endfunction\n", | |
| FunctionDeclaration( | |
| 0, // | |
| L(0, {"function", "f", ";"}), | |
| N(1, // | |
| L(1, {"s", "=", "std::randomize", "(", ")", "with", "{"}), | |
| N(2, // | |
| L(2, {"// comment1"}), // | |
| L(2, {"a", "==", "e", ";"}), // | |
| L(2, {"// comment2"})), // | |
| L(1, {"}", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with randomize-with call with leading comment", | |
| "function f;\n" | |
| "s = std::randomize() with {\n" | |
| "// comment\n" | |
| "a == e;\n" | |
| "if (x) {\n" | |
| "a;\n" | |
| "}\n" | |
| "}; \n" | |
| "endfunction\n", | |
| FunctionDeclaration( | |
| 0, // | |
| L(0, {"function", "f", ";"}), | |
| N(1, // | |
| L(1, {"s", "=", "std::randomize", "(", ")", "with", "{"}), | |
| N(2, // | |
| L(2, {"// comment"}), // | |
| L(2, {"a", "==", "e", ";"}), | |
| N(2, // | |
| L(2, {"if", "(", "x", ")", "{"}), // | |
| L(3, {"a", ";"}), // | |
| L(2, {"}"}))), | |
| L(1, {"}", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with function call inside if statement header", | |
| "function foo;" | |
| "if(aa(bb,cc));" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, L(0, {"function", "foo", ";"}), | |
| N(1, L(1, {"if", "(", "aa", "("}), | |
| N(5, L(5, {"bb", ","}), L(5, {"cc"})), L(3, {")", ")", ";"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with function call inside if statement header and with " | |
| "begin-end block", | |
| "function foo;" | |
| "if (aa(bb,cc,dd,ee))" | |
| "begin end " | |
| "endfunction", | |
| FunctionDeclaration(0, L(0, {"function", "foo", ";"}), | |
| N(1, | |
| N(1, L(1, {"if", "(", "aa", "("}), | |
| N(5, L(5, {"bb", ","}), L(5, {"cc", ","}), | |
| L(5, {"dd", ","}), L(5, {"ee"})), | |
| L(3, {")", ")", "begin"})), | |
| L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "function with kMethodCallExtension inside if statement header and " | |
| "with begin-end block", | |
| "function foo;" | |
| "if (aa.bb(cc,dd,ee))" | |
| "begin end " | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, L(0, {"function", "foo", ";"}), | |
| N(1, | |
| N(1, L(1, {"if", "(", "aa", ".", "bb", "("}), | |
| N(5, L(5, {"cc", ","}), L(5, {"dd", ","}), L(5, {"ee"})), | |
| L(3, {")", ")", "begin"})), | |
| L(1, {"end"})), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "nested kMethodCallExtension calls - one level", | |
| "function foo;" | |
| "aa.bb(cc.dd(a1), ee.ff(a2));" | |
| "endfunction", | |
| FunctionDeclaration(0, L(0, {"function", "foo", ";"}), | |
| N(1, L(1, {"aa", ".", "bb", "("}), | |
| N(3, L(3, {"cc", ".", "dd", "("}), L(5, {"a1"}), | |
| L(3, {")", ","}), L(3, {"ee", ".", "ff", "("}), | |
| L(5, {"a2"}), L(3, {")", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| { | |
| "nested kMethodCallExtension calls - two level", | |
| "function foo;" | |
| "aa.bb(cc.dd(a1.b1(a2), b1), ee.ff(c1, d1));" | |
| "endfunction", | |
| FunctionDeclaration( | |
| 0, L(0, {"function", "foo", ";"}), | |
| N(1, L(1, {"aa", ".", "bb", "("}), | |
| N(3, L(3, {"cc", ".", "dd", "("}), | |
| N(5, L(5, {"a1", ".", "b1", "("}), L(7, {"a2"}), | |
| L(5, {")", ","}), L(5, {"b1"})), | |
| L(3, {")", ","}), L(3, {"ee", ".", "ff", "("}), | |
| N(5, L(5, {"c1", ","}), L(5, {"d1"})), L(3, {")", ")", ";"}))), | |
| L(0, {"endfunction"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from function tests | |
| TEST_F(TreeUnwrapperTest, UnwrapFunctionTests) { | |
| for (const auto& test_case : kUnwrapFunctionTestCases) { | |
| VLOG(4) << "==== kUnwrapFunctionTests ====\n" << test_case.source_code; | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapStructTestCases[] = { | |
| { | |
| "simple struct typedef one member", | |
| "typedef struct {int a;} foo;", | |
| N(0, L(0, {"typedef", "struct", "{"}), L(1, {"int", "a", ";"}), | |
| L(0, {"}", "foo", ";"})), | |
| }, | |
| { | |
| "simple struct typedef multiple members", | |
| "typedef struct {" | |
| "int a;" | |
| "logic [3:0] b;" | |
| "} foo;", | |
| N(0, L(0, {"typedef", "struct", "{"}), | |
| StructUnionMemberList( | |
| 1, L(1, {"int", "a", ";"}), | |
| L(1, {"logic", "[", "3", ":", "0", "]", "b", ";"})), | |
| L(0, {"}", "foo", ";"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from structs | |
| TEST_F(TreeUnwrapperTest, UnwrapStructTests) { | |
| for (const auto& test_case : kUnwrapStructTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapUnionTestCases[] = { | |
| { | |
| "simple union typedef one member", | |
| "typedef union {int a;} foo;", | |
| N(0, L(0, {"typedef", "union", "{"}), L(1, {"int", "a", ";"}), | |
| L(0, {"}", "foo", ";"})), | |
| }, | |
| { | |
| "simple union typedef multiple members", | |
| "typedef union {" | |
| "int a;" | |
| "logic [3:0] b;" | |
| "} foo;", | |
| N(0, L(0, {"typedef", "union", "{"}), | |
| StructUnionMemberList( | |
| 1, L(1, {"int", "a", ";"}), | |
| L(1, {"logic", "[", "3", ":", "0", "]", "b", ";"})), | |
| L(0, {"}", "foo", ";"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from unions | |
| TEST_F(TreeUnwrapperTest, UnwrapUnionTests) { | |
| for (const auto& test_case : kUnwrapUnionTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapEnumTestCases[] = { | |
| { | |
| "simple enum typedef, one member", | |
| "typedef enum { one=1 } foo_e;", | |
| N(0, L(0, {"typedef", "enum", "{"}), L(1, {"one", "=", "1"}), | |
| L(0, {"}", "foo_e", ";"})), | |
| }, | |
| { | |
| "simple enum typedef multiple members", | |
| "typedef enum logic {" | |
| "one=1," | |
| "two=2" | |
| "} foo_e;", | |
| N(0, L(0, {"typedef", "enum", "logic", "{"}), | |
| EnumItemList(1, L(1, {"one", "=", "1", ","}), | |
| L(1, {"two", "=", "2"})), | |
| L(0, {"}", "foo_e", ";"})), | |
| }, | |
| { | |
| "Comment after enum member should attach", | |
| "typedef enum logic {\n" | |
| "one=1, // foo\n" | |
| "two, // bar\n" | |
| "three=3 // baz\n" | |
| "} foo_e;", | |
| N(0, L(0, {"typedef", "enum", "logic", "{"}), | |
| EnumItemList(1, L(1, {"one", "=", "1", ",", "// foo"}), | |
| L(1, {"two", ",", "// bar"}), | |
| L(1, {"three", "=", "3", "// baz"})), | |
| L(0, {"}", "foo_e", ";"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from structs | |
| TEST_F(TreeUnwrapperTest, UnwrapEnumTests) { | |
| for (const auto& test_case : kUnwrapEnumTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapPropertyTestCases[] = { | |
| { | |
| "simple property declaration", | |
| "property myprop;" | |
| "a < b " | |
| "endproperty", | |
| PropertyDeclaration(0, L(0, {"property", "myprop", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endproperty"})), | |
| }, | |
| { | |
| "simple property declaration, terminal semicolon", | |
| "property myprop;" | |
| "a < b;" | |
| "endproperty", | |
| PropertyDeclaration(0, L(0, {"property", "myprop", ";"}), | |
| L(1, {"a", "<", "b", ";"}), L(0, {"endproperty"})), | |
| }, | |
| { | |
| "simple property declaration, with assertion variable declaration", | |
| "property myprop;" | |
| "pkg::thing_t thing;" | |
| "a < b " | |
| "endproperty", | |
| PropertyDeclaration(0, L(0, {"property", "myprop", ";"}), | |
| L(1, {"pkg", "::", "thing_t", "thing", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endproperty"})), | |
| }, | |
| { | |
| "simple property spec inside parentheses", | |
| "program tst;" | |
| "initial begin " | |
| "expect(a|=>b)xx;" | |
| "end " | |
| "endprogram", | |
| ModuleDeclaration( | |
| 0, // doubles as program declaration for now | |
| L(0, {"program", "tst", ";"}), | |
| FlowControl(1, // | |
| L(1, {"initial", "begin"}), | |
| N(2, // | |
| L(2, {"expect", "(", "a", "|=>", "b", ")"}), // | |
| L(3, {"xx", ";"})), | |
| L(1, {"end"})), | |
| L(0, {"endprogram"})), | |
| }, | |
| { | |
| "two property declarations", | |
| "property myprop1;" | |
| "a < b " | |
| "endproperty " | |
| "property myprop2;" | |
| "a > b " | |
| "endproperty", | |
| PropertyDeclaration(0, L(0, {"property", "myprop1", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endproperty"})), | |
| PropertyDeclaration(0, L(0, {"property", "myprop2", ";"}), | |
| L(1, {"a", ">", "b"}), L(0, {"endproperty"})), | |
| }, | |
| { | |
| "two property declarations, with end-labels", | |
| "property myprop1;" | |
| "a < b " | |
| "endproperty : myprop1 " | |
| "property myprop2;" | |
| "a > b " | |
| "endproperty : myprop2", | |
| PropertyDeclaration(0, L(0, {"property", "myprop1", ";"}), | |
| L(1, {"a", "<", "b"}), | |
| L(0, {"endproperty", ":", "myprop1"})), | |
| PropertyDeclaration(0, L(0, {"property", "myprop2", ";"}), | |
| L(1, {"a", ">", "b"}), | |
| L(0, {"endproperty", ":", "myprop2"})), | |
| }, | |
| { | |
| "simple property declaration, two ports", | |
| "property myprop(int foo, int port);" | |
| "a < b " | |
| "endproperty", | |
| PropertyDeclaration(0, | |
| L(0, {"property", "myprop", "(", "int", "foo", ",", | |
| "int", "port", ")", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endproperty"})), | |
| }, | |
| { | |
| "property declaration inside package", | |
| "package pkg;" | |
| "property myprop;" | |
| "a < b " | |
| "endproperty " | |
| "endpackage", | |
| PackageDeclaration( | |
| 0, L(0, {"package", "pkg", ";"}), | |
| PropertyDeclaration(1, L(1, {"property", "myprop", ";"}), | |
| L(2, {"a", "<", "b"}), L(1, {"endproperty"})), | |
| L(0, {"endpackage"})), | |
| }, | |
| { | |
| "property declaration inside module", | |
| "module pkg;" | |
| "property myprop;" | |
| "a < b " | |
| "endproperty " | |
| "endmodule", | |
| ModuleDeclaration( | |
| 0, L(0, {"module", "pkg", ";"}), | |
| PropertyDeclaration(1, L(1, {"property", "myprop", ";"}), | |
| L(2, {"a", "<", "b"}), L(1, {"endproperty"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| /* TODO(b/145241765): fix property-case parsing | |
| { | |
| "property declaration with property case statement", | |
| "module m;" | |
| "property p;" | |
| "case (g) h:a < b; i:c<d endcase " | |
| "endproperty " | |
| "endmodule", | |
| ModuleDeclaration(0, | |
| ModuleHeader(0, L(0, {"module", "m", ";"})), | |
| PropertyDeclaration(1, L(1, {"property", "p", ";"}), | |
| PropertyItemList( | |
| 2, L(2, {"case", "(", "g", ")"}), | |
| CaseItemList(3, L(3, {"h", ":", "a", "<", "b", ";"}), | |
| L(3, {"i", ":", "c", "<", "d", ";"})), | |
| L(2, {"endcase"})), | |
| L(1, {"endproperty"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| */ | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from properties | |
| TEST_F(TreeUnwrapperTest, UnwrapPropertyTests) { | |
| for (const auto& test_case : kUnwrapPropertyTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapCovergroupTestCases[] = { | |
| { | |
| "empty covergroup declarations", | |
| "covergroup cg(string s);" | |
| "endgroup " | |
| "covergroup cg2(string s);" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| L(0, {"endgroup"})), | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg2", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "covergroup declaration with options", | |
| "covergroup cg(string s);" | |
| "option.name = cg_name;" | |
| "option.per_instance=1;" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| CovergroupItemList( | |
| 1, L(1, {"option", ".", "name", "=", "cg_name", ";"}), | |
| L(1, {"option", ".", "per_instance", "=", "1", ";"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "covergroup declaration with coverpoints", | |
| "covergroup cg(string s);" | |
| "q_cp : coverpoint cp;" | |
| "q_cp2 : coverpoint cp2;" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| CovergroupItemList(1, L(1, {"q_cp", ":", "coverpoint", "cp", ";"}), | |
| L(1, {"q_cp2", ":", "coverpoint", "cp2", ";"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "coverpoint with bins", | |
| "covergroup cg(string s);" | |
| "q_cp : coverpoint cp {" | |
| " bins foo = {bar};" | |
| " bins zoo = {pig};" | |
| "}" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| CovergroupItemList( | |
| 1, L(1, {"q_cp", ":", "coverpoint", "cp", "{"}), | |
| CoverpointItemList(2, | |
| N(2, L(2, {"bins", "foo", "=", "{"}), | |
| L(3, {"bar"}), L(2, {"}", ";"})), | |
| N(2, L(2, {"bins", "zoo", "=", "{"}), | |
| L(3, {"pig"}), L(2, {"}", ";"}))), | |
| L(1, {"}"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "covergroup declaration with crosses", | |
| "covergroup cg(string s);" | |
| "x_cross : cross s1, s2;" | |
| "x_cross2 : cross s2, s1;" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| CovergroupItemList( | |
| 1, L(1, {"x_cross", ":", "cross", "s1", ",", "s2", ";"}), | |
| L(1, {"x_cross2", ":", "cross", "s2", ",", "s1", ";"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "cover crosses with bins", | |
| "covergroup cg(string s);" | |
| "x_cross : cross s1, s2{" | |
| " bins a = binsof(x) intersect {d};" | |
| " bins b = binsof(y) intersect {e};" | |
| "}" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), L(0, {")", ";"})), | |
| CovergroupItemList( | |
| 1, L(1, {"x_cross", ":", "cross", "s1", ",", "s2", "{"}), | |
| CrossItemList(2, | |
| N(2, | |
| L(2, {"bins", "a", "=", "binsof", "(", "x", ")", | |
| "intersect", "{"}), | |
| L(3, {"d"}), L(2, {"}", ";"})), | |
| N(2, | |
| L(2, {"bins", "b", "=", "binsof", "(", "y", ")", | |
| "intersect", "{"}), | |
| L(3, {"e"}), L(2, {"}", ";"}))), | |
| L(1, {"}"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| { | |
| "covergroup declaration with a function", | |
| "covergroup cg(string s) with function sample(bit pending);" | |
| "endgroup ", | |
| CovergroupDeclaration( | |
| 0, | |
| CovergroupHeader(0, L(0, {"covergroup", "cg", "("}), | |
| L(2, {"string", "s"}), | |
| L(0, {")", "with", "function", "sample", "("}), | |
| L(2, {"bit", "pending"}), L(0, {")", ";"})), | |
| L(0, {"endgroup"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from covergroups | |
| TEST_F(TreeUnwrapperTest, UnwrapCovergroupTests) { | |
| for (const auto& test_case : kUnwrapCovergroupTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapSequenceTestCases[] = { | |
| { | |
| "simple sequence declaration", | |
| "sequence myseq;" | |
| "a < b " | |
| "endsequence", | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endsequence"})), | |
| }, | |
| { | |
| "simple sequence declaration, terminal semicolon", | |
| "sequence myseq;" | |
| "a < b;" | |
| "endsequence", | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq", ";"}), | |
| L(1, {"a", "<", "b", ";"}), L(0, {"endsequence"})), | |
| }, | |
| { | |
| "simple sequence declaration, with assertion variable declaration", | |
| "sequence myseq;" | |
| "foo bar;" | |
| "a < b " | |
| "endsequence", | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq", ";"}), | |
| L(1, {"foo", "bar", ";"}), L(1, {"a", "<", "b"}), | |
| L(0, {"endsequence"})), | |
| }, | |
| { | |
| "two sequence declarations", | |
| "sequence myseq;" | |
| "a < b " | |
| "endsequence " | |
| "sequence myseq2;" | |
| "a > b " | |
| "endsequence", | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq", ";"}), | |
| L(1, {"a", "<", "b"}), L(0, {"endsequence"})), | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq2", ";"}), | |
| L(1, {"a", ">", "b"}), L(0, {"endsequence"})), | |
| }, | |
| { | |
| "two sequence declarations, with end labels", | |
| "sequence myseq;" | |
| "a < b " | |
| "endsequence : myseq " | |
| "sequence myseq2;" | |
| "a > b " | |
| "endsequence : myseq2", | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq", ";"}), | |
| L(1, {"a", "<", "b"}), | |
| L(0, {"endsequence", ":", "myseq"})), | |
| SequenceDeclaration(0, L(0, {"sequence", "myseq2", ";"}), | |
| L(1, {"a", ">", "b"}), | |
| L(0, {"endsequence", ":", "myseq2"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from sequences | |
| TEST_F(TreeUnwrapperTest, UnwrapSequenceTests) { | |
| for (const auto& test_case : kUnwrapSequenceTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| const TreeUnwrapperTestData kUnwrapPrimitivesTestCases[] = { | |
| { | |
| "one input combinatorial UDP", | |
| "primitive comb(o, i);\n" | |
| " output o;\n" | |
| " input i;\n" | |
| " table\n" | |
| " 1 : 0;\n" | |
| " 0 : 1;\n" | |
| " endtable\n" | |
| "endprimitive", | |
| UDPDeclaration( | |
| 0, L(0, {"primitive", "comb", "(", "o", ",", "i", ")", ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"input", "i", ";"}), | |
| UdpBody(1, L(1, {"table"}), L(2, {"1", ":", "0", ";"}), | |
| L(2, {"0", ":", "1", ";"}), L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "double input UDP", | |
| "primitive comb2(o, s, r); " | |
| "output o; " | |
| "input s; " | |
| "input r; " | |
| "table " | |
| "1 ? : 0; " | |
| "? 1 : 1; " | |
| "endtable " | |
| "endprimitive ", | |
| UDPDeclaration(0, | |
| L(0, {"primitive", "comb2", "(", "o", ",", "s", ",", "r", | |
| ")", ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"input", "s", ";"}), | |
| L(1, {"input", "r", ";"}), | |
| UdpBody(1, // | |
| L(1, {"table"}), // | |
| L(2, {"1", "?", ":", "0", ";"}), // | |
| L(2, {"?", "1", ":", "1", ";"}), // | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "double input UDP with comments", | |
| "primitive comb2(o, s, r); " | |
| "output /* only one */ o;\n" | |
| "// inputs section\n" | |
| "input s; " | |
| "input r; // two of them\n" | |
| "table " | |
| "1 ? : 0; " | |
| "? 1 : 1; " | |
| "endtable " | |
| "endprimitive ", | |
| UDPDeclaration( | |
| 0, | |
| L(0, | |
| {"primitive", "comb2", "(", "o", ",", "s", ",", "r", ")", ";"}), | |
| L(1, {"output", "/* only one */", "o", ";"}), | |
| N(1, L(1, {"// inputs section"}), L(1, {"input", "s", ";"})), | |
| L(1, {"input", "r", ";", "// two of them"}), | |
| UdpBody(1, // | |
| L(1, {"table"}), // | |
| L(2, {"1", "?", ":", "0", ";"}), // | |
| L(2, {"?", "1", ":", "1", ";"}), // | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "10-input UDP", | |
| "primitive comb10(o, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9); " | |
| " output o; " | |
| " input i0, i1, i2, i3, i4, i5, i6, i7, i8, i9; " | |
| " table " | |
| " 0 ? ? ? ? ? ? ? ? 0 : 0;" | |
| " 1 ? ? ? ? ? ? ? ? 0 : 1;" | |
| " 1 ? ? ? ? ? ? ? ? 1 : 1;" | |
| " 0 ? ? ? ? ? ? ? ? 1 : 0;" | |
| " endtable " | |
| "endprimitive ", | |
| UDPDeclaration( | |
| 0, L(0, {"primitive", "comb10", "(", "o", ",", "i0", ",", | |
| "i1", ",", "i2", ",", "i3", ",", "i4", | |
| ",", "i5", ",", "i6", ",", "i7", ",", | |
| "i8", ",", "i9", ")", ";"}), | |
| L(1, {"output", "o", ";"}), | |
| L(1, {"input", "i0", ",", "i1", ",", "i2", ",", | |
| "i3", ",", "i4", ",", "i5", ",", "i6", | |
| ",", "i7", ",", "i8", ",", "i9", ";"}), | |
| UdpBody(1, L(1, {"table"}), | |
| L(2, {"0", "?", "?", "?", "?", "?", "?", "?", "?", "0", ":", | |
| "0", ";"}), | |
| L(2, {"1", "?", "?", "?", "?", "?", "?", "?", "?", "0", ":", | |
| "1", ";"}), | |
| L(2, {"1", "?", "?", "?", "?", "?", "?", "?", "?", "1", ":", | |
| "1", ";"}), | |
| L(2, {"0", "?", "?", "?", "?", "?", "?", "?", "?", "1", ":", | |
| "0", ";"}), | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "level-sensitive sequential UDP", | |
| "primitive level_seq(o, s, r); " | |
| "output o; " | |
| "reg o; " | |
| "input s; " | |
| "input r; " | |
| "table " | |
| "1 ? : ? : 0; " | |
| "? 1 : 0 : -; " | |
| "endtable " | |
| "endprimitive ", | |
| UDPDeclaration(0, | |
| L(0, {"primitive", "level_seq", "(", "o", ",", "s", ",", | |
| "r", ")", ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"reg", "o", ";"}), | |
| L(1, {"input", "s", ";"}), L(1, {"input", "r", ";"}), | |
| UdpBody(1, L(1, {"table"}), // | |
| L(2, {"1", "?", ":", "?", ":", "0", ";"}), // | |
| L(2, {"?", "1", ":", "0", ":", "-", ";"}), // | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "sequential UDP with comments", | |
| "primitive level_seq(o, s, r); " | |
| "output o; " | |
| "reg o; " | |
| "input s; " | |
| "input r; " | |
| "table\n" | |
| "// r s state next\n" | |
| "1 /* rst */ ? : ? : 0; " | |
| "? 1 /* set */ : 0 : -; // no change here\n" | |
| "endtable " | |
| "endprimitive ", | |
| UDPDeclaration( | |
| 0, | |
| L(0, {"primitive", "level_seq", "(", "o", ",", "s", ",", "r", ")", | |
| ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"reg", "o", ";"}), | |
| L(1, {"input", "s", ";"}), L(1, {"input", "r", ";"}), | |
| UdpBody(1, L(1, {"table"}), // | |
| N(2, // | |
| L(2, {"// r s state next"}), // | |
| L(2, {"1", "/* rst */", "?", ":", "?", ":", "0", ";"})), | |
| L(2, {"?", "1", "/* set */", ":", "0", ":", "-", ";", | |
| "// no change here"}), | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "edge-sensitive sequential UDP", | |
| "primitive edge_seq(o, c, d); " | |
| " output o; " | |
| " reg o; " | |
| " input c; " | |
| " input d; " | |
| " table " | |
| " (01) 0 : ? : 0; " | |
| " (01) 1 : ? : 1; " | |
| " (0?) 1 : 1 : 1; " | |
| " (0?) 0 : 0 : 0; " | |
| " (?0) ? : ? : -; " | |
| " ? (?\?) : ? : -; " | |
| " endtable " | |
| "endprimitive ", | |
| UDPDeclaration( | |
| 0, | |
| L(0, {"primitive", "edge_seq", "(", "o", ",", "c", ",", "d", ")", | |
| ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"reg", "o", ";"}), | |
| L(1, {"input", "c", ";"}), L(1, {"input", "d", ";"}), | |
| UdpBody(1, L(1, {"table"}), // | |
| L(2, {"(01)", "0", ":", "?", ":", "0", ";"}), | |
| L(2, {"(01)", "1", ":", "?", ":", "1", ";"}), | |
| L(2, {"(0?)", "1", ":", "1", ":", "1", ";"}), | |
| L(2, {"(0?)", "0", ":", "0", ":", "0", ";"}), | |
| L(2, {"(?0)", "?", ":", "?", ":", "-", ";"}), | |
| L(2, {"?", "(?\?)", ":", "?", ":", "-", ";"}), // | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| { | |
| "mixed sensitivity sequential UDP", | |
| "primitive mixed(o, clk, j, k, preset, clear); " | |
| " output o; " | |
| " reg o; " | |
| " input c; " | |
| " input j, k; " | |
| " input preset, clear; " | |
| " table " | |
| " ? ?? 01 : ? : 1 ; " | |
| " ? ?? *1 : 1 : 1 ; " | |
| " ? ?? 10 : ? : 0 ; " | |
| " ? ?? 1* : 0 : 0 ; " | |
| " r 00 00 : 0 : 1 ; " | |
| " r 00 11 : ? : - ; " | |
| " r 01 11 : ? : 0 ; " | |
| " r 10 11 : ? : 1 ; " | |
| " r 11 11 : 0 : 1 ; " | |
| " r 11 11 : 1 : 0 ; " | |
| " f ?? ?? : ? : - ; " | |
| " b *? ?? : ? : - ; " | |
| " b ?* ?? : ? : - ; " | |
| " endtable " | |
| "endprimitive ", | |
| UDPDeclaration( | |
| 0, | |
| L(0, {"primitive", "mixed", "(", "o", ",", "clk", ",", "j", ",", | |
| "k", ",", "preset", ",", "clear", ")", ";"}), | |
| L(1, {"output", "o", ";"}), L(1, {"reg", "o", ";"}), | |
| L(1, {"input", "c", ";"}), L(1, {"input", "j", ",", "k", ";"}), | |
| L(1, {"input", "preset", ",", "clear", ";"}), | |
| UdpBody(1, L(1, {"table"}), // | |
| L(2, {"?", "?", "?", "0", "1", ":", "?", ":", "1", ";"}), | |
| L(2, {"?", "?", "?", "*", "1", ":", "1", ":", "1", ";"}), | |
| L(2, {"?", "?", "?", "1", "0", ":", "?", ":", "0", ";"}), | |
| L(2, {"?", "?", "?", "1", "*", ":", "0", ":", "0", ";"}), | |
| L(2, {"r", "0", "0", "0", "0", ":", "0", ":", "1", ";"}), | |
| L(2, {"r", "0", "0", "1", "1", ":", "?", ":", "-", ";"}), | |
| L(2, {"r", "0", "1", "1", "1", ":", "?", ":", "0", ";"}), | |
| L(2, {"r", "1", "0", "1", "1", ":", "?", ":", "1", ";"}), | |
| L(2, {"r", "1", "1", "1", "1", ":", "0", ":", "1", ";"}), | |
| L(2, {"r", "1", "1", "1", "1", ":", "1", ":", "0", ";"}), | |
| L(2, {"f", "?", "?", "?", "?", ":", "?", ":", "-", ";"}), | |
| L(2, {"b", "*", "?", "?", "?", ":", "?", ":", "-", ";"}), | |
| L(2, {"b", "?", "*", "?", "?", ":", "?", ":", "-", ";"}), | |
| L(1, {"endtable"})), | |
| L(0, {"endprimitive"})), | |
| }, | |
| // primitive gate instantiation tests | |
| { | |
| "single primitive gate instantiation", | |
| "module m;\n" | |
| "xor x0(a, b, c);\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| N(1, // | |
| L(1, {"xor", "x0", "("}), // | |
| N(3, // | |
| L(3, {"a", ","}), // | |
| L(3, {"b", ","}), // | |
| L(3, {"c"})), // | |
| L(1, {")", ";"})), | |
| L(0, {"endmodule"})), | |
| }, | |
| { | |
| "two primitive gate instantiations", | |
| "module m;\n" | |
| "and x0(a, b, c);\n" | |
| "or x1(a, b, d);\n" | |
| "endmodule\n", | |
| ModuleDeclaration(0, L(0, {"module", "m", ";"}), | |
| ModuleItemList(1, | |
| N(1, // | |
| L(1, {"and", "x0", "("}), // | |
| N(3, // | |
| L(3, {"a", ","}), // | |
| L(3, {"b", ","}), // | |
| L(3, {"c"})), // | |
| L(1, {")", ";"})), | |
| N(1, // | |
| L(1, {"or", "x1", "("}), // | |
| N(3, // | |
| L(3, {"a", ","}), // | |
| L(3, {"b", ","}), // | |
| L(3, {"d"})), // | |
| L(1, {")", ";"}))), | |
| L(0, {"endmodule"})), | |
| }, | |
| }; | |
| // Test that TreeUnwrapper produces correct UnwrappedLines from primitives | |
| TEST_F(TreeUnwrapperTest, UnwrapPrimitivesTests) { | |
| for (const auto& test_case : kUnwrapPrimitivesTestCases) { | |
| auto tree_unwrapper = CreateTreeUnwrapper(test_case.source_code); | |
| const auto* uwline_tree = tree_unwrapper->Unwrap(); | |
| EXPECT_TRUE(VerifyUnwrappedLines(&std::cout, *ABSL_DIE_IF_NULL(uwline_tree), | |
| test_case)); | |
| } | |
| } | |
| } // namespace | |
| } // namespace formatter | |
| } // namespace verilog |