blob: cbf9f761fc2a41731e7ca6ff573d456e10cdf3e6 [file] [log] [blame] [edit]
// 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/CST/statement.h"
#include <vector>
#include "common/analysis/matcher/matcher.h"
#include "common/analysis/matcher/matcher_builders.h"
#include "common/analysis/syntax_tree_search.h"
#include "common/text/concrete_syntax_leaf.h"
#include "common/text/concrete_syntax_tree.h"
#include "common/text/symbol.h"
#include "common/text/token_info.h"
#include "common/text/tree_utils.h"
#include "verilog/CST/verilog_matchers.h" // IWYU pragma: keep
namespace verilog {
using verible::Symbol;
using verible::SymbolCastToNode;
using verible::SyntaxTreeNode;
static const SyntaxTreeNode& GetGenericStatementBody(
const SyntaxTreeNode& node) {
// In most controlled constructs, the controlled statement body is
// in tail position. Exceptions include: DoWhile.
return SymbolCastToNode(*node.children().back());
}
const SyntaxTreeNode& GetIfClauseGenerateBody(const Symbol& if_clause) {
const auto& body_node = GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(if_clause), NodeEnum::kGenerateIfClause));
return GetSubtreeAsNode(body_node, NodeEnum::kGenerateIfBody, 0);
}
const SyntaxTreeNode& GetElseClauseGenerateBody(const Symbol& else_clause) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(else_clause), NodeEnum::kGenerateElseClause));
return GetSubtreeAsNode(body_node, NodeEnum::kGenerateElseBody, 0);
}
const SyntaxTreeNode& GetLoopGenerateBody(const Symbol& loop) {
return GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(loop), NodeEnum::kLoopGenerateConstruct));
}
const SyntaxTreeNode& GetConditionalGenerateIfClause(
const Symbol& conditional) {
return GetSubtreeAsNode(conditional, NodeEnum::kConditionalGenerateConstruct,
0, NodeEnum::kGenerateIfClause);
}
const SyntaxTreeNode* GetConditionalGenerateElseClause(
const Symbol& conditional) {
const auto& node = CheckNodeEnum(SymbolCastToNode(conditional),
NodeEnum::kConditionalGenerateConstruct);
if (node.children().size() < 2) return nullptr;
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr),
NodeEnum::kGenerateElseClause);
}
const SyntaxTreeNode& GetIfClauseStatementBody(const Symbol& if_clause) {
const auto& body_node = GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(if_clause), NodeEnum::kIfClause));
return GetSubtreeAsNode(body_node, NodeEnum::kIfBody, 0);
}
const SyntaxTreeNode& GetElseClauseStatementBody(const Symbol& else_clause) {
const auto& body_node = GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(else_clause), NodeEnum::kElseClause));
return GetSubtreeAsNode(body_node, NodeEnum::kElseBody, 0);
}
const SyntaxTreeNode& GetConditionalStatementIfClause(
const Symbol& conditional) {
return GetSubtreeAsNode(conditional, NodeEnum::kConditionalStatement, 0,
NodeEnum::kIfClause);
}
const SyntaxTreeNode* GetConditionalStatementElseClause(
const Symbol& conditional) {
const auto& node = CheckNodeEnum(SymbolCastToNode(conditional),
NodeEnum::kConditionalStatement);
if (node.children().size() < 2) return nullptr;
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode& GetAssertionStatementAssertClause(
const Symbol& assertion_statement) {
return GetSubtreeAsNode(assertion_statement, NodeEnum::kAssertionStatement, 0,
NodeEnum::kAssertionClause);
}
const SyntaxTreeNode* GetAssertionClauseStatementBody(
const Symbol& assertion_clause) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(assertion_clause), NodeEnum::kAssertionClause));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kAssertionBody, 0));
}
const SyntaxTreeNode* GetAssertionStatementElseClause(
const Symbol& assertion_statement) {
const auto& node = CheckNodeEnum(SymbolCastToNode(assertion_statement),
NodeEnum::kAssertionStatement);
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode& GetAssumeStatementAssumeClause(
const Symbol& assume_statement) {
return GetSubtreeAsNode(assume_statement, NodeEnum::kAssumeStatement, 0,
NodeEnum::kAssumeClause);
}
const SyntaxTreeNode* GetAssumeClauseStatementBody(
const Symbol& assume_clause) {
const auto& body_node = GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(assume_clause), NodeEnum::kAssumeClause));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kAssumeBody, 0));
}
const SyntaxTreeNode* GetAssumeStatementElseClause(
const Symbol& assume_statement) {
const auto& node = CheckNodeEnum(SymbolCastToNode(assume_statement),
NodeEnum::kAssumeStatement);
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode* GetCoverStatementBody(const Symbol& cover_statement) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(cover_statement), NodeEnum::kCoverStatement));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kCoverBody, 0));
}
const SyntaxTreeNode* GetWaitStatementBody(const Symbol& wait_statement) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(wait_statement), NodeEnum::kWaitStatement));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kWaitBody, 0));
}
const SyntaxTreeNode& GetAssertPropertyStatementAssertClause(
const Symbol& assert_property_statement) {
return GetSubtreeAsNode(assert_property_statement,
NodeEnum::kAssertPropertyStatement, 0,
NodeEnum::kAssertPropertyClause);
}
const SyntaxTreeNode* GetAssertPropertyStatementBody(
const Symbol& assert_clause) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(assert_clause), NodeEnum::kAssertPropertyClause));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kAssertPropertyBody, 0));
}
const SyntaxTreeNode* GetAssertPropertyStatementElseClause(
const Symbol& assert_property_statement) {
const auto& node = CheckNodeEnum(SymbolCastToNode(assert_property_statement),
NodeEnum::kAssertPropertyStatement);
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode& GetAssumePropertyStatementAssumeClause(
const Symbol& assume_property_statement) {
return GetSubtreeAsNode(assume_property_statement,
NodeEnum::kAssumePropertyStatement, 0,
NodeEnum::kAssumePropertyClause);
}
const SyntaxTreeNode* GetAssumePropertyStatementBody(
const Symbol& assume_clause) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(assume_clause), NodeEnum::kAssumePropertyClause));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kAssumePropertyBody, 0));
}
const SyntaxTreeNode* GetAssumePropertyStatementElseClause(
const Symbol& assume_property_statement) {
const auto& node = CheckNodeEnum(SymbolCastToNode(assume_property_statement),
NodeEnum::kAssumePropertyStatement);
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode& GetExpectPropertyStatementExpectClause(
const Symbol& expect_property_statement) {
return GetSubtreeAsNode(expect_property_statement,
NodeEnum::kExpectPropertyStatement, 0,
NodeEnum::kExpectPropertyClause);
}
const SyntaxTreeNode* GetExpectPropertyStatementBody(
const Symbol& expect_clause) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(expect_clause), NodeEnum::kExpectPropertyClause));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kExpectPropertyBody, 0));
}
const SyntaxTreeNode* GetExpectPropertyStatementElseClause(
const Symbol& expect_property_statement) {
const auto& node = CheckNodeEnum(SymbolCastToNode(expect_property_statement),
NodeEnum::kExpectPropertyStatement);
const Symbol* else_ptr = node.children().back().get();
if (else_ptr == nullptr) return nullptr;
return &CheckNodeEnum(SymbolCastToNode(*else_ptr), NodeEnum::kElseClause);
}
const SyntaxTreeNode* GetCoverPropertyStatementBody(
const Symbol& cover_property) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(cover_property), NodeEnum::kCoverPropertyStatement));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kCoverPropertyBody, 0));
}
const SyntaxTreeNode* GetCoverSequenceStatementBody(
const Symbol& cover_sequence) {
const auto& body_node = GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(cover_sequence), NodeEnum::kCoverSequenceStatement));
return verible::CheckOptionalSymbolAsNode(
GetSubtreeAsSymbol(body_node, NodeEnum::kCoverSequenceBody, 0));
}
const SyntaxTreeNode& GetLoopStatementBody(const Symbol& loop) {
return GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(loop), NodeEnum::kForLoopStatement));
}
const SyntaxTreeNode& GetDoWhileStatementBody(const Symbol& do_while) {
return GetSubtreeAsNode(SymbolCastToNode(do_while),
NodeEnum::kDoWhileLoopStatement, 1);
}
const SyntaxTreeNode& GetForeverStatementBody(const Symbol& forever) {
return GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(forever), NodeEnum::kForeverLoopStatement));
}
const SyntaxTreeNode& GetForeachStatementBody(const Symbol& foreach) {
return GetGenericStatementBody(CheckNodeEnum(
SymbolCastToNode(foreach), NodeEnum::kForeachLoopStatement));
}
const SyntaxTreeNode& GetRepeatStatementBody(const Symbol& repeat) {
return GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(repeat), NodeEnum::kRepeatLoopStatement));
}
const SyntaxTreeNode& GetWhileStatementBody(const Symbol& while_stmt) {
return GetGenericStatementBody(CheckNodeEnum(SymbolCastToNode(while_stmt),
NodeEnum::kWhileLoopStatement));
}
const SyntaxTreeNode& GetProceduralTimingControlStatementBody(
const Symbol& proc_timing_control) {
return GetGenericStatementBody(
CheckNodeEnum(SymbolCastToNode(proc_timing_control),
NodeEnum::kProceduralTimingControlStatement));
}
const SyntaxTreeNode* GetAnyControlStatementBody(const Symbol& statement) {
switch (NodeEnum(SymbolCastToNode(statement).Tag().tag)) {
// generate
case NodeEnum::kGenerateIfClause:
return &GetIfClauseGenerateBody(statement);
case NodeEnum::kGenerateElseClause:
return &GetElseClauseGenerateBody(statement);
case NodeEnum::kLoopGenerateConstruct:
return &GetLoopGenerateBody(statement);
// statements
case NodeEnum::kIfClause:
return &GetIfClauseStatementBody(statement);
case NodeEnum::kElseClause:
return &GetElseClauseStatementBody(statement);
case NodeEnum::kForLoopStatement:
return &GetLoopStatementBody(statement);
case NodeEnum::kDoWhileLoopStatement:
return &GetDoWhileStatementBody(statement);
case NodeEnum::kForeverLoopStatement:
return &GetForeverStatementBody(statement);
case NodeEnum::kForeachLoopStatement:
return &GetForeachStatementBody(statement);
case NodeEnum::kRepeatLoopStatement:
return &GetRepeatStatementBody(statement);
case NodeEnum::kWhileLoopStatement:
return &GetWhileStatementBody(statement);
case NodeEnum::kProceduralTimingControlStatement:
return &GetProceduralTimingControlStatementBody(statement);
// immediate assertions
case NodeEnum::kAssertionClause:
return GetAssertionClauseStatementBody(statement);
case NodeEnum::kAssumeClause:
return GetAssumeClauseStatementBody(statement);
case NodeEnum::kCoverStatement:
return GetCoverStatementBody(statement);
case NodeEnum::kWaitStatement:
return GetWaitStatementBody(statement);
// concurrent assertions
case NodeEnum::kAssertPropertyClause:
return GetAssertPropertyStatementBody(statement);
case NodeEnum::kAssumePropertyClause:
return GetAssumePropertyStatementBody(statement);
case NodeEnum::kExpectPropertyClause:
return GetExpectPropertyStatementBody(statement);
case NodeEnum::kCoverPropertyStatement:
return GetCoverPropertyStatementBody(statement);
case NodeEnum::kCoverSequenceStatement:
return GetCoverSequenceStatementBody(statement);
default:
return nullptr;
}
}
const SyntaxTreeNode* GetAnyConditionalIfClause(const Symbol& conditional) {
// by IfClause, we main the first clause
switch (NodeEnum(SymbolCastToNode(conditional).Tag().tag)) {
// generate
case NodeEnum::kConditionalGenerateConstruct:
return &GetConditionalGenerateIfClause(conditional);
// statement
case NodeEnum::kConditionalStatement:
return &GetConditionalStatementIfClause(conditional);
// immediate assertions
case NodeEnum::kAssertionStatement:
return &GetAssertionStatementAssertClause(conditional);
case NodeEnum::kAssumeStatement:
return &GetAssumeStatementAssumeClause(conditional);
// concurrent assertions
case NodeEnum::kAssertPropertyStatement:
return &GetAssertPropertyStatementAssertClause(conditional);
case NodeEnum::kAssumePropertyStatement:
return &GetAssumePropertyStatementAssumeClause(conditional);
case NodeEnum::kExpectPropertyStatement:
return &GetExpectPropertyStatementExpectClause(conditional);
default:
return nullptr;
}
}
const SyntaxTreeNode* GetAnyConditionalElseClause(const Symbol& conditional) {
switch (NodeEnum(SymbolCastToNode(conditional).Tag().tag)) {
// generate
case NodeEnum::kConditionalGenerateConstruct:
return GetConditionalGenerateElseClause(conditional);
// statement
case NodeEnum::kConditionalStatement:
return GetConditionalStatementElseClause(conditional);
// immediate assertions
case NodeEnum::kAssertionStatement:
return GetAssertionStatementElseClause(conditional);
case NodeEnum::kAssumeStatement:
return GetAssumeStatementElseClause(conditional);
// concurrent assertions
case NodeEnum::kAssertPropertyStatement:
return GetAssertPropertyStatementElseClause(conditional);
case NodeEnum::kAssumePropertyStatement:
return GetAssumePropertyStatementElseClause(conditional);
case NodeEnum::kExpectPropertyStatement:
return GetExpectPropertyStatementElseClause(conditional);
default:
return nullptr;
}
}
} // namespace verilog