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