| // Copyright 2017-2023 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/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/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 |
| #include "verilog/CST/verilog_nonterminals.h" |
| |
| 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->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->size() < 2) return nullptr; |
| const Symbol *else_ptr = node->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->size() < 2) return nullptr; |
| const Symbol *else_ptr = node->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->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->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->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->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->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); |
| const verible::SyntaxTreeNode *local_root = |
| GetLocalRootFromReference(*lpvalue); |
| if (!local_root) return nullptr; |
| const verible::Symbol *identifiers = GetIdentifiersFromLocalRoot(*local_root); |
| return AutoUnwrapIdentifier(*identifiers); |
| } |
| |
| // 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); |
| } |
| |
| const verible::SyntaxTreeNode *GetProceduralTimingControlFromAlways( |
| const verible::SyntaxTreeNode &always_statement) { |
| return verible::GetSubtreeAsNode(always_statement, NodeEnum::kAlwaysStatement, |
| 1, |
| NodeEnum::kProceduralTimingControlStatement); |
| } |
| |
| const verible::Symbol *GetEventControlFromProceduralTimingControl( |
| const verible::SyntaxTreeNode &proc_timing_ctrl) { |
| return verible::GetSubtreeAsNode(proc_timing_ctrl, |
| NodeEnum::kProceduralTimingControlStatement, |
| 0, NodeEnum::kEventControl); |
| } |
| |
| } // namespace verilog |