| // 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/parameters.h" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "absl/strings/string_view.h" |
| #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 "common/util/casts.h" |
| #include "common/util/logging.h" |
| #include "verilog/CST/identifier.h" |
| #include "verilog/CST/verilog_matchers.h" // IWYU pragma: keep |
| #include "verilog/parser/verilog_token_enum.h" |
| |
| namespace verilog { |
| |
| using verible::down_cast; |
| using verible::SyntaxTreeLeaf; |
| |
| std::vector<verible::TreeSearchMatch> FindAllParamDeclarations( |
| const verible::Symbol& root) { |
| return verible::SearchSyntaxTree(root, NodekParamDeclaration()); |
| } |
| |
| verilog_tokentype GetParamKeyword(const verible::Symbol& symbol) { |
| // Currently the LRM is vague on what to do if no parameter/localparam is |
| // declared, see example below. As such, if it's not declared, we will treat |
| // it as a parameter. |
| // |
| // module foo #(int Bar = 1); endmodule |
| // |
| const auto* param_keyword_symbol = |
| verible::GetSubtreeAsSymbol(symbol, NodeEnum::kParamDeclaration, 0); |
| if (param_keyword_symbol == nullptr) return TK_parameter; |
| const auto* leaf = |
| down_cast<const SyntaxTreeLeaf*>(ABSL_DIE_IF_NULL(param_keyword_symbol)); |
| return static_cast<verilog_tokentype>(leaf->get().token_enum()); |
| } |
| |
| const verible::Symbol* GetParamTypeSymbol(const verible::Symbol& symbol) { |
| return verible::GetSubtreeAsSymbol(symbol, NodeEnum::kParamDeclaration, 1); |
| } |
| |
| const verible::TokenInfo& GetParameterNameToken(const verible::Symbol& symbol) { |
| const auto* param_type_symbol = GetParamTypeSymbol(symbol); |
| |
| // Check for implicit type declaration, in which case [2] will be a leaf. |
| const auto* identifier_symbol = |
| verible::GetSubtreeAsSymbol(*param_type_symbol, NodeEnum::kParamType, 2); |
| auto t = ABSL_DIE_IF_NULL(identifier_symbol)->Tag(); |
| const SyntaxTreeLeaf* identifier_leaf = nullptr; |
| if (t.kind == verible::SymbolKind::kNode) |
| identifier_leaf = GetIdentifier(*identifier_symbol); |
| else |
| identifier_leaf = down_cast<const SyntaxTreeLeaf*>(identifier_symbol); |
| |
| return ABSL_DIE_IF_NULL(identifier_leaf)->get(); |
| } |
| |
| std::vector<const verible::TokenInfo*> GetAllParameterNameTokens( |
| const verible::Symbol& symbol) { |
| std::vector<const verible::TokenInfo*> identifiers; |
| identifiers.push_back(&GetParameterNameToken(symbol)); |
| |
| for (const auto* s : GetAllAssignedParameterSymbols(symbol)) { |
| identifiers.push_back(&GetAssignedParameterNameToken(*s)); |
| } |
| |
| return identifiers; |
| } |
| |
| const verible::TokenInfo& GetAssignedParameterNameToken( |
| const verible::Symbol& symbol) { |
| const auto* identifier = SymbolCastToNode(symbol)[0].get(); |
| |
| return AutoUnwrapIdentifier(*ABSL_DIE_IF_NULL(identifier))->get(); |
| } |
| |
| std::vector<const verible::Symbol*> GetAllAssignedParameterSymbols( |
| const verible::Symbol& root) { |
| std::vector<const verible::Symbol*> symbols; |
| |
| for (const auto& id : SearchSyntaxTree(root, NodekParameterAssign())) { |
| symbols.push_back(id.match); |
| } |
| |
| return symbols; |
| } |
| |
| const verible::TokenInfo& GetSymbolIdentifierFromParamDeclaration( |
| const verible::Symbol& symbol) { |
| // Assert that symbol is a 'parameter type' declaration. |
| CHECK(IsParamTypeDeclaration(symbol)); |
| |
| const auto* type_symbol = GetTypeAssignmentFromParamDeclaration(symbol); |
| const auto* symbol_identifier_leaf = |
| GetIdentifierLeafFromTypeAssignment(*ABSL_DIE_IF_NULL(type_symbol)); |
| return ABSL_DIE_IF_NULL(symbol_identifier_leaf)->get(); |
| } |
| |
| bool IsParamTypeDeclaration(const verible::Symbol& symbol) { |
| // Assert that symbol is a parameter declaration. |
| auto t = symbol.Tag(); |
| CHECK_EQ(t.kind, verible::SymbolKind::kNode); |
| CHECK_EQ(NodeEnum(t.tag), NodeEnum::kParamDeclaration); |
| |
| const auto* param_type_symbol = GetParamTypeSymbol(symbol); |
| if (param_type_symbol->Kind() == verible::SymbolKind::kLeaf) { |
| // Check that its token_enum is TK_type. |
| const auto* tk_type_leaf = |
| down_cast<const SyntaxTreeLeaf*>(param_type_symbol); |
| CHECK_EQ(tk_type_leaf->get().token_enum(), TK_type); |
| return true; |
| } |
| return false; |
| } |
| |
| const verible::Symbol* GetTypeAssignmentFromParamDeclaration( |
| const verible::Symbol& symbol) { |
| // Get the Type AssignmentList or kTypeAssignment symbol. |
| const auto& assignment_symbol = |
| verible::GetSubtreeAsNode(symbol, NodeEnum::kParamDeclaration, 2); |
| const auto assignment_tag = assignment_symbol.Tag(); |
| |
| // Check which type of node it is. |
| if (NodeEnum(assignment_tag.tag) == NodeEnum::kTypeAssignment) { |
| return &assignment_symbol; |
| } else { |
| const auto& type_symbol = verible::GetSubtreeAsNode( |
| assignment_symbol, NodeEnum::kTypeAssignmentList, 0, |
| NodeEnum::kTypeAssignment); |
| return &type_symbol; |
| } |
| } |
| |
| const verible::SyntaxTreeLeaf* GetIdentifierLeafFromTypeAssignment( |
| const verible::Symbol& symbol) { |
| return &verible::GetSubtreeAsLeaf(symbol, NodeEnum::kTypeAssignment, 0); |
| } |
| |
| const verible::Symbol* GetParamTypeInfoSymbol(const verible::Symbol& symbol) { |
| const auto* param_type_symbol = GetParamTypeSymbol(symbol); |
| return verible::GetSubtreeAsSymbol(*param_type_symbol, NodeEnum::kParamType, |
| 0); |
| } |
| |
| namespace { |
| // TODO(hzeller): provide something like this in tree_utils.h ? |
| struct EnumTokenIndex { |
| NodeEnum expected_type; |
| int next_index; |
| }; |
| const verible::Symbol* TryDescentPath( |
| const verible::Symbol& symbol, std::initializer_list<EnumTokenIndex> path) { |
| const verible::Symbol* value = &symbol; |
| for (auto p : path) { |
| value = GetSubtreeAsSymbol(*value, p.expected_type, p.next_index); |
| if (value == nullptr) return nullptr; |
| } |
| return value; |
| } |
| } // namespace |
| |
| const verible::Symbol* GetParamAssignExpression(const verible::Symbol& symbol) { |
| return TryDescentPath(symbol, {{NodeEnum::kParamDeclaration, 2}, |
| {NodeEnum::kTrailingAssign, 1}, |
| {NodeEnum::kExpression, 0}}); |
| } |
| |
| bool IsTypeInfoEmpty(const verible::Symbol& symbol) { |
| // Assert that symbol is NodekTypeInfo |
| CHECK_EQ(symbol.Kind(), verible::SymbolKind::kNode); |
| CHECK_EQ(NodeEnum(symbol.Tag().tag), NodeEnum::kTypeInfo); |
| |
| const auto& type_info_node = verible::SymbolCastToNode(symbol); |
| |
| return (type_info_node[0] == nullptr && type_info_node[1] == nullptr && |
| type_info_node[2] == nullptr); |
| } |
| |
| } // namespace verilog |