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