1 //===-- lib/Parser/unparse.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 // Generates Fortran from the content of a parse tree, using the 10 // traversal templates in parse-tree-visitor.h. 11 12 #include "flang/Parser/unparse.h" 13 #include "flang/Common/Fortran.h" 14 #include "flang/Common/idioms.h" 15 #include "flang/Common/indirection.h" 16 #include "flang/Parser/characters.h" 17 #include "flang/Parser/parse-tree-visitor.h" 18 #include "flang/Parser/parse-tree.h" 19 #include "flang/Parser/tools.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <algorithm> 22 #include <cinttypes> 23 #include <cstddef> 24 #include <set> 25 26 namespace Fortran::parser { 27 28 class UnparseVisitor { 29 public: 30 UnparseVisitor(llvm::raw_ostream &out, int indentationAmount, 31 Encoding encoding, bool capitalize, bool backslashEscapes, 32 preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) 33 : out_{out}, indentationAmount_{indentationAmount}, encoding_{encoding}, 34 capitalizeKeywords_{capitalize}, backslashEscapes_{backslashEscapes}, 35 preStatement_{preStatement}, asFortran_{asFortran} {} 36 37 // In nearly all cases, this code avoids defining Boolean-valued Pre() 38 // callbacks for the parse tree walking framework in favor of two void 39 // functions, Before() and Unparse(), which imply true and false return 40 // values for Pre() respectively. 41 template <typename T> void Before(const T &) {} 42 template <typename T> double Unparse(const T &); // not void, never used 43 44 template <typename T> bool Pre(const T &x) { 45 if constexpr (std::is_void_v<decltype(Unparse(x))>) { 46 // There is a local definition of Unparse() for this type. It 47 // overrides the parse tree walker's default Walk() over the descendents. 48 Before(x); 49 Unparse(x); 50 Post(x); 51 return false; // Walk() does not visit descendents 52 } else if constexpr (HasTypedExpr<T>::value) { 53 // Format the expression representation from semantics 54 if (asFortran_ && x.typedExpr) { 55 asFortran_->expr(out_, *x.typedExpr); 56 return false; 57 } else { 58 return true; 59 } 60 } else { 61 Before(x); 62 return true; // there's no Unparse() defined here, Walk() the descendents 63 } 64 } 65 template <typename T> void Post(const T &) {} 66 67 // Emit simple types as-is. 68 void Unparse(const std::string &x) { Put(x); } 69 void Unparse(int x) { Put(std::to_string(x)); } 70 void Unparse(unsigned int x) { Put(std::to_string(x)); } 71 void Unparse(long x) { Put(std::to_string(x)); } 72 void Unparse(unsigned long x) { Put(std::to_string(x)); } 73 void Unparse(long long x) { Put(std::to_string(x)); } 74 void Unparse(unsigned long long x) { Put(std::to_string(x)); } 75 void Unparse(char x) { Put(x); } 76 77 // Statement labels and ends of lines 78 template <typename T> void Before(const Statement<T> &x) { 79 if (preStatement_) { 80 (*preStatement_)(x.source, out_, indent_); 81 } 82 Walk(x.label, " "); 83 } 84 template <typename T> void Post(const Statement<T> &) { Put('\n'); } 85 86 // The special-case formatting functions for these productions are 87 // ordered to correspond roughly to their order of appearance in 88 // the Fortran 2018 standard (and parse-tree.h). 89 90 void Unparse(const Program &x) { // R501 91 Walk("", x.v, "\n"); // put blank lines between ProgramUnits 92 } 93 94 void Unparse(const Name &x) { // R603 95 Put(x.ToString()); 96 } 97 void Unparse(const DefinedOperator::IntrinsicOperator &x) { // R608 98 switch (x) { 99 case DefinedOperator::IntrinsicOperator::Power: 100 Put("**"); 101 break; 102 case DefinedOperator::IntrinsicOperator::Multiply: 103 Put('*'); 104 break; 105 case DefinedOperator::IntrinsicOperator::Divide: 106 Put('/'); 107 break; 108 case DefinedOperator::IntrinsicOperator::Add: 109 Put('+'); 110 break; 111 case DefinedOperator::IntrinsicOperator::Subtract: 112 Put('-'); 113 break; 114 case DefinedOperator::IntrinsicOperator::Concat: 115 Put("//"); 116 break; 117 case DefinedOperator::IntrinsicOperator::LT: 118 Put('<'); 119 break; 120 case DefinedOperator::IntrinsicOperator::LE: 121 Put("<="); 122 break; 123 case DefinedOperator::IntrinsicOperator::EQ: 124 Put("=="); 125 break; 126 case DefinedOperator::IntrinsicOperator::NE: 127 Put("/="); 128 break; 129 case DefinedOperator::IntrinsicOperator::GE: 130 Put(">="); 131 break; 132 case DefinedOperator::IntrinsicOperator::GT: 133 Put('>'); 134 break; 135 default: 136 Put('.'), Word(DefinedOperator::EnumToString(x)), Put('.'); 137 } 138 } 139 void Post(const Star &) { Put('*'); } // R701 &c. 140 void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701 141 void Unparse(const DeclarationTypeSpec::Type &x) { // R703 142 Word("TYPE("), Walk(x.derived), Put(')'); 143 } 144 void Unparse(const DeclarationTypeSpec::Class &x) { 145 Word("CLASS("), Walk(x.derived), Put(')'); 146 } 147 void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); } 148 void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); } 149 void Unparse(const DeclarationTypeSpec::Record &x) { 150 Word("RECORD/"), Walk(x.v), Put('/'); 151 } 152 void Before(const IntrinsicTypeSpec::Real &) { // R704 153 Word("REAL"); 154 } 155 void Before(const IntrinsicTypeSpec::Complex &) { Word("COMPLEX"); } 156 void Post(const IntrinsicTypeSpec::DoublePrecision &) { 157 Word("DOUBLE PRECISION"); 158 } 159 void Before(const IntrinsicTypeSpec::Character &) { Word("CHARACTER"); } 160 void Before(const IntrinsicTypeSpec::Logical &) { Word("LOGICAL"); } 161 void Post(const IntrinsicTypeSpec::DoubleComplex &) { 162 Word("DOUBLE COMPLEX"); 163 } 164 void Before(const UnsignedTypeSpec &) { Word("UNSIGNED"); } 165 void Before(const IntrinsicVectorTypeSpec &) { Word("VECTOR("); } 166 void Post(const IntrinsicVectorTypeSpec &) { Put(')'); } 167 void Post(const VectorTypeSpec::PairVectorTypeSpec &) { 168 Word("__VECTOR_PAIR"); 169 } 170 void Post(const VectorTypeSpec::QuadVectorTypeSpec &) { 171 Word("__VECTOR_QUAD"); 172 } 173 void Before(const IntegerTypeSpec &) { // R705 174 Word("INTEGER"); 175 } 176 void Unparse(const KindSelector &x) { // R706 177 common::visit( 178 common::visitors{ 179 [&](const ScalarIntConstantExpr &y) { 180 Put('('), Word("KIND="), Walk(y), Put(')'); 181 }, 182 [&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); }, 183 }, 184 x.u); 185 } 186 void Unparse(const SignedIntLiteralConstant &x) { // R707 187 Put(std::get<CharBlock>(x.t).ToString()); 188 Walk("_", std::get<std::optional<KindParam>>(x.t)); 189 } 190 void Unparse(const IntLiteralConstant &x) { // R708 191 Put(std::get<CharBlock>(x.t).ToString()); 192 Walk("_", std::get<std::optional<KindParam>>(x.t)); 193 } 194 void Unparse(const Sign &x) { // R712 195 Put(x == Sign::Negative ? '-' : '+'); 196 } 197 void Unparse(const RealLiteralConstant &x) { // R714, R715 198 Put(x.real.source.ToString()), Walk("_", x.kind); 199 } 200 void Unparse(const ComplexLiteralConstant &x) { // R718 - R720 201 Put('('), Walk(x.t, ","), Put(')'); 202 } 203 void Unparse(const CharSelector::LengthAndKind &x) { // R721 204 Put('('), Word("KIND="), Walk(x.kind); 205 Walk(", LEN=", x.length), Put(')'); 206 } 207 void Unparse(const LengthSelector &x) { // R722 208 common::visit(common::visitors{ 209 [&](const TypeParamValue &y) { 210 Put('('), Word("LEN="), Walk(y), Put(')'); 211 }, 212 [&](const CharLength &y) { Put('*'), Walk(y); }, 213 }, 214 x.u); 215 } 216 void Unparse(const CharLength &x) { // R723 217 common::visit( 218 common::visitors{ 219 [&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); }, 220 [&](const std::int64_t &y) { Walk(y); }, 221 }, 222 x.u); 223 } 224 void Unparse(const CharLiteralConstant &x) { // R724 225 const auto &str{std::get<std::string>(x.t)}; 226 if (const auto &k{std::get<std::optional<KindParam>>(x.t)}) { 227 Walk(*k), Put('_'); 228 } 229 PutNormalized(str); 230 } 231 void Unparse(const HollerithLiteralConstant &x) { 232 auto ucs{DecodeString<std::u32string, Encoding::UTF_8>(x.v, false)}; 233 Unparse(ucs.size()); 234 Put('H'); 235 for (char32_t ch : ucs) { 236 EncodedCharacter encoded{EncodeCharacter(encoding_, ch)}; 237 for (int j{0}; j < encoded.bytes; ++j) { 238 Put(encoded.buffer[j]); 239 } 240 } 241 } 242 void Unparse(const LogicalLiteralConstant &x) { // R725 243 Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE."); 244 Walk("_", std::get<std::optional<KindParam>>(x.t)); 245 } 246 void Unparse(const DerivedTypeStmt &x) { // R727 247 Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", "); 248 Put(" :: "), Walk(std::get<Name>(x.t)); 249 Walk("(", std::get<std::list<Name>>(x.t), ", ", ")"); 250 Indent(); 251 } 252 void Unparse(const Abstract &) { // R728, &c. 253 Word("ABSTRACT"); 254 } 255 void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); } 256 void Unparse(const TypeAttrSpec::Extends &x) { 257 Word("EXTENDS("), Walk(x.v), Put(')'); 258 } 259 void Unparse(const EndTypeStmt &x) { // R730 260 Outdent(), Word("END TYPE"), Walk(" ", x.v); 261 } 262 void Unparse(const SequenceStmt &) { // R731 263 Word("SEQUENCE"); 264 } 265 void Unparse(const TypeParamDefStmt &x) { // R732 266 Walk(std::get<IntegerTypeSpec>(x.t)); 267 Put(", "), Walk(std::get<common::TypeParamAttr>(x.t)); 268 Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", "); 269 } 270 void Unparse(const TypeParamDecl &x) { // R733 271 Walk(std::get<Name>(x.t)); 272 Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t)); 273 } 274 void Unparse(const DataComponentDefStmt &x) { // R737 275 const auto &dts{std::get<DeclarationTypeSpec>(x.t)}; 276 const auto &attrs{std::get<std::list<ComponentAttrSpec>>(x.t)}; 277 const auto &decls{std::get<std::list<ComponentOrFill>>(x.t)}; 278 Walk(dts), Walk(", ", attrs, ", "); 279 if (!attrs.empty() || 280 (!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) && 281 std::none_of( 282 decls.begin(), decls.end(), [](const ComponentOrFill &c) { 283 return common::visit( 284 common::visitors{ 285 [](const ComponentDecl &d) { 286 const auto &init{ 287 std::get<std::optional<Initialization>>(d.t)}; 288 return init && 289 std::holds_alternative<std::list< 290 common::Indirection<DataStmtValue>>>( 291 init->u); 292 }, 293 [](const FillDecl &) { return false; }, 294 }, 295 c.u); 296 }))) { 297 Put(" ::"); 298 } 299 Put(' '), Walk(decls, ", "); 300 } 301 void Unparse(const Allocatable &) { // R738 302 Word("ALLOCATABLE"); 303 } 304 void Unparse(const Pointer &) { Word("POINTER"); } 305 void Unparse(const Contiguous &) { Word("CONTIGUOUS"); } 306 void Before(const ComponentAttrSpec &x) { 307 common::visit(common::visitors{ 308 [&](const CoarraySpec &) { Word("CODIMENSION["); }, 309 [&](const ComponentArraySpec &) { Word("DIMENSION("); }, 310 [](const auto &) {}, 311 }, 312 x.u); 313 } 314 void Post(const ComponentAttrSpec &x) { 315 common::visit(common::visitors{ 316 [&](const CoarraySpec &) { Put(']'); }, 317 [&](const ComponentArraySpec &) { Put(')'); }, 318 [](const auto &) {}, 319 }, 320 x.u); 321 } 322 void Unparse(const ComponentDecl &x) { // R739 323 Walk(std::get<ObjectName>(x.t)); 324 Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")"); 325 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 326 Walk("*", std::get<std::optional<CharLength>>(x.t)); 327 Walk(std::get<std::optional<Initialization>>(x.t)); 328 } 329 void Unparse(const FillDecl &x) { // DEC extension 330 Put("%FILL"); 331 Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")"); 332 Walk("*", std::get<std::optional<CharLength>>(x.t)); 333 } 334 void Unparse(const ComponentArraySpec &x) { // R740 335 common::visit( 336 common::visitors{ 337 [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); }, 338 [&](const DeferredShapeSpecList &y) { Walk(y); }, 339 }, 340 x.u); 341 } 342 void Unparse(const ProcComponentDefStmt &x) { // R741 343 Word("PROCEDURE("); 344 Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')'); 345 Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", "); 346 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", "); 347 } 348 void Unparse(const NoPass &) { // R742 349 Word("NOPASS"); 350 } 351 void Unparse(const Pass &x) { Word("PASS"), Walk("(", x.v, ")"); } 352 void Unparse(const Initialization &x) { // R743 & R805 353 common::visit( 354 common::visitors{ 355 [&](const ConstantExpr &y) { Put(" = "), Walk(y); }, 356 [&](const NullInit &y) { Put(" => "), Walk(y); }, 357 [&](const InitialDataTarget &y) { Put(" => "), Walk(y); }, 358 [&](const std::list<common::Indirection<DataStmtValue>> &y) { 359 Walk("/", y, ", ", "/"); 360 }, 361 }, 362 x.u); 363 } 364 void Unparse(const PrivateStmt &) { // R745 365 Word("PRIVATE"); 366 } 367 void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749 368 Word("PROCEDURE"), Walk(", ", x.attributes, ", "); 369 Put(" :: "), Walk(x.declarations, ", "); 370 } 371 void Unparse(const TypeBoundProcedureStmt::WithInterface &x) { 372 Word("PROCEDURE("), Walk(x.interfaceName), Put("), "); 373 Walk(x.attributes); 374 Put(" :: "), Walk(x.bindingNames, ", "); 375 } 376 void Unparse(const TypeBoundProcDecl &x) { // R750 377 Walk(std::get<Name>(x.t)); 378 Walk(" => ", std::get<std::optional<Name>>(x.t)); 379 } 380 void Unparse(const TypeBoundGenericStmt &x) { // R751 381 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t)); 382 Put(" :: "), Walk(std::get<common::Indirection<GenericSpec>>(x.t)); 383 Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", "); 384 } 385 void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752 386 void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); } 387 void Unparse(const FinalProcedureStmt &x) { // R753 388 Word("FINAL :: "), Walk(x.v, ", "); 389 } 390 void Unparse(const DerivedTypeSpec &x) { // R754 391 Walk(std::get<Name>(x.t)); 392 Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")"); 393 } 394 void Unparse(const TypeParamSpec &x) { // R755 395 Walk(std::get<std::optional<Keyword>>(x.t), "="); 396 Walk(std::get<TypeParamValue>(x.t)); 397 } 398 void Unparse(const StructureConstructor &x) { // R756 399 Walk(std::get<DerivedTypeSpec>(x.t)); 400 Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')'); 401 } 402 void Unparse(const ComponentSpec &x) { // R757 403 Walk(std::get<std::optional<Keyword>>(x.t), "="); 404 Walk(std::get<ComponentDataSource>(x.t)); 405 } 406 void Unparse(const EnumDefStmt &) { // R760 407 Word("ENUM, BIND(C)"), Indent(); 408 } 409 void Unparse(const EnumeratorDefStmt &x) { // R761 410 Word("ENUMERATOR :: "), Walk(x.v, ", "); 411 } 412 void Unparse(const Enumerator &x) { // R762 413 Walk(std::get<NamedConstant>(x.t)); 414 Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t)); 415 } 416 void Post(const EndEnumStmt &) { // R763 417 Outdent(), Word("END ENUM"); 418 } 419 void Unparse(const BOZLiteralConstant &x) { // R764 - R767 420 Put(x.v); 421 } 422 void Unparse(const AcValue::Triplet &x) { // R773 423 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t)); 424 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t)); 425 } 426 void Unparse(const ArrayConstructor &x) { // R769 427 Put('['), Walk(x.v), Put(']'); 428 } 429 void Unparse(const AcSpec &x) { // R770 430 Walk(x.type, "::"), Walk(x.values, ", "); 431 } 432 template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) { 433 Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper); 434 Walk(",", x.step); 435 } 436 void Unparse(const AcImpliedDo &x) { // R774 437 Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", "); 438 Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')'); 439 } 440 void Unparse(const AcImpliedDoControl &x) { // R775 441 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 442 Walk(std::get<AcImpliedDoControl::Bounds>(x.t)); 443 } 444 445 void Unparse(const TypeDeclarationStmt &x) { // R801 446 const auto &dts{std::get<DeclarationTypeSpec>(x.t)}; 447 const auto &attrs{std::get<std::list<AttrSpec>>(x.t)}; 448 const auto &decls{std::get<std::list<EntityDecl>>(x.t)}; 449 Walk(dts), Walk(", ", attrs, ", "); 450 451 static const auto isInitializerOldStyle{[](const Initialization &i) { 452 return std::holds_alternative< 453 std::list<common::Indirection<DataStmtValue>>>(i.u); 454 }}; 455 static const auto hasAssignmentInitializer{[](const EntityDecl &d) { 456 // Does a declaration have a new-style =x initializer? 457 const auto &init{std::get<std::optional<Initialization>>(d.t)}; 458 return init && !isInitializerOldStyle(*init); 459 }}; 460 static const auto hasSlashDelimitedInitializer{[](const EntityDecl &d) { 461 // Does a declaration have an old-style /x/ initializer? 462 const auto &init{std::get<std::optional<Initialization>>(d.t)}; 463 return init && isInitializerOldStyle(*init); 464 }}; 465 const auto useDoubledColons{[&]() { 466 bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)}; 467 if (!attrs.empty()) { 468 // Attributes after the type require :: before the entities. 469 CHECK(!isRecord); 470 return true; 471 } 472 if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) { 473 // Always use :: with new style standard initializers (=x), 474 // since the standard requires them to appear (even in free form, 475 // where mandatory spaces already disambiguate INTEGER J=666). 476 CHECK(!isRecord); 477 return true; 478 } 479 if (isRecord) { 480 // Never put :: in a legacy extension RECORD// statement. 481 return false; 482 } 483 // The :: is optional for this declaration. Avoid usage that can 484 // crash the pgf90 compiler. 485 if (std::any_of( 486 decls.begin(), decls.end(), hasSlashDelimitedInitializer)) { 487 // Don't use :: when a declaration uses legacy DATA-statement-like 488 // /x/ initialization. 489 return false; 490 } 491 // Don't use :: with intrinsic types. Otherwise, use it. 492 return !std::holds_alternative<IntrinsicTypeSpec>(dts.u); 493 }}; 494 495 if (useDoubledColons()) { 496 Put(" ::"); 497 } 498 Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", "); 499 } 500 void Before(const AttrSpec &x) { // R802 501 common::visit(common::visitors{ 502 [&](const CoarraySpec &) { Word("CODIMENSION["); }, 503 [&](const ArraySpec &) { Word("DIMENSION("); }, 504 [](const auto &) {}, 505 }, 506 x.u); 507 } 508 void Post(const AttrSpec &x) { 509 common::visit(common::visitors{ 510 [&](const CoarraySpec &) { Put(']'); }, 511 [&](const ArraySpec &) { Put(')'); }, 512 [](const auto &) {}, 513 }, 514 x.u); 515 } 516 void Unparse(const EntityDecl &x) { // R803 517 Walk(std::get<ObjectName>(x.t)); 518 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 519 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 520 Walk("*", std::get<std::optional<CharLength>>(x.t)); 521 Walk(std::get<std::optional<Initialization>>(x.t)); 522 } 523 void Unparse(const NullInit &) { // R806 524 Word("NULL()"); 525 } 526 void Unparse(const LanguageBindingSpec &x) { // R808 & R1528 527 Word("BIND(C"); 528 Walk( 529 ", NAME=", std::get<std::optional<ScalarDefaultCharConstantExpr>>(x.t)); 530 if (std::get<bool>(x.t)) { 531 Word(", CDEFINED"); 532 } 533 Put(')'); 534 } 535 void Unparse(const CoarraySpec &x) { // R809 536 common::visit(common::visitors{ 537 [&](const DeferredCoshapeSpecList &y) { Walk(y); }, 538 [&](const ExplicitCoshapeSpec &y) { Walk(y); }, 539 }, 540 x.u); 541 } 542 void Unparse(const DeferredCoshapeSpecList &x) { // R810 543 for (auto j{x.v}; j > 0; --j) { 544 Put(':'); 545 if (j > 1) { 546 Put(','); 547 } 548 } 549 } 550 void Unparse(const ExplicitCoshapeSpec &x) { // R811 551 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ","); 552 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*'); 553 } 554 void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818 555 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"); 556 Walk(std::get<SpecificationExpr>(x.t)); 557 } 558 void Unparse(const ArraySpec &x) { // R815 559 common::visit( 560 common::visitors{ 561 [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); }, 562 [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); }, 563 [&](const DeferredShapeSpecList &y) { Walk(y); }, 564 [&](const AssumedSizeSpec &y) { Walk(y); }, 565 [&](const ImpliedShapeSpec &y) { Walk(y); }, 566 [&](const AssumedRankSpec &y) { Walk(y); }, 567 }, 568 x.u); 569 } 570 void Post(const AssumedShapeSpec &) { Put(':'); } // R819 571 void Unparse(const DeferredShapeSpecList &x) { // R820 572 for (auto j{x.v}; j > 0; --j) { 573 Put(':'); 574 if (j > 1) { 575 Put(','); 576 } 577 } 578 } 579 void Unparse(const AssumedImpliedSpec &x) { // R821 580 Walk(x.v, ":"); 581 Put('*'); 582 } 583 void Unparse(const AssumedSizeSpec &x) { // R822 584 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ","); 585 Walk(std::get<AssumedImpliedSpec>(x.t)); 586 } 587 void Unparse(const ImpliedShapeSpec &x) { // R823 588 Walk(x.v, ","); 589 } 590 void Post(const AssumedRankSpec &) { Put(".."); } // R825 591 void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); } 592 void Post(const External &) { Word("EXTERNAL"); } 593 void Post(const Intrinsic &) { Word("INTRINSIC"); } 594 void Post(const Optional &) { Word("OPTIONAL"); } 595 void Post(const Parameter &) { Word("PARAMETER"); } 596 void Post(const Protected &) { Word("PROTECTED"); } 597 void Post(const Save &) { Word("SAVE"); } 598 void Post(const Target &) { Word("TARGET"); } 599 void Post(const Value &) { Word("VALUE"); } 600 void Post(const Volatile &) { Word("VOLATILE"); } 601 void Unparse(const IntentSpec &x) { // R826 602 Word("INTENT("), Walk(x.v), Put(")"); 603 } 604 void Unparse(const AccessStmt &x) { // R827 605 Walk(std::get<AccessSpec>(x.t)); 606 Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", "); 607 } 608 void Unparse(const AllocatableStmt &x) { // R829 609 Word("ALLOCATABLE :: "), Walk(x.v, ", "); 610 } 611 void Unparse(const ObjectDecl &x) { // R830 & R860 612 Walk(std::get<ObjectName>(x.t)); 613 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 614 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 615 } 616 void Unparse(const AsynchronousStmt &x) { // R831 617 Word("ASYNCHRONOUS :: "), Walk(x.v, ", "); 618 } 619 void Unparse(const BindStmt &x) { // R832 620 Walk(x.t, " :: "); 621 } 622 void Unparse(const BindEntity &x) { // R833 623 bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common}; 624 const char *slash{isCommon ? "/" : ""}; 625 Put(slash), Walk(std::get<Name>(x.t)), Put(slash); 626 } 627 void Unparse(const CodimensionStmt &x) { // R834 628 Word("CODIMENSION :: "), Walk(x.v, ", "); 629 } 630 void Unparse(const CodimensionDecl &x) { // R835 631 Walk(std::get<Name>(x.t)); 632 Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']'); 633 } 634 void Unparse(const ContiguousStmt &x) { // R836 635 Word("CONTIGUOUS :: "), Walk(x.v, ", "); 636 } 637 void Unparse(const DataStmt &x) { // R837 638 Word("DATA "), Walk(x.v, ", "); 639 } 640 void Unparse(const DataStmtSet &x) { // R838 641 Walk(std::get<std::list<DataStmtObject>>(x.t), ", "); 642 Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/'); 643 } 644 void Unparse(const DataImpliedDo &x) { // R840, R842 645 Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(','); 646 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 647 Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')'); 648 } 649 void Unparse(const DataStmtValue &x) { // R843 650 Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*"); 651 Walk(std::get<DataStmtConstant>(x.t)); 652 } 653 void Unparse(const DimensionStmt &x) { // R848 654 Word("DIMENSION :: "), Walk(x.v, ", "); 655 } 656 void Unparse(const DimensionStmt::Declaration &x) { 657 Walk(std::get<Name>(x.t)); 658 Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')'); 659 } 660 void Unparse(const IntentStmt &x) { // R849 661 Walk(x.t, " :: "); 662 } 663 void Unparse(const OptionalStmt &x) { // R850 664 Word("OPTIONAL :: "), Walk(x.v, ", "); 665 } 666 void Unparse(const ParameterStmt &x) { // R851 667 Word("PARAMETER("), Walk(x.v, ", "), Put(')'); 668 } 669 void Unparse(const NamedConstantDef &x) { // R852 670 Walk(x.t, "="); 671 } 672 void Unparse(const PointerStmt &x) { // R853 673 Word("POINTER :: "), Walk(x.v, ", "); 674 } 675 void Unparse(const PointerDecl &x) { // R854 676 Walk(std::get<Name>(x.t)); 677 Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")"); 678 } 679 void Unparse(const ProtectedStmt &x) { // R855 680 Word("PROTECTED :: "), Walk(x.v, ", "); 681 } 682 void Unparse(const SaveStmt &x) { // R856 683 Word("SAVE"), Walk(" :: ", x.v, ", "); 684 } 685 void Unparse(const SavedEntity &x) { // R857, R858 686 bool isCommon{ 687 std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common}; 688 const char *slash{isCommon ? "/" : ""}; 689 Put(slash), Walk(std::get<Name>(x.t)), Put(slash); 690 } 691 void Unparse(const TargetStmt &x) { // R859 692 Word("TARGET :: "), Walk(x.v, ", "); 693 } 694 void Unparse(const ValueStmt &x) { // R861 695 Word("VALUE :: "), Walk(x.v, ", "); 696 } 697 void Unparse(const VolatileStmt &x) { // R862 698 Word("VOLATILE :: "), Walk(x.v, ", "); 699 } 700 void Unparse(const ImplicitStmt &x) { // R863 701 Word("IMPLICIT "); 702 common::visit( 703 common::visitors{ 704 [&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); }, 705 [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) { 706 Word("NONE"), Walk(" (", y, ", ", ")"); 707 }, 708 }, 709 x.u); 710 } 711 void Unparse(const ImplicitSpec &x) { // R864 712 Walk(std::get<DeclarationTypeSpec>(x.t)); 713 Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')'); 714 } 715 void Unparse(const LetterSpec &x) { // R865 716 Put(*std::get<const char *>(x.t)); 717 auto second{std::get<std::optional<const char *>>(x.t)}; 718 if (second) { 719 Put('-'), Put(**second); 720 } 721 } 722 void Unparse(const ImportStmt &x) { // R867 723 Word("IMPORT"); 724 switch (x.kind) { 725 case common::ImportKind::Default: 726 Walk(" :: ", x.names, ", "); 727 break; 728 case common::ImportKind::Only: 729 Put(", "), Word("ONLY: "); 730 Walk(x.names, ", "); 731 break; 732 case common::ImportKind::None: 733 Word(", NONE"); 734 break; 735 case common::ImportKind::All: 736 Word(", ALL"); 737 break; 738 } 739 } 740 void Unparse(const NamelistStmt &x) { // R868 741 Word("NAMELIST"), Walk(x.v, ", "); 742 } 743 void Unparse(const NamelistStmt::Group &x) { 744 Put('/'), Walk(std::get<Name>(x.t)), Put('/'); 745 Walk(std::get<std::list<Name>>(x.t), ", "); 746 } 747 void Unparse(const EquivalenceStmt &x) { // R870, R871 748 Word("EQUIVALENCE"); 749 const char *separator{" "}; 750 for (const std::list<EquivalenceObject> &y : x.v) { 751 Put(separator), Put('('), Walk(y), Put(')'); 752 separator = ", "; 753 } 754 } 755 void Unparse(const CommonStmt &x) { // R873 756 Word("COMMON "); 757 Walk(x.blocks); 758 } 759 void Unparse(const CommonBlockObject &x) { // R874 760 Walk(std::get<Name>(x.t)); 761 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 762 } 763 void Unparse(const CommonStmt::Block &x) { 764 Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/"); 765 Walk(std::get<std::list<CommonBlockObject>>(x.t)); 766 } 767 768 void Unparse(const Substring &x) { // R908, R909 769 Walk(std::get<DataRef>(x.t)); 770 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')'); 771 } 772 void Unparse(const CharLiteralConstantSubstring &x) { 773 Walk(std::get<CharLiteralConstant>(x.t)); 774 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')'); 775 } 776 void Unparse(const SubstringInquiry &x) { 777 Walk(x.v); 778 Put(x.source.end()[-1] == 'n' ? "%LEN" : "%KIND"); 779 } 780 void Unparse(const SubstringRange &x) { // R910 781 Walk(x.t, ":"); 782 } 783 void Unparse(const PartRef &x) { // R912 784 Walk(x.name); 785 Walk("(", x.subscripts, ",", ")"); 786 Walk(x.imageSelector); 787 } 788 void Unparse(const StructureComponent &x) { // R913 789 Walk(x.base); 790 if (structureComponents_.find(x.component.source) != 791 structureComponents_.end()) { 792 Put('.'); 793 } else { 794 Put('%'); 795 } 796 Walk(x.component); 797 } 798 void Unparse(const ArrayElement &x) { // R917 799 Walk(x.base); 800 Put('('), Walk(x.subscripts, ","), Put(')'); 801 } 802 void Unparse(const SubscriptTriplet &x) { // R921 803 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t)); 804 Walk(":", std::get<2>(x.t)); 805 } 806 void Unparse(const ImageSelector &x) { // R924 807 Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ","); 808 Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']'); 809 } 810 void Before(const ImageSelectorSpec::Stat &) { // R926 811 Word("STAT="); 812 } 813 void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); } 814 void Before(const ImageSelectorSpec &x) { 815 if (std::holds_alternative<TeamValue>(x.u)) { 816 Word("TEAM="); 817 } 818 } 819 void Unparse(const AllocateStmt &x) { // R927 820 Word("ALLOCATE("); 821 Walk(std::get<std::optional<TypeSpec>>(x.t), "::"); 822 Walk(std::get<std::list<Allocation>>(x.t), ", "); 823 Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')'); 824 } 825 void Before(const AllocOpt &x) { // R928, R931 826 common::visit(common::visitors{ 827 [&](const AllocOpt::Mold &) { Word("MOLD="); }, 828 [&](const AllocOpt::Source &) { Word("SOURCE="); }, 829 [&](const AllocOpt::Stream &) { Word("STREAM="); }, 830 [&](const AllocOpt::Pinned &) { Word("PINNED="); }, 831 [](const StatOrErrmsg &) {}, 832 }, 833 x.u); 834 } 835 void Unparse(const Allocation &x) { // R932 836 Walk(std::get<AllocateObject>(x.t)); 837 Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")"); 838 Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]"); 839 } 840 void Unparse(const AllocateShapeSpec &x) { // R934 & R938 841 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"); 842 Walk(std::get<BoundExpr>(x.t)); 843 } 844 void Unparse(const AllocateCoarraySpec &x) { // R937 845 Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ","); 846 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*'); 847 } 848 void Unparse(const NullifyStmt &x) { // R939 849 Word("NULLIFY("), Walk(x.v, ", "), Put(')'); 850 } 851 void Unparse(const DeallocateStmt &x) { // R941 852 Word("DEALLOCATE("); 853 Walk(std::get<std::list<AllocateObject>>(x.t), ", "); 854 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 855 } 856 void Before(const StatOrErrmsg &x) { // R942 & R1165 857 common::visit(common::visitors{ 858 [&](const StatVariable &) { Word("STAT="); }, 859 [&](const MsgVariable &) { Word("ERRMSG="); }, 860 }, 861 x.u); 862 } 863 864 // R1001 - R1022 865 void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); } 866 void Before(const Expr::UnaryPlus &) { Put("+"); } 867 void Before(const Expr::Negate &) { Put("-"); } 868 void Before(const Expr::NOT &) { Word(".NOT."); } 869 void Unparse(const Expr::PercentLoc &x) { 870 Word("%LOC("), Walk(x.v), Put(')'); 871 } 872 void Unparse(const Expr::Power &x) { Walk(x.t, "**"); } 873 void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); } 874 void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); } 875 void Unparse(const Expr::Add &x) { Walk(x.t, "+"); } 876 void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); } 877 void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); } 878 void Unparse(const Expr::LT &x) { Walk(x.t, "<"); } 879 void Unparse(const Expr::LE &x) { Walk(x.t, "<="); } 880 void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); } 881 void Unparse(const Expr::NE &x) { Walk(x.t, "/="); } 882 void Unparse(const Expr::GE &x) { Walk(x.t, ">="); } 883 void Unparse(const Expr::GT &x) { Walk(x.t, ">"); } 884 void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); } 885 void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); } 886 void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); } 887 void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); } 888 void Unparse(const Expr::ComplexConstructor &x) { 889 Put('('), Walk(x.t, ","), Put(')'); 890 } 891 void Unparse(const Expr::DefinedBinary &x) { 892 Walk(std::get<1>(x.t)); // left 893 Walk(std::get<DefinedOpName>(x.t)); 894 Walk(std::get<2>(x.t)); // right 895 } 896 void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415 897 Walk(x.v); 898 } 899 void Unparse(const AssignmentStmt &x) { // R1032 900 if (asFortran_ && x.typedAssignment.get()) { 901 Put(' '); 902 asFortran_->assignment(out_, *x.typedAssignment); 903 Put('\n'); 904 } else { 905 Walk(x.t, " = "); 906 } 907 } 908 void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038 909 if (asFortran_ && x.typedAssignment.get()) { 910 Put(' '); 911 asFortran_->assignment(out_, *x.typedAssignment); 912 Put('\n'); 913 } else { 914 Walk(std::get<DataRef>(x.t)); 915 common::visit( 916 common::visitors{ 917 [&](const std::list<BoundsRemapping> &y) { 918 Put('('), Walk(y), Put(')'); 919 }, 920 [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); }, 921 }, 922 std::get<PointerAssignmentStmt::Bounds>(x.t).u); 923 Put(" => "), Walk(std::get<Expr>(x.t)); 924 } 925 } 926 void Post(const BoundsSpec &) { // R1035 927 Put(':'); 928 } 929 void Unparse(const BoundsRemapping &x) { // R1036 930 Walk(x.t, ":"); 931 } 932 void Unparse(const WhereStmt &x) { // R1041, R1045, R1046 933 Word("WHERE ("), Walk(x.t, ") "); 934 } 935 void Unparse(const WhereConstructStmt &x) { // R1043 936 Walk(std::get<std::optional<Name>>(x.t), ": "); 937 Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')'); 938 Indent(); 939 } 940 void Unparse(const MaskedElsewhereStmt &x) { // R1047 941 Outdent(); 942 Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')'); 943 Walk(" ", std::get<std::optional<Name>>(x.t)); 944 Indent(); 945 } 946 void Unparse(const ElsewhereStmt &x) { // R1048 947 Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent(); 948 } 949 void Unparse(const EndWhereStmt &x) { // R1049 950 Outdent(), Word("END WHERE"), Walk(" ", x.v); 951 } 952 void Unparse(const ForallConstructStmt &x) { // R1051 953 Walk(std::get<std::optional<Name>>(x.t), ": "); 954 Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t)); 955 Indent(); 956 } 957 void Unparse(const EndForallStmt &x) { // R1054 958 Outdent(), Word("END FORALL"), Walk(" ", x.v); 959 } 960 void Before(const ForallStmt &) { // R1055 961 Word("FORALL"); 962 } 963 964 void Unparse(const AssociateStmt &x) { // R1103 965 Walk(std::get<std::optional<Name>>(x.t), ": "); 966 Word("ASSOCIATE ("); 967 Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent(); 968 } 969 void Unparse(const Association &x) { // R1104 970 Walk(x.t, " => "); 971 } 972 void Unparse(const EndAssociateStmt &x) { // R1106 973 Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v); 974 } 975 void Unparse(const BlockStmt &x) { // R1108 976 Walk(x.v, ": "), Word("BLOCK"), Indent(); 977 } 978 void Unparse(const EndBlockStmt &x) { // R1110 979 Outdent(), Word("END BLOCK"), Walk(" ", x.v); 980 } 981 void Unparse(const ChangeTeamStmt &x) { // R1112 982 Walk(std::get<std::optional<Name>>(x.t), ": "); 983 Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t)); 984 Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", "); 985 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 986 Indent(); 987 } 988 void Unparse(const CoarrayAssociation &x) { // R1113 989 Walk(x.t, " => "); 990 } 991 void Unparse(const EndChangeTeamStmt &x) { // R1114 992 Outdent(), Word("END TEAM ("); 993 Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", "); 994 Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t)); 995 } 996 void Unparse(const CriticalStmt &x) { // R1117 997 Walk(std::get<std::optional<Name>>(x.t), ": "); 998 Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", "); 999 Put(')'), Indent(); 1000 } 1001 void Unparse(const EndCriticalStmt &x) { // R1118 1002 Outdent(), Word("END CRITICAL"), Walk(" ", x.v); 1003 } 1004 void Unparse(const DoConstruct &x) { // R1119, R1120 1005 Walk(std::get<Statement<NonLabelDoStmt>>(x.t)); 1006 Indent(), Walk(std::get<Block>(x.t), ""), Outdent(); 1007 Walk(std::get<Statement<EndDoStmt>>(x.t)); 1008 } 1009 void Unparse(const LabelDoStmt &x) { // R1121 1010 Word("DO "), Walk(std::get<Label>(x.t)); 1011 Walk(" ", std::get<std::optional<LoopControl>>(x.t)); 1012 } 1013 void Unparse(const NonLabelDoStmt &x) { // R1122 1014 Walk(std::get<std::optional<Name>>(x.t), ": "); 1015 Word("DO "); 1016 Walk(std::get<std::optional<Label>>(x.t), " "); 1017 Walk(std::get<std::optional<LoopControl>>(x.t)); 1018 } 1019 void Unparse(const LoopControl &x) { // R1123 1020 common::visit(common::visitors{ 1021 [&](const ScalarLogicalExpr &y) { 1022 Word("WHILE ("), Walk(y), Put(')'); 1023 }, 1024 [&](const auto &y) { Walk(y); }, 1025 }, 1026 x.u); 1027 } 1028 void Unparse(const ConcurrentHeader &x) { // R1125 1029 Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 1030 Walk(std::get<std::list<ConcurrentControl>>(x.t), ", "); 1031 Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')'); 1032 } 1033 void Unparse(const ConcurrentControl &x) { // R1126 - R1128 1034 Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t)); 1035 Put(':'), Walk(std::get<2>(x.t)); 1036 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t)); 1037 } 1038 void Before(const LoopControl::Concurrent &) { // R1129 1039 Word("CONCURRENT"); 1040 } 1041 void Unparse(const LocalitySpec::Local &x) { 1042 Word("LOCAL("), Walk(x.v, ", "), Put(')'); 1043 } 1044 void Unparse(const LocalitySpec::LocalInit &x) { 1045 Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')'); 1046 } 1047 void Unparse(const LocalitySpec::Reduce &x) { 1048 Word("REDUCE("), Walk(std::get<parser::ReductionOperator>(x.t)); 1049 Walk(":", std::get<std::list<parser::Name>>(x.t), ",", ")"); 1050 } 1051 void Unparse(const LocalitySpec::Shared &x) { 1052 Word("SHARED("), Walk(x.v, ", "), Put(')'); 1053 } 1054 void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); } 1055 void Unparse(const EndDoStmt &x) { // R1132 1056 Word("END DO"), Walk(" ", x.v); 1057 } 1058 void Unparse(const CycleStmt &x) { // R1133 1059 Word("CYCLE"), Walk(" ", x.v); 1060 } 1061 void Unparse(const IfThenStmt &x) { // R1135 1062 Walk(std::get<std::optional<Name>>(x.t), ": "); 1063 Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t)); 1064 Put(") "), Word("THEN"), Indent(); 1065 } 1066 void Unparse(const ElseIfStmt &x) { // R1136 1067 Outdent(), Word("ELSE IF ("); 1068 Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN"); 1069 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1070 } 1071 void Unparse(const ElseStmt &x) { // R1137 1072 Outdent(), Word("ELSE"), Walk(" ", x.v), Indent(); 1073 } 1074 void Unparse(const EndIfStmt &x) { // R1138 1075 Outdent(), Word("END IF"), Walk(" ", x.v); 1076 } 1077 void Unparse(const IfStmt &x) { // R1139 1078 Word("IF ("), Walk(x.t, ") "); 1079 } 1080 void Unparse(const SelectCaseStmt &x) { // R1141, R1144 1081 Walk(std::get<std::optional<Name>>(x.t), ": "); 1082 Word("SELECT CASE ("); 1083 Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent(); 1084 } 1085 void Unparse(const CaseStmt &x) { // R1142 1086 Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t)); 1087 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1088 } 1089 void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R1155 1090 Outdent(), Word("END SELECT"), Walk(" ", x.v); 1091 } 1092 void Unparse(const CaseSelector &x) { // R1145 1093 common::visit(common::visitors{ 1094 [&](const std::list<CaseValueRange> &y) { 1095 Put('('), Walk(y), Put(')'); 1096 }, 1097 [&](const Default &) { Word("DEFAULT"); }, 1098 }, 1099 x.u); 1100 } 1101 void Unparse(const CaseValueRange::Range &x) { // R1146 1102 Walk(x.lower), Put(':'), Walk(x.upper); 1103 } 1104 void Unparse(const SelectRankStmt &x) { // R1149 1105 Walk(std::get<0>(x.t), ": "); 1106 Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => "); 1107 Walk(std::get<Selector>(x.t)), Put(')'), Indent(); 1108 } 1109 void Unparse(const SelectRankCaseStmt &x) { // R1150 1110 Outdent(), Word("RANK "); 1111 common::visit(common::visitors{ 1112 [&](const ScalarIntConstantExpr &y) { 1113 Put('('), Walk(y), Put(')'); 1114 }, 1115 [&](const Star &) { Put("(*)"); }, 1116 [&](const Default &) { Word("DEFAULT"); }, 1117 }, 1118 std::get<SelectRankCaseStmt::Rank>(x.t).u); 1119 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1120 } 1121 void Unparse(const SelectTypeStmt &x) { // R1153 1122 Walk(std::get<0>(x.t), ": "); 1123 Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => "); 1124 Walk(std::get<Selector>(x.t)), Put(')'), Indent(); 1125 } 1126 void Unparse(const TypeGuardStmt &x) { // R1154 1127 Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t)); 1128 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1129 } 1130 void Unparse(const TypeGuardStmt::Guard &x) { 1131 common::visit( 1132 common::visitors{ 1133 [&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); }, 1134 [&](const DerivedTypeSpec &y) { 1135 Word("CLASS IS ("), Walk(y), Put(')'); 1136 }, 1137 [&](const Default &) { Word("CLASS DEFAULT"); }, 1138 }, 1139 x.u); 1140 } 1141 void Unparse(const ExitStmt &x) { // R1156 1142 Word("EXIT"), Walk(" ", x.v); 1143 } 1144 void Before(const GotoStmt &) { // R1157 1145 Word("GO TO "); 1146 } 1147 void Unparse(const ComputedGotoStmt &x) { // R1158 1148 Word("GO TO ("), Walk(x.t, "), "); 1149 } 1150 void Unparse(const ContinueStmt &) { // R1159 1151 Word("CONTINUE"); 1152 } 1153 void Unparse(const StopStmt &x) { // R1160, R1161 1154 if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) { 1155 Word("ERROR "); 1156 } 1157 Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t)); 1158 Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t)); 1159 } 1160 void Unparse(const FailImageStmt &) { // R1163 1161 Word("FAIL IMAGE"); 1162 } 1163 void Unparse(const NotifyWaitStmt &x) { // F2023: R1166 1164 Word("NOTIFY WAIT ("), Walk(std::get<Scalar<Variable>>(x.t)); 1165 Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", "); 1166 Put(')'); 1167 } 1168 void Unparse(const SyncAllStmt &x) { // R1164 1169 Word("SYNC ALL ("), Walk(x.v, ", "), Put(')'); 1170 } 1171 void Unparse(const SyncImagesStmt &x) { // R1166 1172 Word("SYNC IMAGES ("); 1173 Walk(std::get<SyncImagesStmt::ImageSet>(x.t)); 1174 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1175 } 1176 void Unparse(const SyncMemoryStmt &x) { // R1168 1177 Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')'); 1178 } 1179 void Unparse(const SyncTeamStmt &x) { // R1169 1180 Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t)); 1181 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1182 } 1183 void Unparse(const EventPostStmt &x) { // R1170 1184 Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t)); 1185 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1186 } 1187 void Before(const EventWaitSpec &x) { // R1173, R1174 1188 common::visit(common::visitors{ 1189 [&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); }, 1190 [](const StatOrErrmsg &) {}, 1191 }, 1192 x.u); 1193 } 1194 void Unparse(const EventWaitStmt &x) { // R1170 1195 Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t)); 1196 Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", "); 1197 Put(')'); 1198 } 1199 void Unparse(const FormTeamStmt &x) { // R1175, R1177 1200 Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t)); 1201 Put(','), Walk(std::get<TeamVariable>(x.t)); 1202 Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", "); 1203 Put(')'); 1204 } 1205 void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1178 1206 common::visit(common::visitors{ 1207 [&](const ScalarIntExpr &) { Word("NEW_INDEX="); }, 1208 [](const StatOrErrmsg &) {}, 1209 }, 1210 x.u); 1211 } 1212 void Unparse(const LockStmt &x) { // R1179 1213 Word("LOCK ("), Walk(std::get<LockVariable>(x.t)); 1214 Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", "); 1215 Put(')'); 1216 } 1217 void Before(const LockStmt::LockStat &x) { // R1180 1218 common::visit( 1219 common::visitors{ 1220 [&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); }, 1221 [](const StatOrErrmsg &) {}, 1222 }, 1223 x.u); 1224 } 1225 void Unparse(const UnlockStmt &x) { // R1181 1226 Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t)); 1227 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "); 1228 Put(')'); 1229 } 1230 1231 void Unparse(const OpenStmt &x) { // R1204 1232 Word("OPEN ("), Walk(x.v, ", "), Put(')'); 1233 } 1234 bool Pre(const ConnectSpec &x) { // R1205 1235 return common::visit(common::visitors{ 1236 [&](const FileUnitNumber &) { 1237 Word("UNIT="); 1238 return true; 1239 }, 1240 [&](const FileNameExpr &) { 1241 Word("FILE="); 1242 return true; 1243 }, 1244 [&](const ConnectSpec::CharExpr &y) { 1245 Walk(y.t, "="); 1246 return false; 1247 }, 1248 [&](const MsgVariable &) { 1249 Word("IOMSG="); 1250 return true; 1251 }, 1252 [&](const StatVariable &) { 1253 Word("IOSTAT="); 1254 return true; 1255 }, 1256 [&](const ConnectSpec::Recl &) { 1257 Word("RECL="); 1258 return true; 1259 }, 1260 [&](const ConnectSpec::Newunit &) { 1261 Word("NEWUNIT="); 1262 return true; 1263 }, 1264 [&](const ErrLabel &) { 1265 Word("ERR="); 1266 return true; 1267 }, 1268 [&](const StatusExpr &) { 1269 Word("STATUS="); 1270 return true; 1271 }, 1272 }, 1273 x.u); 1274 } 1275 void Unparse(const CloseStmt &x) { // R1208 1276 Word("CLOSE ("), Walk(x.v, ", "), Put(')'); 1277 } 1278 void Before(const CloseStmt::CloseSpec &x) { // R1209 1279 common::visit(common::visitors{ 1280 [&](const FileUnitNumber &) { Word("UNIT="); }, 1281 [&](const StatVariable &) { Word("IOSTAT="); }, 1282 [&](const MsgVariable &) { Word("IOMSG="); }, 1283 [&](const ErrLabel &) { Word("ERR="); }, 1284 [&](const StatusExpr &) { Word("STATUS="); }, 1285 }, 1286 x.u); 1287 } 1288 void Unparse(const ReadStmt &x) { // R1210 1289 Word("READ "); 1290 if (x.iounit) { 1291 Put('('), Walk(x.iounit); 1292 if (x.format) { 1293 Put(", "), Walk(x.format); 1294 } 1295 Walk(", ", x.controls, ", "); 1296 Put(')'); 1297 } else if (x.format) { 1298 Walk(x.format); 1299 if (!x.items.empty()) { 1300 Put(", "); 1301 } 1302 } else { 1303 Put('('), Walk(x.controls, ", "), Put(')'); 1304 } 1305 Walk(" ", x.items, ", "); 1306 } 1307 void Unparse(const WriteStmt &x) { // R1211 1308 Word("WRITE ("); 1309 if (x.iounit) { 1310 Walk(x.iounit); 1311 if (x.format) { 1312 Put(", "), Walk(x.format); 1313 } 1314 Walk(", ", x.controls, ", "); 1315 } else { 1316 Walk(x.controls, ", "); 1317 } 1318 Put(')'), Walk(" ", x.items, ", "); 1319 } 1320 void Unparse(const PrintStmt &x) { // R1212 1321 Word("PRINT "), Walk(std::get<Format>(x.t)); 1322 Walk(", ", std::get<std::list<OutputItem>>(x.t), ", "); 1323 } 1324 bool Pre(const IoControlSpec &x) { // R1213 1325 return common::visit(common::visitors{ 1326 [&](const IoUnit &) { 1327 Word("UNIT="); 1328 return true; 1329 }, 1330 [&](const Format &) { 1331 Word("FMT="); 1332 return true; 1333 }, 1334 [&](const Name &) { 1335 Word("NML="); 1336 return true; 1337 }, 1338 [&](const IoControlSpec::CharExpr &y) { 1339 Walk(y.t, "="); 1340 return false; 1341 }, 1342 [&](const IoControlSpec::Asynchronous &) { 1343 Word("ASYNCHRONOUS="); 1344 return true; 1345 }, 1346 [&](const EndLabel &) { 1347 Word("END="); 1348 return true; 1349 }, 1350 [&](const EorLabel &) { 1351 Word("EOR="); 1352 return true; 1353 }, 1354 [&](const ErrLabel &) { 1355 Word("ERR="); 1356 return true; 1357 }, 1358 [&](const IdVariable &) { 1359 Word("ID="); 1360 return true; 1361 }, 1362 [&](const MsgVariable &) { 1363 Word("IOMSG="); 1364 return true; 1365 }, 1366 [&](const StatVariable &) { 1367 Word("IOSTAT="); 1368 return true; 1369 }, 1370 [&](const IoControlSpec::Pos &) { 1371 Word("POS="); 1372 return true; 1373 }, 1374 [&](const IoControlSpec::Rec &) { 1375 Word("REC="); 1376 return true; 1377 }, 1378 [&](const IoControlSpec::Size &) { 1379 Word("SIZE="); 1380 return true; 1381 }, 1382 }, 1383 x.u); 1384 } 1385 void Unparse(const InputImpliedDo &x) { // R1218 1386 Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", "); 1387 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')'); 1388 } 1389 void Unparse(const OutputImpliedDo &x) { // R1219 1390 Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", "); 1391 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')'); 1392 } 1393 void Unparse(const WaitStmt &x) { // R1222 1394 Word("WAIT ("), Walk(x.v, ", "), Put(')'); 1395 } 1396 void Before(const WaitSpec &x) { // R1223 1397 common::visit(common::visitors{ 1398 [&](const FileUnitNumber &) { Word("UNIT="); }, 1399 [&](const EndLabel &) { Word("END="); }, 1400 [&](const EorLabel &) { Word("EOR="); }, 1401 [&](const ErrLabel &) { Word("ERR="); }, 1402 [&](const IdExpr &) { Word("ID="); }, 1403 [&](const MsgVariable &) { Word("IOMSG="); }, 1404 [&](const StatVariable &) { Word("IOSTAT="); }, 1405 }, 1406 x.u); 1407 } 1408 void Unparse(const BackspaceStmt &x) { // R1224 1409 Word("BACKSPACE ("), Walk(x.v, ", "), Put(')'); 1410 } 1411 void Unparse(const EndfileStmt &x) { // R1225 1412 Word("ENDFILE ("), Walk(x.v, ", "), Put(')'); 1413 } 1414 void Unparse(const RewindStmt &x) { // R1226 1415 Word("REWIND ("), Walk(x.v, ", "), Put(')'); 1416 } 1417 void Before(const PositionOrFlushSpec &x) { // R1227 & R1229 1418 common::visit(common::visitors{ 1419 [&](const FileUnitNumber &) { Word("UNIT="); }, 1420 [&](const MsgVariable &) { Word("IOMSG="); }, 1421 [&](const StatVariable &) { Word("IOSTAT="); }, 1422 [&](const ErrLabel &) { Word("ERR="); }, 1423 }, 1424 x.u); 1425 } 1426 void Unparse(const FlushStmt &x) { // R1228 1427 Word("FLUSH ("), Walk(x.v, ", "), Put(')'); 1428 } 1429 void Unparse(const InquireStmt &x) { // R1230 1430 Word("INQUIRE ("); 1431 common::visit( 1432 common::visitors{ 1433 [&](const InquireStmt::Iolength &y) { 1434 Word("IOLENGTH="), Walk(y.t, ") "); 1435 }, 1436 [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); }, 1437 }, 1438 x.u); 1439 } 1440 bool Pre(const InquireSpec &x) { // R1231 1441 return common::visit(common::visitors{ 1442 [&](const FileUnitNumber &) { 1443 Word("UNIT="); 1444 return true; 1445 }, 1446 [&](const FileNameExpr &) { 1447 Word("FILE="); 1448 return true; 1449 }, 1450 [&](const InquireSpec::CharVar &y) { 1451 Walk(y.t, "="); 1452 return false; 1453 }, 1454 [&](const InquireSpec::IntVar &y) { 1455 Walk(y.t, "="); 1456 return false; 1457 }, 1458 [&](const InquireSpec::LogVar &y) { 1459 Walk(y.t, "="); 1460 return false; 1461 }, 1462 [&](const IdExpr &) { 1463 Word("ID="); 1464 return true; 1465 }, 1466 [&](const ErrLabel &) { 1467 Word("ERR="); 1468 return true; 1469 }, 1470 }, 1471 x.u); 1472 } 1473 1474 void Before(const FormatStmt &) { // R1301 1475 Word("FORMAT"); 1476 } 1477 void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R1305 1478 Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ","); 1479 Walk("*(", x.unlimitedItems, ",", ")"), Put(')'); 1480 } 1481 void Unparse(const format::FormatItem &x) { // R1304, R1306, R1321 1482 if (x.repeatCount) { 1483 Walk(*x.repeatCount); 1484 } 1485 common::visit(common::visitors{ 1486 [&](const std::string &y) { PutNormalized(y); }, 1487 [&](const std::list<format::FormatItem> &y) { 1488 Walk("(", y, ",", ")"); 1489 }, 1490 [&](const auto &y) { Walk(y); }, 1491 }, 1492 x.u); 1493 } 1494 void Unparse( 1495 const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311 1496 switch (x.kind) { 1497 #define FMT(x) \ 1498 case format::IntrinsicTypeDataEditDesc::Kind::x: \ 1499 Put(#x); \ 1500 break 1501 FMT(I); 1502 FMT(B); 1503 FMT(O); 1504 FMT(Z); 1505 FMT(F); 1506 FMT(E); 1507 FMT(EN); 1508 FMT(ES); 1509 FMT(EX); 1510 FMT(G); 1511 FMT(L); 1512 FMT(A); 1513 FMT(D); 1514 #undef FMT 1515 } 1516 Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth); 1517 } 1518 void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312 1519 Word("DT"); 1520 if (!x.type.empty()) { 1521 Put('"'), Put(x.type), Put('"'); 1522 } 1523 Walk("(", x.parameters, ",", ")"); 1524 } 1525 void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R1320 1526 switch (x.kind) { 1527 case format::ControlEditDesc::Kind::T: 1528 Word("T"); 1529 Walk(x.count); 1530 break; 1531 case format::ControlEditDesc::Kind::TL: 1532 Word("TL"); 1533 Walk(x.count); 1534 break; 1535 case format::ControlEditDesc::Kind::TR: 1536 Word("TR"); 1537 Walk(x.count); 1538 break; 1539 case format::ControlEditDesc::Kind::X: 1540 if (x.count != 1) { 1541 Walk(x.count); 1542 } 1543 Word("X"); 1544 break; 1545 case format::ControlEditDesc::Kind::Slash: 1546 if (x.count != 1) { 1547 Walk(x.count); 1548 } 1549 Put('/'); 1550 break; 1551 case format::ControlEditDesc::Kind::Colon: 1552 Put(':'); 1553 break; 1554 case format::ControlEditDesc::Kind::P: 1555 Walk(x.count); 1556 Word("P"); 1557 break; 1558 #define FMT(x) \ 1559 case format::ControlEditDesc::Kind::x: \ 1560 Put(#x); \ 1561 break 1562 FMT(SS); 1563 FMT(SP); 1564 FMT(S); 1565 FMT(BN); 1566 FMT(BZ); 1567 FMT(RU); 1568 FMT(RD); 1569 FMT(RZ); 1570 FMT(RN); 1571 FMT(RC); 1572 FMT(RP); 1573 FMT(DC); 1574 FMT(DP); 1575 #undef FMT 1576 case format::ControlEditDesc::Kind::Dollar: 1577 Put('$'); 1578 break; 1579 case format::ControlEditDesc::Kind::Backslash: 1580 Put('\\'); 1581 break; 1582 } 1583 } 1584 1585 void Before(const MainProgram &x) { // R1401 1586 if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) { 1587 Indent(); 1588 } 1589 } 1590 void Before(const ProgramStmt &) { // R1402 1591 Word("PROGRAM "), Indent(); 1592 } 1593 void Unparse(const EndProgramStmt &x) { // R1403 1594 EndSubprogram("PROGRAM", x.v); 1595 } 1596 void Before(const ModuleStmt &) { // R1405 1597 Word("MODULE "), Indent(); 1598 } 1599 void Unparse(const EndModuleStmt &x) { // R1406 1600 EndSubprogram("MODULE", x.v); 1601 } 1602 void Unparse(const UseStmt &x) { // R1409 1603 Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName); 1604 common::visit( 1605 common::visitors{ 1606 [&](const std::list<Rename> &y) { Walk(", ", y, ", "); }, 1607 [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); }, 1608 }, 1609 x.u); 1610 } 1611 void Unparse(const Rename &x) { // R1411 1612 common::visit(common::visitors{ 1613 [&](const Rename::Names &y) { Walk(y.t, " => "); }, 1614 [&](const Rename::Operators &y) { 1615 Word("OPERATOR("), Walk(y.t, ") => OPERATOR("), 1616 Put(")"); 1617 }, 1618 }, 1619 x.u); 1620 } 1621 void Unparse(const SubmoduleStmt &x) { // R1417 1622 Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent(); 1623 } 1624 void Unparse(const ParentIdentifier &x) { // R1418 1625 Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t)); 1626 } 1627 void Unparse(const EndSubmoduleStmt &x) { // R1419 1628 EndSubprogram("SUBMODULE", x.v); 1629 } 1630 void Unparse(const BlockDataStmt &x) { // R1421 1631 Word("BLOCK DATA"), Walk(" ", x.v), Indent(); 1632 } 1633 void Unparse(const EndBlockDataStmt &x) { // R1422 1634 EndSubprogram("BLOCK DATA", x.v); 1635 } 1636 1637 void Unparse(const InterfaceStmt &x) { // R1503 1638 common::visit(common::visitors{ 1639 [&](const std::optional<GenericSpec> &y) { 1640 Word("INTERFACE"), Walk(" ", y); 1641 }, 1642 [&](const Abstract &) { Word("ABSTRACT INTERFACE"); }, 1643 }, 1644 x.u); 1645 Indent(); 1646 } 1647 void Unparse(const EndInterfaceStmt &x) { // R1504 1648 Outdent(), Word("END INTERFACE"), Walk(" ", x.v); 1649 } 1650 void Unparse(const ProcedureStmt &x) { // R1506 1651 if (std::get<ProcedureStmt::Kind>(x.t) == 1652 ProcedureStmt::Kind::ModuleProcedure) { 1653 Word("MODULE "); 1654 } 1655 Word("PROCEDURE :: "); 1656 Walk(std::get<std::list<Name>>(x.t), ", "); 1657 } 1658 void Before(const GenericSpec &x) { // R1508, R1509 1659 common::visit( 1660 common::visitors{ 1661 [&](const DefinedOperator &) { Word("OPERATOR("); }, 1662 [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); }, 1663 [&](const GenericSpec::ReadFormatted &) { 1664 Word("READ(FORMATTED)"); 1665 }, 1666 [&](const GenericSpec::ReadUnformatted &) { 1667 Word("READ(UNFORMATTED)"); 1668 }, 1669 [&](const GenericSpec::WriteFormatted &) { 1670 Word("WRITE(FORMATTED)"); 1671 }, 1672 [&](const GenericSpec::WriteUnformatted &) { 1673 Word("WRITE(UNFORMATTED)"); 1674 }, 1675 [](const auto &) {}, 1676 }, 1677 x.u); 1678 } 1679 void Post(const GenericSpec &x) { 1680 common::visit(common::visitors{ 1681 [&](const DefinedOperator &) { Put(')'); }, 1682 [](const auto &) {}, 1683 }, 1684 x.u); 1685 } 1686 void Unparse(const GenericStmt &x) { // R1510 1687 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t)); 1688 Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => "); 1689 Walk(std::get<std::list<Name>>(x.t), ", "); 1690 } 1691 void Unparse(const ExternalStmt &x) { // R1511 1692 Word("EXTERNAL :: "), Walk(x.v, ", "); 1693 } 1694 void Unparse(const ProcedureDeclarationStmt &x) { // R1512 1695 Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t)); 1696 Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", "); 1697 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", "); 1698 } 1699 void Unparse(const ProcDecl &x) { // R1515 1700 Walk(std::get<Name>(x.t)); 1701 Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t)); 1702 } 1703 void Unparse(const IntrinsicStmt &x) { // R1519 1704 Word("INTRINSIC :: "), Walk(x.v, ", "); 1705 } 1706 void Unparse(const CallStmt::StarOrExpr &x) { 1707 if (x.v) { 1708 Walk(*x.v); 1709 } else { 1710 Word("*"); 1711 } 1712 } 1713 void Unparse(const CallStmt::Chevrons &x) { // CUDA 1714 Walk(std::get<0>(x.t)); // grid 1715 Word(","), Walk(std::get<1>(x.t)); // block 1716 Walk(",", std::get<2>(x.t)); // bytes 1717 Walk(",", std::get<3>(x.t)); // stream 1718 } 1719 void Unparse(const FunctionReference &x) { // R1520 1720 Walk(std::get<ProcedureDesignator>(x.v.t)); 1721 Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')'); 1722 } 1723 void Unparse(const CallStmt &x) { // R1521 1724 if (asFortran_ && x.typedCall.get()) { 1725 Put(' '); 1726 asFortran_->call(out_, *x.typedCall); 1727 Put('\n'); 1728 } else { 1729 const auto &pd{std::get<ProcedureDesignator>(x.call.t)}; 1730 Word("CALL "), Walk(pd); 1731 Walk("<<<", x.chevrons, ">>>"); 1732 const auto &args{std::get<std::list<ActualArgSpec>>(x.call.t)}; 1733 if (args.empty()) { 1734 if (std::holds_alternative<ProcComponentRef>(pd.u)) { 1735 Put("()"); // pgf90 crashes on CALL to tbp without parentheses 1736 } 1737 } else { 1738 Walk("(", args, ", ", ")"); 1739 } 1740 } 1741 } 1742 void Unparse(const ActualArgSpec &x) { // R1523 1743 Walk(std::get<std::optional<Keyword>>(x.t), "="); 1744 Walk(std::get<ActualArg>(x.t)); 1745 } 1746 void Unparse(const ActualArg::PercentRef &x) { // R1524 1747 Word("%REF("), Walk(x.v), Put(')'); 1748 } 1749 void Unparse(const ActualArg::PercentVal &x) { 1750 Word("%VAL("), Walk(x.v), Put(')'); 1751 } 1752 void Before(const AltReturnSpec &) { // R1525 1753 Put('*'); 1754 } 1755 void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527 1756 void Post(const PrefixSpec::Impure) { Word("IMPURE"); } 1757 void Post(const PrefixSpec::Module) { Word("MODULE"); } 1758 void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); } 1759 void Post(const PrefixSpec::Pure) { Word("PURE"); } 1760 void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); } 1761 void Unparse(const PrefixSpec::Attributes &x) { 1762 Word("ATTRIBUTES("), Walk(x.v), Word(")"); 1763 } 1764 void Unparse(const PrefixSpec::Launch_Bounds &x) { 1765 Word("LAUNCH_BOUNDS("), Walk(x.v), Word(")"); 1766 } 1767 void Unparse(const PrefixSpec::Cluster_Dims &x) { 1768 Word("CLUSTER_DIMS("), Walk(x.v), Word(")"); 1769 } 1770 void Unparse(const FunctionStmt &x) { // R1530 1771 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " "); 1772 Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("("); 1773 Walk(std::get<std::list<Name>>(x.t), ", "), Put(')'); 1774 Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent(); 1775 } 1776 void Unparse(const Suffix &x) { // R1532 1777 if (x.resultName) { 1778 Word("RESULT("), Walk(x.resultName), Put(')'); 1779 Walk(" ", x.binding); 1780 } else { 1781 Walk(x.binding); 1782 } 1783 } 1784 void Unparse(const EndFunctionStmt &x) { // R1533 1785 EndSubprogram("FUNCTION", x.v); 1786 } 1787 void Unparse(const SubroutineStmt &x) { // R1535 1788 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " "); 1789 Word("SUBROUTINE "), Walk(std::get<Name>(x.t)); 1790 const auto &args{std::get<std::list<DummyArg>>(x.t)}; 1791 const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)}; 1792 if (args.empty()) { 1793 Walk(" () ", bind); 1794 } else { 1795 Walk(" (", args, ", ", ")"); 1796 Walk(" ", bind); 1797 } 1798 Indent(); 1799 } 1800 void Unparse(const EndSubroutineStmt &x) { // R1537 1801 EndSubprogram("SUBROUTINE", x.v); 1802 } 1803 void Before(const MpSubprogramStmt &) { // R1539 1804 Word("MODULE PROCEDURE "), Indent(); 1805 } 1806 void Unparse(const EndMpSubprogramStmt &x) { // R1540 1807 EndSubprogram("PROCEDURE", x.v); 1808 } 1809 void Unparse(const EntryStmt &x) { // R1541 1810 Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("("); 1811 Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")"); 1812 Walk(" ", std::get<std::optional<Suffix>>(x.t)); 1813 } 1814 void Unparse(const ReturnStmt &x) { // R1542 1815 Word("RETURN"), Walk(" ", x.v); 1816 } 1817 void Unparse(const ContainsStmt &) { // R1543 1818 Outdent(); 1819 Word("CONTAINS"); 1820 Indent(); 1821 } 1822 void Unparse(const StmtFunctionStmt &x) { // R1544 1823 Walk(std::get<Name>(x.t)), Put('('); 1824 Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = "); 1825 Walk(std::get<Scalar<Expr>>(x.t)); 1826 } 1827 1828 // Directives, extensions, and deprecated constructs 1829 void Unparse(const CompilerDirective &x) { 1830 common::visit( 1831 common::visitors{ 1832 [&](const std::list<CompilerDirective::IgnoreTKR> &tkr) { 1833 Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty 1834 Walk(" ", tkr, ", "); 1835 }, 1836 [&](const CompilerDirective::LoopCount &lcount) { 1837 Walk("!DIR$ LOOP COUNT (", lcount.v, ", ", ")"); 1838 }, 1839 [&](const std::list<CompilerDirective::AssumeAligned> 1840 &assumeAligned) { 1841 Word("!DIR$ ASSUME_ALIGNED "); 1842 Walk(" ", assumeAligned, ", "); 1843 }, 1844 [&](const CompilerDirective::VectorAlways &valways) { 1845 Word("!DIR$ VECTOR ALWAYS"); 1846 }, 1847 [&](const std::list<CompilerDirective::NameValue> &names) { 1848 Walk("!DIR$ ", names, " "); 1849 }, 1850 [&](const CompilerDirective::Unrecognized &) { 1851 Word("!DIR$ "); 1852 Word(x.source.ToString()); 1853 }, 1854 }, 1855 x.u); 1856 Put('\n'); 1857 } 1858 void Unparse(const CompilerDirective::IgnoreTKR &x) { 1859 if (const auto &maybeList{ 1860 std::get<std::optional<std::list<const char *>>>(x.t)}) { 1861 Put("("); 1862 for (const char *tkr : *maybeList) { 1863 Put(*tkr); 1864 } 1865 Put(") "); 1866 } 1867 Walk(std::get<Name>(x.t)); 1868 } 1869 void Unparse(const CompilerDirective::NameValue &x) { 1870 Walk(std::get<Name>(x.t)); 1871 Walk("=", std::get<std::optional<std::uint64_t>>(x.t)); 1872 } 1873 void Unparse(const CompilerDirective::AssumeAligned &x) { 1874 Walk(std::get<common::Indirection<Designator>>(x.t)); 1875 Put(":"); 1876 Walk(std::get<uint64_t>(x.t)); 1877 } 1878 1879 // OpenACC Directives & Clauses 1880 void Unparse(const AccAtomicCapture &x) { 1881 BeginOpenACC(); 1882 Word("!$ACC CAPTURE"); 1883 Put("\n"); 1884 EndOpenACC(); 1885 Walk(std::get<AccAtomicCapture::Stmt1>(x.t)); 1886 Put("\n"); 1887 Walk(std::get<AccAtomicCapture::Stmt2>(x.t)); 1888 BeginOpenACC(); 1889 Word("!$ACC END ATOMIC\n"); 1890 EndOpenACC(); 1891 } 1892 void Unparse(const AccAtomicRead &x) { 1893 BeginOpenACC(); 1894 Word("!$ACC ATOMIC READ"); 1895 Put("\n"); 1896 EndOpenACC(); 1897 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1898 BeginOpenACC(); 1899 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1900 EndOpenACC(); 1901 } 1902 void Unparse(const AccAtomicWrite &x) { 1903 BeginOpenACC(); 1904 Word("!$ACC ATOMIC WRITE"); 1905 Put("\n"); 1906 EndOpenACC(); 1907 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1908 BeginOpenACC(); 1909 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1910 EndOpenACC(); 1911 } 1912 void Unparse(const AccAtomicUpdate &x) { 1913 BeginOpenACC(); 1914 Word("!$ACC ATOMIC UPDATE"); 1915 Put("\n"); 1916 EndOpenACC(); 1917 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1918 BeginOpenACC(); 1919 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1920 EndOpenACC(); 1921 } 1922 void Unparse(const llvm::acc::Directive &x) { 1923 Word(llvm::acc::getOpenACCDirectiveName(x).str()); 1924 } 1925 #define GEN_FLANG_CLAUSE_UNPARSE 1926 #include "llvm/Frontend/OpenACC/ACC.inc" 1927 void Unparse(const AccObjectListWithModifier &x) { 1928 Walk(std::get<std::optional<AccDataModifier>>(x.t), ":"); 1929 Walk(std::get<AccObjectList>(x.t)); 1930 } 1931 void Unparse(const AccBindClause &x) { 1932 common::visit(common::visitors{ 1933 [&](const Name &y) { Walk(y); }, 1934 [&](const ScalarDefaultCharExpr &y) { Walk(y); }, 1935 }, 1936 x.u); 1937 } 1938 void Unparse(const AccDefaultClause &x) { 1939 switch (x.v) { 1940 case llvm::acc::DefaultValue::ACC_Default_none: 1941 Put("NONE"); 1942 break; 1943 case llvm::acc::DefaultValue::ACC_Default_present: 1944 Put("PRESENT"); 1945 break; 1946 } 1947 } 1948 void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); } 1949 void Unparse(const AccGangArgList &x) { Walk(x.v, ","); } 1950 void Before(const AccSizeExpr &x) { 1951 if (!x.v) 1952 Put("*"); 1953 } 1954 void Before(const AccGangArg &x) { 1955 common::visit(common::visitors{ 1956 [&](const AccGangArg::Num &) { Word("NUM:"); }, 1957 [&](const AccGangArg::Dim &) { Word("DIM:"); }, 1958 [&](const AccGangArg::Static &) { Word("STATIC:"); }, 1959 [](const StatOrErrmsg &) {}, 1960 }, 1961 x.u); 1962 } 1963 void Unparse(const AccCollapseArg &x) { 1964 const auto &force{std::get<bool>(x.t)}; 1965 const auto &collapseValue{std::get<parser::ScalarIntConstantExpr>(x.t)}; 1966 if (force) { 1967 Put("FORCE:"); 1968 } 1969 Walk(collapseValue); 1970 } 1971 void Unparse(const OpenACCBlockConstruct &x) { 1972 BeginOpenACC(); 1973 Word("!$ACC "); 1974 Walk(std::get<AccBeginBlockDirective>(x.t)); 1975 Put("\n"); 1976 EndOpenACC(); 1977 Walk(std::get<Block>(x.t), ""); 1978 BeginOpenACC(); 1979 Word("!$ACC END "); 1980 Walk(std::get<AccEndBlockDirective>(x.t)); 1981 Put("\n"); 1982 EndOpenACC(); 1983 } 1984 void Unparse(const OpenACCLoopConstruct &x) { 1985 BeginOpenACC(); 1986 Word("!$ACC "); 1987 Walk(std::get<AccBeginLoopDirective>(x.t)); 1988 Put("\n"); 1989 EndOpenACC(); 1990 Walk(std::get<std::optional<DoConstruct>>(x.t)); 1991 } 1992 void Unparse(const AccBeginLoopDirective &x) { 1993 Walk(std::get<AccLoopDirective>(x.t)); 1994 Walk(std::get<AccClauseList>(x.t)); 1995 } 1996 void Unparse(const OpenACCStandaloneConstruct &x) { 1997 BeginOpenACC(); 1998 Word("!$ACC "); 1999 Walk(std::get<AccStandaloneDirective>(x.t)); 2000 Walk(std::get<AccClauseList>(x.t)); 2001 Put("\n"); 2002 EndOpenACC(); 2003 } 2004 void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) { 2005 BeginOpenACC(); 2006 Word("!$ACC "); 2007 Walk(std::get<AccDeclarativeDirective>(x.t)); 2008 Walk(std::get<AccClauseList>(x.t)); 2009 Put("\n"); 2010 EndOpenACC(); 2011 } 2012 void Unparse(const OpenACCCombinedConstruct &x) { 2013 BeginOpenACC(); 2014 Word("!$ACC "); 2015 Walk(std::get<AccBeginCombinedDirective>(x.t)); 2016 Put("\n"); 2017 EndOpenACC(); 2018 Walk(std::get<std::optional<DoConstruct>>(x.t)); 2019 BeginOpenACC(); 2020 Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t), 2021 "\n"); 2022 EndOpenACC(); 2023 } 2024 void Unparse(const OpenACCRoutineConstruct &x) { 2025 BeginOpenACC(); 2026 Word("!$ACC ROUTINE"); 2027 Walk("(", std::get<std::optional<Name>>(x.t), ")"); 2028 Walk(std::get<AccClauseList>(x.t)); 2029 Put("\n"); 2030 EndOpenACC(); 2031 } 2032 void Unparse(const AccObject &x) { 2033 common::visit(common::visitors{ 2034 [&](const Designator &y) { Walk(y); }, 2035 [&](const Name &y) { Put("/"), Walk(y), Put("/"); }, 2036 }, 2037 x.u); 2038 } 2039 void Unparse(const AccObjectList &x) { Walk(x.v, ","); } 2040 void Unparse(const AccObjectListWithReduction &x) { 2041 Walk(std::get<ReductionOperator>(x.t)); 2042 Put(":"); 2043 Walk(std::get<AccObjectList>(x.t)); 2044 } 2045 void Unparse(const OpenACCCacheConstruct &x) { 2046 BeginOpenACC(); 2047 Word("!$ACC "); 2048 Word("CACHE("); 2049 Walk(std::get<AccObjectListWithModifier>(x.t)); 2050 Put(")"); 2051 Put("\n"); 2052 EndOpenACC(); 2053 } 2054 void Unparse(const AccWaitArgument &x) { 2055 Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":"); 2056 Walk(std::get<std::list<ScalarIntExpr>>(x.t), ","); 2057 } 2058 void Unparse(const OpenACCWaitConstruct &x) { 2059 BeginOpenACC(); 2060 Word("!$ACC "); 2061 Word("WAIT("); 2062 Walk(std::get<std::optional<AccWaitArgument>>(x.t)); 2063 Walk(std::get<AccClauseList>(x.t)); 2064 Put(")"); 2065 Put("\n"); 2066 EndOpenACC(); 2067 } 2068 2069 // OpenMP Clauses & Directives 2070 void Unparse(const OmpObject &x) { 2071 common::visit(common::visitors{ 2072 [&](const Designator &y) { Walk(y); }, 2073 [&](const Name &y) { Put("/"), Walk(y), Put("/"); }, 2074 }, 2075 x.u); 2076 } 2077 void Unparse(const OmpIteratorSpecifier &x) { 2078 Walk(std::get<TypeDeclarationStmt>(x.t)); 2079 Put(" = "); 2080 Walk(std::get<SubscriptTriplet>(x.t)); 2081 } 2082 void Unparse(const OmpIterator &x) { 2083 Word("ITERATOR("); 2084 Walk(x.v); 2085 Put(")"); 2086 } 2087 void Unparse(const OmpLastprivateClause &x) { 2088 Walk( 2089 std::get<std::optional<OmpLastprivateClause::LastprivateModifier>>(x.t), 2090 ":"); 2091 Walk(std::get<OmpObjectList>(x.t)); 2092 } 2093 void Unparse(const OmpMapClause &x) { 2094 auto &typeMod = 2095 std::get<std::optional<std::list<OmpMapClause::TypeModifier>>>(x.t); 2096 auto &iter = std::get<std::optional<std::list<OmpIterator>>>(x.t); 2097 auto &type = std::get<std::optional<std::list<OmpMapClause::Type>>>(x.t); 2098 auto &mapper = std::get<OmpMapperIdentifier>(x.t); 2099 2100 // For a given list of items, if the item has a value, then walk it. 2101 // Print commas between items that have values. 2102 // Return 'true' if something did get printed, otherwise 'false'. 2103 bool needComma{false}; 2104 if (mapper.v) { 2105 Word("MAPPER("); 2106 Walk(*mapper.v); 2107 Put(")"); 2108 needComma = true; 2109 } 2110 if (typeMod) { 2111 if (needComma) { 2112 Put(", "); 2113 } 2114 Walk(*typeMod); 2115 needComma = true; 2116 } 2117 if (iter) { 2118 if (needComma) { 2119 Put(", "); 2120 } 2121 Walk(*iter); 2122 needComma = true; 2123 } 2124 if (type) { 2125 if (needComma) { 2126 Put(", "); 2127 } 2128 Walk(*type); 2129 needComma = true; 2130 } 2131 if (needComma) { 2132 Put(": "); 2133 } 2134 Walk(std::get<OmpObjectList>(x.t)); 2135 } 2136 void Unparse(const OmpScheduleClause &x) { 2137 using Modifier = OmpScheduleClause::Modifier; 2138 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":"); 2139 Walk(std::get<OmpScheduleClause::Kind>(x.t)); 2140 Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t)); 2141 } 2142 void Unparse(const OmpDeviceClause &x) { 2143 Walk(std::get<std::optional<OmpDeviceClause::DeviceModifier>>(x.t), ":"); 2144 Walk(std::get<ScalarIntExpr>(x.t)); 2145 } 2146 void Unparse(const OmpAffinityClause &x) { 2147 Walk(std::get<std::optional<OmpIterator>>(x.t), ":"); 2148 Walk(std::get<OmpObjectList>(x.t)); 2149 } 2150 void Unparse(const OmpAlignedClause &x) { 2151 Walk(std::get<OmpObjectList>(x.t)); 2152 Put(","); 2153 Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t)); 2154 } 2155 void Unparse(const OmpFromClause &x) { 2156 auto &expect{ 2157 std::get<std::optional<std::list<OmpFromClause::Expectation>>>(x.t)}; 2158 auto &iter{std::get<std::optional<std::list<OmpIterator>>>(x.t)}; 2159 bool needComma{false}; 2160 if (expect) { 2161 Walk(*expect); 2162 needComma = true; 2163 } 2164 if (iter) { 2165 if (needComma) { 2166 Put(", "); 2167 } 2168 Walk(*iter); 2169 needComma = true; 2170 } 2171 if (needComma) { 2172 Put(": "); 2173 } 2174 Walk(std::get<OmpObjectList>(x.t)); 2175 } 2176 void Unparse(const OmpIfClause &x) { 2177 Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":"); 2178 Walk(std::get<ScalarLogicalExpr>(x.t)); 2179 } 2180 void Unparse(const OmpLinearClause::WithoutModifier &x) { 2181 Walk(x.names, ", "); 2182 Walk(":", x.step); 2183 } 2184 void Unparse(const OmpLinearClause::WithModifier &x) { 2185 Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")"); 2186 Walk(":", x.step); 2187 } 2188 void Unparse(const OmpReductionClause &x) { 2189 using Modifier = OmpReductionClause::Modifier; 2190 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":"); 2191 Walk(std::get<OmpObjectList>(x.t)); 2192 } 2193 void Unparse(const OmpDetachClause &x) { Walk(x.v); } 2194 void Unparse(const OmpInReductionClause &x) { 2195 Walk(std::get<OmpReductionIdentifier>(x.t)); 2196 Put(":"); 2197 Walk(std::get<OmpObjectList>(x.t)); 2198 } 2199 void Unparse(const OmpAllocateClause &x) { 2200 Walk( 2201 std::get<std::optional<OmpAllocateClause::AllocateModifier>>(x.t), ":"); 2202 Walk(std::get<OmpObjectList>(x.t)); 2203 } 2204 void Unparse(const OmpAllocateClause::AllocateModifier &x) { 2205 common::visit( 2206 common::visitors{ 2207 [&](const OmpAllocateClause::AllocateModifier::Allocator &y) { 2208 Walk(y); 2209 }, 2210 [&](const OmpAllocateClause::AllocateModifier::ComplexModifier &y) { 2211 Word("ALLOCATOR("); 2212 Walk(std::get<OmpAllocateClause::AllocateModifier::Allocator>( 2213 y.t)); 2214 Put(")"); 2215 Put(","); 2216 Walk(std::get<OmpAllocateClause::AllocateModifier::Align>(y.t)); 2217 }, 2218 [&](const OmpAllocateClause::AllocateModifier::Align &y) { 2219 Walk(y); 2220 }, 2221 }, 2222 x.u); 2223 } 2224 void Unparse(const OmpAllocateClause::AllocateModifier::Align &x) { 2225 Word("ALIGN("); 2226 Walk(x.v); 2227 Put(")"); 2228 } 2229 void Unparse(const OmpOrderClause &x) { 2230 using Modifier = OmpOrderClause::Modifier; 2231 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":"); 2232 Walk(std::get<OmpOrderClause::Ordering>(x.t)); 2233 } 2234 void Unparse(const OmpGrainsizeClause &x) { 2235 Walk(std::get<std::optional<OmpGrainsizeClause::Prescriptiveness>>(x.t), 2236 ":"); 2237 Walk(std::get<ScalarIntExpr>(x.t)); 2238 } 2239 void Unparse(const OmpNumTasksClause &x) { 2240 Walk( 2241 std::get<std::optional<OmpNumTasksClause::Prescriptiveness>>(x.t), ":"); 2242 Walk(std::get<ScalarIntExpr>(x.t)); 2243 } 2244 void Unparse(const OmpDoacross::Sink &x) { 2245 Word("SINK: "); 2246 Walk(x.v.v); 2247 } 2248 void Unparse(const OmpDoacross::Source &) { Word("SOURCE"); } 2249 void Unparse(const OmpDependClause::TaskDep &x) { 2250 Walk(std::get<OmpTaskDependenceType>(x.t)); 2251 Put(":"); 2252 Walk(std::get<OmpObjectList>(x.t)); 2253 } 2254 void Unparse(const OmpDefaultmapClause &x) { 2255 using Modifier = OmpDefaultmapClause::Modifier; 2256 Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t)); 2257 Walk(":", std::get<std::optional<std::list<Modifier>>>(x.t)); 2258 } 2259 void Unparse(const OmpToClause &x) { 2260 auto &expect{ 2261 std::get<std::optional<std::list<OmpToClause::Expectation>>>(x.t)}; 2262 auto &iter{std::get<std::optional<std::list<OmpIterator>>>(x.t)}; 2263 bool needComma{false}; 2264 if (expect) { 2265 Walk(*expect); 2266 needComma = true; 2267 } 2268 if (iter) { 2269 if (needComma) { 2270 Put(", "); 2271 } 2272 Walk(*iter); 2273 needComma = true; 2274 } 2275 if (needComma) { 2276 Put(": "); 2277 } 2278 Walk(std::get<OmpObjectList>(x.t)); 2279 } 2280 #define GEN_FLANG_CLAUSE_UNPARSE 2281 #include "llvm/Frontend/OpenMP/OMP.inc" 2282 void Unparse(const OmpLoopDirective &x) { 2283 switch (x.v) { 2284 case llvm::omp::Directive::OMPD_distribute: 2285 Word("DISTRIBUTE "); 2286 break; 2287 case llvm::omp::Directive::OMPD_distribute_parallel_do: 2288 Word("DISTRIBUTE PARALLEL DO "); 2289 break; 2290 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd: 2291 Word("DISTRIBUTE PARALLEL DO SIMD "); 2292 break; 2293 case llvm::omp::Directive::OMPD_distribute_simd: 2294 Word("DISTRIBUTE SIMD "); 2295 break; 2296 case llvm::omp::Directive::OMPD_do: 2297 Word("DO "); 2298 break; 2299 case llvm::omp::Directive::OMPD_do_simd: 2300 Word("DO SIMD "); 2301 break; 2302 case llvm::omp::Directive::OMPD_loop: 2303 Word("LOOP "); 2304 break; 2305 case llvm::omp::Directive::OMPD_masked_taskloop_simd: 2306 Word("MASKED TASKLOOP SIMD"); 2307 break; 2308 case llvm::omp::Directive::OMPD_masked_taskloop: 2309 Word("MASKED TASKLOOP"); 2310 break; 2311 case llvm::omp::Directive::OMPD_master_taskloop_simd: 2312 Word("MASTER TASKLOOP SIMD"); 2313 break; 2314 case llvm::omp::Directive::OMPD_master_taskloop: 2315 Word("MASTER TASKLOOP"); 2316 break; 2317 case llvm::omp::Directive::OMPD_parallel_do: 2318 Word("PARALLEL DO "); 2319 break; 2320 case llvm::omp::Directive::OMPD_parallel_do_simd: 2321 Word("PARALLEL DO SIMD "); 2322 break; 2323 case llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd: 2324 Word("PARALLEL MASKED TASKLOOP SIMD"); 2325 break; 2326 case llvm::omp::Directive::OMPD_parallel_masked_taskloop: 2327 Word("PARALLEL MASKED TASKLOOP"); 2328 break; 2329 case llvm::omp::Directive::OMPD_parallel_master_taskloop_simd: 2330 Word("PARALLEL MASTER TASKLOOP SIMD"); 2331 break; 2332 case llvm::omp::Directive::OMPD_parallel_master_taskloop: 2333 Word("PARALLEL MASTER TASKLOOP"); 2334 break; 2335 case llvm::omp::Directive::OMPD_simd: 2336 Word("SIMD "); 2337 break; 2338 case llvm::omp::Directive::OMPD_target_loop: 2339 Word("TARGET LOOP "); 2340 break; 2341 case llvm::omp::Directive::OMPD_target_parallel_do: 2342 Word("TARGET PARALLEL DO "); 2343 break; 2344 case llvm::omp::Directive::OMPD_target_parallel_do_simd: 2345 Word("TARGET PARALLEL DO SIMD "); 2346 break; 2347 case llvm::omp::Directive::OMPD_target_parallel_loop: 2348 Word("TARGET PARALLEL LOOP "); 2349 break; 2350 case llvm::omp::Directive::OMPD_target_teams_distribute: 2351 Word("TARGET TEAMS DISTRIBUTE "); 2352 break; 2353 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: 2354 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO "); 2355 break; 2356 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: 2357 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD "); 2358 break; 2359 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: 2360 Word("TARGET TEAMS DISTRIBUTE SIMD "); 2361 break; 2362 case llvm::omp::Directive::OMPD_target_teams_loop: 2363 Word("TARGET TEAMS LOOP "); 2364 break; 2365 case llvm::omp::Directive::OMPD_target_simd: 2366 Word("TARGET SIMD "); 2367 break; 2368 case llvm::omp::Directive::OMPD_taskloop: 2369 Word("TASKLOOP "); 2370 break; 2371 case llvm::omp::Directive::OMPD_taskloop_simd: 2372 Word("TASKLOOP SIMD "); 2373 break; 2374 case llvm::omp::Directive::OMPD_teams_distribute: 2375 Word("TEAMS DISTRIBUTE "); 2376 break; 2377 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do: 2378 Word("TEAMS DISTRIBUTE PARALLEL DO "); 2379 break; 2380 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd: 2381 Word("TEAMS DISTRIBUTE PARALLEL DO SIMD "); 2382 break; 2383 case llvm::omp::Directive::OMPD_teams_distribute_simd: 2384 Word("TEAMS DISTRIBUTE SIMD "); 2385 break; 2386 case llvm::omp::Directive::OMPD_tile: 2387 Word("TILE "); 2388 break; 2389 case llvm::omp::Directive::OMPD_unroll: 2390 Word("UNROLL "); 2391 break; 2392 default: 2393 break; 2394 } 2395 } 2396 void Unparse(const OmpObjectList &x) { Walk(x.v, ","); } 2397 void Unparse(const OmpSimpleStandaloneDirective &x) { 2398 switch (x.v) { 2399 case llvm::omp::Directive::OMPD_barrier: 2400 Word("BARRIER "); 2401 break; 2402 case llvm::omp::Directive::OMPD_scan: 2403 Word("SCAN "); 2404 break; 2405 case llvm::omp::Directive::OMPD_taskwait: 2406 Word("TASKWAIT "); 2407 break; 2408 case llvm::omp::Directive::OMPD_taskyield: 2409 Word("TASKYIELD "); 2410 break; 2411 case llvm::omp::Directive::OMPD_target_enter_data: 2412 Word("TARGET ENTER DATA "); 2413 break; 2414 case llvm::omp::Directive::OMPD_target_exit_data: 2415 Word("TARGET EXIT DATA "); 2416 break; 2417 case llvm::omp::Directive::OMPD_target_update: 2418 Word("TARGET UPDATE "); 2419 break; 2420 case llvm::omp::Directive::OMPD_ordered: 2421 Word("ORDERED "); 2422 break; 2423 default: 2424 // Nothing to be done 2425 break; 2426 } 2427 } 2428 void Unparse(const OmpBlockDirective &x) { 2429 switch (x.v) { 2430 case llvm::omp::Directive::OMPD_masked: 2431 Word("MASKED"); 2432 break; 2433 case llvm::omp::Directive::OMPD_master: 2434 Word("MASTER"); 2435 break; 2436 case llvm::omp::Directive::OMPD_ordered: 2437 Word("ORDERED "); 2438 break; 2439 case llvm::omp::Directive::OMPD_parallel_masked: 2440 Word("PARALLEL MASKED"); 2441 break; 2442 case llvm::omp::Directive::OMPD_parallel_master: 2443 Word("PARALLEL MASTER"); 2444 break; 2445 case llvm::omp::Directive::OMPD_parallel_workshare: 2446 Word("PARALLEL WORKSHARE "); 2447 break; 2448 case llvm::omp::Directive::OMPD_parallel: 2449 Word("PARALLEL "); 2450 break; 2451 case llvm::omp::Directive::OMPD_scope: 2452 Word("SCOPE "); 2453 break; 2454 case llvm::omp::Directive::OMPD_single: 2455 Word("SINGLE "); 2456 break; 2457 case llvm::omp::Directive::OMPD_target_data: 2458 Word("TARGET DATA "); 2459 break; 2460 case llvm::omp::Directive::OMPD_target_parallel: 2461 Word("TARGET PARALLEL "); 2462 break; 2463 case llvm::omp::Directive::OMPD_target_teams: 2464 Word("TARGET TEAMS "); 2465 break; 2466 case llvm::omp::Directive::OMPD_target: 2467 Word("TARGET "); 2468 break; 2469 case llvm::omp::Directive::OMPD_taskgroup: 2470 Word("TASKGROUP "); 2471 break; 2472 case llvm::omp::Directive::OMPD_task: 2473 Word("TASK "); 2474 break; 2475 case llvm::omp::Directive::OMPD_teams: 2476 Word("TEAMS "); 2477 break; 2478 case llvm::omp::Directive::OMPD_workshare: 2479 Word("WORKSHARE "); 2480 break; 2481 default: 2482 // Nothing to be done 2483 break; 2484 } 2485 } 2486 2487 void Unparse(const OmpAtomicDefaultMemOrderClause &x) { 2488 Word(ToUpperCaseLetters(common::EnumToString(x.v))); 2489 } 2490 2491 void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); } 2492 2493 void Unparse(const OmpAtomic &x) { 2494 BeginOpenMP(); 2495 Word("!$OMP ATOMIC"); 2496 Walk(std::get<OmpAtomicClauseList>(x.t)); 2497 Put("\n"); 2498 EndOpenMP(); 2499 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2500 BeginOpenMP(); 2501 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2502 EndOpenMP(); 2503 } 2504 void Unparse(const OmpAtomicCapture &x) { 2505 BeginOpenMP(); 2506 Word("!$OMP ATOMIC"); 2507 Walk(std::get<0>(x.t)); 2508 Word(" CAPTURE"); 2509 Walk(std::get<2>(x.t)); 2510 Put("\n"); 2511 EndOpenMP(); 2512 Walk(std::get<OmpAtomicCapture::Stmt1>(x.t)); 2513 Put("\n"); 2514 Walk(std::get<OmpAtomicCapture::Stmt2>(x.t)); 2515 BeginOpenMP(); 2516 Word("!$OMP END ATOMIC\n"); 2517 EndOpenMP(); 2518 } 2519 void Unparse(const OmpAtomicRead &x) { 2520 BeginOpenMP(); 2521 Word("!$OMP ATOMIC"); 2522 Walk(std::get<0>(x.t)); 2523 Word(" READ"); 2524 Walk(std::get<2>(x.t)); 2525 Put("\n"); 2526 EndOpenMP(); 2527 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2528 BeginOpenMP(); 2529 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2530 EndOpenMP(); 2531 } 2532 void Unparse(const OmpAtomicUpdate &x) { 2533 BeginOpenMP(); 2534 Word("!$OMP ATOMIC"); 2535 Walk(std::get<0>(x.t)); 2536 Word(" UPDATE"); 2537 Walk(std::get<2>(x.t)); 2538 Put("\n"); 2539 EndOpenMP(); 2540 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2541 BeginOpenMP(); 2542 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2543 EndOpenMP(); 2544 } 2545 void Unparse(const OmpAtomicWrite &x) { 2546 BeginOpenMP(); 2547 Word("!$OMP ATOMIC"); 2548 Walk(std::get<0>(x.t)); 2549 Word(" WRITE"); 2550 Walk(std::get<2>(x.t)); 2551 Put("\n"); 2552 EndOpenMP(); 2553 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2554 BeginOpenMP(); 2555 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2556 EndOpenMP(); 2557 } 2558 void Unparse(const OpenMPExecutableAllocate &x) { 2559 const auto &fields = 2560 std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>( 2561 x.t); 2562 if (fields) { 2563 for (const auto &decl : *fields) { 2564 Walk(decl); 2565 } 2566 } 2567 BeginOpenMP(); 2568 Word("!$OMP ALLOCATE"); 2569 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")"); 2570 Walk(std::get<OmpClauseList>(x.t)); 2571 Put("\n"); 2572 EndOpenMP(); 2573 Walk(std::get<Statement<AllocateStmt>>(x.t)); 2574 } 2575 void Unparse(const OpenMPDeclarativeAllocate &x) { 2576 BeginOpenMP(); 2577 Word("!$OMP ALLOCATE"); 2578 Put(" ("); 2579 Walk(std::get<OmpObjectList>(x.t)); 2580 Put(")"); 2581 Walk(std::get<OmpClauseList>(x.t)); 2582 Put("\n"); 2583 EndOpenMP(); 2584 } 2585 void Unparse(const OmpEndAllocators &x) { 2586 BeginOpenMP(); 2587 Word("!$OMP END ALLOCATE"); 2588 Put("\n"); 2589 EndOpenMP(); 2590 } 2591 void Unparse(const OpenMPAllocatorsConstruct &x) { 2592 BeginOpenMP(); 2593 Word("!$OMP ALLOCATE"); 2594 Walk(std::get<OmpClauseList>(x.t)); 2595 Put("\n"); 2596 EndOpenMP(); 2597 Walk(std::get<Statement<AllocateStmt>>(x.t)); 2598 if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) { 2599 Walk(*end); 2600 } 2601 } 2602 void Unparse(const OmpCriticalDirective &x) { 2603 BeginOpenMP(); 2604 Word("!$OMP CRITICAL"); 2605 Walk(" (", std::get<std::optional<Name>>(x.t), ")"); 2606 Walk(std::get<OmpClauseList>(x.t)); 2607 Put("\n"); 2608 EndOpenMP(); 2609 } 2610 void Unparse(const OmpEndCriticalDirective &x) { 2611 BeginOpenMP(); 2612 Word("!$OMP END CRITICAL"); 2613 Walk(" (", std::get<std::optional<Name>>(x.t), ")"); 2614 Put("\n"); 2615 EndOpenMP(); 2616 } 2617 void Unparse(const OpenMPCriticalConstruct &x) { 2618 Walk(std::get<OmpCriticalDirective>(x.t)); 2619 Walk(std::get<Block>(x.t), ""); 2620 Walk(std::get<OmpEndCriticalDirective>(x.t)); 2621 } 2622 void Unparse(const OmpDeclareTargetWithList &x) { 2623 Put("("), Walk(x.v), Put(")"); 2624 } 2625 void Unparse(const OmpReductionInitializerClause &x) { 2626 Word(" INITIALIZER(OMP_PRIV = "); 2627 Walk(x.v); 2628 Put(")"); 2629 } 2630 void Unparse(const OmpReductionCombiner::FunctionCombiner &x) { 2631 const auto &pd = std::get<ProcedureDesignator>(x.v.t); 2632 const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t); 2633 Walk(pd); 2634 if (args.empty()) { 2635 if (std::holds_alternative<ProcComponentRef>(pd.u)) { 2636 Put("()"); 2637 } 2638 } else { 2639 Walk("(", args, ", ", ")"); 2640 } 2641 } 2642 void Unparse(const OpenMPDeclareReductionConstruct &x) { 2643 Put("("); 2644 Walk(std::get<OmpReductionIdentifier>(x.t)), Put(" : "); 2645 Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : "); 2646 Walk(std::get<OmpReductionCombiner>(x.t)); 2647 Put(")"); 2648 Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t)); 2649 } 2650 bool Pre(const OpenMPDeclarativeConstruct &x) { 2651 BeginOpenMP(); 2652 Word("!$OMP "); 2653 return common::visit( 2654 common::visitors{ 2655 [&](const OpenMPDeclarativeAllocate &z) { 2656 Word("ALLOCATE ("); 2657 Walk(std::get<OmpObjectList>(z.t)); 2658 Put(")"); 2659 Walk(std::get<OmpClauseList>(z.t)); 2660 Put("\n"); 2661 EndOpenMP(); 2662 return false; 2663 }, 2664 [&](const OpenMPDeclareMapperConstruct &z) { 2665 Word("DECLARE MAPPER ("); 2666 const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)}; 2667 if (auto mapname{std::get<std::optional<Name>>(spec.t)}) { 2668 Walk(mapname); 2669 Put(":"); 2670 } 2671 Walk(std::get<TypeSpec>(spec.t)); 2672 Put("::"); 2673 Walk(std::get<Name>(spec.t)); 2674 Put(")"); 2675 2676 Walk(std::get<OmpClauseList>(z.t)); 2677 Put("\n"); 2678 return false; 2679 }, 2680 [&](const OpenMPDeclareReductionConstruct &) { 2681 Word("DECLARE REDUCTION "); 2682 return true; 2683 }, 2684 [&](const OpenMPDeclareSimdConstruct &y) { 2685 Word("DECLARE SIMD "); 2686 Walk("(", std::get<std::optional<Name>>(y.t), ")"); 2687 Walk(std::get<OmpClauseList>(y.t)); 2688 Put("\n"); 2689 EndOpenMP(); 2690 return false; 2691 }, 2692 [&](const OpenMPDeclareTargetConstruct &) { 2693 Word("DECLARE TARGET "); 2694 return true; 2695 }, 2696 [&](const OpenMPRequiresConstruct &y) { 2697 Word("REQUIRES "); 2698 Walk(std::get<OmpClauseList>(y.t)); 2699 Put("\n"); 2700 EndOpenMP(); 2701 return false; 2702 }, 2703 [&](const OpenMPThreadprivate &) { 2704 Word("THREADPRIVATE ("); 2705 return true; 2706 }, 2707 }, 2708 x.u); 2709 } 2710 void Post(const OpenMPDeclarativeConstruct &) { 2711 Put("\n"); 2712 EndOpenMP(); 2713 } 2714 void Post(const OpenMPThreadprivate &) { 2715 Put(")\n"); 2716 EndOpenMP(); 2717 } 2718 void Unparse(const OmpSectionsDirective &x) { 2719 switch (x.v) { 2720 case llvm::omp::Directive::OMPD_sections: 2721 Word("SECTIONS "); 2722 break; 2723 case llvm::omp::Directive::OMPD_parallel_sections: 2724 Word("PARALLEL SECTIONS "); 2725 break; 2726 default: 2727 break; 2728 } 2729 } 2730 void Unparse(const OmpSectionBlocks &x) { 2731 for (const auto &y : x.v) { 2732 BeginOpenMP(); 2733 Word("!$OMP SECTION"); 2734 Put("\n"); 2735 EndOpenMP(); 2736 // y.u is an OpenMPSectionConstruct 2737 // (y.u).v is Block 2738 Walk(std::get<OpenMPSectionConstruct>(y.u).v, ""); 2739 } 2740 } 2741 void Unparse(const OpenMPSectionsConstruct &x) { 2742 BeginOpenMP(); 2743 Word("!$OMP "); 2744 Walk(std::get<OmpBeginSectionsDirective>(x.t)); 2745 Put("\n"); 2746 EndOpenMP(); 2747 Walk(std::get<OmpSectionBlocks>(x.t)); 2748 BeginOpenMP(); 2749 Word("!$OMP END "); 2750 Walk(std::get<OmpEndSectionsDirective>(x.t)); 2751 Put("\n"); 2752 EndOpenMP(); 2753 } 2754 void Unparse(const OpenMPCancellationPointConstruct &x) { 2755 BeginOpenMP(); 2756 Word("!$OMP CANCELLATION POINT "); 2757 Walk(std::get<OmpCancelType>(x.t)); 2758 Put("\n"); 2759 EndOpenMP(); 2760 } 2761 void Unparse(const OpenMPCancelConstruct &x) { 2762 BeginOpenMP(); 2763 Word("!$OMP CANCEL "); 2764 Walk(std::get<OmpCancelType>(x.t)); 2765 Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t)); 2766 Put("\n"); 2767 EndOpenMP(); 2768 } 2769 void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); } 2770 void Unparse(const OmpAtomicClause &x) { 2771 common::visit(common::visitors{ 2772 [&](const OmpMemoryOrderClause &y) { Walk(y); }, 2773 [&](const OmpClause &z) { Walk(z); }, 2774 }, 2775 x.u); 2776 } 2777 void Unparse(const OpenMPDepobjConstruct &x) { 2778 BeginOpenMP(); 2779 Word("!$OMP DEPOBJ"); 2780 Put("("); 2781 Walk(std::get<OmpObject>(x.t)); 2782 Put(") "); 2783 Walk(std::get<OmpClause>(x.t)); 2784 Put("\n"); 2785 EndOpenMP(); 2786 } 2787 void Unparse(const OpenMPFlushConstruct &x) { 2788 BeginOpenMP(); 2789 Word("!$OMP FLUSH "); 2790 Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t)); 2791 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")"); 2792 Put("\n"); 2793 EndOpenMP(); 2794 } 2795 void Unparse(const OmpEndLoopDirective &x) { 2796 BeginOpenMP(); 2797 Word("!$OMP END "); 2798 Walk(std::get<OmpLoopDirective>(x.t)); 2799 Walk(std::get<OmpClauseList>(x.t)); 2800 Put("\n"); 2801 EndOpenMP(); 2802 } 2803 void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); } 2804 void Unparse(const OpenMPSimpleStandaloneConstruct &x) { 2805 BeginOpenMP(); 2806 Word("!$OMP "); 2807 Walk(std::get<OmpSimpleStandaloneDirective>(x.t)); 2808 Walk(std::get<OmpClauseList>(x.t)); 2809 Put("\n"); 2810 EndOpenMP(); 2811 } 2812 void Unparse(const OpenMPBlockConstruct &x) { 2813 BeginOpenMP(); 2814 Word("!$OMP "); 2815 Walk(std::get<OmpBeginBlockDirective>(x.t)); 2816 Put("\n"); 2817 EndOpenMP(); 2818 Walk(std::get<Block>(x.t), ""); 2819 BeginOpenMP(); 2820 Word("!$OMP END "); 2821 Walk(std::get<OmpEndBlockDirective>(x.t)); 2822 Put("\n"); 2823 EndOpenMP(); 2824 } 2825 void Unparse(const OpenMPLoopConstruct &x) { 2826 BeginOpenMP(); 2827 Word("!$OMP "); 2828 Walk(std::get<OmpBeginLoopDirective>(x.t)); 2829 Put("\n"); 2830 EndOpenMP(); 2831 Walk(std::get<std::optional<DoConstruct>>(x.t)); 2832 Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t)); 2833 } 2834 void Unparse(const BasedPointer &x) { 2835 Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t)); 2836 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')'); 2837 } 2838 void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); } 2839 void Unparse(const CUDAAttributesStmt &x) { 2840 Word("ATTRIBUTES("), Walk(std::get<common::CUDADataAttr>(x.t)); 2841 Word(") "), Walk(std::get<std::list<Name>>(x.t), ", "); 2842 } 2843 void Post(const StructureField &x) { 2844 if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) { 2845 for (const auto &item : 2846 std::get<std::list<ComponentOrFill>>(def->statement.t)) { 2847 if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) { 2848 structureComponents_.insert(std::get<Name>(comp->t).source); 2849 } 2850 } 2851 } 2852 } 2853 void Unparse(const StructureStmt &x) { 2854 Word("STRUCTURE "); 2855 // The name, if present, includes the /slashes/ 2856 Walk(std::get<std::optional<Name>>(x.t)); 2857 Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", "); 2858 Indent(); 2859 } 2860 void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); } 2861 void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); } 2862 void Post(const Map::MapStmt &) { Word("MAP"), Indent(); } 2863 void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); } 2864 void Post(const StructureDef::EndStructureStmt &) { 2865 Outdent(), Word("END STRUCTURE"); 2866 } 2867 void Unparse(const OldParameterStmt &x) { 2868 Word("PARAMETER "), Walk(x.v, ", "); 2869 } 2870 void Unparse(const ArithmeticIfStmt &x) { 2871 Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") "); 2872 Walk(std::get<1>(x.t)), Put(", "); 2873 Walk(std::get<2>(x.t)), Put(", "); 2874 Walk(std::get<3>(x.t)); 2875 } 2876 void Unparse(const AssignStmt &x) { 2877 Word("ASSIGN "), Walk(std::get<Label>(x.t)); 2878 Word(" TO "), Walk(std::get<Name>(x.t)); 2879 } 2880 void Unparse(const AssignedGotoStmt &x) { 2881 Word("GO TO "), Walk(std::get<Name>(x.t)); 2882 Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")"); 2883 } 2884 void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); } 2885 2886 #define WALK_NESTED_ENUM(CLASS, ENUM) \ 2887 void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); } 2888 WALK_NESTED_ENUM(AccDataModifier, Modifier) 2889 WALK_NESTED_ENUM(AccessSpec, Kind) // R807 2890 WALK_NESTED_ENUM(common, TypeParamAttr) // R734 2891 WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA 2892 WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA 2893 WALK_NESTED_ENUM(IntentSpec, Intent) // R826 2894 WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866 2895 WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205 2896 WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind) 2897 WALK_NESTED_ENUM(InquireSpec::CharVar, Kind) 2898 WALK_NESTED_ENUM(InquireSpec::IntVar, Kind) 2899 WALK_NESTED_ENUM(InquireSpec::LogVar, Kind) 2900 WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506 2901 WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410 2902 WALK_NESTED_ENUM(OmpProcBindClause, Type) // OMP PROC_BIND 2903 WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT 2904 WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP 2905 WALK_NESTED_ENUM(OmpVariableCategory, Value) // OMP variable-category 2906 WALK_NESTED_ENUM( 2907 OmpLastprivateClause, LastprivateModifier) // OMP lastprivate-modifier 2908 WALK_NESTED_ENUM(OmpChunkModifier, Value) // OMP chunk-modifier 2909 WALK_NESTED_ENUM(OmpLinearModifier, Value) // OMP linear-modifier 2910 WALK_NESTED_ENUM(OmpOrderingModifier, Value) // OMP ordering-modifier 2911 WALK_NESTED_ENUM(OmpTaskDependenceType, Value) // OMP task-dependence-type 2912 WALK_NESTED_ENUM(OmpScheduleClause, Kind) // OMP schedule-kind 2913 WALK_NESTED_ENUM(OmpDeviceClause, DeviceModifier) // OMP device modifier 2914 WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE 2915 WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier 2916 WALK_NESTED_ENUM(OmpFromClause, Expectation) // OMP motion-expectation 2917 WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier 2918 WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type 2919 WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering 2920 WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier 2921 WALK_NESTED_ENUM( 2922 OmpGrainsizeClause, Prescriptiveness) // OMP grainsize-modifier 2923 WALK_NESTED_ENUM(OmpNumTasksClause, Prescriptiveness) // OMP numtasks-modifier 2924 WALK_NESTED_ENUM(OmpMapClause, Type) // OMP map-type 2925 WALK_NESTED_ENUM(OmpMapClause, TypeModifier) // OMP map-type-modifier 2926 #undef WALK_NESTED_ENUM 2927 void Unparse(const ReductionOperator::Operator x) { 2928 switch (x) { 2929 case ReductionOperator::Operator::Plus: 2930 Word("+"); 2931 break; 2932 case ReductionOperator::Operator::Multiply: 2933 Word("*"); 2934 break; 2935 case ReductionOperator::Operator::And: 2936 Word(".AND."); 2937 break; 2938 case ReductionOperator::Operator::Or: 2939 Word(".OR."); 2940 break; 2941 case ReductionOperator::Operator::Eqv: 2942 Word(".EQV."); 2943 break; 2944 case ReductionOperator::Operator::Neqv: 2945 Word(".NEQV."); 2946 break; 2947 default: 2948 Word(ReductionOperator::EnumToString(x)); 2949 break; 2950 } 2951 } 2952 2953 void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) { 2954 if (x.v) { 2955 Walk(*x.v); 2956 } else { 2957 Word("*"); 2958 } 2959 } 2960 void Unparse(const CUFKernelDoConstruct::LaunchConfiguration &x) { 2961 Word(" <<<"); 2962 const auto &grid{std::get<0>(x.t)}; 2963 if (grid.empty()) { 2964 Word("*"); 2965 } else if (grid.size() == 1) { 2966 Walk(grid.front()); 2967 } else { 2968 Walk("(", grid, ",", ")"); 2969 } 2970 Word(","); 2971 const auto &block{std::get<1>(x.t)}; 2972 if (block.empty()) { 2973 Word("*"); 2974 } else if (block.size() == 1) { 2975 Walk(block.front()); 2976 } else { 2977 Walk("(", block, ",", ")"); 2978 } 2979 if (const auto &stream{std::get<2>(x.t)}) { 2980 Word(",STREAM="), Walk(*stream); 2981 } 2982 Word(">>>"); 2983 } 2984 void Unparse(const CUFKernelDoConstruct::Directive &x) { 2985 Word("!$CUF KERNEL DO"); 2986 Walk(" (", std::get<std::optional<ScalarIntConstantExpr>>(x.t), ")"); 2987 Walk(std::get<std::optional<CUFKernelDoConstruct::LaunchConfiguration>>( 2988 x.t)); 2989 Walk(" ", std::get<std::list<CUFReduction>>(x.t), " "); 2990 Word("\n"); 2991 } 2992 void Unparse(const CUFKernelDoConstruct &x) { 2993 Walk(std::get<CUFKernelDoConstruct::Directive>(x.t)); 2994 Walk(std::get<std::optional<DoConstruct>>(x.t)); 2995 } 2996 void Unparse(const CUFReduction &x) { 2997 Word("REDUCE("); 2998 Walk(std::get<CUFReduction::Operator>(x.t)); 2999 Walk(":", std::get<std::list<Scalar<Variable>>>(x.t), ",", ")"); 3000 } 3001 3002 void Done() const { CHECK(indent_ == 0); } 3003 3004 private: 3005 void Put(char); 3006 void Put(const char *); 3007 void Put(const std::string &); 3008 void PutNormalized(const std::string &); 3009 void PutKeywordLetter(char); 3010 void Word(const char *); 3011 void Word(const std::string &); 3012 void Word(const std::string_view &); 3013 void Indent() { indent_ += indentationAmount_; } 3014 void Outdent() { 3015 CHECK(indent_ >= indentationAmount_); 3016 indent_ -= indentationAmount_; 3017 } 3018 void BeginOpenMP() { openmpDirective_ = true; } 3019 void EndOpenMP() { openmpDirective_ = false; } 3020 void BeginOpenACC() { openaccDirective_ = true; } 3021 void EndOpenACC() { openaccDirective_ = false; } 3022 3023 // Call back to the traversal framework. 3024 template <typename T> void Walk(const T &x) { 3025 Fortran::parser::Walk(x, *this); 3026 } 3027 3028 // Traverse a std::optional<> value. Emit a prefix and/or a suffix string 3029 // only when it contains a value. 3030 template <typename A> 3031 void Walk( 3032 const char *prefix, const std::optional<A> &x, const char *suffix = "") { 3033 if (x) { 3034 Word(prefix), Walk(*x), Word(suffix); 3035 } 3036 } 3037 template <typename A> 3038 void Walk(const std::optional<A> &x, const char *suffix = "") { 3039 return Walk("", x, suffix); 3040 } 3041 3042 // Traverse a std::list<>. Separate the elements with an optional string. 3043 // Emit a prefix and/or a suffix string only when the list is not empty. 3044 template <typename A> 3045 void Walk(const char *prefix, const std::list<A> &list, 3046 const char *comma = ", ", const char *suffix = "") { 3047 if (!list.empty()) { 3048 const char *str{prefix}; 3049 for (const auto &x : list) { 3050 Word(str), Walk(x); 3051 str = comma; 3052 } 3053 Word(suffix); 3054 } 3055 } 3056 template <typename A> 3057 void Walk(const std::list<A> &list, const char *comma = ", ", 3058 const char *suffix = "") { 3059 return Walk("", list, comma, suffix); 3060 } 3061 3062 // Traverse a std::tuple<>, with an optional separator. 3063 template <std::size_t J = 0, typename T> 3064 void WalkTupleElements(const T &tuple, const char *separator) { 3065 if (J > 0 && J < std::tuple_size_v<T>) { 3066 Word(separator); // this usage dodges "unused parameter" warning 3067 } 3068 if constexpr (J < std::tuple_size_v<T>) { 3069 Walk(std::get<J>(tuple)); 3070 WalkTupleElements<J + 1>(tuple, separator); 3071 } 3072 } 3073 template <typename... A> 3074 void Walk(const std::tuple<A...> &tuple, const char *separator = "") { 3075 WalkTupleElements(tuple, separator); 3076 } 3077 3078 void EndSubprogram(const char *kind, const std::optional<Name> &name) { 3079 Outdent(), Word("END "), Word(kind), Walk(" ", name); 3080 structureComponents_.clear(); 3081 } 3082 3083 llvm::raw_ostream &out_; 3084 int indent_{0}; 3085 const int indentationAmount_{1}; 3086 int column_{1}; 3087 const int maxColumns_{80}; 3088 std::set<CharBlock> structureComponents_; 3089 Encoding encoding_{Encoding::UTF_8}; 3090 bool capitalizeKeywords_{true}; 3091 bool openaccDirective_{false}; 3092 bool openmpDirective_{false}; 3093 bool backslashEscapes_{false}; 3094 preStatementType *preStatement_{nullptr}; 3095 AnalyzedObjectsAsFortran *asFortran_{nullptr}; 3096 }; 3097 3098 void UnparseVisitor::Put(char ch) { 3099 int sav = indent_; 3100 if (openmpDirective_ || openaccDirective_) { 3101 indent_ = 0; 3102 } 3103 if (column_ <= 1) { 3104 if (ch == '\n') { 3105 return; 3106 } 3107 for (int j{0}; j < indent_; ++j) { 3108 out_ << ' '; 3109 } 3110 column_ = indent_ + 2; 3111 } else if (ch == '\n') { 3112 column_ = 1; 3113 } else if (++column_ >= maxColumns_) { 3114 out_ << "&\n"; 3115 for (int j{0}; j < indent_; ++j) { 3116 out_ << ' '; 3117 } 3118 if (openmpDirective_) { 3119 out_ << "!$OMP&"; 3120 column_ = 8; 3121 } else if (openaccDirective_) { 3122 out_ << "!$ACC&"; 3123 column_ = 8; 3124 } else { 3125 out_ << '&'; 3126 column_ = indent_ + 3; 3127 } 3128 } 3129 out_ << ch; 3130 if (openmpDirective_ || openaccDirective_) { 3131 indent_ = sav; 3132 } 3133 } 3134 3135 void UnparseVisitor::Put(const char *str) { 3136 for (; *str != '\0'; ++str) { 3137 Put(*str); 3138 } 3139 } 3140 3141 void UnparseVisitor::Put(const std::string &str) { 3142 for (char ch : str) { 3143 Put(ch); 3144 } 3145 } 3146 3147 void UnparseVisitor::PutNormalized(const std::string &str) { 3148 auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)}; 3149 std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)}; 3150 Put(QuoteCharacterLiteral(encoded, backslashEscapes_)); 3151 } 3152 3153 void UnparseVisitor::PutKeywordLetter(char ch) { 3154 if (capitalizeKeywords_) { 3155 Put(ToUpperCaseLetter(ch)); 3156 } else { 3157 Put(ToLowerCaseLetter(ch)); 3158 } 3159 } 3160 3161 void UnparseVisitor::Word(const char *str) { 3162 for (; *str != '\0'; ++str) { 3163 PutKeywordLetter(*str); 3164 } 3165 } 3166 3167 void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); } 3168 3169 void UnparseVisitor::Word(const std::string_view &str) { 3170 for (std::size_t j{0}; j < str.length(); ++j) { 3171 PutKeywordLetter(str[j]); 3172 } 3173 } 3174 3175 template <typename A> 3176 void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding, 3177 bool capitalizeKeywords, bool backslashEscapes, 3178 preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) { 3179 UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes, 3180 preStatement, asFortran}; 3181 Walk(root, visitor); 3182 visitor.Done(); 3183 } 3184 3185 template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding, 3186 bool, bool, preStatementType *, AnalyzedObjectsAsFortran *); 3187 template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool, 3188 bool, preStatementType *, AnalyzedObjectsAsFortran *); 3189 } // namespace Fortran::parser 3190