blob: be452f5beeeaad7b21df58eaca95c8731a450814 [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/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