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::Unroll &unroll) { 1851 Word("!DIR$ UNROLL"); 1852 Walk(" ", unroll.v); 1853 }, 1854 [&](const CompilerDirective::Unrecognized &) { 1855 Word("!DIR$ "); 1856 Word(x.source.ToString()); 1857 }, 1858 }, 1859 x.u); 1860 Put('\n'); 1861 } 1862 void Unparse(const CompilerDirective::IgnoreTKR &x) { 1863 if (const auto &maybeList{ 1864 std::get<std::optional<std::list<const char *>>>(x.t)}) { 1865 Put("("); 1866 for (const char *tkr : *maybeList) { 1867 Put(*tkr); 1868 } 1869 Put(") "); 1870 } 1871 Walk(std::get<Name>(x.t)); 1872 } 1873 void Unparse(const CompilerDirective::NameValue &x) { 1874 Walk(std::get<Name>(x.t)); 1875 Walk("=", std::get<std::optional<std::uint64_t>>(x.t)); 1876 } 1877 void Unparse(const CompilerDirective::AssumeAligned &x) { 1878 Walk(std::get<common::Indirection<Designator>>(x.t)); 1879 Put(":"); 1880 Walk(std::get<uint64_t>(x.t)); 1881 } 1882 1883 // OpenACC Directives & Clauses 1884 void Unparse(const AccAtomicCapture &x) { 1885 BeginOpenACC(); 1886 Word("!$ACC CAPTURE"); 1887 Put("\n"); 1888 EndOpenACC(); 1889 Walk(std::get<AccAtomicCapture::Stmt1>(x.t)); 1890 Put("\n"); 1891 Walk(std::get<AccAtomicCapture::Stmt2>(x.t)); 1892 BeginOpenACC(); 1893 Word("!$ACC END ATOMIC\n"); 1894 EndOpenACC(); 1895 } 1896 void Unparse(const AccAtomicRead &x) { 1897 BeginOpenACC(); 1898 Word("!$ACC ATOMIC READ"); 1899 Put("\n"); 1900 EndOpenACC(); 1901 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1902 BeginOpenACC(); 1903 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1904 EndOpenACC(); 1905 } 1906 void Unparse(const AccAtomicWrite &x) { 1907 BeginOpenACC(); 1908 Word("!$ACC ATOMIC WRITE"); 1909 Put("\n"); 1910 EndOpenACC(); 1911 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1912 BeginOpenACC(); 1913 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1914 EndOpenACC(); 1915 } 1916 void Unparse(const AccAtomicUpdate &x) { 1917 BeginOpenACC(); 1918 Word("!$ACC ATOMIC UPDATE"); 1919 Put("\n"); 1920 EndOpenACC(); 1921 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 1922 BeginOpenACC(); 1923 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n"); 1924 EndOpenACC(); 1925 } 1926 void Unparse(const llvm::acc::Directive &x) { 1927 Word(llvm::acc::getOpenACCDirectiveName(x).str()); 1928 } 1929 #define GEN_FLANG_CLAUSE_UNPARSE 1930 #include "llvm/Frontend/OpenACC/ACC.inc" 1931 void Unparse(const AccObjectListWithModifier &x) { 1932 Walk(std::get<std::optional<AccDataModifier>>(x.t), ":"); 1933 Walk(std::get<AccObjectList>(x.t)); 1934 } 1935 void Unparse(const AccBindClause &x) { 1936 common::visit(common::visitors{ 1937 [&](const Name &y) { Walk(y); }, 1938 [&](const ScalarDefaultCharExpr &y) { Walk(y); }, 1939 }, 1940 x.u); 1941 } 1942 void Unparse(const AccDefaultClause &x) { 1943 switch (x.v) { 1944 case llvm::acc::DefaultValue::ACC_Default_none: 1945 Put("NONE"); 1946 break; 1947 case llvm::acc::DefaultValue::ACC_Default_present: 1948 Put("PRESENT"); 1949 break; 1950 } 1951 } 1952 void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); } 1953 void Unparse(const AccGangArgList &x) { Walk(x.v, ","); } 1954 void Before(const AccSizeExpr &x) { 1955 if (!x.v) 1956 Put("*"); 1957 } 1958 void Before(const AccGangArg &x) { 1959 common::visit(common::visitors{ 1960 [&](const AccGangArg::Num &) { Word("NUM:"); }, 1961 [&](const AccGangArg::Dim &) { Word("DIM:"); }, 1962 [&](const AccGangArg::Static &) { Word("STATIC:"); }, 1963 [](const StatOrErrmsg &) {}, 1964 }, 1965 x.u); 1966 } 1967 void Unparse(const AccCollapseArg &x) { 1968 const auto &force{std::get<bool>(x.t)}; 1969 const auto &collapseValue{std::get<parser::ScalarIntConstantExpr>(x.t)}; 1970 if (force) { 1971 Put("FORCE:"); 1972 } 1973 Walk(collapseValue); 1974 } 1975 void Unparse(const OpenACCBlockConstruct &x) { 1976 BeginOpenACC(); 1977 Word("!$ACC "); 1978 Walk(std::get<AccBeginBlockDirective>(x.t)); 1979 Put("\n"); 1980 EndOpenACC(); 1981 Walk(std::get<Block>(x.t), ""); 1982 BeginOpenACC(); 1983 Word("!$ACC END "); 1984 Walk(std::get<AccEndBlockDirective>(x.t)); 1985 Put("\n"); 1986 EndOpenACC(); 1987 } 1988 void Unparse(const OpenACCLoopConstruct &x) { 1989 BeginOpenACC(); 1990 Word("!$ACC "); 1991 Walk(std::get<AccBeginLoopDirective>(x.t)); 1992 Put("\n"); 1993 EndOpenACC(); 1994 Walk(std::get<std::optional<DoConstruct>>(x.t)); 1995 } 1996 void Unparse(const AccBeginLoopDirective &x) { 1997 Walk(std::get<AccLoopDirective>(x.t)); 1998 Walk(std::get<AccClauseList>(x.t)); 1999 } 2000 void Unparse(const OpenACCStandaloneConstruct &x) { 2001 BeginOpenACC(); 2002 Word("!$ACC "); 2003 Walk(std::get<AccStandaloneDirective>(x.t)); 2004 Walk(std::get<AccClauseList>(x.t)); 2005 Put("\n"); 2006 EndOpenACC(); 2007 } 2008 void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) { 2009 BeginOpenACC(); 2010 Word("!$ACC "); 2011 Walk(std::get<AccDeclarativeDirective>(x.t)); 2012 Walk(std::get<AccClauseList>(x.t)); 2013 Put("\n"); 2014 EndOpenACC(); 2015 } 2016 void Unparse(const OpenACCCombinedConstruct &x) { 2017 BeginOpenACC(); 2018 Word("!$ACC "); 2019 Walk(std::get<AccBeginCombinedDirective>(x.t)); 2020 Put("\n"); 2021 EndOpenACC(); 2022 Walk(std::get<std::optional<DoConstruct>>(x.t)); 2023 BeginOpenACC(); 2024 Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t), 2025 "\n"); 2026 EndOpenACC(); 2027 } 2028 void Unparse(const OpenACCRoutineConstruct &x) { 2029 BeginOpenACC(); 2030 Word("!$ACC ROUTINE"); 2031 Walk("(", std::get<std::optional<Name>>(x.t), ")"); 2032 Walk(std::get<AccClauseList>(x.t)); 2033 Put("\n"); 2034 EndOpenACC(); 2035 } 2036 void Unparse(const AccObject &x) { 2037 common::visit(common::visitors{ 2038 [&](const Designator &y) { Walk(y); }, 2039 [&](const Name &y) { Put("/"), Walk(y), Put("/"); }, 2040 }, 2041 x.u); 2042 } 2043 void Unparse(const AccObjectList &x) { Walk(x.v, ","); } 2044 void Unparse(const AccObjectListWithReduction &x) { 2045 Walk(std::get<ReductionOperator>(x.t)); 2046 Put(":"); 2047 Walk(std::get<AccObjectList>(x.t)); 2048 } 2049 void Unparse(const OpenACCCacheConstruct &x) { 2050 BeginOpenACC(); 2051 Word("!$ACC "); 2052 Word("CACHE("); 2053 Walk(std::get<AccObjectListWithModifier>(x.t)); 2054 Put(")"); 2055 Put("\n"); 2056 EndOpenACC(); 2057 } 2058 void Unparse(const AccWaitArgument &x) { 2059 Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":"); 2060 Walk(std::get<std::list<ScalarIntExpr>>(x.t), ","); 2061 } 2062 void Unparse(const OpenACCWaitConstruct &x) { 2063 BeginOpenACC(); 2064 Word("!$ACC "); 2065 Word("WAIT("); 2066 Walk(std::get<std::optional<AccWaitArgument>>(x.t)); 2067 Walk(std::get<AccClauseList>(x.t)); 2068 Put(")"); 2069 Put("\n"); 2070 EndOpenACC(); 2071 } 2072 2073 // OpenMP Clauses & Directives 2074 void Unparse(const llvm::omp::Directive &x) { 2075 Word(llvm::omp::getOpenMPDirectiveName(x).str()); 2076 } 2077 void Unparse(const OmpDirectiveSpecification &x) { 2078 Walk(std::get<llvm::omp::Directive>(x.t)); 2079 Walk(std::get<std::optional<common::Indirection<OmpClauseList>>>(x.t)); 2080 } 2081 void Unparse(const OmpTraitScore &x) { 2082 Word("SCORE("); 2083 Walk(x.v); 2084 Put(")"); 2085 } 2086 void Unparse(const OmpTraitPropertyExtension::Complex &x) { 2087 using PropList = std::list<common::Indirection<OmpTraitPropertyExtension>>; 2088 Walk(std::get<OmpTraitPropertyName>(x.t)); 2089 Put("("); 2090 Walk(std::get<PropList>(x.t), ","); 2091 Put(")"); 2092 } 2093 void Unparse(const OmpTraitSelector &x) { 2094 Walk(std::get<OmpTraitSelectorName>(x.t)); 2095 Walk(std::get<std::optional<OmpTraitSelector::Properties>>(x.t)); 2096 } 2097 void Unparse(const OmpTraitSelector::Properties &x) { 2098 Put("("); 2099 Walk(std::get<std::optional<OmpTraitScore>>(x.t), ": "); 2100 Walk(std::get<std::list<OmpTraitProperty>>(x.t)); 2101 Put(")"); 2102 } 2103 void Unparse(const OmpTraitSetSelector &x) { 2104 Walk(std::get<OmpTraitSetSelectorName>(x.t)); 2105 Put("={"); 2106 Walk(std::get<std::list<OmpTraitSelector>>(x.t)); 2107 Put("}"); 2108 } 2109 void Unparse(const OmpContextSelectorSpecification &x) { Walk(x.v, ", "); } 2110 2111 void Unparse(const OmpObject &x) { 2112 common::visit(common::visitors{ 2113 [&](const Designator &y) { Walk(y); }, 2114 [&](const Name &y) { Put("/"), Walk(y), Put("/"); }, 2115 }, 2116 x.u); 2117 } 2118 void Unparse(const OmpDirectiveNameModifier &x) { 2119 Word(llvm::omp::getOpenMPDirectiveName(x.v)); 2120 } 2121 void Unparse(const OmpIteratorSpecifier &x) { 2122 Walk(std::get<TypeDeclarationStmt>(x.t)); 2123 Put(" = "); 2124 Walk(std::get<SubscriptTriplet>(x.t)); 2125 } 2126 void Unparse(const OmpIterator &x) { 2127 Word("ITERATOR("); 2128 Walk(x.v); 2129 Put(")"); 2130 } 2131 void Unparse(const OmpMapper &x) { 2132 Word("MAPPER("); 2133 Walk(x.v); 2134 Put(")"); 2135 } 2136 void Unparse(const OmpLastprivateClause &x) { 2137 using Modifier = OmpLastprivateClause::Modifier; 2138 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2139 Walk(std::get<OmpObjectList>(x.t)); 2140 } 2141 void Unparse(const OmpMapClause &x) { 2142 using Modifier = OmpMapClause::Modifier; 2143 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2144 Walk(std::get<OmpObjectList>(x.t)); 2145 } 2146 void Unparse(const OmpScheduleClause &x) { 2147 using Modifier = OmpScheduleClause::Modifier; 2148 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":"); 2149 Walk(std::get<OmpScheduleClause::Kind>(x.t)); 2150 Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t)); 2151 } 2152 void Unparse(const OmpDeviceClause &x) { 2153 using Modifier = OmpDeviceClause::Modifier; 2154 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2155 Walk(std::get<ScalarIntExpr>(x.t)); 2156 } 2157 void Unparse(const OmpAffinityClause &x) { 2158 using Modifier = OmpAffinityClause::Modifier; 2159 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2160 Walk(std::get<OmpObjectList>(x.t)); 2161 } 2162 void Unparse(const OmpAlignedClause &x) { 2163 using Modifier = OmpAlignedClause::Modifier; 2164 Walk(std::get<OmpObjectList>(x.t)); 2165 Walk(": ", std::get<std::optional<std::list<Modifier>>>(x.t)); 2166 } 2167 void Unparse(const OmpFromClause &x) { 2168 using Modifier = OmpFromClause::Modifier; 2169 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2170 Walk(std::get<OmpObjectList>(x.t)); 2171 } 2172 void Unparse(const OmpIfClause &x) { 2173 using Modifier = OmpIfClause::Modifier; 2174 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2175 Walk(std::get<ScalarLogicalExpr>(x.t)); 2176 } 2177 void Unparse(const OmpStepSimpleModifier &x) { Walk(x.v); } 2178 void Unparse(const OmpStepComplexModifier &x) { 2179 Word("STEP("); 2180 Walk(x.v); 2181 Put(")"); 2182 } 2183 void Unparse(const OmpLinearClause &x) { 2184 using Modifier = OmpLinearClause::Modifier; 2185 auto &modifiers{std::get<std::optional<std::list<Modifier>>>(x.t)}; 2186 if (std::get<bool>(x.t)) { // PostModified 2187 Walk(std::get<OmpObjectList>(x.t)); 2188 Walk(": ", modifiers); 2189 } else { 2190 // Unparse using pre-5.2 syntax. 2191 bool HasStepModifier{false}, HasLinearModifier{false}; 2192 2193 if (modifiers) { 2194 bool NeedComma{false}; 2195 for (const Modifier &m : *modifiers) { 2196 // Print all linear modifiers in case we need to unparse an 2197 // incorrect tree. 2198 if (auto *lmod{std::get_if<parser::OmpLinearModifier>(&m.u)}) { 2199 if (NeedComma) { 2200 Put(","); 2201 } 2202 Walk(*lmod); 2203 HasLinearModifier = true; 2204 NeedComma = true; 2205 } else { 2206 // If not linear-modifier, then it has to be step modifier. 2207 HasStepModifier = true; 2208 } 2209 } 2210 } 2211 2212 if (HasLinearModifier) { 2213 Put("("); 2214 } 2215 Walk(std::get<OmpObjectList>(x.t)); 2216 if (HasLinearModifier) { 2217 Put(")"); 2218 } 2219 2220 if (HasStepModifier) { 2221 Put(": "); 2222 bool NeedComma{false}; 2223 for (const Modifier &m : *modifiers) { 2224 if (!std::holds_alternative<parser::OmpLinearModifier>(m.u)) { 2225 if (NeedComma) { 2226 Put(","); 2227 } 2228 common::visit([&](auto &&s) { Walk(s); }, m.u); 2229 NeedComma = true; 2230 } 2231 } 2232 } 2233 } 2234 } 2235 void Unparse(const OmpReductionClause &x) { 2236 using Modifier = OmpReductionClause::Modifier; 2237 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2238 Walk(std::get<OmpObjectList>(x.t)); 2239 } 2240 void Unparse(const OmpDetachClause &x) { Walk(x.v); } 2241 void Unparse(const OmpInReductionClause &x) { 2242 using Modifier = OmpInReductionClause::Modifier; 2243 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2244 Walk(std::get<OmpObjectList>(x.t)); 2245 } 2246 void Unparse(const OmpTaskReductionClause &x) { 2247 using Modifier = OmpTaskReductionClause::Modifier; 2248 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2249 Walk(std::get<OmpObjectList>(x.t)); 2250 } 2251 void Unparse(const OmpAllocateClause &x) { 2252 using Modifier = OmpAllocateClause::Modifier; 2253 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2254 Walk(std::get<OmpObjectList>(x.t)); 2255 } 2256 void Unparse(const OmpAlignModifier &x) { 2257 Word("ALIGN("); 2258 Walk(x.v); 2259 Put(")"); 2260 } 2261 void Unparse(const OmpAllocatorSimpleModifier &x) { Walk(x.v); } 2262 void Unparse(const OmpAllocatorComplexModifier &x) { 2263 Word("ALLOCATOR("); 2264 Walk(x.v); 2265 Put(")"); 2266 } 2267 void Unparse(const OmpOrderClause &x) { 2268 using Modifier = OmpOrderClause::Modifier; 2269 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":"); 2270 Walk(std::get<OmpOrderClause::Ordering>(x.t)); 2271 } 2272 void Unparse(const OmpGrainsizeClause &x) { 2273 using Modifier = OmpGrainsizeClause::Modifier; 2274 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2275 Walk(std::get<ScalarIntExpr>(x.t)); 2276 } 2277 void Unparse(const OmpNumTasksClause &x) { 2278 using Modifier = OmpNumTasksClause::Modifier; 2279 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2280 Walk(std::get<ScalarIntExpr>(x.t)); 2281 } 2282 void Unparse(const OmpDoacross::Sink &x) { 2283 Word("SINK: "); 2284 Walk(x.v.v); 2285 } 2286 void Unparse(const OmpDoacross::Source &) { Word("SOURCE"); } 2287 void Unparse(const OmpDependClause::TaskDep &x) { 2288 using Modifier = OmpDependClause::TaskDep::Modifier; 2289 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2290 Walk(std::get<OmpObjectList>(x.t)); 2291 } 2292 void Unparse(const OmpDefaultmapClause &x) { 2293 using Modifier = OmpDefaultmapClause::Modifier; 2294 Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t)); 2295 Walk(":", std::get<std::optional<std::list<Modifier>>>(x.t)); 2296 } 2297 void Unparse(const OmpToClause &x) { 2298 using Modifier = OmpToClause::Modifier; 2299 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2300 Walk(std::get<OmpObjectList>(x.t)); 2301 } 2302 void Unparse(const OmpWhenClause &x) { 2303 using Modifier = OmpWhenClause::Modifier; 2304 Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": "); 2305 Walk(std::get<std::optional<OmpDirectiveSpecification>>(x.t)); 2306 } 2307 #define GEN_FLANG_CLAUSE_UNPARSE 2308 #include "llvm/Frontend/OpenMP/OMP.inc" 2309 void Unparse(const OmpLoopDirective &x) { 2310 switch (x.v) { 2311 case llvm::omp::Directive::OMPD_distribute: 2312 Word("DISTRIBUTE "); 2313 break; 2314 case llvm::omp::Directive::OMPD_distribute_parallel_do: 2315 Word("DISTRIBUTE PARALLEL DO "); 2316 break; 2317 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd: 2318 Word("DISTRIBUTE PARALLEL DO SIMD "); 2319 break; 2320 case llvm::omp::Directive::OMPD_distribute_simd: 2321 Word("DISTRIBUTE SIMD "); 2322 break; 2323 case llvm::omp::Directive::OMPD_do: 2324 Word("DO "); 2325 break; 2326 case llvm::omp::Directive::OMPD_do_simd: 2327 Word("DO SIMD "); 2328 break; 2329 case llvm::omp::Directive::OMPD_loop: 2330 Word("LOOP "); 2331 break; 2332 case llvm::omp::Directive::OMPD_masked_taskloop_simd: 2333 Word("MASKED TASKLOOP SIMD"); 2334 break; 2335 case llvm::omp::Directive::OMPD_masked_taskloop: 2336 Word("MASKED TASKLOOP"); 2337 break; 2338 case llvm::omp::Directive::OMPD_master_taskloop_simd: 2339 Word("MASTER TASKLOOP SIMD"); 2340 break; 2341 case llvm::omp::Directive::OMPD_master_taskloop: 2342 Word("MASTER TASKLOOP"); 2343 break; 2344 case llvm::omp::Directive::OMPD_parallel_do: 2345 Word("PARALLEL DO "); 2346 break; 2347 case llvm::omp::Directive::OMPD_parallel_do_simd: 2348 Word("PARALLEL DO SIMD "); 2349 break; 2350 case llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd: 2351 Word("PARALLEL MASKED TASKLOOP SIMD"); 2352 break; 2353 case llvm::omp::Directive::OMPD_parallel_masked_taskloop: 2354 Word("PARALLEL MASKED TASKLOOP"); 2355 break; 2356 case llvm::omp::Directive::OMPD_parallel_master_taskloop_simd: 2357 Word("PARALLEL MASTER TASKLOOP SIMD"); 2358 break; 2359 case llvm::omp::Directive::OMPD_parallel_master_taskloop: 2360 Word("PARALLEL MASTER TASKLOOP"); 2361 break; 2362 case llvm::omp::Directive::OMPD_simd: 2363 Word("SIMD "); 2364 break; 2365 case llvm::omp::Directive::OMPD_target_loop: 2366 Word("TARGET LOOP "); 2367 break; 2368 case llvm::omp::Directive::OMPD_target_parallel_do: 2369 Word("TARGET PARALLEL DO "); 2370 break; 2371 case llvm::omp::Directive::OMPD_target_parallel_do_simd: 2372 Word("TARGET PARALLEL DO SIMD "); 2373 break; 2374 case llvm::omp::Directive::OMPD_target_parallel_loop: 2375 Word("TARGET PARALLEL LOOP "); 2376 break; 2377 case llvm::omp::Directive::OMPD_target_teams_distribute: 2378 Word("TARGET TEAMS DISTRIBUTE "); 2379 break; 2380 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do: 2381 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO "); 2382 break; 2383 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: 2384 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD "); 2385 break; 2386 case llvm::omp::Directive::OMPD_target_teams_distribute_simd: 2387 Word("TARGET TEAMS DISTRIBUTE SIMD "); 2388 break; 2389 case llvm::omp::Directive::OMPD_target_teams_loop: 2390 Word("TARGET TEAMS LOOP "); 2391 break; 2392 case llvm::omp::Directive::OMPD_target_simd: 2393 Word("TARGET SIMD "); 2394 break; 2395 case llvm::omp::Directive::OMPD_taskloop: 2396 Word("TASKLOOP "); 2397 break; 2398 case llvm::omp::Directive::OMPD_taskloop_simd: 2399 Word("TASKLOOP SIMD "); 2400 break; 2401 case llvm::omp::Directive::OMPD_teams_distribute: 2402 Word("TEAMS DISTRIBUTE "); 2403 break; 2404 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do: 2405 Word("TEAMS DISTRIBUTE PARALLEL DO "); 2406 break; 2407 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd: 2408 Word("TEAMS DISTRIBUTE PARALLEL DO SIMD "); 2409 break; 2410 case llvm::omp::Directive::OMPD_teams_distribute_simd: 2411 Word("TEAMS DISTRIBUTE SIMD "); 2412 break; 2413 case llvm::omp::Directive::OMPD_tile: 2414 Word("TILE "); 2415 break; 2416 case llvm::omp::Directive::OMPD_unroll: 2417 Word("UNROLL "); 2418 break; 2419 default: 2420 break; 2421 } 2422 } 2423 void Unparse(const OmpObjectList &x) { Walk(x.v, ","); } 2424 void Unparse(const OmpSimpleStandaloneDirective &x) { 2425 switch (x.v) { 2426 case llvm::omp::Directive::OMPD_barrier: 2427 Word("BARRIER "); 2428 break; 2429 case llvm::omp::Directive::OMPD_scan: 2430 Word("SCAN "); 2431 break; 2432 case llvm::omp::Directive::OMPD_taskwait: 2433 Word("TASKWAIT "); 2434 break; 2435 case llvm::omp::Directive::OMPD_taskyield: 2436 Word("TASKYIELD "); 2437 break; 2438 case llvm::omp::Directive::OMPD_target_enter_data: 2439 Word("TARGET ENTER DATA "); 2440 break; 2441 case llvm::omp::Directive::OMPD_target_exit_data: 2442 Word("TARGET EXIT DATA "); 2443 break; 2444 case llvm::omp::Directive::OMPD_target_update: 2445 Word("TARGET UPDATE "); 2446 break; 2447 case llvm::omp::Directive::OMPD_ordered: 2448 Word("ORDERED "); 2449 break; 2450 default: 2451 // Nothing to be done 2452 break; 2453 } 2454 } 2455 void Unparse(const OmpBlockDirective &x) { 2456 switch (x.v) { 2457 case llvm::omp::Directive::OMPD_masked: 2458 Word("MASKED"); 2459 break; 2460 case llvm::omp::Directive::OMPD_master: 2461 Word("MASTER"); 2462 break; 2463 case llvm::omp::Directive::OMPD_ordered: 2464 Word("ORDERED "); 2465 break; 2466 case llvm::omp::Directive::OMPD_parallel_masked: 2467 Word("PARALLEL MASKED"); 2468 break; 2469 case llvm::omp::Directive::OMPD_parallel_master: 2470 Word("PARALLEL MASTER"); 2471 break; 2472 case llvm::omp::Directive::OMPD_parallel_workshare: 2473 Word("PARALLEL WORKSHARE "); 2474 break; 2475 case llvm::omp::Directive::OMPD_parallel: 2476 Word("PARALLEL "); 2477 break; 2478 case llvm::omp::Directive::OMPD_scope: 2479 Word("SCOPE "); 2480 break; 2481 case llvm::omp::Directive::OMPD_single: 2482 Word("SINGLE "); 2483 break; 2484 case llvm::omp::Directive::OMPD_target_data: 2485 Word("TARGET DATA "); 2486 break; 2487 case llvm::omp::Directive::OMPD_target_parallel: 2488 Word("TARGET PARALLEL "); 2489 break; 2490 case llvm::omp::Directive::OMPD_target_teams: 2491 Word("TARGET TEAMS "); 2492 break; 2493 case llvm::omp::Directive::OMPD_target: 2494 Word("TARGET "); 2495 break; 2496 case llvm::omp::Directive::OMPD_taskgroup: 2497 Word("TASKGROUP "); 2498 break; 2499 case llvm::omp::Directive::OMPD_task: 2500 Word("TASK "); 2501 break; 2502 case llvm::omp::Directive::OMPD_teams: 2503 Word("TEAMS "); 2504 break; 2505 case llvm::omp::Directive::OMPD_workshare: 2506 Word("WORKSHARE "); 2507 break; 2508 default: 2509 // Nothing to be done 2510 break; 2511 } 2512 } 2513 2514 void Unparse(const OmpAtomicDefaultMemOrderClause &x) { 2515 Word(ToUpperCaseLetters(common::EnumToString(x.v))); 2516 } 2517 2518 void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); } 2519 2520 void Unparse(const OmpAtomic &x) { 2521 BeginOpenMP(); 2522 Word("!$OMP ATOMIC"); 2523 Walk(std::get<OmpAtomicClauseList>(x.t)); 2524 Put("\n"); 2525 EndOpenMP(); 2526 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2527 BeginOpenMP(); 2528 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2529 EndOpenMP(); 2530 } 2531 void Unparse(const OmpAtomicCapture &x) { 2532 BeginOpenMP(); 2533 Word("!$OMP ATOMIC"); 2534 Walk(std::get<0>(x.t)); 2535 Word(" CAPTURE"); 2536 Walk(std::get<2>(x.t)); 2537 Put("\n"); 2538 EndOpenMP(); 2539 Walk(std::get<OmpAtomicCapture::Stmt1>(x.t)); 2540 Put("\n"); 2541 Walk(std::get<OmpAtomicCapture::Stmt2>(x.t)); 2542 BeginOpenMP(); 2543 Word("!$OMP END ATOMIC\n"); 2544 EndOpenMP(); 2545 } 2546 void Unparse(const OmpAtomicCompare &x) { 2547 BeginOpenMP(); 2548 Word("!$OMP ATOMIC"); 2549 Walk(std::get<0>(x.t)); 2550 Word(" COMPARE"); 2551 Walk(std::get<2>(x.t)); 2552 Put("\n"); 2553 EndOpenMP(); 2554 Walk(std::get<OmpAtomicCompareIfStmt>(x.t)); 2555 } 2556 void Unparse(const OmpAtomicRead &x) { 2557 BeginOpenMP(); 2558 Word("!$OMP ATOMIC"); 2559 Walk(std::get<0>(x.t)); 2560 Word(" READ"); 2561 Walk(std::get<2>(x.t)); 2562 Put("\n"); 2563 EndOpenMP(); 2564 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2565 BeginOpenMP(); 2566 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2567 EndOpenMP(); 2568 } 2569 void Unparse(const OmpAtomicUpdate &x) { 2570 BeginOpenMP(); 2571 Word("!$OMP ATOMIC"); 2572 Walk(std::get<0>(x.t)); 2573 Word(" UPDATE"); 2574 Walk(std::get<2>(x.t)); 2575 Put("\n"); 2576 EndOpenMP(); 2577 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2578 BeginOpenMP(); 2579 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2580 EndOpenMP(); 2581 } 2582 void Unparse(const OmpAtomicWrite &x) { 2583 BeginOpenMP(); 2584 Word("!$OMP ATOMIC"); 2585 Walk(std::get<0>(x.t)); 2586 Word(" WRITE"); 2587 Walk(std::get<2>(x.t)); 2588 Put("\n"); 2589 EndOpenMP(); 2590 Walk(std::get<Statement<AssignmentStmt>>(x.t)); 2591 BeginOpenMP(); 2592 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n"); 2593 EndOpenMP(); 2594 } 2595 void Unparse(const OpenMPExecutableAllocate &x) { 2596 const auto &fields = 2597 std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>( 2598 x.t); 2599 if (fields) { 2600 for (const auto &decl : *fields) { 2601 Walk(decl); 2602 } 2603 } 2604 BeginOpenMP(); 2605 Word("!$OMP ALLOCATE"); 2606 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")"); 2607 Walk(std::get<OmpClauseList>(x.t)); 2608 Put("\n"); 2609 EndOpenMP(); 2610 Walk(std::get<Statement<AllocateStmt>>(x.t)); 2611 } 2612 void Unparse(const OpenMPDeclarativeAllocate &x) { 2613 BeginOpenMP(); 2614 Word("!$OMP ALLOCATE"); 2615 Put(" ("); 2616 Walk(std::get<OmpObjectList>(x.t)); 2617 Put(")"); 2618 Walk(std::get<OmpClauseList>(x.t)); 2619 Put("\n"); 2620 EndOpenMP(); 2621 } 2622 void Unparse(const OmpEndAllocators &x) { 2623 BeginOpenMP(); 2624 Word("!$OMP END ALLOCATE"); 2625 Put("\n"); 2626 EndOpenMP(); 2627 } 2628 void Unparse(const OpenMPAllocatorsConstruct &x) { 2629 BeginOpenMP(); 2630 Word("!$OMP ALLOCATE"); 2631 Walk(std::get<OmpClauseList>(x.t)); 2632 Put("\n"); 2633 EndOpenMP(); 2634 Walk(std::get<Statement<AllocateStmt>>(x.t)); 2635 if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) { 2636 Walk(*end); 2637 } 2638 } 2639 void Unparse(const OmpCriticalDirective &x) { 2640 BeginOpenMP(); 2641 Word("!$OMP CRITICAL"); 2642 Walk(" (", std::get<std::optional<Name>>(x.t), ")"); 2643 Walk(std::get<OmpClauseList>(x.t)); 2644 Put("\n"); 2645 EndOpenMP(); 2646 } 2647 void Unparse(const OmpEndCriticalDirective &x) { 2648 BeginOpenMP(); 2649 Word("!$OMP END CRITICAL"); 2650 Walk(" (", std::get<std::optional<Name>>(x.t), ")"); 2651 Put("\n"); 2652 EndOpenMP(); 2653 } 2654 void Unparse(const OpenMPCriticalConstruct &x) { 2655 Walk(std::get<OmpCriticalDirective>(x.t)); 2656 Walk(std::get<Block>(x.t), ""); 2657 Walk(std::get<OmpEndCriticalDirective>(x.t)); 2658 } 2659 void Unparse(const OmpDeclareTargetWithList &x) { 2660 Put("("), Walk(x.v), Put(")"); 2661 } 2662 void Unparse(const OmpReductionInitializerClause &x) { 2663 Word(" INITIALIZER(OMP_PRIV = "); 2664 Walk(x.v); 2665 Put(")"); 2666 } 2667 void Unparse(const OmpReductionCombiner::FunctionCombiner &x) { 2668 const auto &pd = std::get<ProcedureDesignator>(x.v.t); 2669 const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t); 2670 Walk(pd); 2671 if (args.empty()) { 2672 if (std::holds_alternative<ProcComponentRef>(pd.u)) { 2673 Put("()"); 2674 } 2675 } else { 2676 Walk("(", args, ", ", ")"); 2677 } 2678 } 2679 void Unparse(const OpenMPDeclareReductionConstruct &x) { 2680 BeginOpenMP(); 2681 Word("!$OMP DECLARE REDUCTION "); 2682 Put("("); 2683 Walk(std::get<OmpReductionIdentifier>(x.t)), Put(" : "); 2684 Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : "); 2685 Walk(std::get<OmpReductionCombiner>(x.t)); 2686 Put(")"); 2687 Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t)); 2688 EndOpenMP(); 2689 } 2690 2691 void Unparse(const OpenMPDeclareMapperConstruct &z) { 2692 BeginOpenMP(); 2693 Word("!$OMP DECLARE MAPPER ("); 2694 const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)}; 2695 if (auto mapname{std::get<std::optional<Name>>(spec.t)}) { 2696 Walk(mapname); 2697 Put(":"); 2698 } 2699 Walk(std::get<TypeSpec>(spec.t)); 2700 Put("::"); 2701 Walk(std::get<Name>(spec.t)); 2702 Put(")"); 2703 2704 Walk(std::get<OmpClauseList>(z.t)); 2705 Put("\n"); 2706 EndOpenMP(); 2707 } 2708 void Unparse(const OpenMPDeclareSimdConstruct &y) { 2709 BeginOpenMP(); 2710 Word("!$OMP DECLARE SIMD "); 2711 Walk("(", std::get<std::optional<Name>>(y.t), ")"); 2712 Walk(std::get<OmpClauseList>(y.t)); 2713 Put("\n"); 2714 EndOpenMP(); 2715 } 2716 void Unparse(const OpenMPDeclareTargetConstruct &x) { 2717 BeginOpenMP(); 2718 Word("!$OMP DECLARE TARGET "); 2719 Walk(std::get<parser::OmpDeclareTargetSpecifier>(x.t)); 2720 Put("\n"); 2721 EndOpenMP(); 2722 } 2723 void Unparse(const OpenMPRequiresConstruct &y) { 2724 BeginOpenMP(); 2725 Word("!$OMP REQUIRES "); 2726 Walk(std::get<OmpClauseList>(y.t)); 2727 Put("\n"); 2728 EndOpenMP(); 2729 } 2730 void Unparse(const OpenMPThreadprivate &x) { 2731 BeginOpenMP(); 2732 Word("!$OMP THREADPRIVATE ("); 2733 Walk(std::get<parser::OmpObjectList>(x.t)); 2734 Put(")\n"); 2735 EndOpenMP(); 2736 } 2737 2738 bool Pre(const OmpMessageClause &x) { 2739 Walk(x.v); 2740 return false; 2741 } 2742 void Unparse(const OmpDispatchDirective &x) { 2743 Word("!$OMP DISPATCH"); 2744 Walk(x.t); 2745 Put("\n"); 2746 } 2747 void Unparse(const OmpEndDispatchDirective &) { 2748 Word("!$OMP END DISPATCH"); 2749 Put("\n"); 2750 } 2751 void Unparse(const OmpErrorDirective &x) { 2752 Word("!$OMP ERROR "); 2753 Walk(x.t); 2754 Put("\n"); 2755 } 2756 void Unparse(const OmpNothingDirective &x) { 2757 Word("!$OMP NOTHING"); 2758 Put("\n"); 2759 } 2760 void Unparse(const OmpSectionsDirective &x) { 2761 switch (x.v) { 2762 case llvm::omp::Directive::OMPD_sections: 2763 Word("SECTIONS "); 2764 break; 2765 case llvm::omp::Directive::OMPD_parallel_sections: 2766 Word("PARALLEL SECTIONS "); 2767 break; 2768 default: 2769 break; 2770 } 2771 } 2772 void Unparse(const OmpSectionBlocks &x) { 2773 for (const auto &y : x.v) { 2774 BeginOpenMP(); 2775 Word("!$OMP SECTION"); 2776 Put("\n"); 2777 EndOpenMP(); 2778 // y.u is an OpenMPSectionConstruct 2779 // (y.u).v is Block 2780 Walk(std::get<OpenMPSectionConstruct>(y.u).v, ""); 2781 } 2782 } 2783 void Unparse(const OpenMPSectionsConstruct &x) { 2784 BeginOpenMP(); 2785 Word("!$OMP "); 2786 Walk(std::get<OmpBeginSectionsDirective>(x.t)); 2787 Put("\n"); 2788 EndOpenMP(); 2789 Walk(std::get<OmpSectionBlocks>(x.t)); 2790 BeginOpenMP(); 2791 Word("!$OMP END "); 2792 Walk(std::get<OmpEndSectionsDirective>(x.t)); 2793 Put("\n"); 2794 EndOpenMP(); 2795 } 2796 void Unparse(const OpenMPCancellationPointConstruct &x) { 2797 BeginOpenMP(); 2798 Word("!$OMP CANCELLATION POINT "); 2799 Walk(std::get<OmpCancelType>(x.t)); 2800 Put("\n"); 2801 EndOpenMP(); 2802 } 2803 void Unparse(const OpenMPCancelConstruct &x) { 2804 BeginOpenMP(); 2805 Word("!$OMP CANCEL "); 2806 Walk(std::get<OmpCancelType>(x.t)); 2807 Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t)); 2808 Put("\n"); 2809 EndOpenMP(); 2810 } 2811 void Unparse(const OmpFailClause &x) { 2812 Word("FAIL("); 2813 Walk(x.v); 2814 Put(")"); 2815 } 2816 void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); } 2817 void Unparse(const OmpAtomicClause &x) { 2818 common::visit(common::visitors{ 2819 [&](const OmpMemoryOrderClause &y) { Walk(y); }, 2820 [&](const OmpFailClause &y) { Walk(y); }, 2821 [&](const OmpClause &z) { Walk(z); }, 2822 }, 2823 x.u); 2824 } 2825 void Unparse(const OmpMetadirectiveDirective &x) { 2826 BeginOpenMP(); 2827 Word("!$OMP METADIRECTIVE "); 2828 Walk(std::get<OmpClauseList>(x.t)); 2829 Put("\n"); 2830 EndOpenMP(); 2831 } 2832 void Unparse(const OpenMPDepobjConstruct &x) { 2833 BeginOpenMP(); 2834 Word("!$OMP DEPOBJ"); 2835 Put("("); 2836 Walk(std::get<OmpObject>(x.t)); 2837 Put(") "); 2838 Walk(std::get<OmpClause>(x.t)); 2839 Put("\n"); 2840 EndOpenMP(); 2841 } 2842 void Unparse(const OpenMPFlushConstruct &x) { 2843 BeginOpenMP(); 2844 Word("!$OMP FLUSH "); 2845 Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t)); 2846 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")"); 2847 Put("\n"); 2848 EndOpenMP(); 2849 } 2850 void Unparse(const OmpEndLoopDirective &x) { 2851 BeginOpenMP(); 2852 Word("!$OMP END "); 2853 Walk(std::get<OmpLoopDirective>(x.t)); 2854 Walk(std::get<OmpClauseList>(x.t)); 2855 Put("\n"); 2856 EndOpenMP(); 2857 } 2858 void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); } 2859 void Unparse(const OpenMPSimpleStandaloneConstruct &x) { 2860 BeginOpenMP(); 2861 Word("!$OMP "); 2862 Walk(std::get<OmpSimpleStandaloneDirective>(x.t)); 2863 Walk(std::get<OmpClauseList>(x.t)); 2864 Put("\n"); 2865 EndOpenMP(); 2866 } 2867 void Unparse(const OpenMPBlockConstruct &x) { 2868 BeginOpenMP(); 2869 Word("!$OMP "); 2870 Walk(std::get<OmpBeginBlockDirective>(x.t)); 2871 Put("\n"); 2872 EndOpenMP(); 2873 Walk(std::get<Block>(x.t), ""); 2874 BeginOpenMP(); 2875 Word("!$OMP END "); 2876 Walk(std::get<OmpEndBlockDirective>(x.t)); 2877 Put("\n"); 2878 EndOpenMP(); 2879 } 2880 void Unparse(const OpenMPLoopConstruct &x) { 2881 BeginOpenMP(); 2882 Word("!$OMP "); 2883 Walk(std::get<OmpBeginLoopDirective>(x.t)); 2884 Put("\n"); 2885 EndOpenMP(); 2886 Walk(std::get<std::optional<DoConstruct>>(x.t)); 2887 Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t)); 2888 } 2889 void Unparse(const BasedPointer &x) { 2890 Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t)); 2891 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')'); 2892 } 2893 void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); } 2894 void Unparse(const CUDAAttributesStmt &x) { 2895 Word("ATTRIBUTES("), Walk(std::get<common::CUDADataAttr>(x.t)); 2896 Word(") "), Walk(std::get<std::list<Name>>(x.t), ", "); 2897 } 2898 void Post(const StructureField &x) { 2899 if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) { 2900 for (const auto &item : 2901 std::get<std::list<ComponentOrFill>>(def->statement.t)) { 2902 if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) { 2903 structureComponents_.insert(std::get<Name>(comp->t).source); 2904 } 2905 } 2906 } 2907 } 2908 void Unparse(const StructureStmt &x) { 2909 Word("STRUCTURE "); 2910 // The name, if present, includes the /slashes/ 2911 Walk(std::get<std::optional<Name>>(x.t)); 2912 Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", "); 2913 Indent(); 2914 } 2915 void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); } 2916 void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); } 2917 void Post(const Map::MapStmt &) { Word("MAP"), Indent(); } 2918 void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); } 2919 void Post(const StructureDef::EndStructureStmt &) { 2920 Outdent(), Word("END STRUCTURE"); 2921 } 2922 void Unparse(const OldParameterStmt &x) { 2923 Word("PARAMETER "), Walk(x.v, ", "); 2924 } 2925 void Unparse(const ArithmeticIfStmt &x) { 2926 Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") "); 2927 Walk(std::get<1>(x.t)), Put(", "); 2928 Walk(std::get<2>(x.t)), Put(", "); 2929 Walk(std::get<3>(x.t)); 2930 } 2931 void Unparse(const AssignStmt &x) { 2932 Word("ASSIGN "), Walk(std::get<Label>(x.t)); 2933 Word(" TO "), Walk(std::get<Name>(x.t)); 2934 } 2935 void Unparse(const AssignedGotoStmt &x) { 2936 Word("GO TO "), Walk(std::get<Name>(x.t)); 2937 Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")"); 2938 } 2939 void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); } 2940 2941 #define WALK_NESTED_ENUM(CLASS, ENUM) \ 2942 void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); } 2943 WALK_NESTED_ENUM(AccDataModifier, Modifier) 2944 WALK_NESTED_ENUM(AccessSpec, Kind) // R807 2945 WALK_NESTED_ENUM(common, TypeParamAttr) // R734 2946 WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA 2947 WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA 2948 WALK_NESTED_ENUM(IntentSpec, Intent) // R826 2949 WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866 2950 WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205 2951 WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind) 2952 WALK_NESTED_ENUM(InquireSpec::CharVar, Kind) 2953 WALK_NESTED_ENUM(InquireSpec::IntVar, Kind) 2954 WALK_NESTED_ENUM(InquireSpec::LogVar, Kind) 2955 WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506 2956 WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410 2957 WALK_NESTED_ENUM(OmpAtClause, ActionTime) // OMP at 2958 WALK_NESTED_ENUM(OmpBindClause, Binding) // OMP bind 2959 WALK_NESTED_ENUM(OmpProcBindClause, AffinityPolicy) // OMP proc_bind 2960 WALK_NESTED_ENUM(OmpDefaultClause, DataSharingAttribute) // OMP default 2961 WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP defaultmap 2962 WALK_NESTED_ENUM(OmpVariableCategory, Value) // OMP variable-category 2963 WALK_NESTED_ENUM(OmpLastprivateModifier, Value) // OMP lastprivate-modifier 2964 WALK_NESTED_ENUM(OmpChunkModifier, Value) // OMP chunk-modifier 2965 WALK_NESTED_ENUM(OmpLinearModifier, Value) // OMP linear-modifier 2966 WALK_NESTED_ENUM(OmpOrderingModifier, Value) // OMP ordering-modifier 2967 WALK_NESTED_ENUM(OmpTaskDependenceType, Value) // OMP task-dependence-type 2968 WALK_NESTED_ENUM(OmpScheduleClause, Kind) // OMP schedule-kind 2969 WALK_NESTED_ENUM(OmpSeverityClause, Severity) // OMP severity 2970 WALK_NESTED_ENUM(OmpDeviceModifier, Value) // OMP device modifier 2971 WALK_NESTED_ENUM( 2972 OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type 2973 WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier 2974 WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation 2975 WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type 2976 WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering 2977 WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier 2978 WALK_NESTED_ENUM(OmpPrescriptiveness, Value) // OMP prescriptiveness 2979 WALK_NESTED_ENUM(OmpMapType, Value) // OMP map-type 2980 WALK_NESTED_ENUM(OmpMapTypeModifier, Value) // OMP map-type-modifier 2981 WALK_NESTED_ENUM(OmpTraitSelectorName, Value) 2982 WALK_NESTED_ENUM(OmpTraitSetSelectorName, Value) 2983 2984 #undef WALK_NESTED_ENUM 2985 void Unparse(const ReductionOperator::Operator x) { 2986 switch (x) { 2987 case ReductionOperator::Operator::Plus: 2988 Word("+"); 2989 break; 2990 case ReductionOperator::Operator::Multiply: 2991 Word("*"); 2992 break; 2993 case ReductionOperator::Operator::And: 2994 Word(".AND."); 2995 break; 2996 case ReductionOperator::Operator::Or: 2997 Word(".OR."); 2998 break; 2999 case ReductionOperator::Operator::Eqv: 3000 Word(".EQV."); 3001 break; 3002 case ReductionOperator::Operator::Neqv: 3003 Word(".NEQV."); 3004 break; 3005 default: 3006 Word(ReductionOperator::EnumToString(x)); 3007 break; 3008 } 3009 } 3010 3011 void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) { 3012 if (x.v) { 3013 Walk(*x.v); 3014 } else { 3015 Word("*"); 3016 } 3017 } 3018 void Unparse(const CUFKernelDoConstruct::LaunchConfiguration &x) { 3019 Word(" <<<"); 3020 const auto &grid{std::get<0>(x.t)}; 3021 if (grid.empty()) { 3022 Word("*"); 3023 } else if (grid.size() == 1) { 3024 Walk(grid.front()); 3025 } else { 3026 Walk("(", grid, ",", ")"); 3027 } 3028 Word(","); 3029 const auto &block{std::get<1>(x.t)}; 3030 if (block.empty()) { 3031 Word("*"); 3032 } else if (block.size() == 1) { 3033 Walk(block.front()); 3034 } else { 3035 Walk("(", block, ",", ")"); 3036 } 3037 if (const auto &stream{std::get<2>(x.t)}) { 3038 Word(",STREAM="), Walk(*stream); 3039 } 3040 Word(">>>"); 3041 } 3042 void Unparse(const CUFKernelDoConstruct::Directive &x) { 3043 Word("!$CUF KERNEL DO"); 3044 Walk(" (", std::get<std::optional<ScalarIntConstantExpr>>(x.t), ")"); 3045 Walk(std::get<std::optional<CUFKernelDoConstruct::LaunchConfiguration>>( 3046 x.t)); 3047 Walk(" ", std::get<std::list<CUFReduction>>(x.t), " "); 3048 Word("\n"); 3049 } 3050 void Unparse(const CUFKernelDoConstruct &x) { 3051 Walk(std::get<CUFKernelDoConstruct::Directive>(x.t)); 3052 Walk(std::get<std::optional<DoConstruct>>(x.t)); 3053 } 3054 void Unparse(const CUFReduction &x) { 3055 Word("REDUCE("); 3056 Walk(std::get<CUFReduction::Operator>(x.t)); 3057 Walk(":", std::get<std::list<Scalar<Variable>>>(x.t), ",", ")"); 3058 } 3059 3060 void Done() const { CHECK(indent_ == 0); } 3061 3062 private: 3063 void Put(char); 3064 void Put(const char *); 3065 void Put(const std::string &); 3066 void PutNormalized(const std::string &); 3067 void PutKeywordLetter(char); 3068 void Word(const char *); 3069 void Word(const std::string &); 3070 void Word(const std::string_view &); 3071 void Indent() { indent_ += indentationAmount_; } 3072 void Outdent() { 3073 CHECK(indent_ >= indentationAmount_); 3074 indent_ -= indentationAmount_; 3075 } 3076 void BeginOpenMP() { openmpDirective_ = true; } 3077 void EndOpenMP() { openmpDirective_ = false; } 3078 void BeginOpenACC() { openaccDirective_ = true; } 3079 void EndOpenACC() { openaccDirective_ = false; } 3080 3081 // Call back to the traversal framework. 3082 template <typename T> void Walk(const T &x) { 3083 Fortran::parser::Walk(x, *this); 3084 } 3085 3086 // Traverse a std::optional<> value. Emit a prefix and/or a suffix string 3087 // only when it contains a value. 3088 template <typename A> 3089 void Walk( 3090 const char *prefix, const std::optional<A> &x, const char *suffix = "") { 3091 if (x) { 3092 Word(prefix), Walk(*x), Word(suffix); 3093 } 3094 } 3095 template <typename A> 3096 void Walk(const std::optional<A> &x, const char *suffix = "") { 3097 return Walk("", x, suffix); 3098 } 3099 3100 // Traverse a std::list<>. Separate the elements with an optional string. 3101 // Emit a prefix and/or a suffix string only when the list is not empty. 3102 template <typename A> 3103 void Walk(const char *prefix, const std::list<A> &list, 3104 const char *comma = ", ", const char *suffix = "") { 3105 if (!list.empty()) { 3106 const char *str{prefix}; 3107 for (const auto &x : list) { 3108 Word(str), Walk(x); 3109 str = comma; 3110 } 3111 Word(suffix); 3112 } 3113 } 3114 template <typename A> 3115 void Walk(const std::list<A> &list, const char *comma = ", ", 3116 const char *suffix = "") { 3117 return Walk("", list, comma, suffix); 3118 } 3119 3120 // Traverse a std::tuple<>, with an optional separator. 3121 template <std::size_t J = 0, typename T> 3122 void WalkTupleElements(const T &tuple, const char *separator) { 3123 if (J > 0 && J < std::tuple_size_v<T>) { 3124 Word(separator); // this usage dodges "unused parameter" warning 3125 } 3126 if constexpr (J < std::tuple_size_v<T>) { 3127 Walk(std::get<J>(tuple)); 3128 WalkTupleElements<J + 1>(tuple, separator); 3129 } 3130 } 3131 template <typename... A> 3132 void Walk(const std::tuple<A...> &tuple, const char *separator = "") { 3133 WalkTupleElements(tuple, separator); 3134 } 3135 3136 void EndSubprogram(const char *kind, const std::optional<Name> &name) { 3137 Outdent(), Word("END "), Word(kind), Walk(" ", name); 3138 structureComponents_.clear(); 3139 } 3140 3141 llvm::raw_ostream &out_; 3142 int indent_{0}; 3143 const int indentationAmount_{1}; 3144 int column_{1}; 3145 const int maxColumns_{80}; 3146 std::set<CharBlock> structureComponents_; 3147 Encoding encoding_{Encoding::UTF_8}; 3148 bool capitalizeKeywords_{true}; 3149 bool openaccDirective_{false}; 3150 bool openmpDirective_{false}; 3151 bool backslashEscapes_{false}; 3152 preStatementType *preStatement_{nullptr}; 3153 AnalyzedObjectsAsFortran *asFortran_{nullptr}; 3154 }; 3155 3156 void UnparseVisitor::Put(char ch) { 3157 int sav = indent_; 3158 if (openmpDirective_ || openaccDirective_) { 3159 indent_ = 0; 3160 } 3161 if (column_ <= 1) { 3162 if (ch == '\n') { 3163 return; 3164 } 3165 for (int j{0}; j < indent_; ++j) { 3166 out_ << ' '; 3167 } 3168 column_ = indent_ + 2; 3169 } else if (ch == '\n') { 3170 column_ = 1; 3171 } else if (++column_ >= maxColumns_) { 3172 out_ << "&\n"; 3173 for (int j{0}; j < indent_; ++j) { 3174 out_ << ' '; 3175 } 3176 if (openmpDirective_) { 3177 out_ << "!$OMP&"; 3178 column_ = 8; 3179 } else if (openaccDirective_) { 3180 out_ << "!$ACC&"; 3181 column_ = 8; 3182 } else { 3183 out_ << '&'; 3184 column_ = indent_ + 3; 3185 } 3186 } 3187 out_ << ch; 3188 if (openmpDirective_ || openaccDirective_) { 3189 indent_ = sav; 3190 } 3191 } 3192 3193 void UnparseVisitor::Put(const char *str) { 3194 for (; *str != '\0'; ++str) { 3195 Put(*str); 3196 } 3197 } 3198 3199 void UnparseVisitor::Put(const std::string &str) { 3200 for (char ch : str) { 3201 Put(ch); 3202 } 3203 } 3204 3205 void UnparseVisitor::PutNormalized(const std::string &str) { 3206 auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)}; 3207 std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)}; 3208 Put(QuoteCharacterLiteral(encoded, backslashEscapes_)); 3209 } 3210 3211 void UnparseVisitor::PutKeywordLetter(char ch) { 3212 if (capitalizeKeywords_) { 3213 Put(ToUpperCaseLetter(ch)); 3214 } else { 3215 Put(ToLowerCaseLetter(ch)); 3216 } 3217 } 3218 3219 void UnparseVisitor::Word(const char *str) { 3220 for (; *str != '\0'; ++str) { 3221 PutKeywordLetter(*str); 3222 } 3223 } 3224 3225 void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); } 3226 3227 void UnparseVisitor::Word(const std::string_view &str) { 3228 for (std::size_t j{0}; j < str.length(); ++j) { 3229 PutKeywordLetter(str[j]); 3230 } 3231 } 3232 3233 template <typename A> 3234 void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding, 3235 bool capitalizeKeywords, bool backslashEscapes, 3236 preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) { 3237 UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes, 3238 preStatement, asFortran}; 3239 Walk(root, visitor); 3240 visitor.Done(); 3241 } 3242 3243 template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding, 3244 bool, bool, preStatementType *, AnalyzedObjectsAsFortran *); 3245 template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool, 3246 bool, preStatementType *, AnalyzedObjectsAsFortran *); 3247 } // namespace Fortran::parser 3248