LAA: improve code in getStrideFromPointer (NFC) (#124780)
[llvm-project.git] / flang / lib / Evaluate / formatting.cpp
blobf3a53c1f983dfa23d844c45f36b607baedca483f
1 //===-- lib/Evaluate/formatting.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 //===----------------------------------------------------------------------===//
9 #include "flang/Evaluate/formatting.h"
10 #include "flang/Common/Fortran.h"
11 #include "flang/Evaluate/call.h"
12 #include "flang/Evaluate/constant.h"
13 #include "flang/Evaluate/expression.h"
14 #include "flang/Evaluate/fold.h"
15 #include "flang/Evaluate/tools.h"
16 #include "flang/Parser/characters.h"
17 #include "flang/Semantics/semantics.h"
18 #include "flang/Semantics/symbol.h"
19 #include "llvm/Support/raw_ostream.h"
21 namespace Fortran::evaluate {
23 // Constant arrays can have non-default lower bounds, but this can't be
24 // expressed in Fortran syntax directly, only implied through the use of
25 // named constant (PARAMETER) definitions. For debugging, setting this flag
26 // enables a non-standard %LBOUND=[...] argument to the RESHAPE intrinsic
27 // calls used to dumy constants. It's off by default so that this syntax
28 // doesn't show up in module files.
29 static const bool printLbounds{false};
31 static void ShapeAsFortran(llvm::raw_ostream &o,
32 const ConstantSubscripts &shape, const ConstantSubscripts &lbounds,
33 bool hasNonDefaultLowerBound) {
34 if (GetRank(shape) > 1 || hasNonDefaultLowerBound) {
35 o << ",shape=";
36 char ch{'['};
37 for (auto dim : shape) {
38 o << ch << dim;
39 ch = ',';
41 o << ']';
42 if (hasNonDefaultLowerBound) {
43 o << ",%lbound=";
44 ch = '[';
45 for (auto lb : lbounds) {
46 o << ch << lb;
47 ch = ',';
49 o << ']';
51 o << ')';
55 template <typename RESULT, typename VALUE>
56 llvm::raw_ostream &ConstantBase<RESULT, VALUE>::AsFortran(
57 llvm::raw_ostream &o) const {
58 bool hasNonDefaultLowerBound{printLbounds && HasNonDefaultLowerBound()};
59 if (Rank() > 1 || hasNonDefaultLowerBound) {
60 o << "reshape(";
62 if (Rank() > 0) {
63 o << '[' << GetType().AsFortran() << "::";
65 bool first{true};
66 for (const auto &value : values_) {
67 if (first) {
68 first = false;
69 } else {
70 o << ',';
72 if constexpr (Result::category == TypeCategory::Integer) {
73 o << value.SignedDecimal() << '_' << Result::kind;
74 } else if constexpr (Result::category == TypeCategory::Unsigned) {
75 o << value.UnsignedDecimal() << "U_" << Result::kind;
76 } else if constexpr (Result::category == TypeCategory::Real ||
77 Result::category == TypeCategory::Complex) {
78 value.AsFortran(o, Result::kind);
79 } else if constexpr (Result::category == TypeCategory::Character) {
80 o << Result::kind << '_' << parser::QuoteCharacterLiteral(value, true);
81 } else if constexpr (Result::category == TypeCategory::Logical) {
82 if (!value.IsCanonical()) {
83 o << "transfer(" << value.word().ToInt64() << "_8,.false._"
84 << Result::kind << ')';
85 } else if (value.IsTrue()) {
86 o << ".true." << '_' << Result::kind;
87 } else {
88 o << ".false." << '_' << Result::kind;
90 } else {
91 StructureConstructor{result_.derivedTypeSpec(), value}.AsFortran(o);
94 if (Rank() > 0) {
95 o << ']';
97 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound);
98 return o;
101 template <int KIND>
102 llvm::raw_ostream &Constant<Type<TypeCategory::Character, KIND>>::AsFortran(
103 llvm::raw_ostream &o) const {
104 bool hasNonDefaultLowerBound{printLbounds && HasNonDefaultLowerBound()};
105 if (Rank() > 1 || hasNonDefaultLowerBound) {
106 o << "reshape(";
108 if (Rank() > 0) {
109 o << '[' << GetType().AsFortran(std::to_string(length_)) << "::";
111 auto total{static_cast<ConstantSubscript>(size())};
112 for (ConstantSubscript j{0}; j < total; ++j) {
113 Scalar<Result> value{values_.substr(j * length_, length_)};
114 if (j > 0) {
115 o << ',';
117 if (Result::kind != 1) {
118 o << Result::kind << '_';
120 o << parser::QuoteCharacterLiteral(value);
122 if (Rank() > 0) {
123 o << ']';
125 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound);
126 return o;
129 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol,
130 std::optional<parser::CharBlock> name = std::nullopt) {
131 const auto &renamings{symbol.owner().context().moduleFileOutputRenamings()};
132 if (auto iter{renamings.find(&symbol)}; iter != renamings.end()) {
133 return o << iter->second.ToString();
134 } else if (name) {
135 return o << name->ToString();
136 } else {
137 return o << symbol.name().ToString();
141 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::string &lit) {
142 return o << parser::QuoteCharacterLiteral(lit);
145 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u16string &lit) {
146 return o << parser::QuoteCharacterLiteral(lit);
149 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u32string &lit) {
150 return o << parser::QuoteCharacterLiteral(lit);
153 template <typename A>
154 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const A &x) {
155 return x.AsFortran(o);
158 template <typename A>
159 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, common::Reference<A> x) {
160 return EmitVar(o, *x);
163 template <typename A>
164 llvm::raw_ostream &EmitVar(
165 llvm::raw_ostream &o, const A *p, const char *kw = nullptr) {
166 if (p) {
167 if (kw) {
168 o << kw;
170 EmitVar(o, *p);
172 return o;
175 template <typename A>
176 llvm::raw_ostream &EmitVar(
177 llvm::raw_ostream &o, const std::optional<A> &x, const char *kw = nullptr) {
178 if (x) {
179 if (kw) {
180 o << kw;
182 EmitVar(o, *x);
184 return o;
187 template <typename A, bool COPY>
188 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o,
189 const common::Indirection<A, COPY> &p, const char *kw = nullptr) {
190 if (kw) {
191 o << kw;
193 EmitVar(o, p.value());
194 return o;
197 template <typename A>
198 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::shared_ptr<A> &p) {
199 CHECK(p);
200 return EmitVar(o, *p);
203 template <typename... A>
204 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::variant<A...> &u) {
205 common::visit([&](const auto &x) { EmitVar(o, x); }, u);
206 return o;
209 llvm::raw_ostream &ActualArgument::AssumedType::AsFortran(
210 llvm::raw_ostream &o) const {
211 return EmitVar(o, *symbol_);
214 llvm::raw_ostream &ActualArgument::AsFortran(llvm::raw_ostream &o) const {
215 if (keyword_) {
216 o << keyword_->ToString() << '=';
218 if (isPercentVal()) {
219 o << "%VAL(";
220 } else if (isPercentRef()) {
221 o << "%REF(";
223 common::visit(
224 common::visitors{
225 [&](const common::CopyableIndirection<Expr<SomeType>> &expr) {
226 expr.value().AsFortran(o);
228 [&](const AssumedType &assumedType) { assumedType.AsFortran(o); },
229 [&](const common::Label &label) { o << '*' << label; },
231 u_);
232 if (isPercentVal() || isPercentRef()) {
233 o << ')';
235 return o;
238 llvm::raw_ostream &SpecificIntrinsic::AsFortran(llvm::raw_ostream &o) const {
239 return o << name;
242 llvm::raw_ostream &ProcedureRef::AsFortran(llvm::raw_ostream &o) const {
243 for (const auto &arg : arguments_) {
244 if (arg && arg->isPassedObject()) {
245 arg->AsFortran(o) << '%';
246 break;
249 proc_.AsFortran(o);
250 if (!chevrons_.empty()) {
251 bool first{true};
252 for (const auto &expr : chevrons_) {
253 if (first) {
254 expr.AsFortran(o << "<<<");
255 first = false;
256 } else {
257 expr.AsFortran(o << ",");
260 o << ">>>";
262 char separator{'('};
263 for (const auto &arg : arguments_) {
264 if (arg && !arg->isPassedObject()) {
265 arg->AsFortran(o << separator);
266 separator = ',';
269 if (separator == '(') {
270 o << '(';
272 return o << ')';
275 // Operator precedence formatting; insert parentheses around operands
276 // only when necessary.
278 enum class Precedence { // in increasing order for sane comparisons
279 DefinedBinary,
281 And,
282 Equivalence, // .EQV., .NEQV.
283 Not, // which binds *less* tightly in Fortran than relations
284 Relational,
285 Additive, // +, -, and (arbitrarily) //
286 Negate, // which binds *less* tightly than *, /, **
287 Multiplicative, // *, /
288 Power, // **, which is right-associative unlike the other dyadic operators
289 DefinedUnary,
290 Top,
293 template <typename A> constexpr Precedence ToPrecedence(const A &) {
294 return Precedence::Top;
296 template <int KIND>
297 static Precedence ToPrecedence(const LogicalOperation<KIND> &x) {
298 switch (x.logicalOperator) {
299 SWITCH_COVERS_ALL_CASES
300 case LogicalOperator::And:
301 return Precedence::And;
302 case LogicalOperator::Or:
303 return Precedence::Or;
304 case LogicalOperator::Not:
305 return Precedence::Not;
306 case LogicalOperator::Eqv:
307 case LogicalOperator::Neqv:
308 return Precedence::Equivalence;
311 template <int KIND> constexpr Precedence ToPrecedence(const Not<KIND> &) {
312 return Precedence::Not;
314 template <typename T> constexpr Precedence ToPrecedence(const Relational<T> &) {
315 return Precedence::Relational;
317 template <typename T> constexpr Precedence ToPrecedence(const Add<T> &) {
318 return Precedence::Additive;
320 template <typename T> constexpr Precedence ToPrecedence(const Subtract<T> &) {
321 return Precedence::Additive;
323 template <int KIND> constexpr Precedence ToPrecedence(const Concat<KIND> &) {
324 return Precedence::Additive;
326 template <typename T> constexpr Precedence ToPrecedence(const Negate<T> &) {
327 return Precedence::Negate;
329 template <typename T> constexpr Precedence ToPrecedence(const Multiply<T> &) {
330 return Precedence::Multiplicative;
332 template <typename T> constexpr Precedence ToPrecedence(const Divide<T> &) {
333 return Precedence::Multiplicative;
335 template <typename T> constexpr Precedence ToPrecedence(const Power<T> &) {
336 return Precedence::Power;
338 template <typename T>
339 constexpr Precedence ToPrecedence(const RealToIntPower<T> &) {
340 return Precedence::Power;
342 template <typename T> static Precedence ToPrecedence(const Constant<T> &x) {
343 static constexpr TypeCategory cat{T::category};
344 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) {
345 if (auto n{GetScalarConstantValue<T>(x)}) {
346 if (n->IsNegative()) {
347 return Precedence::Negate;
351 return Precedence::Top;
353 template <typename T> static Precedence ToPrecedence(const Expr<T> &expr) {
354 return common::visit([](const auto &x) { return ToPrecedence(x); }, expr.u);
357 template <typename T> static bool IsNegatedScalarConstant(const Expr<T> &expr) {
358 static constexpr TypeCategory cat{T::category};
359 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) {
360 if (auto n{GetScalarConstantValue<T>(expr)}) {
361 return n->IsNegative();
364 return false;
367 template <TypeCategory CAT>
368 static bool IsNegatedScalarConstant(const Expr<SomeKind<CAT>> &expr) {
369 return common::visit(
370 [](const auto &x) { return IsNegatedScalarConstant(x); }, expr.u);
373 struct OperatorSpelling {
374 const char *prefix{""}, *infix{","}, *suffix{""};
377 template <typename A> constexpr OperatorSpelling SpellOperator(const A &) {
378 return OperatorSpelling{};
380 template <typename A>
381 constexpr OperatorSpelling SpellOperator(const Negate<A> &) {
382 return OperatorSpelling{"-", "", ""};
384 template <typename A>
385 constexpr OperatorSpelling SpellOperator(const Parentheses<A> &) {
386 return OperatorSpelling{"(", "", ")"};
388 template <int KIND>
389 static OperatorSpelling SpellOperator(const ComplexComponent<KIND> &x) {
390 return {x.isImaginaryPart ? "aimag(" : "real(", "", ")"};
392 template <int KIND>
393 constexpr OperatorSpelling SpellOperator(const Not<KIND> &) {
394 return OperatorSpelling{".NOT.", "", ""};
396 template <int KIND>
397 constexpr OperatorSpelling SpellOperator(const SetLength<KIND> &) {
398 return OperatorSpelling{"%SET_LENGTH(", ",", ")"};
400 template <int KIND>
401 constexpr OperatorSpelling SpellOperator(const ComplexConstructor<KIND> &) {
402 return OperatorSpelling{"(", ",", ")"};
404 template <typename A> constexpr OperatorSpelling SpellOperator(const Add<A> &) {
405 return OperatorSpelling{"", "+", ""};
407 template <typename A>
408 constexpr OperatorSpelling SpellOperator(const Subtract<A> &) {
409 return OperatorSpelling{"", "-", ""};
411 template <typename A>
412 constexpr OperatorSpelling SpellOperator(const Multiply<A> &) {
413 return OperatorSpelling{"", "*", ""};
415 template <typename A>
416 constexpr OperatorSpelling SpellOperator(const Divide<A> &) {
417 return OperatorSpelling{"", "/", ""};
419 template <typename A>
420 constexpr OperatorSpelling SpellOperator(const Power<A> &) {
421 return OperatorSpelling{"", "**", ""};
423 template <typename A>
424 constexpr OperatorSpelling SpellOperator(const RealToIntPower<A> &) {
425 return OperatorSpelling{"", "**", ""};
427 template <typename A>
428 static OperatorSpelling SpellOperator(const Extremum<A> &x) {
429 return OperatorSpelling{
430 x.ordering == Ordering::Less ? "min(" : "max(", ",", ")"};
432 template <int KIND>
433 constexpr OperatorSpelling SpellOperator(const Concat<KIND> &) {
434 return OperatorSpelling{"", "//", ""};
436 template <int KIND>
437 static OperatorSpelling SpellOperator(const LogicalOperation<KIND> &x) {
438 return OperatorSpelling{"", AsFortran(x.logicalOperator), ""};
440 template <typename T>
441 static OperatorSpelling SpellOperator(const Relational<T> &x) {
442 return OperatorSpelling{"", AsFortran(x.opr), ""};
445 template <typename D, typename R, typename... O>
446 llvm::raw_ostream &Operation<D, R, O...>::AsFortran(
447 llvm::raw_ostream &o) const {
448 Precedence lhsPrec{ToPrecedence(left())};
449 OperatorSpelling spelling{SpellOperator(derived())};
450 o << spelling.prefix;
451 Precedence thisPrec{ToPrecedence(derived())};
452 if constexpr (operands == 1) {
453 if (thisPrec != Precedence::Top && lhsPrec < thisPrec) {
454 left().AsFortran(o << '(') << ')';
455 } else {
456 left().AsFortran(o);
458 } else {
459 if (thisPrec != Precedence::Top &&
460 (lhsPrec < thisPrec ||
461 (lhsPrec == Precedence::Power && thisPrec == Precedence::Power))) {
462 left().AsFortran(o << '(') << ')';
463 } else {
464 left().AsFortran(o);
466 o << spelling.infix;
467 Precedence rhsPrec{ToPrecedence(right())};
468 if (thisPrec != Precedence::Top && rhsPrec < thisPrec) {
469 right().AsFortran(o << '(') << ')';
470 } else {
471 right().AsFortran(o);
474 return o << spelling.suffix;
477 template <typename TO, TypeCategory FROMCAT>
478 llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
479 static_assert(TO::category == TypeCategory::Integer ||
480 TO::category == TypeCategory::Real ||
481 TO::category == TypeCategory::Complex ||
482 TO::category == TypeCategory::Character ||
483 TO::category == TypeCategory::Logical ||
484 TO::category == TypeCategory::Unsigned,
485 "Convert<> to bad category!");
486 if constexpr (TO::category == TypeCategory::Character) {
487 this->left().AsFortran(o << "achar(iachar(") << ')';
488 } else if constexpr (TO::category == TypeCategory::Integer) {
489 this->left().AsFortran(o << "int(");
490 } else if constexpr (TO::category == TypeCategory::Real) {
491 this->left().AsFortran(o << "real(");
492 } else if constexpr (TO::category == TypeCategory::Complex) {
493 this->left().AsFortran(o << "cmplx(");
494 } else if constexpr (TO::category == TypeCategory::Logical) {
495 this->left().AsFortran(o << "logical(");
496 } else {
497 this->left().AsFortran(o << "uint(");
499 return o << ",kind=" << TO::kind << ')';
502 llvm::raw_ostream &Relational<SomeType>::AsFortran(llvm::raw_ostream &o) const {
503 common::visit([&](const auto &rel) { rel.AsFortran(o); }, u);
504 return o;
507 template <typename T>
508 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const Expr<T> &expr) {
509 return expr.AsFortran(o);
512 template <typename T>
513 llvm::raw_ostream &EmitArray(
514 llvm::raw_ostream &, const ArrayConstructorValues<T> &);
516 template <typename T>
517 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const ImpliedDo<T> &implDo) {
518 o << '(';
519 EmitArray(o, implDo.values());
520 o << ',' << ImpliedDoIndex::Result::AsFortran()
521 << "::" << implDo.name().ToString() << '=';
522 implDo.lower().AsFortran(o) << ',';
523 implDo.upper().AsFortran(o) << ',';
524 implDo.stride().AsFortran(o) << ')';
525 return o;
528 template <typename T>
529 llvm::raw_ostream &EmitArray(
530 llvm::raw_ostream &o, const ArrayConstructorValues<T> &values) {
531 const char *sep{""};
532 for (const auto &value : values) {
533 o << sep;
534 common::visit([&](const auto &x) { EmitArray(o, x); }, value.u);
535 sep = ",";
537 return o;
540 template <typename T>
541 llvm::raw_ostream &ArrayConstructor<T>::AsFortran(llvm::raw_ostream &o) const {
542 o << '[' << GetType().AsFortran() << "::";
543 EmitArray(o, *this);
544 return o << ']';
547 template <int KIND>
548 llvm::raw_ostream &
549 ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
550 llvm::raw_ostream &o) const {
551 o << '[';
552 if (const auto *len{LEN()}) {
553 o << GetType().AsFortran(len->AsFortran()) << "::";
555 EmitArray(o, *this);
556 return o << ']';
559 llvm::raw_ostream &ArrayConstructor<SomeDerived>::AsFortran(
560 llvm::raw_ostream &o) const {
561 o << '[' << GetType().AsFortran() << "::";
562 EmitArray(o, *this);
563 return o << ']';
566 template <typename RESULT>
567 std::string ExpressionBase<RESULT>::AsFortran() const {
568 std::string buf;
569 llvm::raw_string_ostream ss{buf};
570 AsFortran(ss);
571 return buf;
574 template <typename RESULT>
575 llvm::raw_ostream &ExpressionBase<RESULT>::AsFortran(
576 llvm::raw_ostream &o) const {
577 common::visit(common::visitors{
578 [&](const BOZLiteralConstant &x) {
579 o << "z'" << x.Hexadecimal() << "'";
581 [&](const NullPointer &) { o << "NULL()"; },
582 [&](const common::CopyableIndirection<Substring> &s) {
583 s.value().AsFortran(o);
585 [&](const ImpliedDoIndex &i) { o << i.name.ToString(); },
586 [&](const auto &x) { x.AsFortran(o); },
588 derived().u);
589 return o;
592 static std::string DerivedTypeSpecAsFortran(
593 const semantics::DerivedTypeSpec &spec) {
594 std::string buf;
595 llvm::raw_string_ostream ss{buf};
596 EmitVar(ss, spec.typeSymbol(), spec.name());
597 char ch{'('};
598 for (const auto &[name, value] : spec.parameters()) {
599 ss << ch << name.ToString() << '=';
600 ch = ',';
601 if (value.isAssumed()) {
602 ss << '*';
603 } else if (value.isDeferred()) {
604 ss << ':';
605 } else {
606 value.GetExplicit()->AsFortran(ss);
609 if (ch != '(') {
610 ss << ')';
612 return buf;
615 llvm::raw_ostream &StructureConstructor::AsFortran(llvm::raw_ostream &o) const {
616 o << DerivedTypeSpecAsFortran(result_.derivedTypeSpec());
617 if (values_.empty()) {
618 o << '(';
619 } else {
620 char ch{'('};
621 for (const auto &[symbol, value] : values_) {
622 value.value().AsFortran(EmitVar(o << ch, *symbol) << '=');
623 ch = ',';
626 return o << ')';
629 std::string DynamicType::AsFortran() const {
630 if (derived_) {
631 CHECK(category_ == TypeCategory::Derived);
632 std::string result{DerivedTypeSpecAsFortran(*derived_)};
633 if (IsPolymorphic()) {
634 result = "CLASS("s + result + ')';
636 return result;
637 } else if (charLengthParamValue_ || knownLength()) {
638 std::string result{"CHARACTER(KIND="s + std::to_string(kind_) + ",LEN="};
639 if (knownLength()) {
640 result += std::to_string(*knownLength()) + "_8";
641 } else if (charLengthParamValue_->isAssumed()) {
642 result += '*';
643 } else if (charLengthParamValue_->isDeferred()) {
644 result += ':';
645 } else if (const auto &length{charLengthParamValue_->GetExplicit()}) {
646 result += length->AsFortran();
648 return result + ')';
649 } else if (IsAssumedType()) {
650 return "TYPE(*)";
651 } else if (IsUnlimitedPolymorphic()) {
652 return "CLASS(*)";
653 } else if (IsTypelessIntrinsicArgument()) {
654 return "(typeless intrinsic function argument)";
655 } else {
656 return parser::ToUpperCaseLetters(EnumToString(category_)) + '(' +
657 std::to_string(kind_) + ')';
661 std::string DynamicType::AsFortran(std::string &&charLenExpr) const {
662 if (!charLenExpr.empty() && category_ == TypeCategory::Character) {
663 return "CHARACTER(KIND=" + std::to_string(kind_) +
664 ",LEN=" + std::move(charLenExpr) + ')';
665 } else {
666 return AsFortran();
670 std::string SomeDerived::AsFortran() const {
671 if (IsUnlimitedPolymorphic()) {
672 return "CLASS(*)";
673 } else {
674 return "TYPE("s + DerivedTypeSpecAsFortran(derivedTypeSpec()) + ')';
678 llvm::raw_ostream &BaseObject::AsFortran(llvm::raw_ostream &o) const {
679 return EmitVar(o, u);
682 llvm::raw_ostream &TypeParamInquiry::AsFortran(llvm::raw_ostream &o) const {
683 if (base_) {
684 base_.value().AsFortran(o) << '%';
686 return EmitVar(o, parameter_);
689 llvm::raw_ostream &Component::AsFortran(llvm::raw_ostream &o) const {
690 base_.value().AsFortran(o);
691 return EmitVar(o << '%', symbol_);
694 llvm::raw_ostream &NamedEntity::AsFortran(llvm::raw_ostream &o) const {
695 common::visit(common::visitors{
696 [&](SymbolRef s) { EmitVar(o, s); },
697 [&](const Component &c) { c.AsFortran(o); },
699 u_);
700 return o;
703 llvm::raw_ostream &Triplet::AsFortran(llvm::raw_ostream &o) const {
704 EmitVar(o, lower_) << ':';
705 EmitVar(o, upper_);
706 EmitVar(o << ':', stride_.value());
707 return o;
710 llvm::raw_ostream &Subscript::AsFortran(llvm::raw_ostream &o) const {
711 return EmitVar(o, u);
714 llvm::raw_ostream &ArrayRef::AsFortran(llvm::raw_ostream &o) const {
715 base_.AsFortran(o);
716 char separator{'('};
717 for (const Subscript &ss : subscript_) {
718 ss.AsFortran(o << separator);
719 separator = ',';
721 return o << ')';
724 llvm::raw_ostream &CoarrayRef::AsFortran(llvm::raw_ostream &o) const {
725 bool first{true};
726 for (const Symbol &part : base_) {
727 if (first) {
728 first = false;
729 } else {
730 o << '%';
732 EmitVar(o, part);
734 char separator{'('};
735 for (const auto &sscript : subscript_) {
736 EmitVar(o << separator, sscript);
737 separator = ',';
739 if (separator == ',') {
740 o << ')';
742 separator = '[';
743 for (const auto &css : cosubscript_) {
744 EmitVar(o << separator, css);
745 separator = ',';
747 if (stat_) {
748 EmitVar(o << separator, stat_, "STAT=");
749 separator = ',';
751 if (team_) {
752 EmitVar(
753 o << separator, team_, teamIsTeamNumber_ ? "TEAM_NUMBER=" : "TEAM=");
755 return o << ']';
758 llvm::raw_ostream &DataRef::AsFortran(llvm::raw_ostream &o) const {
759 return EmitVar(o, u);
762 llvm::raw_ostream &Substring::AsFortran(llvm::raw_ostream &o) const {
763 EmitVar(o, parent_) << '(';
764 EmitVar(o, lower_) << ':';
765 return EmitVar(o, upper_) << ')';
768 llvm::raw_ostream &ComplexPart::AsFortran(llvm::raw_ostream &o) const {
769 return complex_.AsFortran(o) << '%' << EnumToString(part_);
772 llvm::raw_ostream &ProcedureDesignator::AsFortran(llvm::raw_ostream &o) const {
773 return EmitVar(o, u);
776 template <typename T>
777 llvm::raw_ostream &Designator<T>::AsFortran(llvm::raw_ostream &o) const {
778 common::visit(common::visitors{
779 [&](SymbolRef symbol) { EmitVar(o, symbol); },
780 [&](const auto &x) { x.AsFortran(o); },
783 return o;
786 llvm::raw_ostream &DescriptorInquiry::AsFortran(llvm::raw_ostream &o) const {
787 switch (field_) {
788 case Field::LowerBound:
789 o << "lbound(";
790 break;
791 case Field::Extent:
792 o << "size(";
793 break;
794 case Field::Stride:
795 o << "%STRIDE(";
796 break;
797 case Field::Rank:
798 o << "int(rank(";
799 break;
800 case Field::Len:
801 o << "int(";
802 break;
804 base_.AsFortran(o);
805 if (field_ == Field::Len) {
806 o << "%len";
807 } else if (field_ == Field::Rank) {
808 o << ")";
809 } else {
810 if (dimension_ >= 0) {
811 o << ",dim=" << (dimension_ + 1);
814 return o << ",kind=" << DescriptorInquiry::Result::kind << ")";
817 llvm::raw_ostream &Assignment::AsFortran(llvm::raw_ostream &o) const {
818 common::visit(
819 common::visitors{
820 [&](const Assignment::Intrinsic &) {
821 rhs.AsFortran(lhs.AsFortran(o) << '=');
823 [&](const ProcedureRef &proc) { proc.AsFortran(o << "CALL "); },
824 [&](const BoundsSpec &bounds) {
825 lhs.AsFortran(o);
826 if (!bounds.empty()) {
827 char sep{'('};
828 for (const auto &bound : bounds) {
829 bound.AsFortran(o << sep) << ':';
830 sep = ',';
832 o << ')';
834 rhs.AsFortran(o << " => ");
836 [&](const BoundsRemapping &bounds) {
837 lhs.AsFortran(o);
838 if (!bounds.empty()) {
839 char sep{'('};
840 for (const auto &bound : bounds) {
841 bound.first.AsFortran(o << sep) << ':';
842 bound.second.AsFortran(o);
843 sep = ',';
845 o << ')';
847 rhs.AsFortran(o << " => ");
851 return o;
854 #ifdef _MSC_VER // disable bogus warning about missing definitions
855 #pragma warning(disable : 4661)
856 #endif
857 INSTANTIATE_CONSTANT_TEMPLATES
858 INSTANTIATE_EXPRESSION_TEMPLATES
859 INSTANTIATE_VARIABLE_TEMPLATES
860 } // namespace Fortran::evaluate