1 //===-- lib/Evaluate/formatting.cpp ---------------------------------------===//
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
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
) {
37 for (auto dim
: shape
) {
42 if (hasNonDefaultLowerBound
) {
45 for (auto lb
: lbounds
) {
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
) {
63 o
<< '[' << GetType().AsFortran() << "::";
66 for (const auto &value
: values_
) {
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
;
88 o
<< ".false." << '_' << Result::kind
;
91 StructureConstructor
{result_
.derivedTypeSpec(), value
}.AsFortran(o
);
97 ShapeAsFortran(o
, shape(), lbounds(), hasNonDefaultLowerBound
);
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
) {
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_
)};
117 if (Result::kind
!= 1) {
118 o
<< Result::kind
<< '_';
120 o
<< parser::QuoteCharacterLiteral(value
);
125 ShapeAsFortran(o
, shape(), lbounds(), hasNonDefaultLowerBound
);
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();
135 return o
<< name
->ToString();
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) {
175 template <typename A
>
176 llvm::raw_ostream
&EmitVar(
177 llvm::raw_ostream
&o
, const std::optional
<A
> &x
, const char *kw
= nullptr) {
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) {
193 EmitVar(o
, p
.value());
197 template <typename A
>
198 llvm::raw_ostream
&EmitVar(llvm::raw_ostream
&o
, const std::shared_ptr
<A
> &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
);
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 {
216 o
<< keyword_
->ToString() << '=';
218 if (isPercentVal()) {
220 } else if (isPercentRef()) {
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
; },
232 if (isPercentVal() || isPercentRef()) {
238 llvm::raw_ostream
&SpecificIntrinsic::AsFortran(llvm::raw_ostream
&o
) const {
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
) << '%';
250 if (!chevrons_
.empty()) {
252 for (const auto &expr
: chevrons_
) {
254 expr
.AsFortran(o
<< "<<<");
257 expr
.AsFortran(o
<< ",");
263 for (const auto &arg
: arguments_
) {
264 if (arg
&& !arg
->isPassedObject()) {
265 arg
->AsFortran(o
<< separator
);
269 if (separator
== '(') {
275 // Operator precedence formatting; insert parentheses around operands
276 // only when necessary.
278 enum class Precedence
{ // in increasing order for sane comparisons
282 Equivalence
, // .EQV., .NEQV.
283 Not
, // which binds *less* tightly in Fortran than relations
285 Additive
, // +, -, and (arbitrarily) //
286 Negate
, // which binds *less* tightly than *, /, **
287 Multiplicative
, // *, /
288 Power
, // **, which is right-associative unlike the other dyadic operators
293 template <typename A
> constexpr Precedence
ToPrecedence(const A
&) {
294 return Precedence::Top
;
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();
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
{"(", "", ")"};
389 static OperatorSpelling
SpellOperator(const ComplexComponent
<KIND
> &x
) {
390 return {x
.isImaginaryPart
? "aimag(" : "real(", "", ")"};
393 constexpr OperatorSpelling
SpellOperator(const Not
<KIND
> &) {
394 return OperatorSpelling
{".NOT.", "", ""};
397 constexpr OperatorSpelling
SpellOperator(const SetLength
<KIND
> &) {
398 return OperatorSpelling
{"%SET_LENGTH(", ",", ")"};
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(", ",", ")"};
433 constexpr OperatorSpelling
SpellOperator(const Concat
<KIND
> &) {
434 return OperatorSpelling
{"", "//", ""};
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
<< '(') << ')';
459 if (thisPrec
!= Precedence::Top
&&
460 (lhsPrec
< thisPrec
||
461 (lhsPrec
== Precedence::Power
&& thisPrec
== Precedence::Power
))) {
462 left().AsFortran(o
<< '(') << ')';
467 Precedence rhsPrec
{ToPrecedence(right())};
468 if (thisPrec
!= Precedence::Top
&& rhsPrec
< thisPrec
) {
469 right().AsFortran(o
<< '(') << ')';
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(");
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
);
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
) {
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
) << ')';
528 template <typename T
>
529 llvm::raw_ostream
&EmitArray(
530 llvm::raw_ostream
&o
, const ArrayConstructorValues
<T
> &values
) {
532 for (const auto &value
: values
) {
534 common::visit([&](const auto &x
) { EmitArray(o
, x
); }, value
.u
);
540 template <typename T
>
541 llvm::raw_ostream
&ArrayConstructor
<T
>::AsFortran(llvm::raw_ostream
&o
) const {
542 o
<< '[' << GetType().AsFortran() << "::";
549 ArrayConstructor
<Type
<TypeCategory::Character
, KIND
>>::AsFortran(
550 llvm::raw_ostream
&o
) const {
552 if (const auto *len
{LEN()}) {
553 o
<< GetType().AsFortran(len
->AsFortran()) << "::";
559 llvm::raw_ostream
&ArrayConstructor
<SomeDerived
>::AsFortran(
560 llvm::raw_ostream
&o
) const {
561 o
<< '[' << GetType().AsFortran() << "::";
566 template <typename RESULT
>
567 std::string ExpressionBase
<RESULT
>::AsFortran() const {
569 llvm::raw_string_ostream ss
{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
); },
592 static std::string
DerivedTypeSpecAsFortran(
593 const semantics::DerivedTypeSpec
&spec
) {
595 llvm::raw_string_ostream ss
{buf
};
596 EmitVar(ss
, spec
.typeSymbol(), spec
.name());
598 for (const auto &[name
, value
] : spec
.parameters()) {
599 ss
<< ch
<< name
.ToString() << '=';
601 if (value
.isAssumed()) {
603 } else if (value
.isDeferred()) {
606 value
.GetExplicit()->AsFortran(ss
);
615 llvm::raw_ostream
&StructureConstructor::AsFortran(llvm::raw_ostream
&o
) const {
616 o
<< DerivedTypeSpecAsFortran(result_
.derivedTypeSpec());
617 if (values_
.empty()) {
621 for (const auto &[symbol
, value
] : values_
) {
622 value
.value().AsFortran(EmitVar(o
<< ch
, *symbol
) << '=');
629 std::string
DynamicType::AsFortran() const {
631 CHECK(category_
== TypeCategory::Derived
);
632 std::string result
{DerivedTypeSpecAsFortran(*derived_
)};
633 if (IsPolymorphic()) {
634 result
= "CLASS("s
+ result
+ ')';
637 } else if (charLengthParamValue_
|| knownLength()) {
638 std::string result
{"CHARACTER(KIND="s
+ std::to_string(kind_
) + ",LEN="};
640 result
+= std::to_string(*knownLength()) + "_8";
641 } else if (charLengthParamValue_
->isAssumed()) {
643 } else if (charLengthParamValue_
->isDeferred()) {
645 } else if (const auto &length
{charLengthParamValue_
->GetExplicit()}) {
646 result
+= length
->AsFortran();
649 } else if (IsAssumedType()) {
651 } else if (IsUnlimitedPolymorphic()) {
653 } else if (IsTypelessIntrinsicArgument()) {
654 return "(typeless intrinsic function argument)";
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
) + ')';
670 std::string
SomeDerived::AsFortran() const {
671 if (IsUnlimitedPolymorphic()) {
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 {
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
); },
703 llvm::raw_ostream
&Triplet::AsFortran(llvm::raw_ostream
&o
) const {
704 EmitVar(o
, lower_
) << ':';
706 EmitVar(o
<< ':', stride_
.value());
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 {
717 for (const Subscript
&ss
: subscript_
) {
718 ss
.AsFortran(o
<< separator
);
724 llvm::raw_ostream
&CoarrayRef::AsFortran(llvm::raw_ostream
&o
) const {
726 for (const Symbol
&part
: base_
) {
735 for (const auto &sscript
: subscript_
) {
736 EmitVar(o
<< separator
, sscript
);
739 if (separator
== ',') {
743 for (const auto &css
: cosubscript_
) {
744 EmitVar(o
<< separator
, css
);
748 EmitVar(o
<< separator
, stat_
, "STAT=");
753 o
<< separator
, team_
, teamIsTeamNumber_
? "TEAM_NUMBER=" : "TEAM=");
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
); },
786 llvm::raw_ostream
&DescriptorInquiry::AsFortran(llvm::raw_ostream
&o
) const {
788 case Field::LowerBound
:
805 if (field_
== Field::Len
) {
807 } else if (field_
== Field::Rank
) {
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 {
820 [&](const Assignment::Intrinsic
&) {
821 rhs
.AsFortran(lhs
.AsFortran(o
) << '=');
823 [&](const ProcedureRef
&proc
) { proc
.AsFortran(o
<< "CALL "); },
824 [&](const BoundsSpec
&bounds
) {
826 if (!bounds
.empty()) {
828 for (const auto &bound
: bounds
) {
829 bound
.AsFortran(o
<< sep
) << ':';
834 rhs
.AsFortran(o
<< " => ");
836 [&](const BoundsRemapping
&bounds
) {
838 if (!bounds
.empty()) {
840 for (const auto &bound
: bounds
) {
841 bound
.first
.AsFortran(o
<< sep
) << ':';
842 bound
.second
.AsFortran(o
);
847 rhs
.AsFortran(o
<< " => ");
854 #ifdef _MSC_VER // disable bogus warning about missing definitions
855 #pragma warning(disable : 4661)
857 INSTANTIATE_CONSTANT_TEMPLATES
858 INSTANTIATE_EXPRESSION_TEMPLATES
859 INSTANTIATE_VARIABLE_TEMPLATES
860 } // namespace Fortran::evaluate