xref: /llvm-project/flang/lib/Parser/parse-tree.cpp (revision bde79c0e27fd0fb1e31c9b8b34ae71716c51a8e8)
1 //===-- lib/Parser/parse-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 "flang/Parser/parse-tree.h"
10 #include "flang/Common/idioms.h"
11 #include "flang/Common/indirection.h"
12 #include "flang/Parser/tools.h"
13 #include "flang/Parser/user-state.h"
14 #include "llvm/Support/raw_ostream.h"
15 #include <algorithm>
16 
17 namespace Fortran::parser {
18 
19 // R867
20 ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
21     : kind{k}, names(std::move(n)) {
22   CHECK(kind == common::ImportKind::Default ||
23       kind == common::ImportKind::Only || names.empty());
24 }
25 
26 // R873
27 CommonStmt::CommonStmt(std::optional<Name> &&name,
28     std::list<CommonBlockObject> &&objects, std::list<Block> &&others) {
29   blocks.emplace_front(std::move(name), std::move(objects));
30   blocks.splice(blocks.end(), std::move(others));
31 }
32 
33 // R901 designator
34 bool Designator::EndsInBareName() const {
35   return common::visit(
36       common::visitors{
37           [](const DataRef &dr) {
38             return std::holds_alternative<Name>(dr.u) ||
39                 std::holds_alternative<common::Indirection<StructureComponent>>(
40                     dr.u);
41           },
42           [](const Substring &) { return false; },
43       },
44       u);
45 }
46 
47 // R911 data-ref -> part-ref [% part-ref]...
48 DataRef::DataRef(std::list<PartRef> &&prl) : u{std::move(prl.front().name)} {
49   for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
50     PartRef &pr{prl.front()};
51     if (!first) {
52       u = common::Indirection<StructureComponent>::Make(
53           std::move(*this), std::move(pr.name));
54     }
55     if (!pr.subscripts.empty()) {
56       u = common::Indirection<ArrayElement>::Make(
57           std::move(*this), std::move(pr.subscripts));
58     }
59     if (pr.imageSelector) {
60       u = common::Indirection<CoindexedNamedObject>::Make(
61           std::move(*this), std::move(*pr.imageSelector));
62     }
63   }
64 }
65 
66 // R1001 - R1022 expression
67 Expr::Expr(Designator &&x)
68     : u{common::Indirection<Designator>::Make(std::move(x))} {}
69 Expr::Expr(FunctionReference &&x)
70     : u{common::Indirection<FunctionReference>::Make(std::move(x))} {}
71 
72 const std::optional<LoopControl> &DoConstruct::GetLoopControl() const {
73   const NonLabelDoStmt &doStmt{
74       std::get<Statement<NonLabelDoStmt>>(t).statement};
75   const std::optional<LoopControl> &control{
76       std::get<std::optional<LoopControl>>(doStmt.t)};
77   return control;
78 }
79 
80 bool DoConstruct::IsDoNormal() const {
81   const std::optional<LoopControl> &control{GetLoopControl()};
82   return control && std::holds_alternative<LoopControl::Bounds>(control->u);
83 }
84 
85 bool DoConstruct::IsDoWhile() const {
86   const std::optional<LoopControl> &control{GetLoopControl()};
87   return control && std::holds_alternative<ScalarLogicalExpr>(control->u);
88 }
89 
90 bool DoConstruct::IsDoConcurrent() const {
91   const std::optional<LoopControl> &control{GetLoopControl()};
92   return control && std::holds_alternative<LoopControl::Concurrent>(control->u);
93 }
94 
95 static Designator MakeArrayElementRef(
96     const Name &name, std::list<Expr> &&subscripts) {
97   ArrayElement arrayElement{DataRef{Name{name}}, std::list<SectionSubscript>{}};
98   for (Expr &expr : subscripts) {
99     arrayElement.subscripts.push_back(
100         SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
101   }
102   return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
103 }
104 
105 static Designator MakeArrayElementRef(
106     StructureComponent &&sc, std::list<Expr> &&subscripts) {
107   ArrayElement arrayElement{DataRef{common::Indirection{std::move(sc)}},
108       std::list<SectionSubscript>{}};
109   for (Expr &expr : subscripts) {
110     arrayElement.subscripts.push_back(
111         SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
112   }
113   return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
114 }
115 
116 // Set source in any type of node that has it.
117 template <typename T> T WithSource(CharBlock source, T &&x) {
118   x.source = source;
119   return std::move(x);
120 }
121 
122 static Expr ActualArgToExpr(ActualArgSpec &arg) {
123   return common::visit(
124       common::visitors{
125           [&](common::Indirection<Expr> &y) { return std::move(y.value()); },
126           [&](common::Indirection<Variable> &y) {
127             return common::visit(
128                 common::visitors{
129                     [&](common::Indirection<Designator> &z) {
130                       return WithSource(
131                           z.value().source, Expr{std::move(z.value())});
132                     },
133                     [&](common::Indirection<FunctionReference> &z) {
134                       return WithSource(
135                           z.value().source, Expr{std::move(z.value())});
136                     },
137                 },
138                 y.value().u);
139           },
140           [&](auto &) -> Expr { common::die("unexpected type"); },
141       },
142       std::get<ActualArg>(arg.t).u);
143 }
144 
145 Designator FunctionReference::ConvertToArrayElementRef() {
146   std::list<Expr> args;
147   for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
148     args.emplace_back(ActualArgToExpr(arg));
149   }
150   return common::visit(
151       common::visitors{
152           [&](const Name &name) {
153             return WithSource(
154                 source, MakeArrayElementRef(name, std::move(args)));
155           },
156           [&](ProcComponentRef &pcr) {
157             return WithSource(source,
158                 MakeArrayElementRef(std::move(pcr.v.thing), std::move(args)));
159           },
160       },
161       std::get<ProcedureDesignator>(v.t).u);
162 }
163 
164 StructureConstructor FunctionReference::ConvertToStructureConstructor(
165     const semantics::DerivedTypeSpec &derived) {
166   Name name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
167   std::list<ComponentSpec> components;
168   for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
169     std::optional<Keyword> keyword;
170     if (auto &kw{std::get<std::optional<Keyword>>(arg.t)}) {
171       keyword.emplace(Keyword{Name{kw->v}});
172     }
173     components.emplace_back(
174         std::move(keyword), ComponentDataSource{ActualArgToExpr(arg)});
175   }
176   DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};
177   spec.derivedTypeSpec = &derived;
178   return StructureConstructor{std::move(spec), std::move(components)};
179 }
180 
181 StructureConstructor ArrayElement::ConvertToStructureConstructor(
182     const semantics::DerivedTypeSpec &derived) {
183   Name name{std::get<parser::Name>(base.u)};
184   std::list<ComponentSpec> components;
185   for (auto &subscript : subscripts) {
186     components.emplace_back(std::optional<Keyword>{},
187         ComponentDataSource{std::move(*Unwrap<Expr>(subscript))});
188   }
189   DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};
190   spec.derivedTypeSpec = &derived;
191   return StructureConstructor{std::move(spec), std::move(components)};
192 }
193 
194 Substring ArrayElement::ConvertToSubstring() {
195   auto iter{subscripts.begin()};
196   CHECK(iter != subscripts.end());
197   auto &triplet{std::get<SubscriptTriplet>(iter->u)};
198   CHECK(!std::get<2>(triplet.t));
199   CHECK(++iter == subscripts.end());
200   return Substring{std::move(base),
201       SubstringRange{std::get<0>(std::move(triplet.t)),
202           std::get<1>(std::move(triplet.t))}};
203 }
204 
205 // R1544 stmt-function-stmt
206 // Convert this stmt-function-stmt to an assignment to the result of a
207 // pointer-valued function call -- which itself will be converted to a
208 // much more likely array element assignment statement if it needs
209 // to be.
210 Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {
211   auto &funcName{std::get<Name>(t)};
212   auto &funcArgs{std::get<std::list<Name>>(t)};
213   auto &funcExpr{std::get<Scalar<Expr>>(t).thing};
214   CharBlock source{funcName.source};
215   // Extend source to include closing parenthesis
216   if (funcArgs.empty()) {
217     CHECK(*source.end() == '(');
218     source = CharBlock{source.begin(), source.end() + 1};
219   }
220   std::list<ActualArgSpec> actuals;
221   for (const Name &arg : funcArgs) {
222     actuals.emplace_back(std::optional<Keyword>{},
223         ActualArg{Expr{WithSource(
224             arg.source, Designator{DataRef{Name{arg.source, arg.symbol}}})}});
225     source.ExtendToCover(arg.source);
226   }
227   CHECK(*source.end() == ')');
228   source = CharBlock{source.begin(), source.end() + 1};
229   FunctionReference funcRef{
230       Call{ProcedureDesignator{Name{funcName.source, funcName.symbol}},
231           std::move(actuals)}};
232   funcRef.source = source;
233   auto variable{Variable{common::Indirection{std::move(funcRef)}}};
234   return Statement{std::nullopt,
235       ActionStmt{common::Indirection{
236           AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};
237 }
238 
239 CharBlock Variable::GetSource() const {
240   return common::visit(
241       common::visitors{
242           [&](const common::Indirection<Designator> &des) {
243             return des.value().source;
244           },
245           [&](const common::Indirection<parser::FunctionReference> &call) {
246             return call.value().source;
247           },
248       },
249       u);
250 }
251 
252 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {
253   return os << x.ToString();
254 }
255 
256 OmpDependenceType::Value OmpDoacross::GetDepType() const {
257   return common::visit( //
258       common::visitors{
259           [](const OmpDoacross::Sink &) {
260             return OmpDependenceType::Value::Sink;
261           },
262           [](const OmpDoacross::Source &) {
263             return OmpDependenceType::Value::Source;
264           },
265       },
266       u);
267 }
268 
269 OmpTaskDependenceType::Value OmpDependClause::TaskDep::GetTaskDepType() const {
270   using Modifier = OmpDependClause::TaskDep::Modifier;
271   auto &modifiers{std::get<std::optional<std::list<Modifier>>>(t)};
272   if (modifiers) {
273     for (auto &m : *modifiers) {
274       if (auto *dep{std::get_if<OmpTaskDependenceType>(&m.u)}) {
275         return dep->v;
276       }
277     }
278     llvm_unreachable("expecting OmpTaskDependenceType in TaskDep");
279   } else {
280     llvm_unreachable("expecting modifiers on OmpDependClause::TaskDep");
281   }
282 }
283 
284 } // namespace Fortran::parser
285 
286 template <typename C> static llvm::omp::Clause getClauseIdForClass(C &&) {
287   using namespace Fortran;
288   using A = llvm::remove_cvref_t<C>; // A is referenced in OMP.inc
289   // The code included below contains a sequence of checks like the following
290   // for each OpenMP clause
291   //   if constexpr (std::is_same_v<A, parser::OmpClause::AcqRel>)
292   //     return llvm::omp::Clause::OMPC_acq_rel;
293   //   [...]
294 #define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
295 #include "llvm/Frontend/OpenMP/OMP.inc"
296 }
297 
298 namespace Fortran::parser {
299 llvm::omp::Clause OmpClause::Id() const {
300   return std::visit([](auto &&s) { return getClauseIdForClass(s); }, u);
301 }
302 } // namespace Fortran::parser
303