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 #ifndef FORTRAN_EVALUATE_VARIABLE_H_
16 #define FORTRAN_EVALUATE_VARIABLE_H_
17 
18 // Defines data structures to represent data access and function calls
19 // for use in expressions and assignment statements.  Both copy and move
20 // semantics are supported.  The representation adheres closely to the
21 // Fortran 2018 language standard (q.v.) and uses strong typing to ensure
22 // that only admissable combinations can be constructed.
23 
24 #include "call.h"
25 #include "common.h"
26 #include "formatting.h"
27 #include "static-data.h"
28 #include "type.h"
29 #include "../common/idioms.h"
30 #include "../common/template.h"
31 #include "../parser/char-block.h"
32 #include <optional>
33 #include <ostream>
34 #include <variant>
35 #include <vector>
36 
37 namespace Fortran::semantics {
38 class Symbol;
39 }
40 
41 namespace Fortran::evaluate {
42 
43 using semantics::Symbol;
44 
45 // Forward declarations
46 struct DataRef;
47 template<typename A> struct Variable;
48 
49 // Reference a base object in memory.  This can be a Fortran symbol,
50 // static data (e.g., CHARACTER literal), or compiler-created temporary.
51 struct BaseObject {
CLASS_BOILERPLATEBaseObject52   CLASS_BOILERPLATE(BaseObject)
53   explicit BaseObject(const Symbol &symbol) : u{&symbol} {}
BaseObjectBaseObject54   explicit BaseObject(StaticDataObject::Pointer &&p) : u{std::move(p)} {}
55   int Rank() const;
56   std::optional<Expr<SubscriptInteger>> LEN() const;
57   bool operator==(const BaseObject &) const;
58   std::ostream &AsFortran(std::ostream &) const;
symbolBaseObject59   const Symbol *symbol() const {
60     if (const auto *result{std::get_if<const Symbol *>(&u)}) {
61       return *result;
62     } else {
63       return nullptr;
64     }
65   }
66   std::variant<const Symbol *, StaticDataObject::Pointer> u;
67 };
68 
69 // R913 structure-component & C920: Defined to be a multi-part
70 // data-ref whose last part has no subscripts (or image-selector, although
71 // that isn't explicit in the document).  Pointer and allocatable components
72 // are not explicitly indirected in this representation.
73 // Complex components (%RE, %IM) are isolated below in ComplexPart.
74 // (Type parameter inquiries look like component references but are distinct
75 // constructs and not represented by this class.)
76 class Component {
77 public:
CLASS_BOILERPLATE(Component)78   CLASS_BOILERPLATE(Component)
79   Component(const DataRef &b, const Symbol &c) : base_{b}, symbol_{&c} {}
Component(DataRef && b,const Symbol & c)80   Component(DataRef &&b, const Symbol &c) : base_{std::move(b)}, symbol_{&c} {}
Component(common::CopyableIndirection<DataRef> && b,const Symbol & c)81   Component(common::CopyableIndirection<DataRef> &&b, const Symbol &c)
82     : base_{std::move(b)}, symbol_{&c} {}
83 
base()84   const DataRef &base() const { return base_.value(); }
base()85   DataRef &base() { return base_.value(); }
86   int Rank() const;
87   const Symbol &GetFirstSymbol() const;
GetLastSymbol()88   const Symbol &GetLastSymbol() const { return *symbol_; }
89   std::optional<Expr<SubscriptInteger>> LEN() const;
90   bool operator==(const Component &) const;
91   std::ostream &AsFortran(std::ostream &) const;
92 
93 private:
94   common::CopyableIndirection<DataRef> base_;
95   const Symbol *symbol_;
96 };
97 
98 // A NamedEntity is either a whole Symbol or a component in an instance
99 // of a derived type.  It may be a descriptor.
100 // TODO: this is basically a symbol with an optional DataRef base;
101 // could be used to replace Component.
102 class NamedEntity {
103 public:
CLASS_BOILERPLATE(NamedEntity)104   CLASS_BOILERPLATE(NamedEntity)
105   explicit NamedEntity(const Symbol &symbol) : u_{&symbol} {}
NamedEntity(Component && c)106   explicit NamedEntity(Component &&c) : u_{std::move(c)} {}
107 
IsSymbol()108   bool IsSymbol() const { return std::holds_alternative<const Symbol *>(u_); }
109   const Symbol &GetFirstSymbol() const;
110   const Symbol &GetLastSymbol() const;
GetComponent()111   const Component &GetComponent() const { return std::get<Component>(u_); }
GetComponent()112   Component &GetComponent() { return std::get<Component>(u_); }
113   const Component *UnwrapComponent() const;  // null if just a Symbol
114   Component *UnwrapComponent();
115 
116   int Rank() const;
117   std::optional<Expr<SubscriptInteger>> LEN() const;
118   bool operator==(const NamedEntity &) const;
119   std::ostream &AsFortran(std::ostream &) const;
120 
121 private:
122   std::variant<const Symbol *, Component> u_;
123 };
124 
125 // R916 type-param-inquiry
126 // N.B. x%LEN for CHARACTER is rewritten in semantics to LEN(x), which is
127 // then handled via LEN() member functions in the various classes.
128 // x%KIND for intrinsic types is similarly rewritten in semantics to
129 // KIND(x), which is then folded to a constant value.
130 // "Bare" type parameter references within a derived type definition do
131 // not have base objects.
132 template<int KIND> class TypeParamInquiry {
133 public:
134   using Result = Type<TypeCategory::Integer, KIND>;
135   CLASS_BOILERPLATE(TypeParamInquiry)
TypeParamInquiry(NamedEntity && x,const Symbol & param)136   TypeParamInquiry(NamedEntity &&x, const Symbol &param)
137     : base_{std::move(x)}, parameter_{&param} {}
TypeParamInquiry(std::optional<NamedEntity> && x,const Symbol & param)138   TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol &param)
139     : base_{std::move(x)}, parameter_{&param} {}
140 
base()141   const std::optional<NamedEntity> &base() const { return base_; }
base()142   std::optional<NamedEntity> &base() { return base_; }
parameter()143   const Symbol &parameter() const { return *parameter_; }
144 
Rank()145   static constexpr int Rank() { return 0; }  // always scalar
146   bool operator==(const TypeParamInquiry &) const;
147   std::ostream &AsFortran(std::ostream &) const;
148 
149 private:
150   std::optional<NamedEntity> base_;
151   const Symbol *parameter_;
152 };
153 
154 EXPAND_FOR_EACH_INTEGER_KIND(
155     TEMPLATE_INSTANTIATION, extern template class TypeParamInquiry, )
156 
157 // R921 subscript-triplet
158 class Triplet {
159 public:
160   Triplet();
161   DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(Triplet)
162   Triplet(std::optional<Expr<SubscriptInteger>> &&,
163       std::optional<Expr<SubscriptInteger>> &&,
164       std::optional<Expr<SubscriptInteger>> &&);
165 
166   std::optional<Expr<SubscriptInteger>> lower() const;
167   Triplet &set_lower(Expr<SubscriptInteger> &&);
168   std::optional<Expr<SubscriptInteger>> upper() const;
169   Triplet &set_upper(Expr<SubscriptInteger> &&);
170   Expr<SubscriptInteger> stride() const;  // N.B. result is not optional<>
171   Triplet &set_stride(Expr<SubscriptInteger> &&);
172 
173   bool operator==(const Triplet &) const;
174   bool IsStrideOne() const;
175   std::ostream &AsFortran(std::ostream &) const;
176 
177 private:
178   std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
179   IndirectSubscriptIntegerExpr stride_;
180 };
181 
182 // R919 subscript when rank 0, R923 vector-subscript when rank 1
183 struct Subscript {
EVALUATE_UNION_CLASS_BOILERPLATESubscript184   EVALUATE_UNION_CLASS_BOILERPLATE(Subscript)
185   explicit Subscript(Expr<SubscriptInteger> &&s)
186     : u{IndirectSubscriptIntegerExpr::Make(std::move(s))} {}
187   int Rank() const;
188   std::ostream &AsFortran(std::ostream &) const;
189   std::variant<IndirectSubscriptIntegerExpr, Triplet> u;
190 };
191 
192 // R917 array-element, R918 array-section; however, the case of an
193 // array-section that is a complex-part-designator is represented here
194 // as a ComplexPart instead.  C919 & C925 require that at most one set of
195 // subscripts have rank greater than 0, but that is not explicit in
196 // these types.
197 class ArrayRef {
198 public:
CLASS_BOILERPLATE(ArrayRef)199   CLASS_BOILERPLATE(ArrayRef)
200   ArrayRef(const Symbol &symbol, std::vector<Subscript> &&ss)
201     : base_{symbol}, subscript_(std::move(ss)) {}
ArrayRef(Component && c,std::vector<Subscript> && ss)202   ArrayRef(Component &&c, std::vector<Subscript> &&ss)
203     : base_{std::move(c)}, subscript_(std::move(ss)) {}
ArrayRef(NamedEntity && base,std::vector<Subscript> && ss)204   ArrayRef(NamedEntity &&base, std::vector<Subscript> &&ss)
205     : base_{std::move(base)}, subscript_(std::move(ss)) {}
206 
base()207   NamedEntity &base() { return base_; }
base()208   const NamedEntity &base() const { return base_; }
subscript()209   std::vector<Subscript> &subscript() { return subscript_; }
subscript()210   const std::vector<Subscript> &subscript() const { return subscript_; }
211 
size()212   int size() const { return static_cast<int>(subscript_.size()); }
at(int n)213   Subscript &at(int n) { return subscript_.at(n); }
at(int n)214   const Subscript &at(int n) const { return subscript_.at(n); }
emplace_back(A && x)215   template<typename A> common::IfNoLvalue<Subscript &, A> emplace_back(A &&x) {
216     return subscript_.emplace_back(std::move(x));
217   }
218 
219   int Rank() const;
220   const Symbol &GetFirstSymbol() const;
221   const Symbol &GetLastSymbol() const;
222   std::optional<Expr<SubscriptInteger>> LEN() const;
223   bool operator==(const ArrayRef &) const;
224   std::ostream &AsFortran(std::ostream &) const;
225 
226 private:
227   NamedEntity base_;
228   std::vector<Subscript> subscript_;
229 };
230 
231 // R914 coindexed-named-object
232 // R924 image-selector, R926 image-selector-spec.
233 // C824 severely limits the usage of derived types with coarray ultimate
234 // components: they can't be pointers, allocatables, arrays, coarrays, or
235 // function results.  They can be components of other derived types.
236 // Although the F'2018 Standard never prohibits multiple image-selectors
237 // per se in the same data-ref or designator, nor the presence of an
238 // image-selector after a part-ref with rank, the constraints on the
239 // derived types that would have be involved make it impossible to declare
240 // an object that could be referenced in these ways (esp. C748 & C825).
241 // C930 precludes having both TEAM= and TEAM_NUMBER=.
242 // TODO C931 prohibits the use of a coindexed object as a stat-variable.
243 class CoarrayRef {
244 public:
245   CLASS_BOILERPLATE(CoarrayRef)
246   CoarrayRef(std::vector<const Symbol *> &&, std::vector<Subscript> &&,
247       std::vector<Expr<SubscriptInteger>> &&);
248 
base()249   const std::vector<const Symbol *> &base() const { return base_; }
base()250   std::vector<const Symbol *> &base() { return base_; }
subscript()251   const std::vector<Subscript> &subscript() const { return subscript_; }
subscript()252   std::vector<Subscript> &subscript() { return subscript_; }
cosubscript()253   const std::vector<Expr<SubscriptInteger>> &cosubscript() const {
254     return cosubscript_;
255   }
cosubscript()256   std::vector<Expr<SubscriptInteger>> &cosubscript() { return cosubscript_; }
257 
258   // These integral expressions for STAT= and TEAM= must be variables
259   // (i.e., Designator or pointer-valued FunctionRef).
260   std::optional<Expr<SomeInteger>> stat() const;
261   CoarrayRef &set_stat(Expr<SomeInteger> &&);
262   std::optional<Expr<SomeInteger>> team() const;
teamIsTeamNumber()263   bool teamIsTeamNumber() const { return teamIsTeamNumber_; }
264   CoarrayRef &set_team(Expr<SomeInteger> &&, bool isTeamNumber = false);
265 
266   int Rank() const;
267   const Symbol &GetFirstSymbol() const;
268   const Symbol &GetLastSymbol() const;
269   NamedEntity GetBase() const;
270   std::optional<Expr<SubscriptInteger>> LEN() const;
271   bool operator==(const CoarrayRef &) const;
272   std::ostream &AsFortran(std::ostream &) const;
273 
274 private:
275   std::vector<const Symbol *> base_;
276   std::vector<Subscript> subscript_;
277   std::vector<Expr<SubscriptInteger>> cosubscript_;
278   std::optional<common::CopyableIndirection<Expr<SomeInteger>>> stat_, team_;
279   bool teamIsTeamNumber_{false};  // false: TEAM=, true: TEAM_NUMBER=
280 };
281 
282 // R911 data-ref is defined syntactically as a series of part-refs, which
283 // would be far too expressive if the constraints were ignored.  Here, the
284 // possible outcomes are spelled out.  Note that a data-ref cannot include
285 // a terminal substring range or complex component designator; use
286 // R901 designator for that.
287 struct DataRef {
EVALUATE_UNION_CLASS_BOILERPLATEDataRef288   EVALUATE_UNION_CLASS_BOILERPLATE(DataRef)
289   explicit DataRef(const Symbol &n) : u{&n} {}
290 
291   int Rank() const;
292   const Symbol &GetFirstSymbol() const;
293   const Symbol &GetLastSymbol() const;
294   std::optional<Expr<SubscriptInteger>> LEN() const;
295   std::ostream &AsFortran(std::ostream &) const;
296 
297   std::variant<const Symbol *, Component, ArrayRef, CoarrayRef> u;
298 };
299 
300 // R908 substring, R909 parent-string, R910 substring-range.
301 // The base object of a substring can be a literal.
302 // In the F2018 standard, substrings of array sections are parsed as
303 // variants of sections instead.
304 class Substring {
305   using Parent = std::variant<DataRef, StaticDataObject::Pointer>;
306 
307 public:
CLASS_BOILERPLATE(Substring)308   CLASS_BOILERPLATE(Substring)
309   Substring(DataRef &&parent, std::optional<Expr<SubscriptInteger>> &&lower,
310       std::optional<Expr<SubscriptInteger>> &&upper)
311     : parent_{std::move(parent)} {
312     SetBounds(lower, upper);
313   }
Substring(StaticDataObject::Pointer && parent,std::optional<Expr<SubscriptInteger>> && lower,std::optional<Expr<SubscriptInteger>> && upper)314   Substring(StaticDataObject::Pointer &&parent,
315       std::optional<Expr<SubscriptInteger>> &&lower,
316       std::optional<Expr<SubscriptInteger>> &&upper)
317     : parent_{std::move(parent)} {
318     SetBounds(lower, upper);
319   }
320 
321   Expr<SubscriptInteger> lower() const;
322   Substring &set_lower(Expr<SubscriptInteger> &&);
323   std::optional<Expr<SubscriptInteger>> upper() const;
324   Substring &set_upper(Expr<SubscriptInteger> &&);
parent()325   const Parent &parent() const { return parent_; }
parent()326   Parent &parent() { return parent_; }
327 
328   int Rank() const;
GetParentIf()329   template<typename A> const A *GetParentIf() const {
330     return std::get_if<A>(&parent_);
331   }
332   BaseObject GetBaseObject() const;
333   const Symbol *GetLastSymbol() const;
334   std::optional<Expr<SubscriptInteger>> LEN() const;
335   bool operator==(const Substring &) const;
336   std::ostream &AsFortran(std::ostream &) const;
337 
338   std::optional<Expr<SomeCharacter>> Fold(FoldingContext &);
339 
340 private:
341   void SetBounds(std::optional<Expr<SubscriptInteger>> &,
342       std::optional<Expr<SubscriptInteger>> &);
343   Parent parent_;
344   std::optional<IndirectSubscriptIntegerExpr> lower_, upper_;
345 };
346 
347 // R915 complex-part-designator
348 // In the F2018 standard, complex parts of array sections are parsed as
349 // variants of sections instead.
350 class ComplexPart {
351 public:
ENUM_CLASS(Part,RE,IM)352   ENUM_CLASS(Part, RE, IM)
353   CLASS_BOILERPLATE(ComplexPart)
354   ComplexPart(DataRef &&z, Part p) : complex_{std::move(z)}, part_{p} {}
complex()355   const DataRef &complex() const { return complex_; }
part()356   Part part() const { return part_; }
357   int Rank() const;
GetFirstSymbol()358   const Symbol &GetFirstSymbol() const { return complex_.GetFirstSymbol(); }
GetLastSymbol()359   const Symbol &GetLastSymbol() const { return complex_.GetLastSymbol(); }
360   bool operator==(const ComplexPart &) const;
361   std::ostream &AsFortran(std::ostream &) const;
362 
363 private:
364   DataRef complex_;
365   Part part_;
366 };
367 
368 // R901 designator is the most general data reference object, apart from
369 // calls to pointer-valued functions.  Its variant holds everything that
370 // a DataRef can, and possibly also a substring reference or a
371 // complex component (%RE/%IM) reference.
372 template<typename T> class Designator {
373   using DataRefs = std::decay_t<decltype(DataRef::u)>;
374   using MaybeSubstring =
375       std::conditional_t<T::category == TypeCategory::Character,
376           std::variant<Substring>, std::variant<>>;
377   using MaybeComplexPart = std::conditional_t<T::category == TypeCategory::Real,
378       std::variant<ComplexPart>, std::variant<>>;
379   using Variant =
380       common::CombineVariants<DataRefs, MaybeSubstring, MaybeComplexPart>;
381 
382 public:
383   using Result = T;
384   static_assert(
385       IsSpecificIntrinsicType<Result> || std::is_same_v<Result, SomeDerived>);
386   EVALUATE_UNION_CLASS_BOILERPLATE(Designator)
387 
Designator(const DataRef & that)388   Designator(const DataRef &that) : u{common::CopyVariant<Variant>(that.u)} {}
Designator(DataRef && that)389   Designator(DataRef &&that)
390     : u{common::MoveVariant<Variant>(std::move(that.u))} {}
391 
392   std::optional<DynamicType> GetType() const;
393   int Rank() const;
394   BaseObject GetBaseObject() const;
395   const Symbol *GetLastSymbol() const;
396   std::optional<Expr<SubscriptInteger>> LEN() const;
397   std::ostream &AsFortran(std::ostream &o) const;
398 
399   Variant u;
400 };
401 
402 FOR_EACH_CHARACTER_KIND(extern template class Designator, )
403 
404 template<typename T> struct Variable {
405   using Result = T;
406   static_assert(IsSpecificIntrinsicType<Result> ||
407       std::is_same_v<Result, SomeKind<TypeCategory::Derived>>);
EVALUATE_UNION_CLASS_BOILERPLATEVariable408   EVALUATE_UNION_CLASS_BOILERPLATE(Variable)
409   std::optional<DynamicType> GetType() const {
410     return std::visit([](const auto &x) { return x.GetType(); }, u);
411   }
RankVariable412   int Rank() const {
413     return std::visit([](const auto &x) { return x.Rank(); }, u);
414   }
AsFortranVariable415   std::ostream &AsFortran(std::ostream &o) const {
416     std::visit([&](const auto &x) { x.AsFortran(o); }, u);
417     return o;
418   }
419   std::variant<Designator<Result>, FunctionRef<Result>> u;
420 };
421 
422 class DescriptorInquiry {
423 public:
424   using Result = SubscriptInteger;
425   ENUM_CLASS(Field, LowerBound, Extent, Stride, Rank)
426 
427   CLASS_BOILERPLATE(DescriptorInquiry)
428   DescriptorInquiry(const NamedEntity &, Field, int);
429   DescriptorInquiry(NamedEntity &&, Field, int);
430 
base()431   NamedEntity &base() { return base_; }
base()432   const NamedEntity &base() const { return base_; }
field()433   Field field() const { return field_; }
dimension()434   int dimension() const { return dimension_; }
435 
Rank()436   static constexpr int Rank() { return 0; }  // always scalar
437   bool operator==(const DescriptorInquiry &) const;
438   std::ostream &AsFortran(std::ostream &) const;
439 
440 private:
441   NamedEntity base_;
442   Field field_;
443   int dimension_{0};  // zero-based
444 };
445 
446 #define INSTANTIATE_VARIABLE_TEMPLATES \
447   EXPAND_FOR_EACH_INTEGER_KIND( \
448       TEMPLATE_INSTANTIATION, template class TypeParamInquiry, ) \
449   FOR_EACH_SPECIFIC_TYPE(template class Designator, )
450 }
451 #endif  // FORTRAN_EVALUATE_VARIABLE_H_
452