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
ImportStmt(common::ImportKind && k,std::list<Name> && n)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
CommonStmt(std::optional<Name> && name,std::list<CommonBlockObject> && objects,std::list<Block> && others)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
EndsInBareName() const34 bool Designator::EndsInBareName() const {
35   return std::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]...
DataRef(std::list<PartRef> && prl)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
Expr(Designator && x)67 Expr::Expr(Designator &&x)
68     : u{common::Indirection<Designator>::Make(std::move(x))} {}
Expr(FunctionReference && x)69 Expr::Expr(FunctionReference &&x)
70     : u{common::Indirection<FunctionReference>::Make(std::move(x))} {}
71 
GetLoopControl() const72 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 
IsDoNormal() const80 bool DoConstruct::IsDoNormal() const {
81   const std::optional<LoopControl> &control{GetLoopControl()};
82   return control && std::holds_alternative<LoopControl::Bounds>(control->u);
83 }
84 
IsDoWhile() const85 bool DoConstruct::IsDoWhile() const {
86   const std::optional<LoopControl> &control{GetLoopControl()};
87   return control && std::holds_alternative<ScalarLogicalExpr>(control->u);
88 }
89 
IsDoConcurrent() const90 bool DoConstruct::IsDoConcurrent() const {
91   const std::optional<LoopControl> &control{GetLoopControl()};
92   return control && std::holds_alternative<LoopControl::Concurrent>(control->u);
93 }
94 
MakeArrayElementRef(const Name & name,std::list<Expr> && subscripts)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 
MakeArrayElementRef(StructureComponent && sc,std::list<Expr> && subscripts)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.
WithSource(CharBlock source,T && x)117 template <typename T> T WithSource(CharBlock source, T &&x) {
118   x.source = source;
119   return std::move(x);
120 }
121 
ActualArgToExpr(ActualArgSpec & arg)122 static Expr ActualArgToExpr(ActualArgSpec &arg) {
123   return std::visit(
124       common::visitors{
125           [&](common::Indirection<Expr> &y) { return std::move(y.value()); },
126           [&](common::Indirection<Variable> &y) {
127             return std::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().v.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 
ConvertToArrayElementRef()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 std::visit(
151       common::visitors{
152           [&](const Name &name) {
153             return WithSource(
154                 v.source, MakeArrayElementRef(name, std::move(args)));
155           },
156           [&](ProcComponentRef &pcr) {
157             return WithSource(v.source,
158                 MakeArrayElementRef(std::move(pcr.v.thing), std::move(args)));
159           },
160       },
161       std::get<ProcedureDesignator>(v.t).u);
162 }
163 
ConvertToStructureConstructor(const semantics::DerivedTypeSpec & derived)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 
ConvertToStructureConstructor(const semantics::DerivedTypeSpec & derived)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 
ConvertToSubstring()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 array element assignment statement.
ConvertToAssignment()207 Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {
208   auto &funcName{std::get<Name>(t)};
209   auto &funcArgs{std::get<std::list<Name>>(t)};
210   auto &funcExpr{std::get<Scalar<Expr>>(t).thing};
211   CharBlock source{funcName.source};
212   std::list<Expr> subscripts;
213   for (Name &arg : funcArgs) {
214     subscripts.push_back(WithSource(arg.source,
215         Expr{common::Indirection{
216             WithSource(arg.source, Designator{DataRef{Name{arg}}})}}));
217     source.ExtendToCover(arg.source);
218   }
219   // extend source to include closing paren
220   if (funcArgs.empty()) {
221     CHECK(*source.end() == '(');
222     source = CharBlock{source.begin(), source.end() + 1};
223   }
224   CHECK(*source.end() == ')');
225   source = CharBlock{source.begin(), source.end() + 1};
226   auto variable{Variable{common::Indirection{WithSource(
227       source, MakeArrayElementRef(funcName, std::move(subscripts)))}}};
228   return Statement{std::nullopt,
229       ActionStmt{common::Indirection{
230           AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};
231 }
232 
GetSource() const233 CharBlock Variable::GetSource() const {
234   return std::visit(
235       common::visitors{
236           [&](const common::Indirection<Designator> &des) {
237             return des.value().source;
238           },
239           [&](const common::Indirection<parser::FunctionReference> &call) {
240             return call.value().v.source;
241           },
242       },
243       u);
244 }
245 
operator <<(llvm::raw_ostream & os,const Name & x)246 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {
247   return os << x.ToString();
248 }
249 
250 } // namespace Fortran::parser
251