1 //===-- lib/Semantics/program-tree.cpp ------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "program-tree.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Parser/char-block.h"
12 #include "flang/Semantics/scope.h"
13
14 namespace Fortran::semantics {
15
16 template <typename T>
BuildSubprogramTree(const parser::Name & name,const T & x)17 static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
18 const auto &spec{std::get<parser::SpecificationPart>(x.t)};
19 const auto &exec{std::get<parser::ExecutionPart>(x.t)};
20 const auto &subps{
21 std::get<std::optional<parser::InternalSubprogramPart>>(x.t)};
22 ProgramTree node{name, spec, &exec};
23 if (subps) {
24 for (const auto &subp :
25 std::get<std::list<parser::InternalSubprogram>>(subps->t)) {
26 std::visit(
27 [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
28 subp.u);
29 }
30 }
31 return node;
32 }
33
BuildSubprogramTree(const parser::Name & name,const parser::BlockData & x)34 static ProgramTree BuildSubprogramTree(
35 const parser::Name &name, const parser::BlockData &x) {
36 const auto &spec{std::get<parser::SpecificationPart>(x.t)};
37 return ProgramTree{name, spec, nullptr};
38 }
39
40 template <typename T>
BuildModuleTree(const parser::Name & name,const T & x)41 static ProgramTree BuildModuleTree(const parser::Name &name, const T &x) {
42 const auto &spec{std::get<parser::SpecificationPart>(x.t)};
43 const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
44 ProgramTree node{name, spec};
45 if (subps) {
46 for (const auto &subp :
47 std::get<std::list<parser::ModuleSubprogram>>(subps->t)) {
48 std::visit(
49 [&](const auto &y) { node.AddChild(ProgramTree::Build(y.value())); },
50 subp.u);
51 }
52 }
53 return node;
54 }
55
Build(const parser::ProgramUnit & x)56 ProgramTree ProgramTree::Build(const parser::ProgramUnit &x) {
57 return std::visit([](const auto &y) { return Build(y.value()); }, x.u);
58 }
59
Build(const parser::MainProgram & x)60 ProgramTree ProgramTree::Build(const parser::MainProgram &x) {
61 const auto &stmt{
62 std::get<std::optional<parser::Statement<parser::ProgramStmt>>>(x.t)};
63 const auto &end{std::get<parser::Statement<parser::EndProgramStmt>>(x.t)};
64 static parser::Name emptyName;
65 auto result{stmt ? BuildSubprogramTree(stmt->statement.v, x).set_stmt(*stmt)
66 : BuildSubprogramTree(emptyName, x)};
67 return result.set_endStmt(end);
68 }
69
Build(const parser::FunctionSubprogram & x)70 ProgramTree ProgramTree::Build(const parser::FunctionSubprogram &x) {
71 const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
72 const auto &end{std::get<parser::Statement<parser::EndFunctionStmt>>(x.t)};
73 const auto &name{std::get<parser::Name>(stmt.statement.t)};
74 return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
75 }
76
Build(const parser::SubroutineSubprogram & x)77 ProgramTree ProgramTree::Build(const parser::SubroutineSubprogram &x) {
78 const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)};
79 const auto &end{std::get<parser::Statement<parser::EndSubroutineStmt>>(x.t)};
80 const auto &name{std::get<parser::Name>(stmt.statement.t)};
81 return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
82 }
83
Build(const parser::SeparateModuleSubprogram & x)84 ProgramTree ProgramTree::Build(const parser::SeparateModuleSubprogram &x) {
85 const auto &stmt{std::get<parser::Statement<parser::MpSubprogramStmt>>(x.t)};
86 const auto &end{
87 std::get<parser::Statement<parser::EndMpSubprogramStmt>>(x.t)};
88 const auto &name{stmt.statement.v};
89 return BuildSubprogramTree(name, x).set_stmt(stmt).set_endStmt(end);
90 }
91
Build(const parser::Module & x)92 ProgramTree ProgramTree::Build(const parser::Module &x) {
93 const auto &stmt{std::get<parser::Statement<parser::ModuleStmt>>(x.t)};
94 const auto &end{std::get<parser::Statement<parser::EndModuleStmt>>(x.t)};
95 const auto &name{stmt.statement.v};
96 return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
97 }
98
Build(const parser::Submodule & x)99 ProgramTree ProgramTree::Build(const parser::Submodule &x) {
100 const auto &stmt{std::get<parser::Statement<parser::SubmoduleStmt>>(x.t)};
101 const auto &end{std::get<parser::Statement<parser::EndSubmoduleStmt>>(x.t)};
102 const auto &name{std::get<parser::Name>(stmt.statement.t)};
103 return BuildModuleTree(name, x).set_stmt(stmt).set_endStmt(end);
104 }
105
Build(const parser::BlockData & x)106 ProgramTree ProgramTree::Build(const parser::BlockData &x) {
107 const auto &stmt{std::get<parser::Statement<parser::BlockDataStmt>>(x.t)};
108 const auto &end{std::get<parser::Statement<parser::EndBlockDataStmt>>(x.t)};
109 static parser::Name emptyName;
110 auto result{stmt.statement.v ? BuildSubprogramTree(*stmt.statement.v, x)
111 : BuildSubprogramTree(emptyName, x)};
112 return result.set_stmt(stmt).set_endStmt(end);
113 }
114
Build(const parser::CompilerDirective &)115 ProgramTree ProgramTree::Build(const parser::CompilerDirective &) {
116 DIE("ProgramTree::Build() called for CompilerDirective");
117 }
118
GetParentId() const119 const parser::ParentIdentifier &ProgramTree::GetParentId() const {
120 const auto *stmt{
121 std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};
122 return std::get<parser::ParentIdentifier>(stmt->statement.t);
123 }
124
IsModule() const125 bool ProgramTree::IsModule() const {
126 auto kind{GetKind()};
127 return kind == Kind::Module || kind == Kind::Submodule;
128 }
129
GetSubpFlag() const130 Symbol::Flag ProgramTree::GetSubpFlag() const {
131 return GetKind() == Kind::Function ? Symbol::Flag::Function
132 : Symbol::Flag::Subroutine;
133 }
134
HasModulePrefix() const135 bool ProgramTree::HasModulePrefix() const {
136 using ListType = std::list<parser::PrefixSpec>;
137 const auto *prefixes{
138 std::visit(common::visitors{
139 [](const parser::Statement<parser::FunctionStmt> *x) {
140 return &std::get<ListType>(x->statement.t);
141 },
142 [](const parser::Statement<parser::SubroutineStmt> *x) {
143 return &std::get<ListType>(x->statement.t);
144 },
145 [](const auto *) -> const ListType * { return nullptr; },
146 },
147 stmt_)};
148 if (prefixes) {
149 for (const auto &prefix : *prefixes) {
150 if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
151 return true;
152 }
153 }
154 }
155 return false;
156 }
157
GetKind() const158 ProgramTree::Kind ProgramTree::GetKind() const {
159 return std::visit(
160 common::visitors{
161 [](const parser::Statement<parser::ProgramStmt> *) {
162 return Kind::Program;
163 },
164 [](const parser::Statement<parser::FunctionStmt> *) {
165 return Kind::Function;
166 },
167 [](const parser::Statement<parser::SubroutineStmt> *) {
168 return Kind::Subroutine;
169 },
170 [](const parser::Statement<parser::MpSubprogramStmt> *) {
171 return Kind::MpSubprogram;
172 },
173 [](const parser::Statement<parser::ModuleStmt> *) {
174 return Kind::Module;
175 },
176 [](const parser::Statement<parser::SubmoduleStmt> *) {
177 return Kind::Submodule;
178 },
179 [](const parser::Statement<parser::BlockDataStmt> *) {
180 return Kind::BlockData;
181 },
182 },
183 stmt_);
184 }
185
set_scope(Scope & scope)186 void ProgramTree::set_scope(Scope &scope) {
187 scope_ = &scope;
188 CHECK(endStmt_);
189 scope.AddSourceRange(*endStmt_);
190 }
191
AddChild(ProgramTree && child)192 void ProgramTree::AddChild(ProgramTree &&child) {
193 children_.emplace_back(std::move(child));
194 }
195
196 } // namespace Fortran::semantics
197