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