| // 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/declaration.h" |
| #include "verilog/CST/identifier.h" |
| #include "verilog/CST/type.h" |
| #include "verilog/CST/verilog_matchers.h" // IWYU pragma: keep |
| |
| namespace verilog { |
| |
| using verible::Symbol; |
| using verible::SymbolCastToNode; |
| using verible::SyntaxTreeNode; |
| |
| std::vector<verible::TreeSearchMatch> FindAllForLoopsInitializations( |
| const verible::Symbol& root) { |
| return SearchSyntaxTree(root, NodekForInitialization()); |
| } |
| |
| std::vector<verible::TreeSearchMatch> FindAllGenerateBlocks( |
| const verible::Symbol& root) { |
| return SearchSyntaxTree(root, NodekGenerateBlock()); |
| } |
| |
| static const SyntaxTreeNode* GetGenericStatementBody( |
| const SyntaxTreeNode* node) { |
| if (!node) return 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(MatchNodeEnumOrNull( |
| SymbolCastToNode(if_clause), NodeEnum::kGenerateIfClause)); |
| if (!body_node) return nullptr; |
| return GetSubtreeAsNode(*body_node, NodeEnum::kGenerateIfBody, 0); |
| } |
| |
| const SyntaxTreeNode* GetElseClauseGenerateBody(const Symbol& else_clause) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(else_clause), NodeEnum::kGenerateElseClause)); |
| if (!body_node) return nullptr; |
| return GetSubtreeAsNode(*body_node, NodeEnum::kGenerateElseBody, 0); |
| } |
| |
| const SyntaxTreeNode* GetLoopGenerateBody(const Symbol& loop) { |
| return GetGenericStatementBody(MatchNodeEnumOrNull( |
| 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 = MatchNodeEnumOrNull( |
| SymbolCastToNode(conditional), NodeEnum::kConditionalGenerateConstruct); |
| if (!node || node->children().size() < 2) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(SymbolCastToNode(*else_ptr), |
| NodeEnum::kGenerateElseClause); |
| } |
| |
| const SyntaxTreeNode* GetIfClauseStatementBody(const Symbol& if_clause) { |
| const auto* body_node = GetGenericStatementBody( |
| MatchNodeEnumOrNull(SymbolCastToNode(if_clause), NodeEnum::kIfClause)); |
| if (!body_node) return nullptr; |
| return GetSubtreeAsNode(*body_node, NodeEnum::kIfBody, 0); |
| } |
| |
| const SyntaxTreeNode* GetElseClauseStatementBody(const Symbol& else_clause) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(else_clause), NodeEnum::kElseClause)); |
| if (!body_node) return nullptr; |
| 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 = MatchNodeEnumOrNull(SymbolCastToNode(conditional), |
| NodeEnum::kConditionalStatement); |
| if (!node || node->children().size() < 2) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(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(MatchNodeEnumOrNull( |
| SymbolCastToNode(assertion_clause), NodeEnum::kAssertionClause)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kAssertionBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetAssertionStatementElseClause( |
| const Symbol& assertion_statement) { |
| const auto* node = MatchNodeEnumOrNull(SymbolCastToNode(assertion_statement), |
| NodeEnum::kAssertionStatement); |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(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(MatchNodeEnumOrNull( |
| SymbolCastToNode(assume_clause), NodeEnum::kAssumeClause)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kAssumeBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetAssumeStatementElseClause( |
| const Symbol& assume_statement) { |
| const auto* node = MatchNodeEnumOrNull(SymbolCastToNode(assume_statement), |
| NodeEnum::kAssumeStatement); |
| if (!node) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(SymbolCastToNode(*else_ptr), |
| NodeEnum::kElseClause); |
| } |
| |
| const SyntaxTreeNode* GetCoverStatementBody(const Symbol& cover_statement) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(cover_statement), NodeEnum::kCoverStatement)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kCoverBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetWaitStatementBody(const Symbol& wait_statement) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(wait_statement), NodeEnum::kWaitStatement)); |
| if (!body_node) return nullptr; |
| 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(MatchNodeEnumOrNull( |
| SymbolCastToNode(assert_clause), NodeEnum::kAssertPropertyClause)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kAssertPropertyBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetAssertPropertyStatementElseClause( |
| const Symbol& assert_property_statement) { |
| const auto* node = |
| MatchNodeEnumOrNull(SymbolCastToNode(assert_property_statement), |
| NodeEnum::kAssertPropertyStatement); |
| if (!node) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(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(MatchNodeEnumOrNull( |
| SymbolCastToNode(assume_clause), NodeEnum::kAssumePropertyClause)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kAssumePropertyBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetAssumePropertyStatementElseClause( |
| const Symbol& assume_property_statement) { |
| const auto* node = |
| MatchNodeEnumOrNull(SymbolCastToNode(assume_property_statement), |
| NodeEnum::kAssumePropertyStatement); |
| if (!node) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(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(MatchNodeEnumOrNull( |
| SymbolCastToNode(expect_clause), NodeEnum::kExpectPropertyClause)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kExpectPropertyBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetExpectPropertyStatementElseClause( |
| const Symbol& expect_property_statement) { |
| const auto* node = |
| MatchNodeEnumOrNull(SymbolCastToNode(expect_property_statement), |
| NodeEnum::kExpectPropertyStatement); |
| if (!node) return nullptr; |
| const Symbol* else_ptr = node->children().back().get(); |
| if (else_ptr == nullptr) return nullptr; |
| return MatchNodeEnumOrNull(SymbolCastToNode(*else_ptr), |
| NodeEnum::kElseClause); |
| } |
| |
| const SyntaxTreeNode* GetCoverPropertyStatementBody( |
| const Symbol& cover_property) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(cover_property), NodeEnum::kCoverPropertyStatement)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kCoverPropertyBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetCoverSequenceStatementBody( |
| const Symbol& cover_sequence) { |
| const auto* body_node = GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(cover_sequence), NodeEnum::kCoverSequenceStatement)); |
| if (!body_node) return nullptr; |
| return verible::CheckOptionalSymbolAsNode( |
| GetSubtreeAsSymbol(*body_node, NodeEnum::kCoverSequenceBody, 0)); |
| } |
| |
| const SyntaxTreeNode* GetLoopStatementBody(const Symbol& loop) { |
| return GetGenericStatementBody( |
| MatchNodeEnumOrNull(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(MatchNodeEnumOrNull( |
| SymbolCastToNode(forever), NodeEnum::kForeverLoopStatement)); |
| } |
| |
| const SyntaxTreeNode* GetForeachStatementBody(const Symbol& foreach) { |
| return GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(foreach), NodeEnum::kForeachLoopStatement)); |
| } |
| |
| const SyntaxTreeNode* GetRepeatStatementBody(const Symbol& repeat) { |
| return GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(repeat), NodeEnum::kRepeatLoopStatement)); |
| } |
| |
| const SyntaxTreeNode* GetWhileStatementBody(const Symbol& while_stmt) { |
| return GetGenericStatementBody(MatchNodeEnumOrNull( |
| SymbolCastToNode(while_stmt), NodeEnum::kWhileLoopStatement)); |
| } |
| |
| const SyntaxTreeNode* GetProceduralTimingControlStatementBody( |
| const Symbol& proc_timing_control) { |
| return GetGenericStatementBody( |
| MatchNodeEnumOrNull(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; |
| } |
| } |
| |
| // Returns the data type node from for loop initialization. |
| const verible::SyntaxTreeNode* GetDataTypeFromForInitialization( |
| const verible::Symbol& for_initialization) { |
| const auto* data_type = verible::GetSubtreeAsSymbol( |
| for_initialization, NodeEnum::kForInitialization, 1); |
| if (data_type == nullptr) { |
| return nullptr; |
| } |
| return &verible::SymbolCastToNode(*data_type); |
| } |
| |
| // Returns the variable name leaf from for loop initialization. |
| const verible::SyntaxTreeLeaf* GetVariableNameFromForInitialization( |
| const verible::Symbol& for_initialization) { |
| const Symbol* child = verible::GetSubtreeAsSymbol( |
| for_initialization, NodeEnum::kForInitialization, 2); |
| if (child->Kind() == verible::SymbolKind::kLeaf) { |
| return &SymbolCastToLeaf(*child); |
| } |
| const verible::SyntaxTreeNode* lpvalue = |
| verible::GetSubtreeAsNode(*child, NodeEnum::kLPValue, 0); |
| return AutoUnwrapIdentifier(*GetUnqualifiedIdFromReferenceCallBase(*lpvalue)); |
| } |
| |
| // Returns the rhs expression from for loop initialization. |
| const verible::SyntaxTreeNode* GetExpressionFromForInitialization( |
| const verible::Symbol& for_initialization) { |
| return verible::GetSubtreeAsNode(for_initialization, |
| NodeEnum::kForInitialization, 4, |
| NodeEnum::kExpression); |
| } |
| |
| const verible::SyntaxTreeNode* GetGenerateBlockBegin( |
| const verible::Symbol& generate_block) { |
| return verible::GetSubtreeAsNode(generate_block, NodeEnum::kGenerateBlock, 0, |
| NodeEnum::kBegin); |
| } |
| |
| const verible::SyntaxTreeNode* GetGenerateBlockEnd( |
| const verible::Symbol& generate_block) { |
| return verible::GetSubtreeAsNode(generate_block, NodeEnum::kGenerateBlock, 2, |
| NodeEnum::kEnd); |
| } |
| |
| } // namespace verilog |