[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / flang / lib / Evaluate / formatting.cpp
blob3581b9c96c19bf45370d004bfd29334e83a63a56
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::Real ||
75 Result::category == TypeCategory::Complex) {
76 value.AsFortran(o, Result::kind);
77 } else if constexpr (Result::category == TypeCategory::Character) {
78 o << Result::kind << '_' << parser::QuoteCharacterLiteral(value, true);
79 } else if constexpr (Result::category == TypeCategory::Logical) {
80 if (!value.IsCanonical()) {
81 o << "transfer(" << value.word().ToInt64() << "_8,.false._"
82 << Result::kind << ')';
83 } else if (value.IsTrue()) {
84 o << ".true." << '_' << Result::kind;
85 } else {
86 o << ".false." << '_' << Result::kind;
88 } else {
89 StructureConstructor{result_.derivedTypeSpec(), value}.AsFortran(o);
92 if (Rank() > 0) {
93 o << ']';
95 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound);
96 return o;
99 template <int KIND>
100 llvm::raw_ostream &Constant<Type<TypeCategory::Character, KIND>>::AsFortran(
101 llvm::raw_ostream &o) const {
102 bool hasNonDefaultLowerBound{printLbounds && HasNonDefaultLowerBound()};
103 if (Rank() > 1 || hasNonDefaultLowerBound) {
104 o << "reshape(";
106 if (Rank() > 0) {
107 o << '[' << GetType().AsFortran(std::to_string(length_)) << "::";
109 auto total{static_cast<ConstantSubscript>(size())};
110 for (ConstantSubscript j{0}; j < total; ++j) {
111 Scalar<Result> value{values_.substr(j * length_, length_)};
112 if (j > 0) {
113 o << ',';
115 if (Result::kind != 1) {
116 o << Result::kind << '_';
118 o << parser::QuoteCharacterLiteral(value);
120 if (Rank() > 0) {
121 o << ']';
123 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound);
124 return o;
127 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol,
128 std::optional<parser::CharBlock> name = std::nullopt) {
129 const auto &renamings{symbol.owner().context().moduleFileOutputRenamings()};
130 if (auto iter{renamings.find(&symbol)}; iter != renamings.end()) {
131 return o << iter->second.ToString();
132 } else if (name) {
133 return o << name->ToString();
134 } else {
135 return o << symbol.name().ToString();
139 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::string &lit) {
140 return o << parser::QuoteCharacterLiteral(lit);
143 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u16string &lit) {
144 return o << parser::QuoteCharacterLiteral(lit);
147 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u32string &lit) {
148 return o << parser::QuoteCharacterLiteral(lit);
151 template <typename A>
152 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const A &x) {
153 return x.AsFortran(o);
156 template <typename A>
157 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, common::Reference<A> x) {
158 return EmitVar(o, *x);
161 template <typename A>
162 llvm::raw_ostream &EmitVar(
163 llvm::raw_ostream &o, const A *p, const char *kw = nullptr) {
164 if (p) {
165 if (kw) {
166 o << kw;
168 EmitVar(o, *p);
170 return o;
173 template <typename A>
174 llvm::raw_ostream &EmitVar(
175 llvm::raw_ostream &o, const std::optional<A> &x, const char *kw = nullptr) {
176 if (x) {
177 if (kw) {
178 o << kw;
180 EmitVar(o, *x);
182 return o;
185 template <typename A, bool COPY>
186 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o,
187 const common::Indirection<A, COPY> &p, const char *kw = nullptr) {
188 if (kw) {
189 o << kw;
191 EmitVar(o, p.value());
192 return o;
195 template <typename A>
196 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::shared_ptr<A> &p) {
197 CHECK(p);
198 return EmitVar(o, *p);
201 template <typename... A>
202 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::variant<A...> &u) {
203 common::visit([&](const auto &x) { EmitVar(o, x); }, u);
204 return o;
207 llvm::raw_ostream &ActualArgument::AssumedType::AsFortran(
208 llvm::raw_ostream &o) const {
209 return EmitVar(o, *symbol_);
212 llvm::raw_ostream &ActualArgument::AsFortran(llvm::raw_ostream &o) const {
213 if (keyword_) {
214 o << keyword_->ToString() << '=';
216 if (isPercentVal()) {
217 o << "%VAL(";
218 } else if (isPercentRef()) {
219 o << "%REF(";
221 common::visit(
222 common::visitors{
223 [&](const common::CopyableIndirection<Expr<SomeType>> &expr) {
224 expr.value().AsFortran(o);
226 [&](const AssumedType &assumedType) { assumedType.AsFortran(o); },
227 [&](const common::Label &label) { o << '*' << label; },
229 u_);
230 if (isPercentVal() || isPercentRef()) {
231 o << ')';
233 return o;
236 llvm::raw_ostream &SpecificIntrinsic::AsFortran(llvm::raw_ostream &o) const {
237 return o << name;
240 llvm::raw_ostream &ProcedureRef::AsFortran(llvm::raw_ostream &o) const {
241 for (const auto &arg : arguments_) {
242 if (arg && arg->isPassedObject()) {
243 arg->AsFortran(o) << '%';
244 break;
247 proc_.AsFortran(o);
248 if (!chevrons_.empty()) {
249 bool first{true};
250 for (const auto &expr : chevrons_) {
251 if (first) {
252 expr.AsFortran(o << "<<<");
253 first = false;
254 } else {
255 expr.AsFortran(o << ",");
258 o << ">>>";
260 char separator{'('};
261 for (const auto &arg : arguments_) {
262 if (arg && !arg->isPassedObject()) {
263 arg->AsFortran(o << separator);
264 separator = ',';
267 if (separator == '(') {
268 o << '(';
270 return o << ')';
273 // Operator precedence formatting; insert parentheses around operands
274 // only when necessary.
276 enum class Precedence { // in increasing order for sane comparisons
277 DefinedBinary,
279 And,
280 Equivalence, // .EQV., .NEQV.
281 Not, // which binds *less* tightly in Fortran than relations
282 Relational,
283 Additive, // +, -, and (arbitrarily) //
284 Negate, // which binds *less* tightly than *, /, **
285 Multiplicative, // *, /
286 Power, // **, which is right-associative unlike the other dyadic operators
287 DefinedUnary,
288 Top,
291 template <typename A> constexpr Precedence ToPrecedence(const A &) {
292 return Precedence::Top;
294 template <int KIND>
295 static Precedence ToPrecedence(const LogicalOperation<KIND> &x) {
296 switch (x.logicalOperator) {
297 SWITCH_COVERS_ALL_CASES
298 case LogicalOperator::And:
299 return Precedence::And;
300 case LogicalOperator::Or:
301 return Precedence::Or;
302 case LogicalOperator::Not:
303 return Precedence::Not;
304 case LogicalOperator::Eqv:
305 case LogicalOperator::Neqv:
306 return Precedence::Equivalence;
309 template <int KIND> constexpr Precedence ToPrecedence(const Not<KIND> &) {
310 return Precedence::Not;
312 template <typename T> constexpr Precedence ToPrecedence(const Relational<T> &) {
313 return Precedence::Relational;
315 template <typename T> constexpr Precedence ToPrecedence(const Add<T> &) {
316 return Precedence::Additive;
318 template <typename T> constexpr Precedence ToPrecedence(const Subtract<T> &) {
319 return Precedence::Additive;
321 template <int KIND> constexpr Precedence ToPrecedence(const Concat<KIND> &) {
322 return Precedence::Additive;
324 template <typename T> constexpr Precedence ToPrecedence(const Negate<T> &) {
325 return Precedence::Negate;
327 template <typename T> constexpr Precedence ToPrecedence(const Multiply<T> &) {
328 return Precedence::Multiplicative;
330 template <typename T> constexpr Precedence ToPrecedence(const Divide<T> &) {
331 return Precedence::Multiplicative;
333 template <typename T> constexpr Precedence ToPrecedence(const Power<T> &) {
334 return Precedence::Power;
336 template <typename T>
337 constexpr Precedence ToPrecedence(const RealToIntPower<T> &) {
338 return Precedence::Power;
340 template <typename T> static Precedence ToPrecedence(const Constant<T> &x) {
341 static constexpr TypeCategory cat{T::category};
342 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) {
343 if (auto n{GetScalarConstantValue<T>(x)}) {
344 if (n->IsNegative()) {
345 return Precedence::Negate;
349 return Precedence::Top;
351 template <typename T> static Precedence ToPrecedence(const Expr<T> &expr) {
352 return common::visit([](const auto &x) { return ToPrecedence(x); }, expr.u);
355 template <typename T> static bool IsNegatedScalarConstant(const Expr<T> &expr) {
356 static constexpr TypeCategory cat{T::category};
357 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) {
358 if (auto n{GetScalarConstantValue<T>(expr)}) {
359 return n->IsNegative();
362 return false;
365 template <TypeCategory CAT>
366 static bool IsNegatedScalarConstant(const Expr<SomeKind<CAT>> &expr) {
367 return common::visit(
368 [](const auto &x) { return IsNegatedScalarConstant(x); }, expr.u);
371 struct OperatorSpelling {
372 const char *prefix{""}, *infix{","}, *suffix{""};
375 template <typename A> constexpr OperatorSpelling SpellOperator(const A &) {
376 return OperatorSpelling{};
378 template <typename A>
379 constexpr OperatorSpelling SpellOperator(const Negate<A> &) {
380 return OperatorSpelling{"-", "", ""};
382 template <typename A>
383 constexpr OperatorSpelling SpellOperator(const Parentheses<A> &) {
384 return OperatorSpelling{"(", "", ")"};
386 template <int KIND>
387 static OperatorSpelling SpellOperator(const ComplexComponent<KIND> &x) {
388 return {x.isImaginaryPart ? "aimag(" : "real(", "", ")"};
390 template <int KIND>
391 constexpr OperatorSpelling SpellOperator(const Not<KIND> &) {
392 return OperatorSpelling{".NOT.", "", ""};
394 template <int KIND>
395 constexpr OperatorSpelling SpellOperator(const SetLength<KIND> &) {
396 return OperatorSpelling{"%SET_LENGTH(", ",", ")"};
398 template <int KIND>
399 constexpr OperatorSpelling SpellOperator(const ComplexConstructor<KIND> &) {
400 return OperatorSpelling{"(", ",", ")"};
402 template <typename A> constexpr OperatorSpelling SpellOperator(const Add<A> &) {
403 return OperatorSpelling{"", "+", ""};
405 template <typename A>
406 constexpr OperatorSpelling SpellOperator(const Subtract<A> &) {
407 return OperatorSpelling{"", "-", ""};
409 template <typename A>
410 constexpr OperatorSpelling SpellOperator(const Multiply<A> &) {
411 return OperatorSpelling{"", "*", ""};
413 template <typename A>
414 constexpr OperatorSpelling SpellOperator(const Divide<A> &) {
415 return OperatorSpelling{"", "/", ""};
417 template <typename A>
418 constexpr OperatorSpelling SpellOperator(const Power<A> &) {
419 return OperatorSpelling{"", "**", ""};
421 template <typename A>
422 constexpr OperatorSpelling SpellOperator(const RealToIntPower<A> &) {
423 return OperatorSpelling{"", "**", ""};
425 template <typename A>
426 static OperatorSpelling SpellOperator(const Extremum<A> &x) {
427 return OperatorSpelling{
428 x.ordering == Ordering::Less ? "min(" : "max(", ",", ")"};
430 template <int KIND>
431 constexpr OperatorSpelling SpellOperator(const Concat<KIND> &) {
432 return OperatorSpelling{"", "//", ""};
434 template <int KIND>
435 static OperatorSpelling SpellOperator(const LogicalOperation<KIND> &x) {
436 return OperatorSpelling{"", AsFortran(x.logicalOperator), ""};
438 template <typename T>
439 static OperatorSpelling SpellOperator(const Relational<T> &x) {
440 return OperatorSpelling{"", AsFortran(x.opr), ""};
443 template <typename D, typename R, typename... O>
444 llvm::raw_ostream &Operation<D, R, O...>::AsFortran(
445 llvm::raw_ostream &o) const {
446 Precedence lhsPrec{ToPrecedence(left())};
447 OperatorSpelling spelling{SpellOperator(derived())};
448 o << spelling.prefix;
449 Precedence thisPrec{ToPrecedence(derived())};
450 if constexpr (operands == 1) {
451 if (thisPrec != Precedence::Top && lhsPrec < thisPrec) {
452 left().AsFortran(o << '(') << ')';
453 } else {
454 left().AsFortran(o);
456 } else {
457 if (thisPrec != Precedence::Top &&
458 (lhsPrec < thisPrec ||
459 (lhsPrec == Precedence::Power && thisPrec == Precedence::Power))) {
460 left().AsFortran(o << '(') << ')';
461 } else {
462 left().AsFortran(o);
464 o << spelling.infix;
465 Precedence rhsPrec{ToPrecedence(right())};
466 if (thisPrec != Precedence::Top && rhsPrec < thisPrec) {
467 right().AsFortran(o << '(') << ')';
468 } else {
469 right().AsFortran(o);
472 return o << spelling.suffix;
475 template <typename TO, TypeCategory FROMCAT>
476 llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const {
477 static_assert(TO::category == TypeCategory::Integer ||
478 TO::category == TypeCategory::Real ||
479 TO::category == TypeCategory::Complex ||
480 TO::category == TypeCategory::Character ||
481 TO::category == TypeCategory::Logical,
482 "Convert<> to bad category!");
483 if constexpr (TO::category == TypeCategory::Character) {
484 this->left().AsFortran(o << "achar(iachar(") << ')';
485 } else if constexpr (TO::category == TypeCategory::Integer) {
486 this->left().AsFortran(o << "int(");
487 } else if constexpr (TO::category == TypeCategory::Real) {
488 this->left().AsFortran(o << "real(");
489 } else if constexpr (TO::category == TypeCategory::Complex) {
490 this->left().AsFortran(o << "cmplx(");
491 } else {
492 this->left().AsFortran(o << "logical(");
494 return o << ",kind=" << TO::kind << ')';
497 llvm::raw_ostream &Relational<SomeType>::AsFortran(llvm::raw_ostream &o) const {
498 common::visit([&](const auto &rel) { rel.AsFortran(o); }, u);
499 return o;
502 template <typename T>
503 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const Expr<T> &expr) {
504 return expr.AsFortran(o);
507 template <typename T>
508 llvm::raw_ostream &EmitArray(
509 llvm::raw_ostream &, const ArrayConstructorValues<T> &);
511 template <typename T>
512 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const ImpliedDo<T> &implDo) {
513 o << '(';
514 EmitArray(o, implDo.values());
515 o << ',' << ImpliedDoIndex::Result::AsFortran()
516 << "::" << implDo.name().ToString() << '=';
517 implDo.lower().AsFortran(o) << ',';
518 implDo.upper().AsFortran(o) << ',';
519 implDo.stride().AsFortran(o) << ')';
520 return o;
523 template <typename T>
524 llvm::raw_ostream &EmitArray(
525 llvm::raw_ostream &o, const ArrayConstructorValues<T> &values) {
526 const char *sep{""};
527 for (const auto &value : values) {
528 o << sep;
529 common::visit([&](const auto &x) { EmitArray(o, x); }, value.u);
530 sep = ",";
532 return o;
535 template <typename T>
536 llvm::raw_ostream &ArrayConstructor<T>::AsFortran(llvm::raw_ostream &o) const {
537 o << '[' << GetType().AsFortran() << "::";
538 EmitArray(o, *this);
539 return o << ']';
542 template <int KIND>
543 llvm::raw_ostream &
544 ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran(
545 llvm::raw_ostream &o) const {
546 o << '[';
547 if (const auto *len{LEN()}) {
548 o << GetType().AsFortran(len->AsFortran()) << "::";
550 EmitArray(o, *this);
551 return o << ']';
554 llvm::raw_ostream &ArrayConstructor<SomeDerived>::AsFortran(
555 llvm::raw_ostream &o) const {
556 o << '[' << GetType().AsFortran() << "::";
557 EmitArray(o, *this);
558 return o << ']';
561 template <typename RESULT>
562 std::string ExpressionBase<RESULT>::AsFortran() const {
563 std::string buf;
564 llvm::raw_string_ostream ss{buf};
565 AsFortran(ss);
566 return buf;
569 template <typename RESULT>
570 llvm::raw_ostream &ExpressionBase<RESULT>::AsFortran(
571 llvm::raw_ostream &o) const {
572 common::visit(common::visitors{
573 [&](const BOZLiteralConstant &x) {
574 o << "z'" << x.Hexadecimal() << "'";
576 [&](const NullPointer &) { o << "NULL()"; },
577 [&](const common::CopyableIndirection<Substring> &s) {
578 s.value().AsFortran(o);
580 [&](const ImpliedDoIndex &i) { o << i.name.ToString(); },
581 [&](const auto &x) { x.AsFortran(o); },
583 derived().u);
584 return o;
587 static std::string DerivedTypeSpecAsFortran(
588 const semantics::DerivedTypeSpec &spec) {
589 std::string buf;
590 llvm::raw_string_ostream ss{buf};
591 EmitVar(ss, spec.typeSymbol(), spec.name());
592 char ch{'('};
593 for (const auto &[name, value] : spec.parameters()) {
594 ss << ch << name.ToString() << '=';
595 ch = ',';
596 if (value.isAssumed()) {
597 ss << '*';
598 } else if (value.isDeferred()) {
599 ss << ':';
600 } else {
601 value.GetExplicit()->AsFortran(ss);
604 if (ch != '(') {
605 ss << ')';
607 return buf;
610 llvm::raw_ostream &StructureConstructor::AsFortran(llvm::raw_ostream &o) const {
611 o << DerivedTypeSpecAsFortran(result_.derivedTypeSpec());
612 if (values_.empty()) {
613 o << '(';
614 } else {
615 char ch{'('};
616 for (const auto &[symbol, value] : values_) {
617 value.value().AsFortran(EmitVar(o << ch, *symbol) << '=');
618 ch = ',';
621 return o << ')';
624 std::string DynamicType::AsFortran() const {
625 if (derived_) {
626 CHECK(category_ == TypeCategory::Derived);
627 std::string result{DerivedTypeSpecAsFortran(*derived_)};
628 if (IsPolymorphic()) {
629 result = "CLASS("s + result + ')';
631 return result;
632 } else if (charLengthParamValue_ || knownLength()) {
633 std::string result{"CHARACTER(KIND="s + std::to_string(kind_) + ",LEN="};
634 if (knownLength()) {
635 result += std::to_string(*knownLength()) + "_8";
636 } else if (charLengthParamValue_->isAssumed()) {
637 result += '*';
638 } else if (charLengthParamValue_->isDeferred()) {
639 result += ':';
640 } else if (const auto &length{charLengthParamValue_->GetExplicit()}) {
641 result += length->AsFortran();
643 return result + ')';
644 } else if (IsAssumedType()) {
645 return "TYPE(*)";
646 } else if (IsUnlimitedPolymorphic()) {
647 return "CLASS(*)";
648 } else if (IsTypelessIntrinsicArgument()) {
649 return "(typeless intrinsic function argument)";
650 } else {
651 return parser::ToUpperCaseLetters(EnumToString(category_)) + '(' +
652 std::to_string(kind_) + ')';
656 std::string DynamicType::AsFortran(std::string &&charLenExpr) const {
657 if (!charLenExpr.empty() && category_ == TypeCategory::Character) {
658 return "CHARACTER(KIND=" + std::to_string(kind_) +
659 ",LEN=" + std::move(charLenExpr) + ')';
660 } else {
661 return AsFortran();
665 std::string SomeDerived::AsFortran() const {
666 if (IsUnlimitedPolymorphic()) {
667 return "CLASS(*)";
668 } else {
669 return "TYPE("s + DerivedTypeSpecAsFortran(derivedTypeSpec()) + ')';
673 llvm::raw_ostream &BaseObject::AsFortran(llvm::raw_ostream &o) const {
674 return EmitVar(o, u);
677 llvm::raw_ostream &TypeParamInquiry::AsFortran(llvm::raw_ostream &o) const {
678 if (base_) {
679 base_.value().AsFortran(o) << '%';
681 return EmitVar(o, parameter_);
684 llvm::raw_ostream &Component::AsFortran(llvm::raw_ostream &o) const {
685 base_.value().AsFortran(o);
686 return EmitVar(o << '%', symbol_);
689 llvm::raw_ostream &NamedEntity::AsFortran(llvm::raw_ostream &o) const {
690 common::visit(common::visitors{
691 [&](SymbolRef s) { EmitVar(o, s); },
692 [&](const Component &c) { c.AsFortran(o); },
694 u_);
695 return o;
698 llvm::raw_ostream &Triplet::AsFortran(llvm::raw_ostream &o) const {
699 EmitVar(o, lower_) << ':';
700 EmitVar(o, upper_);
701 EmitVar(o << ':', stride_.value());
702 return o;
705 llvm::raw_ostream &Subscript::AsFortran(llvm::raw_ostream &o) const {
706 return EmitVar(o, u);
709 llvm::raw_ostream &ArrayRef::AsFortran(llvm::raw_ostream &o) const {
710 base_.AsFortran(o);
711 char separator{'('};
712 for (const Subscript &ss : subscript_) {
713 ss.AsFortran(o << separator);
714 separator = ',';
716 return o << ')';
719 llvm::raw_ostream &CoarrayRef::AsFortran(llvm::raw_ostream &o) const {
720 bool first{true};
721 for (const Symbol &part : base_) {
722 if (first) {
723 first = false;
724 } else {
725 o << '%';
727 EmitVar(o, part);
729 char separator{'('};
730 for (const auto &sscript : subscript_) {
731 EmitVar(o << separator, sscript);
732 separator = ',';
734 if (separator == ',') {
735 o << ')';
737 separator = '[';
738 for (const auto &css : cosubscript_) {
739 EmitVar(o << separator, css);
740 separator = ',';
742 if (stat_) {
743 EmitVar(o << separator, stat_, "STAT=");
744 separator = ',';
746 if (team_) {
747 EmitVar(
748 o << separator, team_, teamIsTeamNumber_ ? "TEAM_NUMBER=" : "TEAM=");
750 return o << ']';
753 llvm::raw_ostream &DataRef::AsFortran(llvm::raw_ostream &o) const {
754 return EmitVar(o, u);
757 llvm::raw_ostream &Substring::AsFortran(llvm::raw_ostream &o) const {
758 EmitVar(o, parent_) << '(';
759 EmitVar(o, lower_) << ':';
760 return EmitVar(o, upper_) << ')';
763 llvm::raw_ostream &ComplexPart::AsFortran(llvm::raw_ostream &o) const {
764 return complex_.AsFortran(o) << '%' << EnumToString(part_);
767 llvm::raw_ostream &ProcedureDesignator::AsFortran(llvm::raw_ostream &o) const {
768 return EmitVar(o, u);
771 template <typename T>
772 llvm::raw_ostream &Designator<T>::AsFortran(llvm::raw_ostream &o) const {
773 common::visit(common::visitors{
774 [&](SymbolRef symbol) { EmitVar(o, symbol); },
775 [&](const auto &x) { x.AsFortran(o); },
778 return o;
781 llvm::raw_ostream &DescriptorInquiry::AsFortran(llvm::raw_ostream &o) const {
782 switch (field_) {
783 case Field::LowerBound:
784 o << "lbound(";
785 break;
786 case Field::Extent:
787 o << "size(";
788 break;
789 case Field::Stride:
790 o << "%STRIDE(";
791 break;
792 case Field::Rank:
793 o << "int(rank(";
794 break;
795 case Field::Len:
796 o << "int(";
797 break;
799 base_.AsFortran(o);
800 if (field_ == Field::Len) {
801 o << "%len";
802 } else if (field_ == Field::Rank) {
803 o << ")";
804 } else {
805 if (dimension_ >= 0) {
806 o << ",dim=" << (dimension_ + 1);
809 return o << ",kind=" << DescriptorInquiry::Result::kind << ")";
812 llvm::raw_ostream &Assignment::AsFortran(llvm::raw_ostream &o) const {
813 common::visit(
814 common::visitors{
815 [&](const Assignment::Intrinsic &) {
816 rhs.AsFortran(lhs.AsFortran(o) << '=');
818 [&](const ProcedureRef &proc) { proc.AsFortran(o << "CALL "); },
819 [&](const BoundsSpec &bounds) {
820 lhs.AsFortran(o);
821 if (!bounds.empty()) {
822 char sep{'('};
823 for (const auto &bound : bounds) {
824 bound.AsFortran(o << sep) << ':';
825 sep = ',';
827 o << ')';
829 rhs.AsFortran(o << " => ");
831 [&](const BoundsRemapping &bounds) {
832 lhs.AsFortran(o);
833 if (!bounds.empty()) {
834 char sep{'('};
835 for (const auto &bound : bounds) {
836 bound.first.AsFortran(o << sep) << ':';
837 bound.second.AsFortran(o);
838 sep = ',';
840 o << ')';
842 rhs.AsFortran(o << " => ");
846 return o;
849 #ifdef _MSC_VER // disable bogus warning about missing definitions
850 #pragma warning(disable : 4661)
851 #endif
852 INSTANTIATE_CONSTANT_TEMPLATES
853 INSTANTIATE_EXPRESSION_TEMPLATES
854 INSTANTIATE_VARIABLE_TEMPLATES
855 } // namespace Fortran::evaluate