blob: 319d9e90dd66fb7aa5d64620f3dcb4c9cc6bac50 [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/tools/kythe/scope_resolver.h"
#include <vector>
#include "absl/strings/string_view.h"
namespace verilog {
namespace kythe {
void Scope::AddMemberItem(const ScopeMemberItem& member_item) {
members_.insert({member_item.signature.Names().back(), member_item});
}
void Scope::AppendScope(const Scope& scope) {
for (const auto& item : scope.Members()) {
members_.insert(item);
}
}
const VName* Scope::SearchForDefinition(absl::string_view name) const {
const auto& found = members_.find(name);
return found == members_.end() ? nullptr : &found->second;
}
void Scope::RemoveMember(const ScopeMemberItem& member) {
members_.erase(member.signature.Names().back());
}
const VName* ScopeContext::SearchForDefinition(absl::string_view name) const {
for (const Scope* scope : verible::make_range(rbegin(), rend())) {
const VName* result = scope->SearchForDefinition(name);
if (result != nullptr) {
return result;
}
}
return nullptr;
}
void ScopeResolver::RemoveDefinitionFromCurrentScope(const VName& vname) {
scope_context_.top().RemoveMember(vname);
}
void ScopeResolver::MapSignatureToScope(const Signature& signature,
const Scope& scope) {
scopes_[signature] = scope; // copy-assign
}
void ScopeResolver::AppendScopeToCurrentScope(const Scope& scope) {
scope_context_.top().AppendScope(scope);
}
void ScopeResolver::AddDefinitionToCurrentScope(
const ScopeMemberItem& new_member) {
scope_context_.top().AddMemberItem(new_member);
}
const VName* ScopeResolver::SearchForDefinitionInGlobalScope(
absl::string_view reference_name) const {
const VName* definition =
SearchForDefinitionInScope(global_scope_signature_, reference_name);
if (definition != nullptr) {
return definition;
}
if (previous_file_scope_resolver_ != nullptr) {
return previous_file_scope_resolver_->SearchForDefinitionInGlobalScope(
reference_name);
}
return nullptr;
}
const VName* ScopeResolver::SearchForDefinitionInScopeContext(
absl::string_view reference_name) const {
return scope_context_.SearchForDefinition(reference_name);
}
const VName* ScopeResolver::SearchForDefinitionInCurrentScope(
absl::string_view name) const {
return scope_context_.top().SearchForDefinition(name);
}
std::vector<std::pair<const VName*, const Scope*>>
ScopeResolver::SearchForDefinitions(
const std::vector<absl::string_view>& names) const {
std::vector<std::pair<const VName*, const Scope*>> definitions;
if (names.empty()) {
return definitions;
}
// Try to find the definition in the scopes of the current file.
const VName* definition = SearchForDefinitionInScopeContext(names[0]);
// Try to find the definition in the previous files' scopes.
if (definition == nullptr && previous_file_scope_resolver_ != nullptr) {
// This is a linear-time search over files.
definition =
previous_file_scope_resolver_->SearchForDefinitionInGlobalScope(
names[0]);
}
if (definition == nullptr) {
return definitions;
}
const Scope* current_scope = SearchForScope(definition->signature);
definitions.push_back({definition, current_scope});
// Iterate over the names and try to find the definition in the current scope.
for (const auto& name : verible::make_range(names.begin() + 1, names.end())) {
if (current_scope == nullptr) {
break;
}
const VName* definition = current_scope->SearchForDefinition(name);
if (definition == nullptr) {
break;
}
current_scope = SearchForScope(definition->signature);
definitions.push_back({definition, current_scope});
}
return definitions;
}
const Scope* ScopeResolver::SearchForScope(const Signature& signature) const {
const auto scope = scopes_.find(signature);
if (scope != scopes_.end()) {
return &scope->second;
}
// Try to find the definition in the previous files' scopes.
// This is a linear-time search over files.
if (previous_file_scope_resolver_ != nullptr) {
return previous_file_scope_resolver_->SearchForScope(signature);
}
return nullptr;
}
const VName* ScopeResolver::SearchForDefinitionInScope(
const Signature& signature, absl::string_view name) const {
const Scope* scope = SearchForScope(signature);
if (scope == nullptr) {
return nullptr;
}
return scope->SearchForDefinition(name);
}
} // namespace kythe
} // namespace verilog