Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Evaluate/expression.h ---------------------*- C++ -*-===// |
---|---|
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 | #ifndef FORTRAN_EVALUATE_EXPRESSION_H_ |
10 | #define FORTRAN_EVALUATE_EXPRESSION_H_ |
11 | |
12 | // Represent Fortran expressions in a type-safe manner. |
13 | // Expressions are the sole owners of their constituents; i.e., there is no |
14 | // context-independent hash table or sharing of common subexpressions, and |
15 | // thus these are trees, not DAGs. Both deep copy and move semantics are |
16 | // supported for expression construction. Expressions may be compared |
17 | // for equality. |
18 | |
19 | #include "common.h" |
20 | #include "constant.h" |
21 | #include "formatting.h" |
22 | #include "type.h" |
23 | #include "variable.h" |
24 | #include "flang/Common/Fortran.h" |
25 | #include "flang/Common/idioms.h" |
26 | #include "flang/Common/indirection.h" |
27 | #include "flang/Common/template.h" |
28 | #include "flang/Parser/char-block.h" |
29 | #include <algorithm> |
30 | #include <list> |
31 | #include <tuple> |
32 | #include <type_traits> |
33 | #include <variant> |
34 | |
35 | namespace llvm { |
36 | class raw_ostream; |
37 | } |
38 | |
39 | namespace Fortran::evaluate { |
40 | |
41 | using common::LogicalOperator; |
42 | using common::RelationalOperator; |
43 | |
44 | // Expressions are represented by specializations of the class template Expr. |
45 | // Each of these specializations wraps a single data member "u" that |
46 | // is a std::variant<> discriminated union over all of the representational |
47 | // types for the constants, variables, operations, and other entities that |
48 | // can be valid expressions in that context: |
49 | // - Expr<Type<CATEGORY, KIND>> represents an expression whose result is of a |
50 | // specific intrinsic type category and kind, e.g. Type<TypeCategory::Real, 4> |
51 | // - Expr<SomeDerived> wraps data and procedure references that result in an |
52 | // instance of a derived type (or CLASS(*) unlimited polymorphic) |
53 | // - Expr<SomeKind<CATEGORY>> is a union of Expr<Type<CATEGORY, K>> for each |
54 | // kind type parameter value K in that intrinsic type category. It represents |
55 | // an expression with known category and any kind. |
56 | // - Expr<SomeType> is a union of Expr<SomeKind<CATEGORY>> over the five |
57 | // intrinsic type categories of Fortran. It represents any valid expression. |
58 | // |
59 | // Everything that can appear in, or as, a valid Fortran expression must be |
60 | // represented with an instance of some class containing a Result typedef that |
61 | // maps to some instantiation of Type<CATEGORY, KIND>, SomeKind<CATEGORY>, |
62 | // or SomeType. (Exception: BOZ literal constants in generic Expr<SomeType>.) |
63 | template <typename A> using ResultType = typename std::decay_t<A>::Result; |
64 | |
65 | // Common Expr<> behaviors: every Expr<T> derives from ExpressionBase<T>. |
66 | template <typename RESULT> class ExpressionBase { |
67 | public: |
68 | using Result = RESULT; |
69 | |
70 | private: |
71 | using Derived = Expr<Result>; |
72 | #if defined(__APPLE__) && defined(__GNUC__) |
73 | Derived &derived(); |
74 | const Derived &derived() const; |
75 | #else |
76 | Derived &derived() { return *static_cast<Derived *>(this); } |
77 | const Derived &derived() const { return *static_cast<const Derived *>(this); } |
78 | #endif |
79 | |
80 | public: |
81 | template <typename A> Derived &operator=(const A &x) { |
82 | Derived &d{derived()}; |
83 | d.u = x; |
84 | return d; |
85 | } |
86 | |
87 | template <typename A> common::IfNoLvalue<Derived &, A> operator=(A &&x) { |
88 | Derived &d{derived()}; |
89 | d.u = std::move(x); |
90 | return d; |
91 | } |
92 | |
93 | std::optional<DynamicType> GetType() const; |
94 | int Rank() const; |
95 | std::string AsFortran() const; |
96 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
97 | LLVM_DUMP_METHOD void dump() const; |
98 | #endif |
99 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
100 | static Derived Rewrite(FoldingContext &, Derived &&); |
101 | }; |
102 | |
103 | // Operations always have specific Fortran result types (i.e., with known |
104 | // intrinsic type category and kind parameter value). The classes that |
105 | // represent the operations all inherit from this Operation<> base class |
106 | // template. Note that Operation has as its first type parameter (DERIVED) a |
107 | // "curiously reoccurring template pattern (CRTP)" reference to the specific |
108 | // operation class being derived from Operation; e.g., Add is defined with |
109 | // struct Add : public Operation<Add, ...>. Uses of instances of Operation<>, |
110 | // including its own member functions, can access each specific class derived |
111 | // from it via its derived() member function with compile-time type safety. |
112 | template <typename DERIVED, typename RESULT, typename... OPERANDS> |
113 | class Operation { |
114 | // The extra final member is a dummy that allows a safe unused reference |
115 | // to element 1 to arise indirectly in the definition of "right()" below |
116 | // when the operation has but a single operand. |
117 | using OperandTypes = std::tuple<OPERANDS..., std::monostate>; |
118 | |
119 | public: |
120 | using Derived = DERIVED; |
121 | using Result = RESULT; |
122 | static constexpr std::size_t operands{sizeof...(OPERANDS)}; |
123 | // Allow specific intrinsic types and Parentheses<SomeDerived> |
124 | static_assert(IsSpecificIntrinsicType<Result> || |
125 | (operands == 1 && std::is_same_v<Result, SomeDerived>)); |
126 | template <int J> using Operand = std::tuple_element_t<J, OperandTypes>; |
127 | |
128 | // Unary operations wrap a single Expr with a CopyableIndirection. |
129 | // Binary operations wrap a tuple of CopyableIndirections to Exprs. |
130 | private: |
131 | using Container = std::conditional_t<operands == 1, |
132 | common::CopyableIndirection<Expr<Operand<0>>>, |
133 | std::tuple<common::CopyableIndirection<Expr<OPERANDS>>...>>; |
134 | |
135 | public: |
136 | CLASS_BOILERPLATE(Operation) |
137 | explicit Operation(const Expr<OPERANDS> &...x) : operand_{x...} {} |
138 | explicit Operation(Expr<OPERANDS> &&...x) : operand_{std::move(x)...} {} |
139 | |
140 | Derived &derived() { return *static_cast<Derived *>(this); } |
141 | const Derived &derived() const { return *static_cast<const Derived *>(this); } |
142 | |
143 | // References to operand expressions from member functions of derived |
144 | // classes for specific operators can be made by index, e.g. operand<0>(), |
145 | // which must be spelled like "this->template operand<0>()" when |
146 | // inherited in a derived class template. There are convenience aliases |
147 | // left() and right() that are not templates. |
148 | template <int J> Expr<Operand<J>> &operand() { |
149 | if constexpr (operands == 1) { |
150 | static_assert(J == 0); |
151 | return operand_.value(); |
152 | } else { |
153 | return std::get<J>(operand_).value(); |
154 | } |
155 | } |
156 | template <int J> const Expr<Operand<J>> &operand() const { |
157 | if constexpr (operands == 1) { |
158 | static_assert(J == 0); |
159 | return operand_.value(); |
160 | } else { |
161 | return std::get<J>(operand_).value(); |
162 | } |
163 | } |
164 | |
165 | Expr<Operand<0>> &left() { return operand<0>(); } |
166 | const Expr<Operand<0>> &left() const { return operand<0>(); } |
167 | |
168 | std::conditional_t<(operands > 1), Expr<Operand<1>> &, void> right() { |
169 | if constexpr (operands > 1) { |
170 | return operand<1>(); |
171 | } |
172 | } |
173 | std::conditional_t<(operands > 1), const Expr<Operand<1>> &, void> |
174 | right() const { |
175 | if constexpr (operands > 1) { |
176 | return operand<1>(); |
177 | } |
178 | } |
179 | |
180 | static constexpr std::conditional_t<Result::category != TypeCategory::Derived, |
181 | std::optional<DynamicType>, void> |
182 | GetType() { |
183 | return Result::GetType(); |
184 | } |
185 | int Rank() const { |
186 | int rank{left().Rank()}; |
187 | if constexpr (operands > 1) { |
188 | return std::max(rank, right().Rank()); |
189 | } else { |
190 | return rank; |
191 | } |
192 | } |
193 | |
194 | bool operator==(const Operation &that) const { |
195 | return operand_ == that.operand_; |
196 | } |
197 | |
198 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
199 | |
200 | private: |
201 | Container operand_; |
202 | }; |
203 | |
204 | // Unary operations |
205 | |
206 | // Conversions to specific types from expressions of known category and |
207 | // dynamic kind. |
208 | template <typename TO, TypeCategory FROMCAT = TO::category> |
209 | struct Convert : public Operation<Convert<TO, FROMCAT>, TO, SomeKind<FROMCAT>> { |
210 | // Fortran doesn't have conversions between kinds of CHARACTER apart from |
211 | // assignments, and in those the data must be convertible to/from 7-bit ASCII. |
212 | static_assert(((TO::category == TypeCategory::Integer || |
213 | TO::category == TypeCategory::Real) && |
214 | (FROMCAT == TypeCategory::Integer || |
215 | FROMCAT == TypeCategory::Real)) || |
216 | TO::category == FROMCAT); |
217 | using Result = TO; |
218 | using Operand = SomeKind<FROMCAT>; |
219 | using Base = Operation<Convert, Result, Operand>; |
220 | using Base::Base; |
221 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
222 | }; |
223 | |
224 | template <typename A> |
225 | struct Parentheses : public Operation<Parentheses<A>, A, A> { |
226 | using Result = A; |
227 | using Operand = A; |
228 | using Base = Operation<Parentheses, A, A>; |
229 | using Base::Base; |
230 | }; |
231 | |
232 | template <> |
233 | struct Parentheses<SomeDerived> |
234 | : public Operation<Parentheses<SomeDerived>, SomeDerived, SomeDerived> { |
235 | public: |
236 | using Result = SomeDerived; |
237 | using Operand = SomeDerived; |
238 | using Base = Operation<Parentheses, SomeDerived, SomeDerived>; |
239 | using Base::Base; |
240 | DynamicType GetType() const; |
241 | }; |
242 | |
243 | template <typename A> struct Negate : public Operation<Negate<A>, A, A> { |
244 | using Result = A; |
245 | using Operand = A; |
246 | using Base = Operation<Negate, A, A>; |
247 | using Base::Base; |
248 | }; |
249 | |
250 | template <int KIND> |
251 | struct ComplexComponent |
252 | : public Operation<ComplexComponent<KIND>, Type<TypeCategory::Real, KIND>, |
253 | Type<TypeCategory::Complex, KIND>> { |
254 | using Result = Type<TypeCategory::Real, KIND>; |
255 | using Operand = Type<TypeCategory::Complex, KIND>; |
256 | using Base = Operation<ComplexComponent, Result, Operand>; |
257 | CLASS_BOILERPLATE(ComplexComponent) |
258 | ComplexComponent(bool isImaginary, const Expr<Operand> &x) |
259 | : Base{x}, isImaginaryPart{isImaginary} {} |
260 | ComplexComponent(bool isImaginary, Expr<Operand> &&x) |
261 | : Base{std::move(x)}, isImaginaryPart{isImaginary} {} |
262 | |
263 | bool isImaginaryPart{true}; |
264 | }; |
265 | |
266 | template <int KIND> |
267 | struct Not : public Operation<Not<KIND>, Type<TypeCategory::Logical, KIND>, |
268 | Type<TypeCategory::Logical, KIND>> { |
269 | using Result = Type<TypeCategory::Logical, KIND>; |
270 | using Operand = Result; |
271 | using Base = Operation<Not, Result, Operand>; |
272 | using Base::Base; |
273 | }; |
274 | |
275 | // Character lengths are determined by context in Fortran and do not |
276 | // have explicit syntax for changing them. Expressions represent |
277 | // changes of length (e.g., for assignments and structure constructors) |
278 | // with this operation. |
279 | template <int KIND> |
280 | struct SetLength |
281 | : public Operation<SetLength<KIND>, Type<TypeCategory::Character, KIND>, |
282 | Type<TypeCategory::Character, KIND>, SubscriptInteger> { |
283 | using Result = Type<TypeCategory::Character, KIND>; |
284 | using CharacterOperand = Result; |
285 | using LengthOperand = SubscriptInteger; |
286 | using Base = Operation<SetLength, Result, CharacterOperand, LengthOperand>; |
287 | using Base::Base; |
288 | }; |
289 | |
290 | // Binary operations |
291 | |
292 | template <typename A> struct Add : public Operation<Add<A>, A, A, A> { |
293 | using Result = A; |
294 | using Operand = A; |
295 | using Base = Operation<Add, A, A, A>; |
296 | using Base::Base; |
297 | }; |
298 | |
299 | template <typename A> struct Subtract : public Operation<Subtract<A>, A, A, A> { |
300 | using Result = A; |
301 | using Operand = A; |
302 | using Base = Operation<Subtract, A, A, A>; |
303 | using Base::Base; |
304 | }; |
305 | |
306 | template <typename A> struct Multiply : public Operation<Multiply<A>, A, A, A> { |
307 | using Result = A; |
308 | using Operand = A; |
309 | using Base = Operation<Multiply, A, A, A>; |
310 | using Base::Base; |
311 | }; |
312 | |
313 | template <typename A> struct Divide : public Operation<Divide<A>, A, A, A> { |
314 | using Result = A; |
315 | using Operand = A; |
316 | using Base = Operation<Divide, A, A, A>; |
317 | using Base::Base; |
318 | }; |
319 | |
320 | template <typename A> struct Power : public Operation<Power<A>, A, A, A> { |
321 | using Result = A; |
322 | using Operand = A; |
323 | using Base = Operation<Power, A, A, A>; |
324 | using Base::Base; |
325 | }; |
326 | |
327 | template <typename A> |
328 | struct RealToIntPower : public Operation<RealToIntPower<A>, A, A, SomeInteger> { |
329 | using Base = Operation<RealToIntPower, A, A, SomeInteger>; |
330 | using Result = A; |
331 | using BaseOperand = A; |
332 | using ExponentOperand = SomeInteger; |
333 | using Base::Base; |
334 | }; |
335 | |
336 | template <typename A> struct Extremum : public Operation<Extremum<A>, A, A, A> { |
337 | using Result = A; |
338 | using Operand = A; |
339 | using Base = Operation<Extremum, A, A, A>; |
340 | CLASS_BOILERPLATE(Extremum) |
341 | Extremum(Ordering ord, const Expr<Operand> &x, const Expr<Operand> &y) |
342 | : Base{x, y}, ordering{ord} {} |
343 | Extremum(Ordering ord, Expr<Operand> &&x, Expr<Operand> &&y) |
344 | : Base{std::move(x), std::move(y)}, ordering{ord} {} |
345 | Ordering ordering{Ordering::Greater}; |
346 | }; |
347 | |
348 | template <int KIND> |
349 | struct ComplexConstructor |
350 | : public Operation<ComplexConstructor<KIND>, |
351 | Type<TypeCategory::Complex, KIND>, Type<TypeCategory::Real, KIND>, |
352 | Type<TypeCategory::Real, KIND>> { |
353 | using Result = Type<TypeCategory::Complex, KIND>; |
354 | using Operand = Type<TypeCategory::Real, KIND>; |
355 | using Base = Operation<ComplexConstructor, Result, Operand, Operand>; |
356 | using Base::Base; |
357 | }; |
358 | |
359 | template <int KIND> |
360 | struct Concat |
361 | : public Operation<Concat<KIND>, Type<TypeCategory::Character, KIND>, |
362 | Type<TypeCategory::Character, KIND>, |
363 | Type<TypeCategory::Character, KIND>> { |
364 | using Result = Type<TypeCategory::Character, KIND>; |
365 | using Operand = Result; |
366 | using Base = Operation<Concat, Result, Operand, Operand>; |
367 | using Base::Base; |
368 | }; |
369 | |
370 | template <int KIND> |
371 | struct LogicalOperation |
372 | : public Operation<LogicalOperation<KIND>, |
373 | Type<TypeCategory::Logical, KIND>, Type<TypeCategory::Logical, KIND>, |
374 | Type<TypeCategory::Logical, KIND>> { |
375 | using Result = Type<TypeCategory::Logical, KIND>; |
376 | using Operand = Result; |
377 | using Base = Operation<LogicalOperation, Result, Operand, Operand>; |
378 | CLASS_BOILERPLATE(LogicalOperation) |
379 | LogicalOperation( |
380 | LogicalOperator opr, const Expr<Operand> &x, const Expr<Operand> &y) |
381 | : Base{x, y}, logicalOperator{opr} {} |
382 | LogicalOperation(LogicalOperator opr, Expr<Operand> &&x, Expr<Operand> &&y) |
383 | : Base{std::move(x), std::move(y)}, logicalOperator{opr} {} |
384 | LogicalOperator logicalOperator; |
385 | }; |
386 | |
387 | // Array constructors |
388 | template <typename RESULT> class ArrayConstructorValues; |
389 | |
390 | struct ImpliedDoIndex { |
391 | using Result = SubscriptInteger; |
392 | bool operator==(const ImpliedDoIndex &) const; |
393 | static constexpr int Rank() { return 0; } |
394 | parser::CharBlock name; // nested implied DOs must use distinct names |
395 | }; |
396 | |
397 | template <typename RESULT> class ImpliedDo { |
398 | public: |
399 | using Result = RESULT; |
400 | using Index = ResultType<ImpliedDoIndex>; |
401 | ImpliedDo(parser::CharBlock name, Expr<Index> &&lower, Expr<Index> &&upper, |
402 | Expr<Index> &&stride, ArrayConstructorValues<Result> &&values) |
403 | : name_{name}, lower_{std::move(lower)}, upper_{std::move(upper)}, |
404 | stride_{std::move(stride)}, values_{std::move(values)} {} |
405 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ImpliedDo) |
406 | bool operator==(const ImpliedDo &) const; |
407 | parser::CharBlock name() const { return name_; } |
408 | Expr<Index> &lower() { return lower_.value(); } |
409 | const Expr<Index> &lower() const { return lower_.value(); } |
410 | Expr<Index> &upper() { return upper_.value(); } |
411 | const Expr<Index> &upper() const { return upper_.value(); } |
412 | Expr<Index> &stride() { return stride_.value(); } |
413 | const Expr<Index> &stride() const { return stride_.value(); } |
414 | ArrayConstructorValues<Result> &values() { return values_.value(); } |
415 | const ArrayConstructorValues<Result> &values() const { |
416 | return values_.value(); |
417 | } |
418 | |
419 | private: |
420 | parser::CharBlock name_; |
421 | common::CopyableIndirection<Expr<Index>> lower_, upper_, stride_; |
422 | common::CopyableIndirection<ArrayConstructorValues<Result>> values_; |
423 | }; |
424 | |
425 | template <typename RESULT> struct ArrayConstructorValue { |
426 | using Result = RESULT; |
427 | EVALUATE_UNION_CLASS_BOILERPLATE(ArrayConstructorValue) |
428 | std::variant<Expr<Result>, ImpliedDo<Result>> u; |
429 | }; |
430 | |
431 | template <typename RESULT> class ArrayConstructorValues { |
432 | public: |
433 | using Result = RESULT; |
434 | using Values = std::vector<ArrayConstructorValue<Result>>; |
435 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructorValues) |
436 | ArrayConstructorValues() {} |
437 | |
438 | bool operator==(const ArrayConstructorValues &) const; |
439 | static constexpr int Rank() { return 1; } |
440 | template <typename A> common::NoLvalue<A> Push(A &&x) { |
441 | values_.emplace_back(std::move(x)); |
442 | } |
443 | |
444 | typename Values::iterator begin() { return values_.begin(); } |
445 | typename Values::const_iterator begin() const { return values_.begin(); } |
446 | typename Values::iterator end() { return values_.end(); } |
447 | typename Values::const_iterator end() const { return values_.end(); } |
448 | |
449 | protected: |
450 | Values values_; |
451 | }; |
452 | |
453 | // Note that there are specializations of ArrayConstructor for character |
454 | // and derived types, since they must carry additional type information, |
455 | // but that an empty ArrayConstructor can be constructed for any type |
456 | // given an expression from which such type information may be gleaned. |
457 | template <typename RESULT> |
458 | class ArrayConstructor : public ArrayConstructorValues<RESULT> { |
459 | public: |
460 | using Result = RESULT; |
461 | using Base = ArrayConstructorValues<Result>; |
462 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor) |
463 | explicit ArrayConstructor(Base &&values) : Base{std::move(values)} {} |
464 | template <typename T> explicit ArrayConstructor(const Expr<T> &) {} |
465 | static constexpr Result result() { return Result{}; } |
466 | static constexpr DynamicType GetType() { return Result::GetType(); } |
467 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
468 | }; |
469 | |
470 | template <int KIND> |
471 | class ArrayConstructor<Type<TypeCategory::Character, KIND>> |
472 | : public ArrayConstructorValues<Type<TypeCategory::Character, KIND>> { |
473 | public: |
474 | using Result = Type<TypeCategory::Character, KIND>; |
475 | using Base = ArrayConstructorValues<Result>; |
476 | DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ArrayConstructor) |
477 | explicit ArrayConstructor(Base &&values) : Base{std::move(values)} {} |
478 | template <typename T> explicit ArrayConstructor(const Expr<T> &) {} |
479 | ArrayConstructor &set_LEN(Expr<SubscriptInteger> &&); |
480 | bool operator==(const ArrayConstructor &) const; |
481 | static constexpr Result result() { return Result{}; } |
482 | static constexpr DynamicType GetType() { return Result::GetType(); } |
483 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
484 | const Expr<SubscriptInteger> *LEN() const { |
485 | return length_ ? &length_->value() : nullptr; |
486 | } |
487 | |
488 | private: |
489 | std::optional<common::CopyableIndirection<Expr<SubscriptInteger>>> length_; |
490 | }; |
491 | |
492 | template <> |
493 | class ArrayConstructor<SomeDerived> |
494 | : public ArrayConstructorValues<SomeDerived> { |
495 | public: |
496 | using Result = SomeDerived; |
497 | using Base = ArrayConstructorValues<Result>; |
498 | CLASS_BOILERPLATE(ArrayConstructor) |
499 | |
500 | ArrayConstructor(const semantics::DerivedTypeSpec &spec, Base &&v) |
501 | : Base{std::move(v)}, result_{spec} {} |
502 | template <typename A> |
503 | explicit ArrayConstructor(const A &prototype) |
504 | : result_{prototype.GetType().value().GetDerivedTypeSpec()} {} |
505 | |
506 | bool operator==(const ArrayConstructor &) const; |
507 | constexpr Result result() const { return result_; } |
508 | constexpr DynamicType GetType() const { return result_.GetType(); } |
509 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
510 | |
511 | private: |
512 | Result result_; |
513 | }; |
514 | |
515 | // Expression representations for each type category. |
516 | |
517 | template <int KIND> |
518 | class Expr<Type<TypeCategory::Integer, KIND>> |
519 | : public ExpressionBase<Type<TypeCategory::Integer, KIND>> { |
520 | public: |
521 | using Result = Type<TypeCategory::Integer, KIND>; |
522 | |
523 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
524 | |
525 | private: |
526 | using Conversions = std::tuple<Convert<Result, TypeCategory::Integer>, |
527 | Convert<Result, TypeCategory::Real>>; |
528 | using Operations = std::tuple<Parentheses<Result>, Negate<Result>, |
529 | Add<Result>, Subtract<Result>, Multiply<Result>, Divide<Result>, |
530 | Power<Result>, Extremum<Result>>; |
531 | using Indices = std::conditional_t<KIND == ImpliedDoIndex::Result::kind, |
532 | std::tuple<ImpliedDoIndex>, std::tuple<>>; |
533 | using TypeParamInquiries = |
534 | std::conditional_t<KIND == TypeParamInquiry::Result::kind, |
535 | std::tuple<TypeParamInquiry>, std::tuple<>>; |
536 | using DescriptorInquiries = |
537 | std::conditional_t<KIND == DescriptorInquiry::Result::kind, |
538 | std::tuple<DescriptorInquiry>, std::tuple<>>; |
539 | using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>, |
540 | Designator<Result>, FunctionRef<Result>>; |
541 | |
542 | public: |
543 | common::TupleToVariant<common::CombineTuples<Operations, Conversions, Indices, |
544 | TypeParamInquiries, DescriptorInquiries, Others>> |
545 | u; |
546 | }; |
547 | |
548 | template <int KIND> |
549 | class Expr<Type<TypeCategory::Real, KIND>> |
550 | : public ExpressionBase<Type<TypeCategory::Real, KIND>> { |
551 | public: |
552 | using Result = Type<TypeCategory::Real, KIND>; |
553 | |
554 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
555 | explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {} |
556 | |
557 | private: |
558 | // N.B. Real->Complex and Complex->Real conversions are done with CMPLX |
559 | // and part access operations (resp.). |
560 | using Conversions = std::variant<Convert<Result, TypeCategory::Integer>, |
561 | Convert<Result, TypeCategory::Real>>; |
562 | using Operations = std::variant<ComplexComponent<KIND>, Parentheses<Result>, |
563 | Negate<Result>, Add<Result>, Subtract<Result>, Multiply<Result>, |
564 | Divide<Result>, Power<Result>, RealToIntPower<Result>, Extremum<Result>>; |
565 | using Others = std::variant<Constant<Result>, ArrayConstructor<Result>, |
566 | Designator<Result>, FunctionRef<Result>>; |
567 | |
568 | public: |
569 | common::CombineVariants<Operations, Conversions, Others> u; |
570 | }; |
571 | |
572 | template <int KIND> |
573 | class Expr<Type<TypeCategory::Complex, KIND>> |
574 | : public ExpressionBase<Type<TypeCategory::Complex, KIND>> { |
575 | public: |
576 | using Result = Type<TypeCategory::Complex, KIND>; |
577 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
578 | explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {} |
579 | using Operations = std::variant<Parentheses<Result>, Negate<Result>, |
580 | Convert<Result, TypeCategory::Complex>, Add<Result>, Subtract<Result>, |
581 | Multiply<Result>, Divide<Result>, Power<Result>, RealToIntPower<Result>, |
582 | ComplexConstructor<KIND>>; |
583 | using Others = std::variant<Constant<Result>, ArrayConstructor<Result>, |
584 | Designator<Result>, FunctionRef<Result>>; |
585 | |
586 | public: |
587 | common::CombineVariants<Operations, Others> u; |
588 | }; |
589 | |
590 | FOR_EACH_INTEGER_KIND(extern template class Expr, ) |
591 | FOR_EACH_REAL_KIND(extern template class Expr, ) |
592 | FOR_EACH_COMPLEX_KIND(extern template class Expr, ) |
593 | |
594 | template <int KIND> |
595 | class Expr<Type<TypeCategory::Character, KIND>> |
596 | : public ExpressionBase<Type<TypeCategory::Character, KIND>> { |
597 | public: |
598 | using Result = Type<TypeCategory::Character, KIND>; |
599 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
600 | explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {} |
601 | explicit Expr(Scalar<Result> &&x) : u{Constant<Result>{std::move(x)}} {} |
602 | |
603 | std::optional<Expr<SubscriptInteger>> LEN() const; |
604 | |
605 | std::variant<Constant<Result>, ArrayConstructor<Result>, Designator<Result>, |
606 | FunctionRef<Result>, Parentheses<Result>, Convert<Result>, Concat<KIND>, |
607 | Extremum<Result>, SetLength<KIND>> |
608 | u; |
609 | }; |
610 | |
611 | FOR_EACH_CHARACTER_KIND(extern template class Expr, ) |
612 | |
613 | // The Relational class template is a helper for constructing logical |
614 | // expressions with polymorphism over the cross product of the possible |
615 | // categories and kinds of comparable operands. |
616 | // Fortran defines a numeric relation with distinct types or kinds as |
617 | // first undergoing the same operand conversions that occur with the intrinsic |
618 | // addition operator. Character relations must have the same kind. |
619 | // There are no relations between LOGICAL values. |
620 | |
621 | template <typename T> |
622 | class Relational : public Operation<Relational<T>, LogicalResult, T, T> { |
623 | public: |
624 | using Result = LogicalResult; |
625 | using Base = Operation<Relational, LogicalResult, T, T>; |
626 | using Operand = typename Base::template Operand<0>; |
627 | static_assert(Operand::category == TypeCategory::Integer || |
628 | Operand::category == TypeCategory::Real || |
629 | Operand::category == TypeCategory::Complex || |
630 | Operand::category == TypeCategory::Character); |
631 | CLASS_BOILERPLATE(Relational) |
632 | Relational( |
633 | RelationalOperator r, const Expr<Operand> &a, const Expr<Operand> &b) |
634 | : Base{a, b}, opr{r} {} |
635 | Relational(RelationalOperator r, Expr<Operand> &&a, Expr<Operand> &&b) |
636 | : Base{std::move(a), std::move(b)}, opr{r} {} |
637 | RelationalOperator opr; |
638 | }; |
639 | |
640 | template <> class Relational<SomeType> { |
641 | using DirectlyComparableTypes = common::CombineTuples<IntegerTypes, RealTypes, |
642 | ComplexTypes, CharacterTypes>; |
643 | |
644 | public: |
645 | using Result = LogicalResult; |
646 | EVALUATE_UNION_CLASS_BOILERPLATE(Relational) |
647 | static constexpr DynamicType GetType() { return Result::GetType(); } |
648 | int Rank() const { |
649 | return common::visit([](const auto &x) { return x.Rank(); }, u); |
650 | } |
651 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &o) const; |
652 | common::MapTemplate<Relational, DirectlyComparableTypes> u; |
653 | }; |
654 | |
655 | FOR_EACH_INTEGER_KIND(extern template class Relational, ) |
656 | FOR_EACH_REAL_KIND(extern template class Relational, ) |
657 | FOR_EACH_CHARACTER_KIND(extern template class Relational, ) |
658 | extern template class Relational<SomeType>; |
659 | |
660 | // Logical expressions of a kind bigger than LogicalResult |
661 | // do not include Relational<> operations as possibilities, |
662 | // since the results of Relationals are always LogicalResult |
663 | // (kind=1). |
664 | template <int KIND> |
665 | class Expr<Type<TypeCategory::Logical, KIND>> |
666 | : public ExpressionBase<Type<TypeCategory::Logical, KIND>> { |
667 | public: |
668 | using Result = Type<TypeCategory::Logical, KIND>; |
669 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
670 | explicit Expr(const Scalar<Result> &x) : u{Constant<Result>{x}} {} |
671 | explicit Expr(bool x) : u{Constant<Result>{x}} {} |
672 | |
673 | private: |
674 | using Operations = std::tuple<Convert<Result>, Parentheses<Result>, Not<KIND>, |
675 | LogicalOperation<KIND>>; |
676 | using Relations = std::conditional_t<KIND == LogicalResult::kind, |
677 | std::tuple<Relational<SomeType>>, std::tuple<>>; |
678 | using Others = std::tuple<Constant<Result>, ArrayConstructor<Result>, |
679 | Designator<Result>, FunctionRef<Result>>; |
680 | |
681 | public: |
682 | common::TupleToVariant<common::CombineTuples<Operations, Relations, Others>> |
683 | u; |
684 | }; |
685 | |
686 | FOR_EACH_LOGICAL_KIND(extern template class Expr, ) |
687 | |
688 | // StructureConstructor pairs a StructureConstructorValues instance |
689 | // (a map associating symbols with expressions) with a derived type |
690 | // specification. There are two other similar classes: |
691 | // - ArrayConstructor<SomeDerived> comprises a derived type spec & |
692 | // zero or more instances of Expr<SomeDerived>; it has rank 1 |
693 | // but not (in the most general case) a known shape. |
694 | // - Constant<SomeDerived> comprises a derived type spec, zero or more |
695 | // homogeneous instances of StructureConstructorValues whose type |
696 | // parameters and component expressions are all constant, and a |
697 | // known shape (possibly scalar). |
698 | // StructureConstructor represents a scalar value of derived type that |
699 | // is not necessarily a constant. It is used only as an Expr<SomeDerived> |
700 | // alternative and as the type Scalar<SomeDerived> (with an assumption |
701 | // of constant component value expressions). |
702 | class StructureConstructor { |
703 | public: |
704 | using Result = SomeDerived; |
705 | |
706 | explicit StructureConstructor(const semantics::DerivedTypeSpec &spec) |
707 | : result_{spec} {} |
708 | StructureConstructor( |
709 | const semantics::DerivedTypeSpec &, const StructureConstructorValues &); |
710 | StructureConstructor( |
711 | const semantics::DerivedTypeSpec &, StructureConstructorValues &&); |
712 | CLASS_BOILERPLATE(StructureConstructor) |
713 | |
714 | constexpr Result result() const { return result_; } |
715 | const semantics::DerivedTypeSpec &derivedTypeSpec() const { |
716 | return result_.derivedTypeSpec(); |
717 | } |
718 | StructureConstructorValues &values() { return values_; } |
719 | const StructureConstructorValues &values() const { return values_; } |
720 | |
721 | bool operator==(const StructureConstructor &) const; |
722 | |
723 | StructureConstructorValues::iterator begin() { return values_.begin(); } |
724 | StructureConstructorValues::const_iterator begin() const { |
725 | return values_.begin(); |
726 | } |
727 | StructureConstructorValues::iterator end() { return values_.end(); } |
728 | StructureConstructorValues::const_iterator end() const { |
729 | return values_.end(); |
730 | } |
731 | |
732 | // can return nullopt |
733 | std::optional<Expr<SomeType>> Find(const Symbol &) const; |
734 | |
735 | StructureConstructor &Add(const semantics::Symbol &, Expr<SomeType> &&); |
736 | int Rank() const { return 0; } |
737 | DynamicType GetType() const; |
738 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &, |
739 | const parser::CharBlock *derivedTypeRename = nullptr) const; |
740 | |
741 | private: |
742 | std::optional<Expr<SomeType>> CreateParentComponent(const Symbol &) const; |
743 | Result result_; |
744 | StructureConstructorValues values_; |
745 | }; |
746 | |
747 | // An expression whose result has a derived type. |
748 | template <> class Expr<SomeDerived> : public ExpressionBase<SomeDerived> { |
749 | public: |
750 | using Result = SomeDerived; |
751 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
752 | std::variant<Constant<Result>, ArrayConstructor<Result>, StructureConstructor, |
753 | Designator<Result>, FunctionRef<Result>, Parentheses<Result>> |
754 | u; |
755 | }; |
756 | |
757 | // A polymorphic expression of known intrinsic type category, but dynamic |
758 | // kind, represented as a discriminated union over Expr<Type<CAT, K>> |
759 | // for each supported kind K in the category. |
760 | template <TypeCategory CAT> |
761 | class Expr<SomeKind<CAT>> : public ExpressionBase<SomeKind<CAT>> { |
762 | public: |
763 | using Result = SomeKind<CAT>; |
764 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
765 | int GetKind() const; |
766 | common::MapTemplate<evaluate::Expr, CategoryTypes<CAT>> u; |
767 | }; |
768 | |
769 | template <> class Expr<SomeCharacter> : public ExpressionBase<SomeCharacter> { |
770 | public: |
771 | using Result = SomeCharacter; |
772 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
773 | int GetKind() const; |
774 | std::optional<Expr<SubscriptInteger>> LEN() const; |
775 | common::MapTemplate<Expr, CategoryTypes<TypeCategory::Character>> u; |
776 | }; |
777 | |
778 | // A variant comprising the Expr<> instantiations over SomeDerived and |
779 | // SomeKind<CATEGORY>. |
780 | using CategoryExpression = common::MapTemplate<Expr, SomeCategory>; |
781 | |
782 | // BOZ literal "typeless" constants must be wide enough to hold a numeric |
783 | // value of any supported kind of INTEGER or REAL. They must also be |
784 | // distinguishable from other integer constants, since they are permitted |
785 | // to be used in only a few situations. |
786 | using BOZLiteralConstant = typename LargestReal::Scalar::Word; |
787 | |
788 | // Null pointers without MOLD= arguments are typed by context. |
789 | struct NullPointer { |
790 | constexpr bool operator==(const NullPointer &) const { return true; } |
791 | constexpr int Rank() const { return 0; } |
792 | }; |
793 | |
794 | // Procedure pointer targets are treated as if they were typeless. |
795 | // They are either procedure designators or values returned from |
796 | // references to functions that return procedure (not object) pointers. |
797 | using TypelessExpression = std::variant<BOZLiteralConstant, NullPointer, |
798 | ProcedureDesignator, ProcedureRef>; |
799 | |
800 | // A completely generic expression, polymorphic across all of the intrinsic type |
801 | // categories and each of their kinds. |
802 | template <> class Expr<SomeType> : public ExpressionBase<SomeType> { |
803 | public: |
804 | using Result = SomeType; |
805 | EVALUATE_UNION_CLASS_BOILERPLATE(Expr) |
806 | |
807 | // Owning references to these generic expressions can appear in other |
808 | // compiler data structures (viz., the parse tree and symbol table), so |
809 | // its destructor is externalized to reduce redundant default instances. |
810 | ~Expr(); |
811 | |
812 | template <TypeCategory CAT, int KIND> |
813 | explicit Expr(const Expr<Type<CAT, KIND>> &x) : u{Expr<SomeKind<CAT>>{x}} {} |
814 | |
815 | template <TypeCategory CAT, int KIND> |
816 | explicit Expr(Expr<Type<CAT, KIND>> &&x) |
817 | : u{Expr<SomeKind<CAT>>{std::move(x)}} {} |
818 | |
819 | template <TypeCategory CAT, int KIND> |
820 | Expr &operator=(const Expr<Type<CAT, KIND>> &x) { |
821 | u = Expr<SomeKind<CAT>>{x}; |
822 | return *this; |
823 | } |
824 | |
825 | template <TypeCategory CAT, int KIND> |
826 | Expr &operator=(Expr<Type<CAT, KIND>> &&x) { |
827 | u = Expr<SomeKind<CAT>>{std::move(x)}; |
828 | return *this; |
829 | } |
830 | |
831 | public: |
832 | common::CombineVariants<TypelessExpression, CategoryExpression> u; |
833 | }; |
834 | |
835 | // An assignment is either intrinsic, user-defined (with a ProcedureRef to |
836 | // specify the procedure to call), or pointer assignment (with possibly empty |
837 | // BoundsSpec or non-empty BoundsRemapping). In all cases there are Exprs |
838 | // representing the LHS and RHS of the assignment. |
839 | class Assignment { |
840 | public: |
841 | Assignment(Expr<SomeType> &&lhs, Expr<SomeType> &&rhs) |
842 | : lhs(std::move(lhs)), rhs(std::move(rhs)) {} |
843 | |
844 | struct Intrinsic {}; |
845 | using BoundsSpec = std::vector<Expr<SubscriptInteger>>; |
846 | using BoundsRemapping = |
847 | std::vector<std::pair<Expr<SubscriptInteger>, Expr<SubscriptInteger>>>; |
848 | llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const; |
849 | |
850 | Expr<SomeType> lhs; |
851 | Expr<SomeType> rhs; |
852 | std::variant<Intrinsic, ProcedureRef, BoundsSpec, BoundsRemapping> u; |
853 | }; |
854 | |
855 | // This wrapper class is used, by means of a forward reference with |
856 | // an owning pointer, to cache analyzed expressions in parse tree nodes. |
857 | struct GenericExprWrapper { |
858 | GenericExprWrapper() {} |
859 | explicit GenericExprWrapper(std::optional<Expr<SomeType>> &&x) |
860 | : v{std::move(x)} {} |
861 | ~GenericExprWrapper(); |
862 | static void Deleter(GenericExprWrapper *); |
863 | std::optional<Expr<SomeType>> v; // vacant if error |
864 | }; |
865 | |
866 | // Like GenericExprWrapper but for analyzed assignments |
867 | struct GenericAssignmentWrapper { |
868 | GenericAssignmentWrapper() {} |
869 | explicit GenericAssignmentWrapper(Assignment &&x) : v{std::move(x)} {} |
870 | explicit GenericAssignmentWrapper(std::optional<Assignment> &&x) |
871 | : v{std::move(x)} {} |
872 | ~GenericAssignmentWrapper(); |
873 | static void Deleter(GenericAssignmentWrapper *); |
874 | std::optional<Assignment> v; // vacant if error |
875 | }; |
876 | |
877 | FOR_EACH_CATEGORY_TYPE(extern template class Expr, ) |
878 | FOR_EACH_TYPE_AND_KIND(extern template class ExpressionBase, ) |
879 | FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructorValues, ) |
880 | FOR_EACH_INTRINSIC_KIND(extern template class ArrayConstructor, ) |
881 | |
882 | // Template instantiations to resolve these "extern template" declarations. |
883 | #define INSTANTIATE_EXPRESSION_TEMPLATES \ |
884 | FOR_EACH_INTRINSIC_KIND(template class Expr, ) \ |
885 | FOR_EACH_CATEGORY_TYPE(template class Expr, ) \ |
886 | FOR_EACH_INTEGER_KIND(template class Relational, ) \ |
887 | FOR_EACH_REAL_KIND(template class Relational, ) \ |
888 | FOR_EACH_CHARACTER_KIND(template class Relational, ) \ |
889 | template class Relational<SomeType>; \ |
890 | FOR_EACH_TYPE_AND_KIND(template class ExpressionBase, ) \ |
891 | FOR_EACH_INTRINSIC_KIND(template class ArrayConstructorValues, ) \ |
892 | FOR_EACH_INTRINSIC_KIND(template class ArrayConstructor, ) |
893 | } // namespace Fortran::evaluate |
894 | #endif // FORTRAN_EVALUATE_EXPRESSION_H_ |
895 |
Warning: This file is not a C or C++ file. It does not have highlighting.