2018-05-01 12:50:34 -07:00
|
|
|
// Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2018-03-22 17:08:20 -07:00
|
|
|
#include "symbol.h"
|
|
|
|
#include "scope.h"
|
2018-06-18 11:03:43 -07:00
|
|
|
#include "../common/idioms.h"
|
2018-03-22 17:08:20 -07:00
|
|
|
#include <memory>
|
|
|
|
|
2018-03-23 12:24:29 -07:00
|
|
|
namespace Fortran::semantics {
|
2018-03-22 17:08:20 -07:00
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const parser::CharBlock &name) {
|
|
|
|
return os << name.ToString();
|
|
|
|
}
|
|
|
|
|
2018-08-02 16:21:27 -07:00
|
|
|
const Scope *ModuleDetails::parent() const {
|
|
|
|
return isSubmodule_ ? &scope_->parent() : nullptr;
|
|
|
|
}
|
|
|
|
const Scope *ModuleDetails::ancestor() const {
|
|
|
|
if (!isSubmodule_) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
for (auto *scope{scope_};;) {
|
|
|
|
auto *parent{&scope->parent()};
|
|
|
|
if (parent->kind() != Scope::Kind::Module) {
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
scope = parent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void ModuleDetails::set_scope(const Scope *scope) {
|
|
|
|
CHECK(!scope_);
|
|
|
|
bool scopeIsSubmodule{scope->parent().kind() == Scope::Kind::Module};
|
|
|
|
CHECK(isSubmodule_ == scopeIsSubmodule);
|
|
|
|
scope_ = scope;
|
|
|
|
}
|
|
|
|
|
2018-04-12 12:59:42 -07:00
|
|
|
void EntityDetails::set_type(const DeclTypeSpec &type) {
|
|
|
|
CHECK(!type_);
|
|
|
|
type_ = type;
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
void ObjectEntityDetails::set_type(const DeclTypeSpec &type) {
|
|
|
|
CHECK(!type_);
|
|
|
|
type_ = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjectEntityDetails::set_shape(const ArraySpec &shape) {
|
2018-04-12 12:59:42 -07:00
|
|
|
CHECK(shape_.empty());
|
|
|
|
for (const auto &shapeSpec : shape) {
|
|
|
|
shape_.push_back(shapeSpec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
ProcEntityDetails::ProcEntityDetails(const EntityDetails &d) {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (auto type{d.type()}) {
|
2018-06-06 11:41:42 -07:00
|
|
|
interface_.set_type(*type);
|
2018-06-05 12:18:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
const Symbol &UseDetails::module() const {
|
|
|
|
// owner is a module so it must have a symbol:
|
|
|
|
return *symbol_->owner().symbol();
|
|
|
|
}
|
|
|
|
|
2018-05-22 16:12:56 -07:00
|
|
|
GenericDetails::GenericDetails(const listType &specificProcs) {
|
|
|
|
for (const auto *proc : specificProcs) {
|
|
|
|
add_specificProc(proc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 08:21:19 -07:00
|
|
|
void GenericDetails::set_specific(Symbol &specific) {
|
2018-05-22 16:12:56 -07:00
|
|
|
CHECK(!specific_);
|
2018-06-22 08:21:19 -07:00
|
|
|
specific_ = &specific;
|
|
|
|
}
|
|
|
|
void GenericDetails::set_derivedType(Symbol &derivedType) {
|
|
|
|
CHECK(!derivedType_);
|
|
|
|
derivedType_ = &derivedType;
|
2018-05-22 16:12:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const Symbol *GenericDetails::CheckSpecific() const {
|
2018-06-19 16:06:41 -07:00
|
|
|
if (specific_) {
|
2018-05-22 16:12:56 -07:00
|
|
|
for (const auto *proc : specificProcs_) {
|
2018-06-19 16:06:41 -07:00
|
|
|
if (proc == specific_) {
|
2018-05-22 16:12:56 -07:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
2018-06-19 16:06:41 -07:00
|
|
|
return specific_;
|
2018-05-22 16:12:56 -07:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:16:42 -07:00
|
|
|
// The name of the kind of details for this symbol.
|
|
|
|
// This is primarily for debugging.
|
2018-07-19 13:28:24 -07:00
|
|
|
std::string DetailsToString(const Details &details) {
|
2018-04-17 14:16:42 -07:00
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-05-22 16:12:56 -07:00
|
|
|
[](const UnknownDetails &) { return "Unknown"; },
|
|
|
|
[](const MainProgramDetails &) { return "MainProgram"; },
|
|
|
|
[](const ModuleDetails &) { return "Module"; },
|
|
|
|
[](const SubprogramDetails &) { return "Subprogram"; },
|
|
|
|
[](const SubprogramNameDetails &) { return "SubprogramName"; },
|
|
|
|
[](const EntityDetails &) { return "Entity"; },
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const ObjectEntityDetails &) { return "ObjectEntity"; },
|
|
|
|
[](const ProcEntityDetails &) { return "ProcEntity"; },
|
2018-06-22 08:21:19 -07:00
|
|
|
[](const DerivedTypeDetails &) { return "DerivedType"; },
|
2018-05-22 16:12:56 -07:00
|
|
|
[](const UseDetails &) { return "Use"; },
|
|
|
|
[](const UseErrorDetails &) { return "UseError"; },
|
|
|
|
[](const GenericDetails &) { return "Generic"; },
|
|
|
|
[](const auto &) { return "unknown"; },
|
2018-04-17 14:16:42 -07:00
|
|
|
},
|
2018-05-03 15:57:56 -07:00
|
|
|
details);
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string Symbol::GetDetailsName() const {
|
|
|
|
return DetailsToString(details_);
|
|
|
|
}
|
|
|
|
|
2018-07-28 14:10:34 -07:00
|
|
|
void Symbol::set_details(const Details &details) {
|
2018-05-14 13:51:13 -07:00
|
|
|
CHECK(CanReplaceDetails(details));
|
2018-07-28 14:10:34 -07:00
|
|
|
details_ = details;
|
2018-05-14 13:51:13 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Symbol::CanReplaceDetails(const Details &details) const {
|
|
|
|
if (has<UnknownDetails>()) {
|
|
|
|
return true; // can always replace UnknownDetails
|
|
|
|
} else {
|
2018-06-05 12:18:35 -07:00
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const UseErrorDetails &) { return true; },
|
|
|
|
[=](const ObjectEntityDetails &) { return has<EntityDetails>(); },
|
|
|
|
[=](const ProcEntityDetails &) { return has<EntityDetails>(); },
|
|
|
|
[=](const SubprogramDetails &) {
|
|
|
|
return has<SubprogramNameDetails>();
|
|
|
|
},
|
|
|
|
[](const auto &) { return false; },
|
|
|
|
},
|
|
|
|
details);
|
2018-05-14 13:51:13 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-22 08:21:19 -07:00
|
|
|
void Symbol::add_occurrence(const SourceName &name) {
|
|
|
|
if (occurrences_.back().begin() != name.begin()) {
|
|
|
|
occurrences_.push_back(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void Symbol::remove_occurrence(const SourceName &name) {
|
2018-07-17 07:02:30 -07:00
|
|
|
auto end{occurrences_.end()};
|
|
|
|
for (auto it{occurrences_.begin()}; it != end; ++it) {
|
2018-06-22 08:21:19 -07:00
|
|
|
if (it->begin() == name.begin()) {
|
|
|
|
occurrences_.erase(it);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-22 16:12:56 -07:00
|
|
|
Symbol &Symbol::GetUltimate() {
|
|
|
|
return const_cast<Symbol &>(static_cast<const Symbol *>(this)->GetUltimate());
|
|
|
|
}
|
2018-05-03 15:57:56 -07:00
|
|
|
const Symbol &Symbol::GetUltimate() const {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (const auto *details{detailsIf<UseDetails>()}) {
|
2018-05-03 15:57:56 -07:00
|
|
|
return details->symbol().GetUltimate();
|
|
|
|
} else {
|
|
|
|
return *this;
|
|
|
|
}
|
2018-04-17 14:16:42 -07:00
|
|
|
}
|
|
|
|
|
2018-06-26 15:01:42 -07:00
|
|
|
const DeclTypeSpec *Symbol::GetType() const {
|
|
|
|
return std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[](const EntityDetails &x) {
|
|
|
|
return x.type().has_value() ? &x.type().value() : nullptr;
|
|
|
|
},
|
|
|
|
[](const ObjectEntityDetails &x) {
|
|
|
|
return x.type().has_value() ? &x.type().value() : nullptr;
|
|
|
|
},
|
|
|
|
[](const ProcEntityDetails &x) { return x.interface().type(); },
|
|
|
|
[](const auto &) {
|
|
|
|
return static_cast<const DeclTypeSpec *>(nullptr);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Symbol::SetType(const DeclTypeSpec &type) {
|
|
|
|
std::visit(
|
|
|
|
common::visitors{
|
|
|
|
[&](EntityDetails &x) { x.set_type(type); },
|
|
|
|
[&](ObjectEntityDetails &x) { x.set_type(type); },
|
|
|
|
[&](ProcEntityDetails &x) { x.interface().set_type(type); },
|
|
|
|
[](auto &) {},
|
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
2018-05-14 13:51:13 -07:00
|
|
|
bool Symbol::isSubprogram() const {
|
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const SubprogramDetails &) { return true; },
|
|
|
|
[](const SubprogramNameDetails &) { return true; },
|
|
|
|
[](const GenericDetails &) { return true; },
|
|
|
|
[](const UseDetails &x) { return x.symbol().isSubprogram(); },
|
|
|
|
[](const auto &) { return false; },
|
2018-05-14 13:51:13 -07:00
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
bool Symbol::HasExplicitInterface() const {
|
|
|
|
return std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-06-05 12:18:35 -07:00
|
|
|
[](const SubprogramDetails &) { return true; },
|
|
|
|
[](const SubprogramNameDetails &) { return true; },
|
|
|
|
[](const ProcEntityDetails &x) { return x.HasExplicitInterface(); },
|
|
|
|
[](const UseDetails &x) { return x.symbol().HasExplicitInterface(); },
|
|
|
|
[](const auto &) { return false; },
|
|
|
|
},
|
|
|
|
details_);
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectEntityDetails::ObjectEntityDetails(const EntityDetails &d)
|
2018-06-22 08:21:19 -07:00
|
|
|
: isDummy_{d.isDummy()}, type_{d.type()} {}
|
2018-06-05 12:18:35 -07:00
|
|
|
|
2018-04-12 12:59:42 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const EntityDetails &x) {
|
2018-06-05 12:18:35 -07:00
|
|
|
if (x.type()) {
|
|
|
|
os << " type: " << *x.type();
|
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &os, const ObjectEntityDetails &x) {
|
2018-04-12 12:59:42 -07:00
|
|
|
if (x.type()) {
|
|
|
|
os << " type: " << *x.type();
|
|
|
|
}
|
|
|
|
if (!x.shape().empty()) {
|
|
|
|
os << " shape:";
|
|
|
|
for (const auto &s : x.shape()) {
|
|
|
|
os << ' ' << s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
bool ProcEntityDetails::HasExplicitInterface() const {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (auto *symbol{interface_.symbol()}) {
|
2018-06-05 12:18:35 -07:00
|
|
|
return symbol->HasExplicitInterface();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &os, const ProcEntityDetails &x) {
|
2018-07-17 07:02:30 -07:00
|
|
|
if (auto *symbol{x.interface_.symbol()}) {
|
2018-06-05 12:18:35 -07:00
|
|
|
os << ' ' << symbol->name().ToString();
|
2018-07-17 07:02:30 -07:00
|
|
|
} else if (auto *type{x.interface_.type()}) {
|
2018-06-05 12:18:35 -07:00
|
|
|
os << ' ' << *type;
|
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-22 08:21:19 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const DerivedTypeDetails &x) {
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-04-17 14:16:42 -07:00
|
|
|
static std::ostream &DumpType(std::ostream &os, const Symbol &symbol) {
|
2018-06-26 15:01:42 -07:00
|
|
|
if (const auto *type{symbol.GetType()}) {
|
|
|
|
os << *type << ' ';
|
2018-04-17 14:16:42 -07:00
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const Details &details) {
|
|
|
|
os << DetailsToString(details);
|
2018-03-22 17:08:20 -07:00
|
|
|
std::visit(
|
2018-06-18 11:03:43 -07:00
|
|
|
common::visitors{
|
2018-04-18 15:06:35 -07:00
|
|
|
[&](const UnknownDetails &x) {},
|
|
|
|
[&](const MainProgramDetails &x) {},
|
2018-08-02 16:21:27 -07:00
|
|
|
[&](const ModuleDetails &x) {
|
|
|
|
if (x.isSubmodule()) {
|
|
|
|
auto &ancestor{x.ancestor()->name()};
|
|
|
|
auto &parent{x.parent()->name()};
|
|
|
|
os << " (" << ancestor.ToString();
|
|
|
|
if (parent != ancestor) {
|
|
|
|
os << ':' << parent.ToString();
|
|
|
|
}
|
|
|
|
os << ")";
|
|
|
|
}
|
|
|
|
},
|
2018-03-22 17:08:20 -07:00
|
|
|
[&](const SubprogramDetails &x) {
|
2018-04-18 15:06:35 -07:00
|
|
|
os << " (";
|
2018-03-22 17:08:20 -07:00
|
|
|
int n = 0;
|
2018-04-17 14:16:42 -07:00
|
|
|
for (const auto &dummy : x.dummyArgs()) {
|
2018-03-22 17:08:20 -07:00
|
|
|
if (n++ > 0) os << ", ";
|
2018-04-17 14:16:42 -07:00
|
|
|
DumpType(os, *dummy);
|
2018-05-03 15:57:56 -07:00
|
|
|
os << dummy->name();
|
2018-03-22 17:08:20 -07:00
|
|
|
}
|
|
|
|
os << ')';
|
2018-04-17 14:16:42 -07:00
|
|
|
if (x.isFunction()) {
|
|
|
|
os << " result(";
|
|
|
|
DumpType(os, x.result());
|
2018-05-03 15:57:56 -07:00
|
|
|
os << x.result().name() << ')';
|
2018-03-22 17:08:20 -07:00
|
|
|
}
|
2018-05-14 13:51:13 -07:00
|
|
|
if (x.isInterface()) {
|
|
|
|
os << " interface";
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[&](const SubprogramNameDetails &x) {
|
|
|
|
os << ' ' << EnumToString(x.kind());
|
2018-03-22 17:08:20 -07:00
|
|
|
},
|
2018-04-18 15:06:35 -07:00
|
|
|
[&](const EntityDetails &x) { os << x; },
|
2018-06-05 12:18:35 -07:00
|
|
|
[&](const ObjectEntityDetails &x) { os << x; },
|
|
|
|
[&](const ProcEntityDetails &x) { os << x; },
|
2018-06-22 08:21:19 -07:00
|
|
|
[&](const DerivedTypeDetails &x) { os << x; },
|
2018-05-03 15:57:56 -07:00
|
|
|
[&](const UseDetails &x) {
|
|
|
|
os << " from " << x.symbol().name() << " in " << x.module().name();
|
|
|
|
},
|
|
|
|
[&](const UseErrorDetails &x) {
|
|
|
|
os << " uses:";
|
|
|
|
for (const auto &pair : x.occurrences()) {
|
|
|
|
os << " from " << pair.second->name() << " at " << *pair.first;
|
|
|
|
}
|
|
|
|
},
|
2018-05-14 13:51:13 -07:00
|
|
|
[&](const GenericDetails &x) {
|
|
|
|
for (const auto *proc : x.specificProcs()) {
|
|
|
|
os << ' ' << proc->name();
|
|
|
|
}
|
|
|
|
},
|
2018-03-22 17:08:20 -07:00
|
|
|
},
|
2018-05-03 15:57:56 -07:00
|
|
|
details);
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-05 12:18:35 -07:00
|
|
|
std::ostream &operator<<(std::ostream &o, Symbol::Flag flag) {
|
|
|
|
return o << Symbol::EnumToString(flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream &operator<<(std::ostream &o, const Symbol::Flags &flags) {
|
|
|
|
std::size_t n{flags.count()};
|
|
|
|
std::size_t seen{0};
|
|
|
|
for (std::size_t j{0}; seen < n; ++j) {
|
|
|
|
Symbol::Flag flag{static_cast<Symbol::Flag>(j)};
|
|
|
|
if (flags.test(flag)) {
|
|
|
|
if (seen++ > 0) {
|
|
|
|
o << ", ";
|
|
|
|
}
|
|
|
|
o << flag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2018-05-03 15:57:56 -07:00
|
|
|
std::ostream &operator<<(std::ostream &os, const Symbol &symbol) {
|
|
|
|
os << symbol.name();
|
|
|
|
if (!symbol.attrs().empty()) {
|
|
|
|
os << ", " << symbol.attrs();
|
|
|
|
}
|
2018-06-05 12:18:35 -07:00
|
|
|
if (!symbol.flags().empty()) {
|
|
|
|
os << " (" << symbol.flags() << ')';
|
|
|
|
}
|
2018-05-03 15:57:56 -07:00
|
|
|
os << ": " << symbol.details_;
|
2018-03-22 17:08:20 -07:00
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-06-26 15:01:42 -07:00
|
|
|
// Output a unique name for a scope by qualifying it with the names of
|
|
|
|
// parent scopes. For scopes without corresponding symbols, use "ANON".
|
|
|
|
static void DumpUniqueName(std::ostream &os, const Scope &scope) {
|
2018-08-22 16:05:06 -07:00
|
|
|
if (scope.kind() != Scope::Kind::Global) {
|
2018-06-26 15:01:42 -07:00
|
|
|
DumpUniqueName(os, scope.parent());
|
|
|
|
os << '/';
|
|
|
|
if (auto *scopeSymbol{scope.symbol()}) {
|
|
|
|
os << scopeSymbol->name().ToString();
|
|
|
|
} else {
|
|
|
|
os << "ANON";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dump a symbol for UnparseWithSymbols. This will be used for tests so the
|
|
|
|
// format should be reasonably stable.
|
|
|
|
std::ostream &DumpForUnparse(
|
|
|
|
std::ostream &os, const Symbol &symbol, bool isDef) {
|
|
|
|
DumpUniqueName(os, symbol.owner());
|
|
|
|
os << '/' << symbol.name().ToString();
|
|
|
|
if (isDef) {
|
|
|
|
if (!symbol.attrs().empty()) {
|
|
|
|
os << ' ' << symbol.attrs();
|
|
|
|
}
|
|
|
|
if (symbol.test(Symbol::Flag::Implicit)) {
|
|
|
|
os << " (implicit)";
|
|
|
|
}
|
|
|
|
os << ' ' << symbol.GetDetailsName();
|
|
|
|
if (const auto *type{symbol.GetType()}) {
|
|
|
|
os << ' ' << *type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return os;
|
|
|
|
}
|
|
|
|
|
2018-03-23 12:24:29 -07:00
|
|
|
} // namespace Fortran::semantics
|