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