blob: 778258a81aea41b96ff87842eaddbba0a5f07b5d [file] [log] [blame]
// 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 statements, and comments",
"module multi_cases;\n"
"case (foo)//c1\n"
"//c2\n"
" A: a aa;//c3\n"
"//c4\n"
"endcase\n"
"endmodule",
ModuleDeclaration(
0, L(0, {"module", "multi_cases", ";"}),
FlowControl(1, L(1, {"case", "(", "foo", ")", "//c1"}),
N(2, //
L(2, {"//c2"}), //
N(2, L(2, {"A", ":"}), //
L(2, {"a", "aa", ";", "//c3"})),
L(2, {"//c4"}) //
),
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 statement, with comments",
"function foo_case;"
"case (y) \n"
"//c1\n"
"k1: return 0;\n"
"//c2\n"
"k2: return 1;\n"
"//c3\n"
"endcase "
"endfunction",
FunctionDeclaration(
0, FunctionHeader(0, {"function", "foo_case", ";"}),
FlowControl(1, L(1, {"case", "(", "y", ")"}),
CaseItemList(2, //
L(2, {"//c1"}), //
N(2, //
L(2, {"k1", ":"}), //
L(2, {"return", "0", ";"})),
L(2, {"//c2"}), //
N(2, //
L(2, {"k2", ":"}), //
L(2, {"return", "1", ";"})),
L(2, {"//c3"}) //
), //
L(1, {"endcase"})), //
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