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 //===----------------------------------------------------------------------===// 8 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/symbol.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 namespace Fortran::evaluate { 21 22 // Constant arrays can have non-default lower bounds, but this can't be 23 // expressed in Fortran syntax directly, only implied through the use of 24 // named constant (PARAMETER) definitions. For debugging, setting this flag 25 // enables a non-standard %LBOUND=[...] argument to the RESHAPE intrinsic 26 // calls used to dumy constants. It's off by default so that this syntax 27 // doesn't show up in module files. 28 static const bool printLbounds{false}; 29 30 static void ShapeAsFortran(llvm::raw_ostream &o, 31 const ConstantSubscripts &shape, const ConstantSubscripts &lbounds, 32 bool hasNonDefaultLowerBound) { 33 if (GetRank(shape) > 1 || hasNonDefaultLowerBound) { 34 o << ",shape="; 35 char ch{'['}; 36 for (auto dim : shape) { 37 o << ch << dim; 38 ch = ','; 39 } 40 o << ']'; 41 if (hasNonDefaultLowerBound) { 42 o << ",%lbound="; 43 ch = '['; 44 for (auto lb : lbounds) { 45 o << ch << lb; 46 ch = ','; 47 } 48 o << ']'; 49 } 50 o << ')'; 51 } 52 } 53 54 template <typename RESULT, typename VALUE> 55 llvm::raw_ostream &ConstantBase<RESULT, VALUE>::AsFortran( 56 llvm::raw_ostream &o, const parser::CharBlock *derivedTypeRename) const { 57 bool hasNonDefaultLowerBound{printLbounds && HasNonDefaultLowerBound()}; 58 if (Rank() > 1 || hasNonDefaultLowerBound) { 59 o << "reshape("; 60 } 61 if (Rank() > 0) { 62 o << '[' << GetType().AsFortran() << "::"; 63 } 64 bool first{true}; 65 for (const auto &value : values_) { 66 if (first) { 67 first = false; 68 } else { 69 o << ','; 70 } 71 if constexpr (Result::category == TypeCategory::Integer) { 72 o << value.SignedDecimal() << '_' << Result::kind; 73 } else if constexpr (Result::category == TypeCategory::Real || 74 Result::category == TypeCategory::Complex) { 75 value.AsFortran(o, Result::kind); 76 } else if constexpr (Result::category == TypeCategory::Character) { 77 o << Result::kind << '_' << parser::QuoteCharacterLiteral(value, true); 78 } else if constexpr (Result::category == TypeCategory::Logical) { 79 if (!value.IsCanonical()) { 80 o << "transfer(" << value.word().ToInt64() << "_8,.false._" 81 << Result::kind << ')'; 82 } else if (value.IsTrue()) { 83 o << ".true." << '_' << Result::kind; 84 } else { 85 o << ".false." << '_' << Result::kind; 86 } 87 } else { 88 StructureConstructor{result_.derivedTypeSpec(), value}.AsFortran( 89 o, derivedTypeRename); 90 } 91 } 92 if (Rank() > 0) { 93 o << ']'; 94 } 95 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound); 96 return o; 97 } 98 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("; 105 } 106 if (Rank() > 0) { 107 o << '[' << GetType().AsFortran(std::to_string(length_)) << "::"; 108 } 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 << ','; 114 } 115 if (Result::kind != 1) { 116 o << Result::kind << '_'; 117 } 118 o << parser::QuoteCharacterLiteral(value); 119 } 120 if (Rank() > 0) { 121 o << ']'; 122 } 123 ShapeAsFortran(o, shape(), lbounds(), hasNonDefaultLowerBound); 124 return o; 125 } 126 127 llvm::raw_ostream &ActualArgument::AssumedType::AsFortran( 128 llvm::raw_ostream &o) const { 129 return o << symbol_->name().ToString(); 130 } 131 132 llvm::raw_ostream &ActualArgument::AsFortran(llvm::raw_ostream &o) const { 133 if (keyword_) { 134 o << keyword_->ToString() << '='; 135 } 136 if (isPercentVal()) { 137 o << "%VAL("; 138 } else if (isPercentRef()) { 139 o << "%REF("; 140 } 141 common::visit( 142 common::visitors{ 143 [&](const common::CopyableIndirection<Expr<SomeType>> &expr) { 144 expr.value().AsFortran(o); 145 }, 146 [&](const AssumedType &assumedType) { assumedType.AsFortran(o); }, 147 [&](const common::Label &label) { o << '*' << label; }, 148 }, 149 u_); 150 if (isPercentVal() || isPercentRef()) { 151 o << ')'; 152 } 153 return o; 154 } 155 156 llvm::raw_ostream &SpecificIntrinsic::AsFortran(llvm::raw_ostream &o) const { 157 return o << name; 158 } 159 160 llvm::raw_ostream &ProcedureRef::AsFortran(llvm::raw_ostream &o) const { 161 for (const auto &arg : arguments_) { 162 if (arg && arg->isPassedObject()) { 163 arg->AsFortran(o) << '%'; 164 break; 165 } 166 } 167 proc_.AsFortran(o); 168 if (!chevrons_.empty()) { 169 bool first{true}; 170 for (const auto &expr : chevrons_) { 171 if (first) { 172 expr.AsFortran(o << "<<<"); 173 first = false; 174 } else { 175 expr.AsFortran(o << ","); 176 } 177 } 178 o << ">>>"; 179 } 180 char separator{'('}; 181 for (const auto &arg : arguments_) { 182 if (arg && !arg->isPassedObject()) { 183 arg->AsFortran(o << separator); 184 separator = ','; 185 } 186 } 187 if (separator == '(') { 188 o << '('; 189 } 190 return o << ')'; 191 } 192 193 // Operator precedence formatting; insert parentheses around operands 194 // only when necessary. 195 196 enum class Precedence { // in increasing order for sane comparisons 197 DefinedBinary, 198 Or, 199 And, 200 Equivalence, // .EQV., .NEQV. 201 Not, // which binds *less* tightly in Fortran than relations 202 Relational, 203 Additive, // +, -, and (arbitrarily) // 204 Negate, // which binds *less* tightly than *, /, ** 205 Multiplicative, // *, / 206 Power, // **, which is right-associative unlike the other dyadic operators 207 DefinedUnary, 208 Top, 209 }; 210 211 template <typename A> constexpr Precedence ToPrecedence(const A &) { 212 return Precedence::Top; 213 } 214 template <int KIND> 215 static Precedence ToPrecedence(const LogicalOperation<KIND> &x) { 216 switch (x.logicalOperator) { 217 SWITCH_COVERS_ALL_CASES 218 case LogicalOperator::And: 219 return Precedence::And; 220 case LogicalOperator::Or: 221 return Precedence::Or; 222 case LogicalOperator::Not: 223 return Precedence::Not; 224 case LogicalOperator::Eqv: 225 case LogicalOperator::Neqv: 226 return Precedence::Equivalence; 227 } 228 } 229 template <int KIND> constexpr Precedence ToPrecedence(const Not<KIND> &) { 230 return Precedence::Not; 231 } 232 template <typename T> constexpr Precedence ToPrecedence(const Relational<T> &) { 233 return Precedence::Relational; 234 } 235 template <typename T> constexpr Precedence ToPrecedence(const Add<T> &) { 236 return Precedence::Additive; 237 } 238 template <typename T> constexpr Precedence ToPrecedence(const Subtract<T> &) { 239 return Precedence::Additive; 240 } 241 template <int KIND> constexpr Precedence ToPrecedence(const Concat<KIND> &) { 242 return Precedence::Additive; 243 } 244 template <typename T> constexpr Precedence ToPrecedence(const Negate<T> &) { 245 return Precedence::Negate; 246 } 247 template <typename T> constexpr Precedence ToPrecedence(const Multiply<T> &) { 248 return Precedence::Multiplicative; 249 } 250 template <typename T> constexpr Precedence ToPrecedence(const Divide<T> &) { 251 return Precedence::Multiplicative; 252 } 253 template <typename T> constexpr Precedence ToPrecedence(const Power<T> &) { 254 return Precedence::Power; 255 } 256 template <typename T> 257 constexpr Precedence ToPrecedence(const RealToIntPower<T> &) { 258 return Precedence::Power; 259 } 260 template <typename T> static Precedence ToPrecedence(const Constant<T> &x) { 261 static constexpr TypeCategory cat{T::category}; 262 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) { 263 if (auto n{GetScalarConstantValue<T>(x)}) { 264 if (n->IsNegative()) { 265 return Precedence::Negate; 266 } 267 } 268 } 269 return Precedence::Top; 270 } 271 template <typename T> static Precedence ToPrecedence(const Expr<T> &expr) { 272 return common::visit([](const auto &x) { return ToPrecedence(x); }, expr.u); 273 } 274 275 template <typename T> static bool IsNegatedScalarConstant(const Expr<T> &expr) { 276 static constexpr TypeCategory cat{T::category}; 277 if constexpr (cat == TypeCategory::Integer || cat == TypeCategory::Real) { 278 if (auto n{GetScalarConstantValue<T>(expr)}) { 279 return n->IsNegative(); 280 } 281 } 282 return false; 283 } 284 285 template <TypeCategory CAT> 286 static bool IsNegatedScalarConstant(const Expr<SomeKind<CAT>> &expr) { 287 return common::visit( 288 [](const auto &x) { return IsNegatedScalarConstant(x); }, expr.u); 289 } 290 291 struct OperatorSpelling { 292 const char *prefix{""}, *infix{","}, *suffix{""}; 293 }; 294 295 template <typename A> constexpr OperatorSpelling SpellOperator(const A &) { 296 return OperatorSpelling{}; 297 } 298 template <typename A> 299 constexpr OperatorSpelling SpellOperator(const Negate<A> &) { 300 return OperatorSpelling{"-", "", ""}; 301 } 302 template <typename A> 303 constexpr OperatorSpelling SpellOperator(const Parentheses<A> &) { 304 return OperatorSpelling{"(", "", ")"}; 305 } 306 template <int KIND> 307 static OperatorSpelling SpellOperator(const ComplexComponent<KIND> &x) { 308 return {x.isImaginaryPart ? "aimag(" : "real(", "", ")"}; 309 } 310 template <int KIND> 311 constexpr OperatorSpelling SpellOperator(const Not<KIND> &) { 312 return OperatorSpelling{".NOT.", "", ""}; 313 } 314 template <int KIND> 315 constexpr OperatorSpelling SpellOperator(const SetLength<KIND> &) { 316 return OperatorSpelling{"%SET_LENGTH(", ",", ")"}; 317 } 318 template <int KIND> 319 constexpr OperatorSpelling SpellOperator(const ComplexConstructor<KIND> &) { 320 return OperatorSpelling{"(", ",", ")"}; 321 } 322 template <typename A> constexpr OperatorSpelling SpellOperator(const Add<A> &) { 323 return OperatorSpelling{"", "+", ""}; 324 } 325 template <typename A> 326 constexpr OperatorSpelling SpellOperator(const Subtract<A> &) { 327 return OperatorSpelling{"", "-", ""}; 328 } 329 template <typename A> 330 constexpr OperatorSpelling SpellOperator(const Multiply<A> &) { 331 return OperatorSpelling{"", "*", ""}; 332 } 333 template <typename A> 334 constexpr OperatorSpelling SpellOperator(const Divide<A> &) { 335 return OperatorSpelling{"", "/", ""}; 336 } 337 template <typename A> 338 constexpr OperatorSpelling SpellOperator(const Power<A> &) { 339 return OperatorSpelling{"", "**", ""}; 340 } 341 template <typename A> 342 constexpr OperatorSpelling SpellOperator(const RealToIntPower<A> &) { 343 return OperatorSpelling{"", "**", ""}; 344 } 345 template <typename A> 346 static OperatorSpelling SpellOperator(const Extremum<A> &x) { 347 return OperatorSpelling{ 348 x.ordering == Ordering::Less ? "min(" : "max(", ",", ")"}; 349 } 350 template <int KIND> 351 constexpr OperatorSpelling SpellOperator(const Concat<KIND> &) { 352 return OperatorSpelling{"", "//", ""}; 353 } 354 template <int KIND> 355 static OperatorSpelling SpellOperator(const LogicalOperation<KIND> &x) { 356 return OperatorSpelling{"", AsFortran(x.logicalOperator), ""}; 357 } 358 template <typename T> 359 static OperatorSpelling SpellOperator(const Relational<T> &x) { 360 return OperatorSpelling{"", AsFortran(x.opr), ""}; 361 } 362 363 template <typename D, typename R, typename... O> 364 llvm::raw_ostream &Operation<D, R, O...>::AsFortran( 365 llvm::raw_ostream &o) const { 366 Precedence lhsPrec{ToPrecedence(left())}; 367 OperatorSpelling spelling{SpellOperator(derived())}; 368 o << spelling.prefix; 369 Precedence thisPrec{ToPrecedence(derived())}; 370 if constexpr (operands == 1) { 371 if (thisPrec != Precedence::Top && lhsPrec < thisPrec) { 372 left().AsFortran(o << '(') << ')'; 373 } else { 374 left().AsFortran(o); 375 } 376 } else { 377 if (thisPrec != Precedence::Top && 378 (lhsPrec < thisPrec || 379 (lhsPrec == Precedence::Power && thisPrec == Precedence::Power))) { 380 left().AsFortran(o << '(') << ')'; 381 } else { 382 left().AsFortran(o); 383 } 384 o << spelling.infix; 385 Precedence rhsPrec{ToPrecedence(right())}; 386 if (thisPrec != Precedence::Top && rhsPrec < thisPrec) { 387 right().AsFortran(o << '(') << ')'; 388 } else { 389 right().AsFortran(o); 390 } 391 } 392 return o << spelling.suffix; 393 } 394 395 template <typename TO, TypeCategory FROMCAT> 396 llvm::raw_ostream &Convert<TO, FROMCAT>::AsFortran(llvm::raw_ostream &o) const { 397 static_assert(TO::category == TypeCategory::Integer || 398 TO::category == TypeCategory::Real || 399 TO::category == TypeCategory::Complex || 400 TO::category == TypeCategory::Character || 401 TO::category == TypeCategory::Logical, 402 "Convert<> to bad category!"); 403 if constexpr (TO::category == TypeCategory::Character) { 404 this->left().AsFortran(o << "achar(iachar(") << ')'; 405 } else if constexpr (TO::category == TypeCategory::Integer) { 406 this->left().AsFortran(o << "int("); 407 } else if constexpr (TO::category == TypeCategory::Real) { 408 this->left().AsFortran(o << "real("); 409 } else if constexpr (TO::category == TypeCategory::Complex) { 410 this->left().AsFortran(o << "cmplx("); 411 } else { 412 this->left().AsFortran(o << "logical("); 413 } 414 return o << ",kind=" << TO::kind << ')'; 415 } 416 417 llvm::raw_ostream &Relational<SomeType>::AsFortran(llvm::raw_ostream &o) const { 418 common::visit([&](const auto &rel) { rel.AsFortran(o); }, u); 419 return o; 420 } 421 422 template <typename T> 423 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const Expr<T> &expr) { 424 return expr.AsFortran(o); 425 } 426 427 template <typename T> 428 llvm::raw_ostream &EmitArray( 429 llvm::raw_ostream &, const ArrayConstructorValues<T> &); 430 431 template <typename T> 432 llvm::raw_ostream &EmitArray(llvm::raw_ostream &o, const ImpliedDo<T> &implDo) { 433 o << '('; 434 EmitArray(o, implDo.values()); 435 o << ',' << ImpliedDoIndex::Result::AsFortran() 436 << "::" << implDo.name().ToString() << '='; 437 implDo.lower().AsFortran(o) << ','; 438 implDo.upper().AsFortran(o) << ','; 439 implDo.stride().AsFortran(o) << ')'; 440 return o; 441 } 442 443 template <typename T> 444 llvm::raw_ostream &EmitArray( 445 llvm::raw_ostream &o, const ArrayConstructorValues<T> &values) { 446 const char *sep{""}; 447 for (const auto &value : values) { 448 o << sep; 449 common::visit([&](const auto &x) { EmitArray(o, x); }, value.u); 450 sep = ","; 451 } 452 return o; 453 } 454 455 template <typename T> 456 llvm::raw_ostream &ArrayConstructor<T>::AsFortran(llvm::raw_ostream &o) const { 457 o << '[' << GetType().AsFortran() << "::"; 458 EmitArray(o, *this); 459 return o << ']'; 460 } 461 462 template <int KIND> 463 llvm::raw_ostream & 464 ArrayConstructor<Type<TypeCategory::Character, KIND>>::AsFortran( 465 llvm::raw_ostream &o) const { 466 o << '['; 467 if (const auto *len{LEN()}) { 468 o << GetType().AsFortran(len->AsFortran()) << "::"; 469 } 470 EmitArray(o, *this); 471 return o << ']'; 472 } 473 474 llvm::raw_ostream &ArrayConstructor<SomeDerived>::AsFortran( 475 llvm::raw_ostream &o) const { 476 o << '[' << GetType().AsFortran() << "::"; 477 EmitArray(o, *this); 478 return o << ']'; 479 } 480 481 template <typename RESULT> 482 std::string ExpressionBase<RESULT>::AsFortran() const { 483 std::string buf; 484 llvm::raw_string_ostream ss{buf}; 485 AsFortran(ss); 486 return ss.str(); 487 } 488 489 template <typename RESULT> 490 llvm::raw_ostream &ExpressionBase<RESULT>::AsFortran( 491 llvm::raw_ostream &o) const { 492 common::visit(common::visitors{ 493 [&](const BOZLiteralConstant &x) { 494 o << "z'" << x.Hexadecimal() << "'"; 495 }, 496 [&](const NullPointer &) { o << "NULL()"; }, 497 [&](const common::CopyableIndirection<Substring> &s) { 498 s.value().AsFortran(o); 499 }, 500 [&](const ImpliedDoIndex &i) { o << i.name.ToString(); }, 501 [&](const auto &x) { x.AsFortran(o); }, 502 }, 503 derived().u); 504 return o; 505 } 506 507 llvm::raw_ostream &StructureConstructor::AsFortran( 508 llvm::raw_ostream &o, const parser::CharBlock *derivedTypeRename) const { 509 o << DerivedTypeSpecAsFortran(result_.derivedTypeSpec(), derivedTypeRename); 510 if (values_.empty()) { 511 o << '('; 512 } else { 513 char ch{'('}; 514 for (const auto &[symbol, value] : values_) { 515 value.value().AsFortran(o << ch << symbol->name().ToString() << '='); 516 ch = ','; 517 } 518 } 519 return o << ')'; 520 } 521 522 std::string DynamicType::AsFortran() const { 523 if (derived_) { 524 CHECK(category_ == TypeCategory::Derived); 525 std::string result{DerivedTypeSpecAsFortran(*derived_)}; 526 if (IsPolymorphic()) { 527 result = "CLASS("s + result + ')'; 528 } 529 return result; 530 } else if (charLengthParamValue_ || knownLength()) { 531 std::string result{"CHARACTER(KIND="s + std::to_string(kind_) + ",LEN="}; 532 if (knownLength()) { 533 result += std::to_string(*knownLength()) + "_8"; 534 } else if (charLengthParamValue_->isAssumed()) { 535 result += '*'; 536 } else if (charLengthParamValue_->isDeferred()) { 537 result += ':'; 538 } else if (const auto &length{charLengthParamValue_->GetExplicit()}) { 539 result += length->AsFortran(); 540 } 541 return result + ')'; 542 } else if (IsAssumedType()) { 543 return "TYPE(*)"; 544 } else if (IsUnlimitedPolymorphic()) { 545 return "CLASS(*)"; 546 } else if (IsTypelessIntrinsicArgument()) { 547 return "(typeless intrinsic function argument)"; 548 } else { 549 return parser::ToUpperCaseLetters(EnumToString(category_)) + '(' + 550 std::to_string(kind_) + ')'; 551 } 552 } 553 554 std::string DynamicType::AsFortran(std::string &&charLenExpr) const { 555 if (!charLenExpr.empty() && category_ == TypeCategory::Character) { 556 return "CHARACTER(KIND=" + std::to_string(kind_) + 557 ",LEN=" + std::move(charLenExpr) + ')'; 558 } else { 559 return AsFortran(); 560 } 561 } 562 563 std::string SomeDerived::AsFortran() const { 564 if (IsUnlimitedPolymorphic()) { 565 return "CLASS(*)"; 566 } else { 567 return "TYPE("s + DerivedTypeSpecAsFortran(derivedTypeSpec()) + ')'; 568 } 569 } 570 571 std::string DerivedTypeSpecAsFortran(const semantics::DerivedTypeSpec &spec, 572 const parser::CharBlock *derivedTypeRename) { 573 std::string buf; 574 llvm::raw_string_ostream ss{buf}; 575 ss << (derivedTypeRename ? *derivedTypeRename : spec.name()).ToString(); 576 char ch{'('}; 577 for (const auto &[name, value] : spec.parameters()) { 578 ss << ch << name.ToString() << '='; 579 ch = ','; 580 if (value.isAssumed()) { 581 ss << '*'; 582 } else if (value.isDeferred()) { 583 ss << ':'; 584 } else { 585 value.GetExplicit()->AsFortran(ss); 586 } 587 } 588 if (ch != '(') { 589 ss << ')'; 590 } 591 return ss.str(); 592 } 593 594 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const Symbol &symbol) { 595 return o << symbol.name().ToString(); 596 } 597 598 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::string &lit) { 599 return o << parser::QuoteCharacterLiteral(lit); 600 } 601 602 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u16string &lit) { 603 return o << parser::QuoteCharacterLiteral(lit); 604 } 605 606 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::u32string &lit) { 607 return o << parser::QuoteCharacterLiteral(lit); 608 } 609 610 template <typename A> 611 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const A &x) { 612 return x.AsFortran(o); 613 } 614 615 template <typename A> 616 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, common::Reference<A> x) { 617 return EmitVar(o, *x); 618 } 619 620 template <typename A> 621 llvm::raw_ostream &EmitVar( 622 llvm::raw_ostream &o, const A *p, const char *kw = nullptr) { 623 if (p) { 624 if (kw) { 625 o << kw; 626 } 627 EmitVar(o, *p); 628 } 629 return o; 630 } 631 632 template <typename A> 633 llvm::raw_ostream &EmitVar( 634 llvm::raw_ostream &o, const std::optional<A> &x, const char *kw = nullptr) { 635 if (x) { 636 if (kw) { 637 o << kw; 638 } 639 EmitVar(o, *x); 640 } 641 return o; 642 } 643 644 template <typename A, bool COPY> 645 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, 646 const common::Indirection<A, COPY> &p, const char *kw = nullptr) { 647 if (kw) { 648 o << kw; 649 } 650 EmitVar(o, p.value()); 651 return o; 652 } 653 654 template <typename A> 655 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::shared_ptr<A> &p) { 656 CHECK(p); 657 return EmitVar(o, *p); 658 } 659 660 template <typename... A> 661 llvm::raw_ostream &EmitVar(llvm::raw_ostream &o, const std::variant<A...> &u) { 662 common::visit([&](const auto &x) { EmitVar(o, x); }, u); 663 return o; 664 } 665 666 llvm::raw_ostream &BaseObject::AsFortran(llvm::raw_ostream &o) const { 667 return EmitVar(o, u); 668 } 669 670 llvm::raw_ostream &TypeParamInquiry::AsFortran(llvm::raw_ostream &o) const { 671 if (base_) { 672 base_.value().AsFortran(o) << '%'; 673 } 674 return EmitVar(o, parameter_); 675 } 676 677 llvm::raw_ostream &Component::AsFortran(llvm::raw_ostream &o) const { 678 base_.value().AsFortran(o); 679 return EmitVar(o << '%', symbol_); 680 } 681 682 llvm::raw_ostream &NamedEntity::AsFortran(llvm::raw_ostream &o) const { 683 common::visit(common::visitors{ 684 [&](SymbolRef s) { EmitVar(o, s); }, 685 [&](const Component &c) { c.AsFortran(o); }, 686 }, 687 u_); 688 return o; 689 } 690 691 llvm::raw_ostream &Triplet::AsFortran(llvm::raw_ostream &o) const { 692 EmitVar(o, lower_) << ':'; 693 EmitVar(o, upper_); 694 EmitVar(o << ':', stride_.value()); 695 return o; 696 } 697 698 llvm::raw_ostream &Subscript::AsFortran(llvm::raw_ostream &o) const { 699 return EmitVar(o, u); 700 } 701 702 llvm::raw_ostream &ArrayRef::AsFortran(llvm::raw_ostream &o) const { 703 base_.AsFortran(o); 704 char separator{'('}; 705 for (const Subscript &ss : subscript_) { 706 ss.AsFortran(o << separator); 707 separator = ','; 708 } 709 return o << ')'; 710 } 711 712 llvm::raw_ostream &CoarrayRef::AsFortran(llvm::raw_ostream &o) const { 713 bool first{true}; 714 for (const Symbol &part : base_) { 715 if (first) { 716 first = false; 717 } else { 718 o << '%'; 719 } 720 EmitVar(o, part); 721 } 722 char separator{'('}; 723 for (const auto &sscript : subscript_) { 724 EmitVar(o << separator, sscript); 725 separator = ','; 726 } 727 if (separator == ',') { 728 o << ')'; 729 } 730 separator = '['; 731 for (const auto &css : cosubscript_) { 732 EmitVar(o << separator, css); 733 separator = ','; 734 } 735 if (stat_) { 736 EmitVar(o << separator, stat_, "STAT="); 737 separator = ','; 738 } 739 if (team_) { 740 EmitVar( 741 o << separator, team_, teamIsTeamNumber_ ? "TEAM_NUMBER=" : "TEAM="); 742 } 743 return o << ']'; 744 } 745 746 llvm::raw_ostream &DataRef::AsFortran(llvm::raw_ostream &o) const { 747 return EmitVar(o, u); 748 } 749 750 llvm::raw_ostream &Substring::AsFortran(llvm::raw_ostream &o) const { 751 EmitVar(o, parent_) << '('; 752 EmitVar(o, lower_) << ':'; 753 return EmitVar(o, upper_) << ')'; 754 } 755 756 llvm::raw_ostream &ComplexPart::AsFortran(llvm::raw_ostream &o) const { 757 return complex_.AsFortran(o) << '%' << EnumToString(part_); 758 } 759 760 llvm::raw_ostream &ProcedureDesignator::AsFortran(llvm::raw_ostream &o) const { 761 return EmitVar(o, u); 762 } 763 764 template <typename T> 765 llvm::raw_ostream &Designator<T>::AsFortran(llvm::raw_ostream &o) const { 766 common::visit(common::visitors{ 767 [&](SymbolRef symbol) { EmitVar(o, symbol); }, 768 [&](const auto &x) { x.AsFortran(o); }, 769 }, 770 u); 771 return o; 772 } 773 774 llvm::raw_ostream &DescriptorInquiry::AsFortran(llvm::raw_ostream &o) const { 775 switch (field_) { 776 case Field::LowerBound: 777 o << "lbound("; 778 break; 779 case Field::Extent: 780 o << "size("; 781 break; 782 case Field::Stride: 783 o << "%STRIDE("; 784 break; 785 case Field::Rank: 786 o << "int(rank("; 787 break; 788 case Field::Len: 789 o << "int("; 790 break; 791 } 792 base_.AsFortran(o); 793 if (field_ == Field::Len) { 794 o << "%len"; 795 } else if (field_ == Field::Rank) { 796 o << ")"; 797 } else { 798 if (dimension_ >= 0) { 799 o << ",dim=" << (dimension_ + 1); 800 } 801 } 802 return o << ",kind=" << DescriptorInquiry::Result::kind << ")"; 803 } 804 805 llvm::raw_ostream &Assignment::AsFortran(llvm::raw_ostream &o) const { 806 common::visit( 807 common::visitors{ 808 [&](const Assignment::Intrinsic &) { 809 rhs.AsFortran(lhs.AsFortran(o) << '='); 810 }, 811 [&](const ProcedureRef &proc) { proc.AsFortran(o << "CALL "); }, 812 [&](const BoundsSpec &bounds) { 813 lhs.AsFortran(o); 814 if (!bounds.empty()) { 815 char sep{'('}; 816 for (const auto &bound : bounds) { 817 bound.AsFortran(o << sep) << ':'; 818 sep = ','; 819 } 820 o << ')'; 821 } 822 rhs.AsFortran(o << " => "); 823 }, 824 [&](const BoundsRemapping &bounds) { 825 lhs.AsFortran(o); 826 if (!bounds.empty()) { 827 char sep{'('}; 828 for (const auto &bound : bounds) { 829 bound.first.AsFortran(o << sep) << ':'; 830 bound.second.AsFortran(o); 831 sep = ','; 832 } 833 o << ')'; 834 } 835 rhs.AsFortran(o << " => "); 836 }, 837 }, 838 u); 839 return o; 840 } 841 842 #ifdef _MSC_VER // disable bogus warning about missing definitions 843 #pragma warning(disable : 4661) 844 #endif 845 INSTANTIATE_CONSTANT_TEMPLATES 846 INSTANTIATE_EXPRESSION_TEMPLATES 847 INSTANTIATE_VARIABLE_TEMPLATES 848 } // namespace Fortran::evaluate 849