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