1 // Copyright (c) 2018-2019, NVIDIA CORPORATION.  All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "parse-tree.h"
16 #include "user-state.h"
17 #include "../common/idioms.h"
18 #include "../common/indirection.h"
19 #include <algorithm>
20 
21 // So "delete Expr;" calls an external destructor for its typedExpr.
22 namespace Fortran::evaluate {
23 struct GenericExprWrapper {
24   ~GenericExprWrapper();
25 };
26 }
27 
28 namespace Fortran::parser {
29 
30 // R867
ImportStmt(common::ImportKind && k,std::list<Name> && n)31 ImportStmt::ImportStmt(common::ImportKind &&k, std::list<Name> &&n)
32   : kind{k}, names(std::move(n)) {
33   CHECK(kind == common::ImportKind::Default ||
34       kind == common::ImportKind::Only || names.empty());
35 }
36 
37 // R873
CommonStmt(std::optional<Name> && name,std::list<CommonBlockObject> && objects,std::list<Block> && others)38 CommonStmt::CommonStmt(std::optional<Name> &&name,
39     std::list<CommonBlockObject> &&objects, std::list<Block> &&others) {
40   blocks.emplace_front(std::move(name), std::move(objects));
41   blocks.splice(blocks.end(), std::move(others));
42 }
43 
44 // R901 designator
EndsInBareName() const45 bool Designator::EndsInBareName() const {
46   return std::visit(
47       common::visitors{
48           [](const DataRef &dr) {
49             return std::holds_alternative<Name>(dr.u) ||
50                 std::holds_alternative<common::Indirection<StructureComponent>>(
51                     dr.u);
52           },
53           [](const Substring &) { return false; },
54       },
55       u);
56 }
57 
58 // R911 data-ref -> part-ref [% part-ref]...
DataRef(std::list<PartRef> && prl)59 DataRef::DataRef(std::list<PartRef> &&prl) : u{std::move(prl.front().name)} {
60   for (bool first{true}; !prl.empty(); first = false, prl.pop_front()) {
61     PartRef &pr{prl.front()};
62     if (!first) {
63       u = common::Indirection<StructureComponent>::Make(
64           std::move(*this), std::move(pr.name));
65     }
66     if (!pr.subscripts.empty()) {
67       u = common::Indirection<ArrayElement>::Make(
68           std::move(*this), std::move(pr.subscripts));
69     }
70     if (pr.imageSelector.has_value()) {
71       u = common::Indirection<CoindexedNamedObject>::Make(
72           std::move(*this), std::move(*pr.imageSelector));
73     }
74   }
75 }
76 
77 // R1001 - R1022 expression
Expr(Designator && x)78 Expr::Expr(Designator &&x)
79   : u{common::Indirection<Designator>::Make(std::move(x))} {}
Expr(FunctionReference && x)80 Expr::Expr(FunctionReference &&x)
81   : u{common::Indirection<FunctionReference>::Make(std::move(x))} {}
82 
GetLoopControl() const83 const std::optional<LoopControl> &DoConstruct::GetLoopControl() const {
84   const NonLabelDoStmt &doStmt{
85       std::get<Statement<NonLabelDoStmt>>(t).statement};
86   const std::optional<LoopControl> &control{
87       std::get<std::optional<LoopControl>>(doStmt.t)};
88   return control;
89 }
90 
IsDoNormal() const91 bool DoConstruct::IsDoNormal() const {
92   const std::optional<LoopControl> &control{GetLoopControl()};
93   return control && std::holds_alternative<LoopControl::Bounds>(control->u);
94 }
95 
IsDoWhile() const96 bool DoConstruct::IsDoWhile() const {
97   const std::optional<LoopControl> &control{GetLoopControl()};
98   return control && std::holds_alternative<ScalarLogicalExpr>(control->u);
99 }
100 
IsDoConcurrent() const101 bool DoConstruct::IsDoConcurrent() const {
102   const std::optional<LoopControl> &control{GetLoopControl()};
103   return control && std::holds_alternative<LoopControl::Concurrent>(control->u);
104 }
105 
MakeArrayElementRef(const Name & name,std::list<Expr> && subscripts)106 static Designator MakeArrayElementRef(
107     const Name &name, std::list<Expr> &&subscripts) {
108   ArrayElement arrayElement{DataRef{Name{name}}, 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 
MakeArrayElementRef(StructureComponent && sc,std::list<Expr> && subscripts)116 static Designator MakeArrayElementRef(
117     StructureComponent &&sc, std::list<Expr> &&subscripts) {
118   ArrayElement arrayElement{DataRef{common::Indirection{std::move(sc)}},
119       std::list<SectionSubscript>{}};
120   for (Expr &expr : subscripts) {
121     arrayElement.subscripts.push_back(
122         SectionSubscript{Integer{common::Indirection{std::move(expr)}}});
123   }
124   return Designator{DataRef{common::Indirection{std::move(arrayElement)}}};
125 }
126 
127 // Set source in any type of node that has it.
WithSource(CharBlock source,T && x)128 template<typename T> T WithSource(CharBlock source, T &&x) {
129   x.source = source;
130   return std::move(x);
131 }
132 
ActualArgToExpr(ActualArgSpec & arg)133 static Expr ActualArgToExpr(ActualArgSpec &arg) {
134   return std::visit(
135       common::visitors{
136           [&](common::Indirection<Expr> &y) { return std::move(y.value()); },
137           [&](common::Indirection<Variable> &y) {
138             return std::visit(
139                 common::visitors{
140                     [&](common::Indirection<Designator> &z) {
141                       return WithSource(
142                           z.value().source, Expr{std::move(z.value())});
143                     },
144                     [&](common::Indirection<FunctionReference> &z) {
145                       return WithSource(
146                           z.value().v.source, Expr{std::move(z.value())});
147                     },
148                 },
149                 y.value().u);
150           },
151           [&](auto &) -> Expr { common::die("unexpected type"); },
152       },
153       std::get<ActualArg>(arg.t).u);
154 }
155 
ConvertToArrayElementRef()156 Designator FunctionReference::ConvertToArrayElementRef() {
157   std::list<Expr> args;
158   for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
159     args.emplace_back(ActualArgToExpr(arg));
160   }
161   return std::visit(
162       common::visitors{
163           [&](const Name &name) {
164             return WithSource(
165                 v.source, MakeArrayElementRef(name, std::move(args)));
166           },
167           [&](ProcComponentRef &pcr) {
168             return WithSource(v.source,
169                 MakeArrayElementRef(std::move(pcr.v.thing), std::move(args)));
170           },
171       },
172       std::get<ProcedureDesignator>(v.t).u);
173 }
174 
ConvertToStructureConstructor(const semantics::DerivedTypeSpec & derived)175 StructureConstructor FunctionReference::ConvertToStructureConstructor(
176     const semantics::DerivedTypeSpec &derived) {
177   Name name{std::get<parser::Name>(std::get<ProcedureDesignator>(v.t).u)};
178   std::list<ComponentSpec> components;
179   for (auto &arg : std::get<std::list<ActualArgSpec>>(v.t)) {
180     std::optional<Keyword> keyword;
181     if (auto &kw{std::get<std::optional<Keyword>>(arg.t)}) {
182       keyword.emplace(Keyword{Name{kw->v}});
183     }
184     components.emplace_back(
185         std::move(keyword), ComponentDataSource{ActualArgToExpr(arg)});
186   }
187   DerivedTypeSpec spec{std::move(name), std::list<TypeParamSpec>{}};
188   spec.derivedTypeSpec = &derived;
189   return StructureConstructor{std::move(spec), std::move(components)};
190 }
191 
ConvertToSubstring()192 Substring ArrayElement::ConvertToSubstring() {
193   auto iter{subscripts.begin()};
194   CHECK(iter != subscripts.end());
195   auto &triplet{std::get<SubscriptTriplet>(iter->u)};
196   CHECK(!std::get<2>(triplet.t).has_value());
197   CHECK(++iter == subscripts.end());
198   return Substring{std::move(base),
199       SubstringRange{std::get<0>(std::move(triplet.t)),
200           std::get<1>(std::move(triplet.t))}};
201 }
202 
203 // R1544 stmt-function-stmt
204 // Convert this stmt-function-stmt to an array element assignment statement.
ConvertToAssignment()205 Statement<ActionStmt> StmtFunctionStmt::ConvertToAssignment() {
206   auto &funcName{std::get<Name>(t)};
207   auto &funcArgs{std::get<std::list<Name>>(t)};
208   auto &funcExpr{std::get<Scalar<Expr>>(t).thing};
209   CharBlock source{funcName.source};
210   std::list<Expr> subscripts;
211   for (Name &arg : funcArgs) {
212     subscripts.push_back(WithSource(arg.source,
213         Expr{common::Indirection{
214             WithSource(arg.source, Designator{DataRef{Name{arg}}})}}));
215     source.ExtendToCover(arg.source);
216   }
217   // extend source to include closing paren
218   if (funcArgs.empty()) {
219     CHECK(*source.end() == '(');
220     source = CharBlock{source.begin(), source.end() + 1};
221   }
222   CHECK(*source.end() == ')');
223   source = CharBlock{source.begin(), source.end() + 1};
224   auto variable{Variable{common::Indirection{WithSource(
225       source, MakeArrayElementRef(funcName, std::move(subscripts)))}}};
226   return Statement{std::nullopt,
227       ActionStmt{common::Indirection{
228           AssignmentStmt{std::move(variable), std::move(funcExpr)}}}};
229 }
230 
GetSource() const231 CharBlock Variable::GetSource() const {
232   return std::visit(
233       common::visitors{
234           [&](const common::Indirection<Designator> &des) {
235             return des.value().source;
236           },
237           [&](const common::Indirection<parser::FunctionReference> &call) {
238             return call.value().v.source;
239           },
240       },
241       u);
242 }
243 
operator <<(std::ostream & os,const Name & x)244 std::ostream &operator<<(std::ostream &os, const Name &x) {
245   return os << x.ToString();
246 }
247 
248 }
249 
250 template class std::unique_ptr<Fortran::evaluate::GenericExprWrapper>;
251