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 
GetParentId() const115 const parser::ParentIdentifier &ProgramTree::GetParentId() const {
116   const auto *stmt{
117       std::get<const parser::Statement<parser::SubmoduleStmt> *>(stmt_)};
118   return std::get<parser::ParentIdentifier>(stmt->statement.t);
119 }
120 
IsModule() const121 bool ProgramTree::IsModule() const {
122   auto kind{GetKind()};
123   return kind == Kind::Module || kind == Kind::Submodule;
124 }
125 
GetSubpFlag() const126 Symbol::Flag ProgramTree::GetSubpFlag() const {
127   return GetKind() == Kind::Function ? Symbol::Flag::Function
128                                      : Symbol::Flag::Subroutine;
129 }
130 
HasModulePrefix() const131 bool ProgramTree::HasModulePrefix() const {
132   using ListType = std::list<parser::PrefixSpec>;
133   const auto *prefixes{
134       std::visit(common::visitors{
135                      [](const parser::Statement<parser::FunctionStmt> *x) {
136                        return &std::get<ListType>(x->statement.t);
137                      },
138                      [](const parser::Statement<parser::SubroutineStmt> *x) {
139                        return &std::get<ListType>(x->statement.t);
140                      },
141                      [](const auto *) -> const ListType * { return nullptr; },
142                  },
143           stmt_)};
144   if (prefixes) {
145     for (const auto &prefix : *prefixes) {
146       if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
147         return true;
148       }
149     }
150   }
151   return false;
152 }
153 
GetKind() const154 ProgramTree::Kind ProgramTree::GetKind() const {
155   return std::visit(
156       common::visitors{
157           [](const parser::Statement<parser::ProgramStmt> *) {
158             return Kind::Program;
159           },
160           [](const parser::Statement<parser::FunctionStmt> *) {
161             return Kind::Function;
162           },
163           [](const parser::Statement<parser::SubroutineStmt> *) {
164             return Kind::Subroutine;
165           },
166           [](const parser::Statement<parser::MpSubprogramStmt> *) {
167             return Kind::MpSubprogram;
168           },
169           [](const parser::Statement<parser::ModuleStmt> *) {
170             return Kind::Module;
171           },
172           [](const parser::Statement<parser::SubmoduleStmt> *) {
173             return Kind::Submodule;
174           },
175           [](const parser::Statement<parser::BlockDataStmt> *) {
176             return Kind::BlockData;
177           },
178       },
179       stmt_);
180 }
181 
set_scope(Scope & scope)182 void ProgramTree::set_scope(Scope &scope) {
183   scope_ = &scope;
184   CHECK(endStmt_);
185   scope.AddSourceRange(*endStmt_);
186 }
187 
AddChild(ProgramTree && child)188 void ProgramTree::AddChild(ProgramTree &&child) {
189   children_.emplace_back(std::move(child));
190 }
191 
192 } // namespace Fortran::semantics
193