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 ¶m) 137 : base_{std::move(x)}, parameter_{¶m} {} TypeParamInquiry(std::optional<NamedEntity> && x,const Symbol & param)138 TypeParamInquiry(std::optional<NamedEntity> &&x, const Symbol ¶m) 139 : base_{std::move(x)}, parameter_{¶m} {} 140 base()141 const std::optional<NamedEntity> &base() const { return base_; } base()142 std::optional<NamedEntity> &base() { return base_; } parameter()143 const Symbol ¶meter() 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