1 //===-- lib/Semantics/program-tree.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "program-tree.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Parser/char-block.h"
12 #include "flang/Semantics/scope.h"
14 namespace Fortran::semantics
{
16 static void GetEntryStmts(
17 ProgramTree
&node
, const parser::SpecificationPart
&spec
) {
18 const auto &implicitPart
{std::get
<parser::ImplicitPart
>(spec
.t
)};
19 for (const parser::ImplicitPartStmt
&stmt
: implicitPart
.v
) {
20 if (const auto *entryStmt
{std::get_if
<
21 parser::Statement
<common::Indirection
<parser::EntryStmt
>>>(
23 node
.AddEntry(entryStmt
->statement
.value());
26 for (const auto &decl
:
27 std::get
<std::list
<parser::DeclarationConstruct
>>(spec
.t
)) {
28 if (const auto *entryStmt
{std::get_if
<
29 parser::Statement
<common::Indirection
<parser::EntryStmt
>>>(
31 node
.AddEntry(entryStmt
->statement
.value());
36 static void GetEntryStmts(
37 ProgramTree
&node
, const parser::ExecutionPart
&exec
) {
38 for (const auto &epConstruct
: exec
.v
) {
39 if (const auto *entryStmt
{std::get_if
<
40 parser::Statement
<common::Indirection
<parser::EntryStmt
>>>(
42 node
.AddEntry(entryStmt
->statement
.value());
47 // Collects generics that define simple names that could include
48 // identically-named subprograms as specific procedures.
49 static void GetGenerics(
50 ProgramTree
&node
, const parser::SpecificationPart
&spec
) {
51 for (const auto &decl
:
52 std::get
<std::list
<parser::DeclarationConstruct
>>(spec
.t
)) {
54 std::get_if
<parser::SpecificationConstruct
>(&decl
.u
)}) {
55 if (const auto *generic
{std::get_if
<
56 parser::Statement
<common::Indirection
<parser::GenericStmt
>>>(
58 const parser::GenericStmt
&genericStmt
{generic
->statement
.value()};
59 const auto &genericSpec
{std::get
<parser::GenericSpec
>(genericStmt
.t
)};
60 node
.AddGeneric(genericSpec
);
61 } else if (const auto *interface
{
62 std::get_if
<common::Indirection
<parser::InterfaceBlock
>>(
64 const parser::InterfaceBlock
&interfaceBlock
{interface
->value()};
65 const parser::InterfaceStmt
&interfaceStmt
{
66 std::get
<parser::Statement
<parser::InterfaceStmt
>>(interfaceBlock
.t
)
68 const auto *genericSpec
{
69 std::get_if
<std::optional
<parser::GenericSpec
>>(&interfaceStmt
.u
)};
70 if (genericSpec
&& genericSpec
->has_value()) {
71 node
.AddGeneric(**genericSpec
);
79 static ProgramTree
BuildSubprogramTree(const parser::Name
&name
, const T
&x
) {
80 const auto &spec
{std::get
<parser::SpecificationPart
>(x
.t
)};
81 const auto &exec
{std::get
<parser::ExecutionPart
>(x
.t
)};
83 std::get
<std::optional
<parser::InternalSubprogramPart
>>(x
.t
)};
84 ProgramTree node
{name
, spec
, &exec
};
85 GetEntryStmts(node
, spec
);
86 GetEntryStmts(node
, exec
);
87 GetGenerics(node
, spec
);
89 for (const auto &subp
:
90 std::get
<std::list
<parser::InternalSubprogram
>>(subps
->t
)) {
92 [&](const auto &y
) { node
.AddChild(ProgramTree::Build(y
.value())); },
99 static ProgramTree
BuildSubprogramTree(
100 const parser::Name
&name
, const parser::BlockData
&x
) {
101 const auto &spec
{std::get
<parser::SpecificationPart
>(x
.t
)};
102 return ProgramTree
{name
, spec
};
105 template <typename T
>
106 static ProgramTree
BuildModuleTree(const parser::Name
&name
, const T
&x
) {
107 const auto &spec
{std::get
<parser::SpecificationPart
>(x
.t
)};
108 const auto &subps
{std::get
<std::optional
<parser::ModuleSubprogramPart
>>(x
.t
)};
109 ProgramTree node
{name
, spec
};
110 GetGenerics(node
, spec
);
112 for (const auto &subp
:
113 std::get
<std::list
<parser::ModuleSubprogram
>>(subps
->t
)) {
115 [&](const auto &y
) { node
.AddChild(ProgramTree::Build(y
.value())); },
122 ProgramTree
ProgramTree::Build(const parser::ProgramUnit
&x
) {
123 return common::visit([](const auto &y
) { return Build(y
.value()); }, x
.u
);
126 ProgramTree
ProgramTree::Build(const parser::MainProgram
&x
) {
128 std::get
<std::optional
<parser::Statement
<parser::ProgramStmt
>>>(x
.t
)};
129 const auto &end
{std::get
<parser::Statement
<parser::EndProgramStmt
>>(x
.t
)};
130 static parser::Name emptyName
;
131 auto result
{stmt
? BuildSubprogramTree(stmt
->statement
.v
, x
).set_stmt(*stmt
)
132 : BuildSubprogramTree(emptyName
, x
)};
133 return result
.set_endStmt(end
);
136 ProgramTree
ProgramTree::Build(const parser::FunctionSubprogram
&x
) {
137 const auto &stmt
{std::get
<parser::Statement
<parser::FunctionStmt
>>(x
.t
)};
138 const auto &end
{std::get
<parser::Statement
<parser::EndFunctionStmt
>>(x
.t
)};
139 const auto &name
{std::get
<parser::Name
>(stmt
.statement
.t
)};
140 const parser::LanguageBindingSpec
*bindingSpec
{};
141 if (const auto &suffix
{
142 std::get
<std::optional
<parser::Suffix
>>(stmt
.statement
.t
)}) {
143 if (suffix
->binding
) {
144 bindingSpec
= &*suffix
->binding
;
147 return BuildSubprogramTree(name
, x
)
150 .set_bindingSpec(bindingSpec
);
153 ProgramTree
ProgramTree::Build(const parser::SubroutineSubprogram
&x
) {
154 const auto &stmt
{std::get
<parser::Statement
<parser::SubroutineStmt
>>(x
.t
)};
155 const auto &end
{std::get
<parser::Statement
<parser::EndSubroutineStmt
>>(x
.t
)};
156 const auto &name
{std::get
<parser::Name
>(stmt
.statement
.t
)};
157 const parser::LanguageBindingSpec
*bindingSpec
{};
158 if (const auto &binding
{std::get
<std::optional
<parser::LanguageBindingSpec
>>(
159 stmt
.statement
.t
)}) {
160 bindingSpec
= &*binding
;
162 return BuildSubprogramTree(name
, x
)
165 .set_bindingSpec(bindingSpec
);
168 ProgramTree
ProgramTree::Build(const parser::SeparateModuleSubprogram
&x
) {
169 const auto &stmt
{std::get
<parser::Statement
<parser::MpSubprogramStmt
>>(x
.t
)};
171 std::get
<parser::Statement
<parser::EndMpSubprogramStmt
>>(x
.t
)};
172 const auto &name
{stmt
.statement
.v
};
173 return BuildSubprogramTree(name
, x
).set_stmt(stmt
).set_endStmt(end
);
176 ProgramTree
ProgramTree::Build(const parser::Module
&x
) {
177 const auto &stmt
{std::get
<parser::Statement
<parser::ModuleStmt
>>(x
.t
)};
178 const auto &end
{std::get
<parser::Statement
<parser::EndModuleStmt
>>(x
.t
)};
179 const auto &name
{stmt
.statement
.v
};
180 return BuildModuleTree(name
, x
).set_stmt(stmt
).set_endStmt(end
);
183 ProgramTree
ProgramTree::Build(const parser::Submodule
&x
) {
184 const auto &stmt
{std::get
<parser::Statement
<parser::SubmoduleStmt
>>(x
.t
)};
185 const auto &end
{std::get
<parser::Statement
<parser::EndSubmoduleStmt
>>(x
.t
)};
186 const auto &name
{std::get
<parser::Name
>(stmt
.statement
.t
)};
187 return BuildModuleTree(name
, x
).set_stmt(stmt
).set_endStmt(end
);
190 ProgramTree
ProgramTree::Build(const parser::BlockData
&x
) {
191 const auto &stmt
{std::get
<parser::Statement
<parser::BlockDataStmt
>>(x
.t
)};
192 const auto &end
{std::get
<parser::Statement
<parser::EndBlockDataStmt
>>(x
.t
)};
193 static parser::Name emptyName
;
194 auto result
{stmt
.statement
.v
? BuildSubprogramTree(*stmt
.statement
.v
, x
)
195 : BuildSubprogramTree(emptyName
, x
)};
196 return result
.set_stmt(stmt
).set_endStmt(end
);
199 ProgramTree
ProgramTree::Build(const parser::CompilerDirective
&) {
200 DIE("ProgramTree::Build() called for CompilerDirective");
203 ProgramTree
ProgramTree::Build(const parser::OpenACCRoutineConstruct
&) {
204 DIE("ProgramTree::Build() called for OpenACCRoutineConstruct");
207 const parser::ParentIdentifier
&ProgramTree::GetParentId() const {
209 std::get
<const parser::Statement
<parser::SubmoduleStmt
> *>(stmt_
)};
210 return std::get
<parser::ParentIdentifier
>(stmt
->statement
.t
);
213 bool ProgramTree::IsModule() const {
214 auto kind
{GetKind()};
215 return kind
== Kind::Module
|| kind
== Kind::Submodule
;
218 Symbol::Flag
ProgramTree::GetSubpFlag() const {
219 return GetKind() == Kind::Function
? Symbol::Flag::Function
220 : Symbol::Flag::Subroutine
;
223 bool ProgramTree::HasModulePrefix() const {
224 if (std::holds_alternative
<
225 const parser::Statement
<parser::MpSubprogramStmt
> *>(stmt_
)) {
226 return true; // MODULE PROCEDURE foo
228 using ListType
= std::list
<parser::PrefixSpec
>;
229 const auto *prefixes
{common::visit(
231 [](const parser::Statement
<parser::FunctionStmt
> *x
) {
232 return &std::get
<ListType
>(x
->statement
.t
);
234 [](const parser::Statement
<parser::SubroutineStmt
> *x
) {
235 return &std::get
<ListType
>(x
->statement
.t
);
237 [](const auto *) -> const ListType
* { return nullptr; },
241 for (const auto &prefix
: *prefixes
) {
242 if (std::holds_alternative
<parser::PrefixSpec::Module
>(prefix
.u
)) {
250 ProgramTree::Kind
ProgramTree::GetKind() const {
251 return common::visit(
253 [](const parser::Statement
<parser::ProgramStmt
> *) {
254 return Kind::Program
;
256 [](const parser::Statement
<parser::FunctionStmt
> *) {
257 return Kind::Function
;
259 [](const parser::Statement
<parser::SubroutineStmt
> *) {
260 return Kind::Subroutine
;
262 [](const parser::Statement
<parser::MpSubprogramStmt
> *) {
263 return Kind::MpSubprogram
;
265 [](const parser::Statement
<parser::ModuleStmt
> *) {
268 [](const parser::Statement
<parser::SubmoduleStmt
> *) {
269 return Kind::Submodule
;
271 [](const parser::Statement
<parser::BlockDataStmt
> *) {
272 return Kind::BlockData
;
278 void ProgramTree::set_scope(Scope
&scope
) {
281 scope
.AddSourceRange(*endStmt_
);
284 void ProgramTree::AddChild(ProgramTree
&&child
) {
285 children_
.emplace_back(std::move(child
));
288 void ProgramTree::AddEntry(const parser::EntryStmt
&entryStmt
) {
289 entryStmts_
.emplace_back(entryStmt
);
292 void ProgramTree::AddGeneric(const parser::GenericSpec
&generic
) {
293 genericSpecs_
.emplace_back(generic
);
296 } // namespace Fortran::semantics