• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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