return Bound{std::move(expr)};
}
+template<typename T>
+static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
+ const auto &spec{std::get<parser::SpecificationPart>(x.t)};
+ const auto &exec{std::get<parser::ExecutionPart>(x.t)};
+ const auto &subps{
+ std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
+ ProgramTree node{name, spec, &exec};
+ if (subps) {
+ for (const auto &subp :
+ std::get<std::list<parser::InternalSubprogram>>(subps->t)) {
+ std::visit(
+ [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
+ subp.u);
+ }
+ }
+ return node;
+}
+
+template<typename T>
+static ProgramTree BuildModuleTree(const parser::Name &name, const T &x) {
+ const auto &spec{std::get<parser::SpecificationPart>(x.t)};
+ const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
+ ProgramTree node{name, spec};
+ if (subps) {
+ for (const auto &subp :
+ std::get<std::list<parser::ModuleSubprogram>>(subps->t)) {
+ std::visit(
+ [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
+ subp.u);
+ }
+ }
+ return node;
+}
+
+ProgramTree ProgramTree::Build(const parser::ProgramUnit &x) {
+ return std::visit([](const auto &y) { return Build(y.value()); }, x.u);
+}
+ProgramTree ProgramTree::Build(const parser::MainProgram &x) {
+ const auto &stmt{
+ std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(x.t)};
+ const auto &end{std::get<parser::Statement<parser::EndProgramStmt>>(x.t)};
+ static parser::Name emptyName;
+ const auto &name{stmt ? stmt->statement.v : emptyName};
+ return BuildSubprogramTree(name, x).set_stmt(*stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::FunctionSubprogram &x) {
+ const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
+ const auto &end{std::get<parser::Statement<parser::EndFunctionStmt>>(x.t)};
+ const auto &name{std::get<parser::Name>(stmt.statement.t)};
+ return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::SubroutineSubprogram &x) {
+ const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)};
+ const auto &end{std::get<parser::Statement<parser::EndSubroutineStmt>>(x.t)};
+ const auto &name{std::get<parser::Name>(stmt.statement.t)};
+ return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::SeparateModuleSubprogram &x) {
+ const auto &stmt{std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t)};
+ const auto &end{
+ std::get<parser::Statement<parser::EndMpSubprogramStmt>>(x.t)};
+ const auto &name{stmt.statement.v};
+ return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::Module &x) {
+ const auto &stmt{std::get<parser::Statement<parser::ModuleStmt>>(x.t)};
+ const auto &end{std::get<parser::Statement<parser::EndModuleStmt>>(x.t)};
+ const auto &name{stmt.statement.v};
+ return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::Submodule &x) {
+ const auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
+ const auto &end{std::get<parser::Statement<parser::EndSubmoduleStmt>>(x.t)};
+ const auto &name{std::get<parser::Name>(stmt.statement.t)};
+ return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
+}
+ProgramTree ProgramTree::Build(const parser::BlockData &x) {
+ DIE("BlockData not yet implemented");
+}
+
+const parser::ParentIdentifier &ProgramTree::GetParentId() const {
+ const auto *stmt{
+ std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};
+ return std::get<parser::ParentIdentifier>(stmt->statement.t);
+}
+
+bool ProgramTree::IsModule() const {
+ auto kind{GetKind()};
+ return kind == Kind::Module || kind == Kind::Submodule;
+}
+
+Symbol::Flag ProgramTree::GetSubpFlag() const {
+ return GetKind() == Kind::Function ? Symbol::Flag::Function
+ : Symbol::Flag::Subroutine;
+}
+
+bool ProgramTree::HasModulePrefix() const {
+ using ListType = std::list<parser::PrefixSpec>;
+ const auto *prefixes{std::visit(
+ common::visitors{
+ [](const parser::Statement<parser::FunctionStmt> *x) {
+ return &std::get<ListType>(x->statement.t);
+ },
+ [](const parser::Statement<parser::SubroutineStmt> *x) {
+ return &std::get<ListType>(x->statement.t);
+ },
+ [](const auto *) -> const ListType * { return nullptr; },
+ },
+ stmt_)};
+ if (prefixes) {
+ for (const auto &prefix : *prefixes) {
+ if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ProgramTree::Kind ProgramTree::GetKind() const {
+ return std::visit(
+ common::visitors{
+ [](const parser::Statement<parser::ProgramStmt> *) {
+ return Kind::Program;
+ },
+ [](const parser::Statement<parser::FunctionStmt> *) {
+ return Kind::Function;
+ },
+ [](const parser::Statement<parser::SubroutineStmt> *) {
+ return Kind::Subroutine;
+ },
+ [](const parser::Statement<parser::MpSubprogramStmt> *) {
+ return Kind::MpSubprogram;
+ },
+ [](const parser::Statement<parser::ModuleStmt> *) {
+ return Kind::Module;
+ },
+ [](const parser::Statement<parser::SubmoduleStmt> *) {
+ return Kind::Submodule;
+ },
+ },
+ stmt_);
+}
+
+void ProgramTree::set_scope(Scope &scope) {
+ scope_ = &scope;
+ CHECK(endStmt_);
+ scope.AddSourceRange(*endStmt_);
+}
+
+void ProgramTree::AddChild(ProgramTree &&child) {
+ children_.emplace_back(std::move(child));
+}
+
}
#include "symbol.h"
#include "type.h"
#include "../parser/message.h"
-
-namespace Fortran::parser {
-class CharBlock;
-struct ArraySpec;
-struct ComponentArraySpec;
-struct CoarraySpec;
-struct DefinedOpName;
-struct GenericSpec;
-struct Name;
-}
+#include "../parser/parse-tree.h"
namespace Fortran::semantics {
ArraySpec AnalyzeCoarraySpec(
SemanticsContext &context, const parser::CoarraySpec &);
-}
+// A tree of program units and their contained subprograms.
+// The root nodes represent: main program, function, subroutine,
+// module subprogram, module, or submodule.
+class ProgramTree {
+public:
+ static ProgramTree Build(const parser::ProgramUnit &);
+ static ProgramTree Build(const parser::MainProgram &);
+ static ProgramTree Build(const parser::FunctionSubprogram &);
+ static ProgramTree Build(const parser::SubroutineSubprogram &);
+ static ProgramTree Build(const parser::SeparateModuleSubprogram &);
+ static ProgramTree Build(const parser::Module &);
+ static ProgramTree Build(const parser::Submodule &);
+ static ProgramTree Build(const parser::BlockData &);
+
+ ENUM_CLASS(Kind, // kind of node
+ Program, Function, Subroutine, MpSubprogram, Module, Submodule)
+ using Stmt = std::variant< // the statement that introduces the program unit
+ const parser::Statement<parser::ProgramStmt> *,
+ const parser::Statement<parser::FunctionStmt> *,
+ const parser::Statement<parser::SubroutineStmt> *,
+ const parser::Statement<parser::MpSubprogramStmt> *,
+ const parser::Statement<parser::ModuleStmt> *,
+ const parser::Statement<parser::SubmoduleStmt> *>;
+
+ ProgramTree(const parser::Name &name, const parser::SpecificationPart &spec,
+ const parser::ExecutionPart *exec = nullptr)
+ : name_{name}, spec_{spec}, exec_{exec} {}
+
+ const parser::Name &name() const { return name_; }
+ Kind GetKind() const;
+ const Stmt &stmt() const { return stmt_; }
+ const parser::ParentIdentifier &GetParentId() const; // only for Submodule
+ const parser::SpecificationPart &spec() const { return spec_; }
+ const parser::ExecutionPart *exec() const { return exec_; }
+ std::vector<ProgramTree> &children() { return children_; }
+ const std::vector<ProgramTree> &children() const { return children_; }
+ Symbol::Flag GetSubpFlag() const;
+ bool IsModule() const; // Module or Submodule
+ bool HasModulePrefix() const; // in function or subroutine stmt
+ Scope *scope() const { return scope_; }
+ void set_scope(Scope &);
+ void AddChild(ProgramTree &&);
+
+ template<typename T> ProgramTree &set_stmt(const parser::Statement<T> &stmt) {
+ stmt_ = &stmt;
+ return *this;
+ }
+ template<typename T>
+ ProgramTree &set_endStmt(const parser::Statement<T> &stmt) {
+ endStmt_ = &stmt.source;
+ return *this;
+ }
+private:
+ const parser::Name &name_;
+ Stmt stmt_{
+ static_cast<const parser::Statement<parser::ProgramStmt> *>(nullptr)};
+ const parser::SpecificationPart &spec_;
+ const parser::ExecutionPart *exec_{nullptr};
+ std::vector<ProgramTree> children_;
+ Scope *scope_{nullptr};
+ const parser::CharBlock *endStmt_{nullptr};
+};
+
+}
#endif // FORTRAN_SEMANTICS_RESOLVE_NAMES_H_
void PushScope(Scope::Kind kind, Symbol *symbol);
void PushScope(Scope &scope);
void PopScope();
- void ClearScopes() {
- PopScope(); // trigger ConvertToObjectEntity calls
- currScope_ = &context().globalScope();
- }
+ void SetScope(Scope &);
template<typename T> bool Pre(const parser::Statement<T> &x) {
messageHandler().set_currStmtSource(&x.source);
}
protected:
- // When subpNamesOnly_ is set we are only collecting procedure names.
- // Create symbols with SubprogramNameDetails of the given kind.
- std::optional<SubprogramKind> subpNamesOnly_;
-
// Apply the implicit type rules to this symbol.
void ApplyImplicitRules(Symbol &);
const DeclTypeSpec *GetImplicitType(Symbol &);
const DeclTypeSpec &MakeLogicalType(
const std::optional<parser::KindSelector> &);
- // Walk the ModuleSubprogramPart or InternalSubprogramPart collecting names.
- template<typename T>
- void WalkSubprogramPart(const std::optional<T> &subpPart) {
- if (subpPart) {
- if (std::is_same_v<T, parser::ModuleSubprogramPart>) {
- subpNamesOnly_ = SubprogramKind::Module;
- } else if (std::is_same_v<T, parser::InternalSubprogramPart>) {
- subpNamesOnly_ = SubprogramKind::Internal;
- } else {
- static_assert("unexpected type");
- }
- Walk(*subpPart);
- subpNamesOnly_ = std::nullopt;
- }
- }
-
private:
Scope *currScope_{nullptr};
};
class ModuleVisitor : public virtual ScopeHandler {
public:
- bool Pre(const parser::Module &);
- void Post(const parser::Module &);
- bool Pre(const parser::Submodule &);
- void Post(const parser::Submodule &);
bool Pre(const parser::AccessStmt &);
bool Pre(const parser::Only &);
bool Pre(const parser::Rename::Names &);
bool Pre(const parser::UseStmt &);
void Post(const parser::UseStmt &);
+ void BeginModule(const parser::Name &, bool isSubmodule);
+ bool BeginSubmodule(const parser::Name &, const parser::ParentIdentifier &);
+ void ApplyDefaultAccess();
+
private:
// The default access spec for this module.
Attr defaultAccess_{Attr::PUBLIC};
const Scope *useModuleScope_{nullptr};
Symbol &SetAccess(const SourceName &, Attr);
- void ApplyDefaultAccess();
void AddUse(const parser::Rename::Names &);
void AddUse(const parser::Rename::Operators &);
Symbol *AddUse(const SourceName &);
// Record a use from useModuleScope_ of use Name/Symbol as local Name/Symbol
SymbolRename AddUse(const SourceName &localName, const SourceName &useName);
void AddUse(const SourceName &, Symbol &localSymbol, const Symbol &useSymbol);
- Symbol &BeginModule(const parser::Name &, bool isSubmodule,
- const std::optional<parser::ModuleSubprogramPart> &);
Scope *FindModule(const parser::Name &, Scope *ancestor = nullptr);
};
void Post(const parser::SubroutineStmt &);
bool Pre(const parser::FunctionStmt &);
void Post(const parser::FunctionStmt &);
- bool Pre(const parser::SubroutineSubprogram &);
- void Post(const parser::SubroutineSubprogram &);
- bool Pre(const parser::FunctionSubprogram &);
- void Post(const parser::FunctionSubprogram &);
bool Pre(const parser::InterfaceBody::Subroutine &);
void Post(const parser::InterfaceBody::Subroutine &);
bool Pre(const parser::InterfaceBody::Function &);
void Post(const parser::InterfaceBody::Function &);
- bool Pre(const parser::SeparateModuleSubprogram &);
- void Post(const parser::SeparateModuleSubprogram &);
bool Pre(const parser::Suffix &);
bool Pre(const parser::PrefixSpec &);
void Post(const parser::ImplicitPart &);
+ bool BeginSubprogram(
+ const parser::Name &, Symbol::Flag, bool hasModulePrefix = false);
+ void EndSubprogram();
+
protected:
// Set when we see a stmt function that is really an array element assignment
bool badStmtFuncFound_{false};
const SourceName *source{nullptr};
} funcInfo_;
- bool BeginSubprogram(const parser::Name &, Symbol::Flag, bool hasModulePrefix,
- const std::optional<parser::InternalSubprogramPart> &);
- void EndSubprogram();
// Create a subprogram symbol in the current scope and push a new scope.
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag);
Symbol *GetSpecificFromGeneric(const parser::Name &);
template<typename T> void Post(const T &) {}
void Post(const parser::SpecificationPart &);
- bool Pre(const parser::MainProgram &);
- void Post(const parser::EndProgramStmt &);
void Post(const parser::Program &);
bool Pre(const parser::ImplicitStmt &);
void Post(const parser::PointerObject &);
void Post(const parser::TypeGuardStmt &);
bool Pre(const parser::StmtFunctionStmt &);
bool Pre(const parser::DefinedOpName &);
+ bool Pre(const parser::ProgramUnit &);
+
+ // These nodes should never be reached: they are handled in ProgramUnit
+ bool Pre(const parser::MainProgram &) { DIE("unreachable"); }
+ bool Pre(const parser::FunctionSubprogram &) { DIE("unreachable"); }
+ bool Pre(const parser::SubroutineSubprogram &) { DIE("unreachable"); }
+ bool Pre(const parser::SeparateModuleSubprogram &) { DIE("unreachable"); }
+ bool Pre(const parser::Module &) { DIE("unreachable"); }
+ bool Pre(const parser::Submodule &) { DIE("unreachable"); }
+ bool Pre(const parser::BlockData &) { DIE("unreachable"); }
private:
// Kind of procedure we are expecting to see in a ProcedureDesignator
void HandleCall(Symbol::Flag, const parser::Call &);
void HandleProcedureName(Symbol::Flag, const parser::Name &);
bool SetProcFlag(const parser::Name &, Symbol &, Symbol::Flag);
+ void ResolveExecutionParts(const ProgramTree &);
+ void AddSubpNames(const ProgramTree &);
+ bool BeginScope(const ProgramTree &);
+ void ResolveSpecificationParts(ProgramTree &);
};
// ImplicitRules implementation
auto &symbol{*pair.second};
ConvertToObjectEntity(symbol); // if not a proc by now, it is an object
}
- currScope_ = &currScope_->parent();
+ SetScope(currScope_->parent());
+}
+void ScopeHandler::SetScope(Scope &scope) {
+ currScope_ = &scope;
ImplicitRulesVisitor::SetScope(InclusiveScope());
}
}
}
-bool ModuleVisitor::Pre(const parser::Submodule &x) {
- auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
- auto &name{std::get<parser::Name>(stmt.statement.t)};
- auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
- auto &parentId{std::get<parser::ParentIdentifier>(stmt.statement.t)};
+bool ModuleVisitor::BeginSubmodule(
+ const parser::Name &name, const parser::ParentIdentifier &parentId) {
auto &ancestorName{std::get<parser::Name>(parentId.t)};
auto &parentName{std::get<std::optional<parser::Name>>(parentId.t)};
Scope *ancestor{FindModule(ancestorName)};
return false;
}
PushScope(*parentScope); // submodule is hosted in parent
- BeginModule(name, true, subpPart);
+ BeginModule(name, true);
if (!ancestor->AddSubmodule(name.source, currScope())) {
Say(name, "Module '%s' already has a submodule named '%s'"_err_en_US,
ancestorName.source, name.source);
}
return true;
}
-void ModuleVisitor::Post(const parser::Submodule &) { ClearScopes(); }
-bool ModuleVisitor::Pre(const parser::Module &x) {
- // Make a symbol and push a scope for this module
- const auto &name{
- std::get<parser::Statement<parser::ModuleStmt>>(x.t).statement.v};
- auto &subpPart{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
- BeginModule(name, false, subpPart);
- return true;
-}
-
-void ModuleVisitor::Post(const parser::Module &) {
- ApplyDefaultAccess();
- PopScope();
- prevAccessStmt_ = nullptr;
-}
-
-Symbol &ModuleVisitor::BeginModule(const parser::Name &name, bool isSubmodule,
- const std::optional<parser::ModuleSubprogramPart> &subpPart) {
+void ModuleVisitor::BeginModule(const parser::Name &name, bool isSubmodule) {
auto &symbol{MakeSymbol(name, ModuleDetails{isSubmodule})};
auto &details{symbol.get<ModuleDetails>()};
PushScope(Scope::Kind::Module, &symbol);
details.set_scope(&currScope());
- WalkSubprogramPart(subpPart);
- return symbol;
+ prevAccessStmt_ = nullptr;
}
// Find a module or submodule by name and return its scope.
funcInfo_ = {};
}
-bool HasModulePrefix(const std::list<parser::PrefixSpec> &prefixes) {
- for (const auto &prefix : prefixes) {
- if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
- return true;
- }
- }
- return false;
-}
-bool SubprogramVisitor::Pre(const parser::SubroutineSubprogram &x) {
- const auto &stmt{
- std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement};
- bool hasModulePrefix{
- HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmt.t))};
- const auto &name{std::get<parser::Name>(stmt.t)};
- const auto &subpPart{
- std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
- return BeginSubprogram(
- name, Symbol::Flag::Subroutine, hasModulePrefix, subpPart);
-}
-void SubprogramVisitor::Post(const parser::SubroutineSubprogram &) {
- EndSubprogram();
-}
-
-bool SubprogramVisitor::Pre(const parser::FunctionSubprogram &x) {
- const auto &stmt{
- std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement};
- bool hasModulePrefix{
- HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmt.t))};
- const auto &name{std::get<parser::Name>(stmt.t)};
- const auto &subpPart{
- std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
- return BeginSubprogram(
- name, Symbol::Flag::Function, hasModulePrefix, subpPart);
-}
-void SubprogramVisitor::Post(const parser::FunctionSubprogram &) {
- EndSubprogram();
-}
-
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Subroutine &x) {
const auto &name{std::get<parser::Name>(
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t)};
- return BeginSubprogram(name, Symbol::Flag::Subroutine,
- /*hasModulePrefix*/ false, std::nullopt);
+ return BeginSubprogram(name, Symbol::Flag::Subroutine);
}
void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &) {
EndSubprogram();
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Function &x) {
const auto &name{std::get<parser::Name>(
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t)};
- return BeginSubprogram(
- name, Symbol::Flag::Function, /*hasModulePrefix*/ false, std::nullopt);
+ return BeginSubprogram(name, Symbol::Flag::Function);
}
void SubprogramVisitor::Post(const parser::InterfaceBody::Function &) {
EndSubprogram();
return symbol.get<SubprogramDetails>();
}
-bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
- Symbol::Flag subpFlag, bool hasModulePrefix,
- const std::optional<parser::InternalSubprogramPart> &subpPart) {
- if (subpNamesOnly_) {
- auto &symbol{MakeSymbol(name, SubprogramNameDetails{*subpNamesOnly_})};
- symbol.set(subpFlag);
- return false;
- }
+bool SubprogramVisitor::BeginSubprogram(
+ const parser::Name &name, Symbol::Flag subpFlag, bool hasModulePrefix) {
if (hasModulePrefix && !inInterfaceBlock()) {
auto *symbol{FindSymbol(name)};
if (!symbol || !symbol->IsSeparateModuleProc()) {
} else {
PushSubprogramScope(name, subpFlag);
}
- WalkSubprogramPart(subpPart);
return true;
}
-void SubprogramVisitor::EndSubprogram() {
- if (!subpNamesOnly_) {
- PopScope();
- }
-}
-
-bool SubprogramVisitor::Pre(const parser::SeparateModuleSubprogram &x) {
- if (subpNamesOnly_) {
- return false;
- }
- const auto &name{
- std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t).statement.v};
- const auto &subpPart{
- std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
- return BeginSubprogram(
- name, Symbol::Flag::Subroutine, /*hasModulePrefix*/ true, subpPart);
-}
-
-void SubprogramVisitor::Post(const parser::SeparateModuleSubprogram &) {
- EndSubprogram();
-}
+void SubprogramVisitor::EndSubprogram() { PopScope(); }
Symbol &SubprogramVisitor::PushSubprogramScope(
const parser::Name &name, Symbol::Flag subpFlag) {
if (flag == Symbol::Flag::Function) {
ApplyImplicitRules(symbol);
}
+ } else if (symbol.GetType() != nullptr && flag == Symbol::Flag::Subroutine) {
+ SayWithDecl(
+ name, symbol, "Cannot call function '%s' like a subroutine"_err_en_US);
}
return true;
}
}
}
-bool ResolveNamesVisitor::Pre(const parser::MainProgram &x) {
- using stmtType = std::optional<parser::Statement<parser::ProgramStmt>>;
- Symbol *symbol{nullptr};
- if (auto &stmt{std::get<stmtType>(x.t)}) {
- symbol = &MakeSymbol(stmt->statement.v, MainProgramDetails{});
- }
- PushScope(Scope::Kind::MainProgram, symbol);
- auto &subpPart{std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
- WalkSubprogramPart(subpPart);
- return true;
-}
-
-void ResolveNamesVisitor::Post(const parser::EndProgramStmt &) { PopScope(); }
-
bool ResolveNamesVisitor::Pre(const parser::ImplicitStmt &x) {
return CheckNotInBlock("IMPLICIT") && ImplicitRulesVisitor::Pre(x);
}
return false;
}
+bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
+ auto root{ProgramTree::Build(x)};
+ SetScope(context().globalScope());
+ ResolveSpecificationParts(root);
+ SetScope(context().globalScope());
+ ResolveExecutionParts(root);
+ return false;
+}
+
+// Build the scope tree and resolve names in the specification parts of this
+// node and its children
+void ResolveNamesVisitor::ResolveSpecificationParts(ProgramTree &node) {
+ if (!BeginScope(node)) {
+ return; // an error prevented scope from being created
+ }
+ Scope &scope{currScope()};
+ node.set_scope(scope);
+ AddSubpNames(node);
+ std::visit([&](const auto *x) { Walk(*x); }, node.stmt());
+ Walk(node.spec());
+ if (node.IsModule()) {
+ ApplyDefaultAccess();
+ }
+ for (auto &child : node.children()) {
+ ResolveSpecificationParts(child);
+ }
+ PopScope();
+}
+
+// Add SubprogramNameDetails symbols for contained subprograms
+void ResolveNamesVisitor::AddSubpNames(const ProgramTree &node) {
+ auto kind{
+ node.IsModule() ? SubprogramKind::Module : SubprogramKind::Internal};
+ for (const auto &child : node.children()) {
+ auto &symbol{MakeSymbol(child.name(), SubprogramNameDetails{kind})};
+ symbol.set(child.GetSubpFlag());
+ }
+}
+
+// Push a new scope for this node or return false on error.
+bool ResolveNamesVisitor::BeginScope(const ProgramTree &node) {
+ switch (node.GetKind()) {
+ case ProgramTree::Kind::Program:
+ PushScope(Scope::Kind::MainProgram,
+ &MakeSymbol(node.name(), MainProgramDetails{}));
+ return true;
+ case ProgramTree::Kind::Function:
+ case ProgramTree::Kind::Subroutine:
+ return BeginSubprogram(
+ node.name(), node.GetSubpFlag(), node.HasModulePrefix());
+ case ProgramTree::Kind::MpSubprogram:
+ return BeginSubprogram(
+ node.name(), Symbol::Flag::Subroutine, /*hasModulePrefix*/ true);
+ case ProgramTree::Kind::Module: BeginModule(node.name(), false); return true;
+ case ProgramTree::Kind::Submodule:
+ return BeginSubmodule(node.name(), node.GetParentId());
+ default: CRASH_NO_CASE;
+ }
+}
+
+// Resolve names in the execution part of this node and its children
+void ResolveNamesVisitor::ResolveExecutionParts(const ProgramTree &node) {
+ if (!node.scope()) {
+ return; // error occurred creating scope
+ }
+ SetScope(*node.scope());
+ if (const auto *exec{node.exec()}) {
+ Walk(*exec);
+ }
+ for (const auto &child : node.children()) {
+ ResolveExecutionParts(child);
+ }
+}
+
void ResolveNamesVisitor::Post(const parser::Program &) {
// ensure that all temps were deallocated
CHECK(!attrs_);