164ab3302SCarolineConcatto //===-- lib/Semantics/program-tree.cpp ------------------------------------===//
264ab3302SCarolineConcatto //
364ab3302SCarolineConcatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
464ab3302SCarolineConcatto // See https://llvm.org/LICENSE.txt for license information.
564ab3302SCarolineConcatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664ab3302SCarolineConcatto //
764ab3302SCarolineConcatto //===----------------------------------------------------------------------===//
864ab3302SCarolineConcatto
964ab3302SCarolineConcatto #include "program-tree.h"
1064ab3302SCarolineConcatto #include "flang/Common/idioms.h"
1164ab3302SCarolineConcatto #include "flang/Parser/char-block.h"
1264ab3302SCarolineConcatto #include "flang/Semantics/scope.h"
1364ab3302SCarolineConcatto
1464ab3302SCarolineConcatto namespace Fortran::semantics {
1564ab3302SCarolineConcatto
GetEntryStmts(ProgramTree & node,const parser::SpecificationPart & spec)16bed947f7SPeter Klausler static void GetEntryStmts(
17bed947f7SPeter Klausler ProgramTree &node, const parser::SpecificationPart &spec) {
18bed947f7SPeter Klausler const auto &implicitPart{std::get<parser::ImplicitPart>(spec.t)};
19bed947f7SPeter Klausler for (const parser::ImplicitPartStmt &stmt : implicitPart.v) {
20bed947f7SPeter Klausler if (const auto *entryStmt{std::get_if<
21bed947f7SPeter Klausler parser::Statement<common::Indirection<parser::EntryStmt>>>(
22bed947f7SPeter Klausler &stmt.u)}) {
23bed947f7SPeter Klausler node.AddEntry(entryStmt->statement.value());
24bed947f7SPeter Klausler }
25bed947f7SPeter Klausler }
26bed947f7SPeter Klausler for (const auto &decl :
27bed947f7SPeter Klausler std::get<std::list<parser::DeclarationConstruct>>(spec.t)) {
28bed947f7SPeter Klausler if (const auto *entryStmt{std::get_if<
29bed947f7SPeter Klausler parser::Statement<common::Indirection<parser::EntryStmt>>>(
30bed947f7SPeter Klausler &decl.u)}) {
31bed947f7SPeter Klausler node.AddEntry(entryStmt->statement.value());
32bed947f7SPeter Klausler }
33bed947f7SPeter Klausler }
34bed947f7SPeter Klausler }
35bed947f7SPeter Klausler
GetEntryStmts(ProgramTree & node,const parser::ExecutionPart & exec)36bed947f7SPeter Klausler static void GetEntryStmts(
37bed947f7SPeter Klausler ProgramTree &node, const parser::ExecutionPart &exec) {
38bed947f7SPeter Klausler for (const auto &epConstruct : exec.v) {
39bed947f7SPeter Klausler if (const auto *entryStmt{std::get_if<
40bed947f7SPeter Klausler parser::Statement<common::Indirection<parser::EntryStmt>>>(
41bed947f7SPeter Klausler &epConstruct.u)}) {
42bed947f7SPeter Klausler node.AddEntry(entryStmt->statement.value());
43bed947f7SPeter Klausler }
44bed947f7SPeter Klausler }
45bed947f7SPeter Klausler }
46bed947f7SPeter Klausler
47fc510998SPeter Klausler // Collects generics that define simple names that could include
48fc510998SPeter Klausler // identically-named subprograms as specific procedures.
GetGenerics(ProgramTree & node,const parser::SpecificationPart & spec)49fc510998SPeter Klausler static void GetGenerics(
50fc510998SPeter Klausler ProgramTree &node, const parser::SpecificationPart &spec) {
51fc510998SPeter Klausler for (const auto &decl :
52fc510998SPeter Klausler std::get<std::list<parser::DeclarationConstruct>>(spec.t)) {
53fc510998SPeter Klausler if (const auto *spec{
54fc510998SPeter Klausler std::get_if<parser::SpecificationConstruct>(&decl.u)}) {
55fc510998SPeter Klausler if (const auto *generic{std::get_if<
56fc510998SPeter Klausler parser::Statement<common::Indirection<parser::GenericStmt>>>(
57fc510998SPeter Klausler &spec->u)}) {
58fc510998SPeter Klausler const parser::GenericStmt &genericStmt{generic->statement.value()};
59fc510998SPeter Klausler const auto &genericSpec{std::get<parser::GenericSpec>(genericStmt.t)};
60fc510998SPeter Klausler node.AddGeneric(genericSpec);
61fc510998SPeter Klausler } else if (const auto *interface{
62fc510998SPeter Klausler std::get_if<common::Indirection<parser::InterfaceBlock>>(
63fc510998SPeter Klausler &spec->u)}) {
64fc510998SPeter Klausler const parser::InterfaceBlock &interfaceBlock{interface->value()};
65fc510998SPeter Klausler const parser::InterfaceStmt &interfaceStmt{
66fc510998SPeter Klausler std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)
67fc510998SPeter Klausler .statement};
68fc510998SPeter Klausler const auto *genericSpec{
69fc510998SPeter Klausler std::get_if<std::optional<parser::GenericSpec>>(&interfaceStmt.u)};
70fc510998SPeter Klausler if (genericSpec && genericSpec->has_value()) {
71fc510998SPeter Klausler node.AddGeneric(**genericSpec);
72fc510998SPeter Klausler }
73fc510998SPeter Klausler }
74fc510998SPeter Klausler }
75fc510998SPeter Klausler }
76fc510998SPeter Klausler }
77fc510998SPeter Klausler
7864ab3302SCarolineConcatto template <typename T>
BuildSubprogramTree(const parser::Name & name,const T & x)7964ab3302SCarolineConcatto static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
8064ab3302SCarolineConcatto const auto &spec{std::get<parser::SpecificationPart>(x.t)};
8164ab3302SCarolineConcatto const auto &exec{std::get<parser::ExecutionPart>(x.t)};
8264ab3302SCarolineConcatto const auto &subps{
8364ab3302SCarolineConcatto std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
8464ab3302SCarolineConcatto ProgramTree node{name, spec, &exec};
85bed947f7SPeter Klausler GetEntryStmts(node, spec);
86bed947f7SPeter Klausler GetEntryStmts(node, exec);
87fc510998SPeter Klausler GetGenerics(node, spec);
8864ab3302SCarolineConcatto if (subps) {
8964ab3302SCarolineConcatto for (const auto &subp :
9064ab3302SCarolineConcatto std::get<std::list<parser::InternalSubprogram>>(subps->t)) {
91cd03e96fSPeter Klausler common::visit(
9264ab3302SCarolineConcatto [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
9364ab3302SCarolineConcatto subp.u);
9464ab3302SCarolineConcatto }
9564ab3302SCarolineConcatto }
9664ab3302SCarolineConcatto return node;
9764ab3302SCarolineConcatto }
9864ab3302SCarolineConcatto
BuildSubprogramTree(const parser::Name & name,const parser::BlockData & x)9964ab3302SCarolineConcatto static ProgramTree BuildSubprogramTree(
10064ab3302SCarolineConcatto const parser::Name &name, const parser::BlockData &x) {
10164ab3302SCarolineConcatto const auto &spec{std::get<parser::SpecificationPart>(x.t)};
102bed947f7SPeter Klausler return ProgramTree{name, spec};
10364ab3302SCarolineConcatto }
10464ab3302SCarolineConcatto
10564ab3302SCarolineConcatto template <typename T>
BuildModuleTree(const parser::Name & name,const T & x)10664ab3302SCarolineConcatto static ProgramTree BuildModuleTree(const parser::Name &name, const T &x) {
10764ab3302SCarolineConcatto const auto &spec{std::get<parser::SpecificationPart>(x.t)};
10864ab3302SCarolineConcatto const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
10964ab3302SCarolineConcatto ProgramTree node{name, spec};
110fc510998SPeter Klausler GetGenerics(node, spec);
11164ab3302SCarolineConcatto if (subps) {
11264ab3302SCarolineConcatto for (const auto &subp :
11364ab3302SCarolineConcatto std::get<std::list<parser::ModuleSubprogram>>(subps->t)) {
114cd03e96fSPeter Klausler common::visit(
11564ab3302SCarolineConcatto [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
11664ab3302SCarolineConcatto subp.u);
11764ab3302SCarolineConcatto }
11864ab3302SCarolineConcatto }
11964ab3302SCarolineConcatto return node;
12064ab3302SCarolineConcatto }
12164ab3302SCarolineConcatto
Build(const parser::ProgramUnit & x)12264ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::ProgramUnit &x) {
123cd03e96fSPeter Klausler return common::visit([](const auto &y) { return Build(y.value()); }, x.u);
12464ab3302SCarolineConcatto }
12564ab3302SCarolineConcatto
Build(const parser::MainProgram & x)12664ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::MainProgram &x) {
12764ab3302SCarolineConcatto const auto &stmt{
12864ab3302SCarolineConcatto std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(x.t)};
12964ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndProgramStmt>>(x.t)};
13064ab3302SCarolineConcatto static parser::Name emptyName;
13164ab3302SCarolineConcatto auto result{stmt ? BuildSubprogramTree(stmt->statement.v, x).set_stmt(*stmt)
13264ab3302SCarolineConcatto : BuildSubprogramTree(emptyName, x)};
13364ab3302SCarolineConcatto return result.set_endStmt(end);
13464ab3302SCarolineConcatto }
13564ab3302SCarolineConcatto
Build(const parser::FunctionSubprogram & x)13664ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::FunctionSubprogram &x) {
13764ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
13864ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndFunctionStmt>>(x.t)};
13964ab3302SCarolineConcatto const auto &name{std::get<parser::Name>(stmt.statement.t)};
140*72904a99SPeter Klausler const parser::LanguageBindingSpec *bindingSpec{};
141*72904a99SPeter Klausler if (const auto &suffix{
142*72904a99SPeter Klausler std::get<std::optional<parser::Suffix>>(stmt.statement.t)}) {
143*72904a99SPeter Klausler if (suffix->binding) {
144*72904a99SPeter Klausler bindingSpec = &*suffix->binding;
145*72904a99SPeter Klausler }
146*72904a99SPeter Klausler }
147*72904a99SPeter Klausler return BuildSubprogramTree(name, x)
148*72904a99SPeter Klausler .set_stmt(stmt)
149*72904a99SPeter Klausler .set_endStmt(end)
150*72904a99SPeter Klausler .set_bindingSpec(bindingSpec);
15164ab3302SCarolineConcatto }
15264ab3302SCarolineConcatto
Build(const parser::SubroutineSubprogram & x)15364ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::SubroutineSubprogram &x) {
15464ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)};
15564ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndSubroutineStmt>>(x.t)};
15664ab3302SCarolineConcatto const auto &name{std::get<parser::Name>(stmt.statement.t)};
157*72904a99SPeter Klausler const parser::LanguageBindingSpec *bindingSpec{};
158*72904a99SPeter Klausler if (const auto &binding{std::get<std::optional<parser::LanguageBindingSpec>>(
159*72904a99SPeter Klausler stmt.statement.t)}) {
160*72904a99SPeter Klausler bindingSpec = &*binding;
161*72904a99SPeter Klausler }
162*72904a99SPeter Klausler return BuildSubprogramTree(name, x)
163*72904a99SPeter Klausler .set_stmt(stmt)
164*72904a99SPeter Klausler .set_endStmt(end)
165*72904a99SPeter Klausler .set_bindingSpec(bindingSpec);
16664ab3302SCarolineConcatto }
16764ab3302SCarolineConcatto
Build(const parser::SeparateModuleSubprogram & x)16864ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::SeparateModuleSubprogram &x) {
16964ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t)};
17064ab3302SCarolineConcatto const auto &end{
17164ab3302SCarolineConcatto std::get<parser::Statement<parser::EndMpSubprogramStmt>>(x.t)};
17264ab3302SCarolineConcatto const auto &name{stmt.statement.v};
17364ab3302SCarolineConcatto return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
17464ab3302SCarolineConcatto }
17564ab3302SCarolineConcatto
Build(const parser::Module & x)17664ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::Module &x) {
17764ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::ModuleStmt>>(x.t)};
17864ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndModuleStmt>>(x.t)};
17964ab3302SCarolineConcatto const auto &name{stmt.statement.v};
18064ab3302SCarolineConcatto return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
18164ab3302SCarolineConcatto }
18264ab3302SCarolineConcatto
Build(const parser::Submodule & x)18364ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::Submodule &x) {
18464ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
18564ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndSubmoduleStmt>>(x.t)};
18664ab3302SCarolineConcatto const auto &name{std::get<parser::Name>(stmt.statement.t)};
18764ab3302SCarolineConcatto return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
18864ab3302SCarolineConcatto }
18964ab3302SCarolineConcatto
Build(const parser::BlockData & x)19064ab3302SCarolineConcatto ProgramTree ProgramTree::Build(const parser::BlockData &x) {
19164ab3302SCarolineConcatto const auto &stmt{std::get<parser::Statement<parser::BlockDataStmt>>(x.t)};
19264ab3302SCarolineConcatto const auto &end{std::get<parser::Statement<parser::EndBlockDataStmt>>(x.t)};
19364ab3302SCarolineConcatto static parser::Name emptyName;
19464ab3302SCarolineConcatto auto result{stmt.statement.v ? BuildSubprogramTree(*stmt.statement.v, x)
19564ab3302SCarolineConcatto : BuildSubprogramTree(emptyName, x)};
19664ab3302SCarolineConcatto return result.set_stmt(stmt).set_endStmt(end);
19764ab3302SCarolineConcatto }
19864ab3302SCarolineConcatto
Build(const parser::CompilerDirective &)19913cee14bSpeter klausler ProgramTree ProgramTree::Build(const parser::CompilerDirective &) {
20013cee14bSpeter klausler DIE("ProgramTree::Build() called for CompilerDirective");
20113cee14bSpeter klausler }
20213cee14bSpeter klausler
GetParentId() const20364ab3302SCarolineConcatto const parser::ParentIdentifier &ProgramTree::GetParentId() const {
20464ab3302SCarolineConcatto const auto *stmt{
20564ab3302SCarolineConcatto std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};
20664ab3302SCarolineConcatto return std::get<parser::ParentIdentifier>(stmt->statement.t);
20764ab3302SCarolineConcatto }
20864ab3302SCarolineConcatto
IsModule() const20964ab3302SCarolineConcatto bool ProgramTree::IsModule() const {
21064ab3302SCarolineConcatto auto kind{GetKind()};
21164ab3302SCarolineConcatto return kind == Kind::Module || kind == Kind::Submodule;
21264ab3302SCarolineConcatto }
21364ab3302SCarolineConcatto
GetSubpFlag() const21464ab3302SCarolineConcatto Symbol::Flag ProgramTree::GetSubpFlag() const {
21564ab3302SCarolineConcatto return GetKind() == Kind::Function ? Symbol::Flag::Function
21664ab3302SCarolineConcatto : Symbol::Flag::Subroutine;
21764ab3302SCarolineConcatto }
21864ab3302SCarolineConcatto
HasModulePrefix() const21964ab3302SCarolineConcatto bool ProgramTree::HasModulePrefix() const {
22064ab3302SCarolineConcatto using ListType = std::list<parser::PrefixSpec>;
221cd03e96fSPeter Klausler const auto *prefixes{common::visit(
222cd03e96fSPeter Klausler common::visitors{
22364ab3302SCarolineConcatto [](const parser::Statement<parser::FunctionStmt> *x) {
22464ab3302SCarolineConcatto return &std::get<ListType>(x->statement.t);
22564ab3302SCarolineConcatto },
22664ab3302SCarolineConcatto [](const parser::Statement<parser::SubroutineStmt> *x) {
22764ab3302SCarolineConcatto return &std::get<ListType>(x->statement.t);
22864ab3302SCarolineConcatto },
22964ab3302SCarolineConcatto [](const auto *) -> const ListType * { return nullptr; },
23064ab3302SCarolineConcatto },
23164ab3302SCarolineConcatto stmt_)};
23264ab3302SCarolineConcatto if (prefixes) {
23364ab3302SCarolineConcatto for (const auto &prefix : *prefixes) {
23464ab3302SCarolineConcatto if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
23564ab3302SCarolineConcatto return true;
23664ab3302SCarolineConcatto }
23764ab3302SCarolineConcatto }
23864ab3302SCarolineConcatto }
23964ab3302SCarolineConcatto return false;
24064ab3302SCarolineConcatto }
24164ab3302SCarolineConcatto
GetKind() const24264ab3302SCarolineConcatto ProgramTree::Kind ProgramTree::GetKind() const {
243cd03e96fSPeter Klausler return common::visit(
24464ab3302SCarolineConcatto common::visitors{
24564ab3302SCarolineConcatto [](const parser::Statement<parser::ProgramStmt> *) {
24664ab3302SCarolineConcatto return Kind::Program;
24764ab3302SCarolineConcatto },
24864ab3302SCarolineConcatto [](const parser::Statement<parser::FunctionStmt> *) {
24964ab3302SCarolineConcatto return Kind::Function;
25064ab3302SCarolineConcatto },
25164ab3302SCarolineConcatto [](const parser::Statement<parser::SubroutineStmt> *) {
25264ab3302SCarolineConcatto return Kind::Subroutine;
25364ab3302SCarolineConcatto },
25464ab3302SCarolineConcatto [](const parser::Statement<parser::MpSubprogramStmt> *) {
25564ab3302SCarolineConcatto return Kind::MpSubprogram;
25664ab3302SCarolineConcatto },
25764ab3302SCarolineConcatto [](const parser::Statement<parser::ModuleStmt> *) {
25864ab3302SCarolineConcatto return Kind::Module;
25964ab3302SCarolineConcatto },
26064ab3302SCarolineConcatto [](const parser::Statement<parser::SubmoduleStmt> *) {
26164ab3302SCarolineConcatto return Kind::Submodule;
26264ab3302SCarolineConcatto },
26364ab3302SCarolineConcatto [](const parser::Statement<parser::BlockDataStmt> *) {
26464ab3302SCarolineConcatto return Kind::BlockData;
26564ab3302SCarolineConcatto },
26664ab3302SCarolineConcatto },
26764ab3302SCarolineConcatto stmt_);
26864ab3302SCarolineConcatto }
26964ab3302SCarolineConcatto
set_scope(Scope & scope)27064ab3302SCarolineConcatto void ProgramTree::set_scope(Scope &scope) {
27164ab3302SCarolineConcatto scope_ = &scope;
27264ab3302SCarolineConcatto CHECK(endStmt_);
27364ab3302SCarolineConcatto scope.AddSourceRange(*endStmt_);
27464ab3302SCarolineConcatto }
27564ab3302SCarolineConcatto
AddChild(ProgramTree && child)27664ab3302SCarolineConcatto void ProgramTree::AddChild(ProgramTree &&child) {
27764ab3302SCarolineConcatto children_.emplace_back(std::move(child));
27864ab3302SCarolineConcatto }
27964ab3302SCarolineConcatto
AddEntry(const parser::EntryStmt & entryStmt)280bed947f7SPeter Klausler void ProgramTree::AddEntry(const parser::EntryStmt &entryStmt) {
281bed947f7SPeter Klausler entryStmts_.emplace_back(entryStmt);
282bed947f7SPeter Klausler }
283bed947f7SPeter Klausler
AddGeneric(const parser::GenericSpec & generic)284fc510998SPeter Klausler void ProgramTree::AddGeneric(const parser::GenericSpec &generic) {
285fc510998SPeter Klausler genericSpecs_.emplace_back(generic);
286fc510998SPeter Klausler }
287fc510998SPeter Klausler
2881f879005STim Keith } // namespace Fortran::semantics
289