brintos

brintos / llvm-project-archived public Read only

0
0
Text · 104.9 KiB · 8e9c7d0 Raw
3098 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// Generates Fortran from the content of a parse tree, using the10// traversal templates in parse-tree-visitor.h.11 12#include "flang/Parser/unparse.h"13#include "flang/Common/idioms.h"14#include "flang/Common/indirection.h"15#include "flang/Parser/characters.h"16#include "flang/Parser/parse-tree-visitor.h"17#include "flang/Parser/parse-tree.h"18#include "flang/Parser/tools.h"19#include "flang/Support/Fortran.h"20#include "flang/Support/LangOptions.h"21#include "llvm/Support/raw_ostream.h"22#include <algorithm>23#include <cinttypes>24#include <cstddef>25#include <set>26 27namespace Fortran::parser {28 29class UnparseVisitor {30public:31  UnparseVisitor(llvm::raw_ostream &out, const common::LangOptions &langOpts,32      int indentationAmount, Encoding encoding, bool capitalize,33      bool backslashEscapes, preStatementType *preStatement,34      AnalyzedObjectsAsFortran *asFortran)35      : out_{out}, langOpts_{langOpts}, indentationAmount_{indentationAmount},36        encoding_{encoding}, capitalizeKeywords_{capitalize},37        backslashEscapes_{backslashEscapes}, preStatement_{preStatement},38        asFortran_{asFortran} {}39 40  // In nearly all cases, this code avoids defining Boolean-valued Pre()41  // callbacks for the parse tree walking framework in favor of two void42  // functions, Before() and Unparse(), which imply true and false return43  // values for Pre() respectively.44  template <typename T> void Before(const T &) {}45  template <typename T> double Unparse(const T &); // not void, never used46 47  template <typename T> bool Pre(const T &x) {48    if constexpr (std::is_void_v<decltype(Unparse(x))>) {49      // There is a local definition of Unparse() for this type.  It50      // overrides the parse tree walker's default Walk() over the descendents.51      Before(x);52      Unparse(x);53      Post(x);54      return false; // Walk() does not visit descendents55    } else if constexpr (HasTypedExpr<T>::value) {56      // Format the expression representation from semantics57      if (asFortran_ && x.typedExpr) {58        asFortran_->expr(out_, *x.typedExpr);59        return false;60      } else {61        return true;62      }63    } else {64      Before(x);65      return true; // there's no Unparse() defined here, Walk() the descendents66    }67  }68  template <typename T> void Post(const T &) {}69 70  // Emit simple types as-is.71  void Unparse(const std::string &x) { Put(x); }72  void Unparse(int x) { Put(std::to_string(x)); }73  void Unparse(unsigned int x) { Put(std::to_string(x)); }74  void Unparse(long x) { Put(std::to_string(x)); }75  void Unparse(unsigned long x) { Put(std::to_string(x)); }76  void Unparse(long long x) { Put(std::to_string(x)); }77  void Unparse(unsigned long long x) { Put(std::to_string(x)); }78  void Unparse(char x) { Put(x); }79 80  // Statement labels and ends of lines81  template <typename T> void Before(const Statement<T> &x) {82    if (preStatement_) {83      (*preStatement_)(x.source, out_, indent_);84    }85    Walk(x.label, " ");86  }87  template <typename T> void Post(const Statement<T> &) { Put('\n'); }88 89  // The special-case formatting functions for these productions are90  // ordered to correspond roughly to their order of appearance in91  // the Fortran 2018 standard (and parse-tree.h).92 93  void Unparse(const Program &x) { // R50194    Walk("", x.v, "\n"); // put blank lines between ProgramUnits95  }96 97  void Unparse(const Name &x) { // R60398    Put(x.ToString());99  }100  void Unparse(const DefinedOperator::IntrinsicOperator &x) { // R608101    switch (x) {102    case DefinedOperator::IntrinsicOperator::Power:103      Put("**");104      break;105    case DefinedOperator::IntrinsicOperator::Multiply:106      Put('*');107      break;108    case DefinedOperator::IntrinsicOperator::Divide:109      Put('/');110      break;111    case DefinedOperator::IntrinsicOperator::Add:112      Put('+');113      break;114    case DefinedOperator::IntrinsicOperator::Subtract:115      Put('-');116      break;117    case DefinedOperator::IntrinsicOperator::Concat:118      Put("//");119      break;120    case DefinedOperator::IntrinsicOperator::LT:121      Put('<');122      break;123    case DefinedOperator::IntrinsicOperator::LE:124      Put("<=");125      break;126    case DefinedOperator::IntrinsicOperator::EQ:127      Put("==");128      break;129    case DefinedOperator::IntrinsicOperator::NE:130      Put("/=");131      break;132    case DefinedOperator::IntrinsicOperator::GE:133      Put(">=");134      break;135    case DefinedOperator::IntrinsicOperator::GT:136      Put('>');137      break;138    default:139      Put('.'), Word(DefinedOperator::EnumToString(x)), Put('.');140    }141  }142  void Post(const Star &) { Put('*'); } // R701 &c.143  void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701144  void Unparse(const DeclarationTypeSpec::Type &x) { // R703145    Word("TYPE("), Walk(x.derived), Put(')');146  }147  void Unparse(const DeclarationTypeSpec::Class &x) {148    Word("CLASS("), Walk(x.derived), Put(')');149  }150  void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); }151  void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); }152  void Unparse(const DeclarationTypeSpec::Record &x) {153    Word("RECORD/"), Walk(x.v), Put('/');154  }155  void Before(const IntrinsicTypeSpec::Real &) { // R704156    Word("REAL");157  }158  void Before(const IntrinsicTypeSpec::Complex &) { Word("COMPLEX"); }159  void Post(const IntrinsicTypeSpec::DoublePrecision &) {160    Word("DOUBLE PRECISION");161  }162  void Before(const IntrinsicTypeSpec::Character &) { Word("CHARACTER"); }163  void Before(const IntrinsicTypeSpec::Logical &) { Word("LOGICAL"); }164  void Post(const IntrinsicTypeSpec::DoubleComplex &) {165    Word("DOUBLE COMPLEX");166  }167  void Before(const UnsignedTypeSpec &) { Word("UNSIGNED"); }168  void Before(const IntrinsicVectorTypeSpec &) { Word("VECTOR("); }169  void Post(const IntrinsicVectorTypeSpec &) { Put(')'); }170  void Post(const VectorTypeSpec::PairVectorTypeSpec &) {171    Word("__VECTOR_PAIR");172  }173  void Post(const VectorTypeSpec::QuadVectorTypeSpec &) {174    Word("__VECTOR_QUAD");175  }176  void Before(const IntegerTypeSpec &) { // R705177    Word("INTEGER");178  }179  void Unparse(const KindSelector &x) { // R706180    common::visit(181        common::visitors{182            [&](const ScalarIntConstantExpr &y) {183              Put('('), Word("KIND="), Walk(y), Put(')');184            },185            [&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); },186        },187        x.u);188  }189  void Unparse(const SignedIntLiteralConstant &x) { // R707190    Put(std::get<CharBlock>(x.t).ToString());191    Walk("_", std::get<std::optional<KindParam>>(x.t));192  }193  void Unparse(const IntLiteralConstant &x) { // R708194    Put(std::get<CharBlock>(x.t).ToString());195    Walk("_", std::get<std::optional<KindParam>>(x.t));196  }197  void Unparse(const Sign &x) { // R712198    Put(x == Sign::Negative ? '-' : '+');199  }200  void Unparse(const RealLiteralConstant &x) { // R714, R715201    Put(x.real.source.ToString()), Walk("_", x.kind);202  }203  void Unparse(const ComplexLiteralConstant &x) { // R718 - R720204    Put('('), Walk(x.t, ","), Put(')');205  }206  void Unparse(const CharSelector::LengthAndKind &x) { // R721207    Put('('), Word("KIND="), Walk(x.kind);208    Walk(", LEN=", x.length), Put(')');209  }210  void Unparse(const LengthSelector &x) { // R722211    common::visit(common::visitors{212                      [&](const TypeParamValue &y) {213                        Put('('), Word("LEN="), Walk(y), Put(')');214                      },215                      [&](const CharLength &y) { Put('*'), Walk(y); },216                  },217        x.u);218  }219  void Unparse(const CharLength &x) { // R723220    common::visit(221        common::visitors{222            [&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); },223            [&](const std::int64_t &y) { Walk(y); },224        },225        x.u);226  }227  void Unparse(const CharLiteralConstant &x) { // R724228    const auto &str{std::get<std::string>(x.t)};229    if (const auto &k{std::get<std::optional<KindParam>>(x.t)}) {230      Walk(*k), Put('_');231    }232    PutNormalized(str);233  }234  void Unparse(const HollerithLiteralConstant &x) {235    auto ucs{DecodeString<std::u32string, Encoding::UTF_8>(x.v, false)};236    Unparse(ucs.size());237    Put('H');238    for (char32_t ch : ucs) {239      EncodedCharacter encoded{EncodeCharacter(encoding_, ch)};240      for (int j{0}; j < encoded.bytes; ++j) {241        Put(encoded.buffer[j]);242      }243    }244  }245  void Unparse(const LogicalLiteralConstant &x) { // R725246    Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE.");247    Walk("_", std::get<std::optional<KindParam>>(x.t));248  }249  void Unparse(const DerivedTypeStmt &x) { // R727250    Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", ");251    Put(" :: "), Walk(std::get<Name>(x.t));252    Walk("(", std::get<std::list<Name>>(x.t), ", ", ")");253    Indent();254  }255  void Unparse(const Abstract &) { // R728, &c.256    Word("ABSTRACT");257  }258  void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); }259  void Unparse(const TypeAttrSpec::Extends &x) {260    Word("EXTENDS("), Walk(x.v), Put(')');261  }262  void Unparse(const EndTypeStmt &x) { // R730263    Outdent(), Word("END TYPE"), Walk(" ", x.v);264  }265  void Unparse(const SequenceStmt &) { // R731266    Word("SEQUENCE");267  }268  void Unparse(const TypeParamDefStmt &x) { // R732269    Walk(std::get<IntegerTypeSpec>(x.t));270    Put(", "), Walk(std::get<common::TypeParamAttr>(x.t));271    Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", ");272  }273  void Unparse(const TypeParamDecl &x) { // R733274    Walk(std::get<Name>(x.t));275    Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t));276  }277  void Unparse(const DataComponentDefStmt &x) { // R737278    const auto &dts{std::get<DeclarationTypeSpec>(x.t)};279    const auto &attrs{std::get<std::list<ComponentAttrSpec>>(x.t)};280    const auto &decls{std::get<std::list<ComponentOrFill>>(x.t)};281    Walk(dts), Walk(", ", attrs, ", ");282    if (!attrs.empty() ||283        (!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) &&284            std::none_of(285                decls.begin(), decls.end(), [](const ComponentOrFill &c) {286                  return common::visit(287                      common::visitors{288                          [](const ComponentDecl &d) {289                            const auto &init{290                                std::get<std::optional<Initialization>>(d.t)};291                            return init &&292                                std::holds_alternative<std::list<293                                    common::Indirection<DataStmtValue>>>(294                                    init->u);295                          },296                          [](const FillDecl &) { return false; },297                      },298                      c.u);299                }))) {300      Put(" ::");301    }302    Put(' '), Walk(decls, ", ");303  }304  void Unparse(const Allocatable &) { // R738305    Word("ALLOCATABLE");306  }307  void Unparse(const Pointer &) { Word("POINTER"); }308  void Unparse(const Contiguous &) { Word("CONTIGUOUS"); }309  void Before(const ComponentAttrSpec &x) {310    common::visit(common::visitors{311                      [&](const CoarraySpec &) { Word("CODIMENSION["); },312                      [&](const ComponentArraySpec &) { Word("DIMENSION("); },313                      [](const auto &) {},314                  },315        x.u);316  }317  void Post(const ComponentAttrSpec &x) {318    common::visit(common::visitors{319                      [&](const CoarraySpec &) { Put(']'); },320                      [&](const ComponentArraySpec &) { Put(')'); },321                      [](const auto &) {},322                  },323        x.u);324  }325  void Unparse(const ComponentDecl &x) { // R739326    Walk(std::get<ObjectName>(x.t));327    Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")");328    Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");329    Walk("*", std::get<std::optional<CharLength>>(x.t));330    Walk(std::get<std::optional<Initialization>>(x.t));331  }332  void Unparse(const FillDecl &x) { // DEC extension333    Put("%FILL");334    Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")");335    Walk("*", std::get<std::optional<CharLength>>(x.t));336  }337  void Unparse(const ComponentArraySpec &x) { // R740338    common::visit(339        common::visitors{340            [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },341            [&](const DeferredShapeSpecList &y) { Walk(y); },342        },343        x.u);344  }345  void Unparse(const ProcComponentDefStmt &x) { // R741346    Word("PROCEDURE(");347    Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')');348    Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", ");349    Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");350  }351  void Unparse(const NoPass &) { // R742352    Word("NOPASS");353  }354  void Unparse(const Pass &x) { Word("PASS"), Walk("(", x.v, ")"); }355  void Unparse(const Initialization &x) { // R743 & R805356    common::visit(357        common::visitors{358            [&](const ConstantExpr &y) { Put(" = "), Walk(y); },359            [&](const NullInit &y) { Put(" => "), Walk(y); },360            [&](const InitialDataTarget &y) { Put(" => "), Walk(y); },361            [&](const std::list<common::Indirection<DataStmtValue>> &y) {362              Walk("/", y, ", ", "/");363            },364        },365        x.u);366  }367  void Unparse(const PrivateStmt &) { // R745368    Word("PRIVATE");369  }370  void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749371    Word("PROCEDURE"), Walk(", ", x.attributes, ", ");372    Put(" :: "), Walk(x.declarations, ", ");373  }374  void Unparse(const TypeBoundProcedureStmt::WithInterface &x) {375    Word("PROCEDURE("), Walk(x.interfaceName), Put("), ");376    Walk(x.attributes);377    Put(" :: "), Walk(x.bindingNames, ", ");378  }379  void Unparse(const TypeBoundProcDecl &x) { // R750380    Walk(std::get<Name>(x.t));381    Walk(" => ", std::get<std::optional<Name>>(x.t));382  }383  void Unparse(const TypeBoundGenericStmt &x) { // R751384    Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));385    Put(" :: "), Walk(std::get<common::Indirection<GenericSpec>>(x.t));386    Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", ");387  }388  void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752389  void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); }390  void Unparse(const FinalProcedureStmt &x) { // R753391    Word("FINAL :: "), Walk(x.v, ", ");392  }393  void Unparse(const DerivedTypeSpec &x) { // R754394    Walk(std::get<Name>(x.t));395    Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")");396  }397  void Unparse(const TypeParamSpec &x) { // R755398    Walk(std::get<std::optional<Keyword>>(x.t), "=");399    Walk(std::get<TypeParamValue>(x.t));400  }401  void Unparse(const StructureConstructor &x) { // R756402    Walk(std::get<DerivedTypeSpec>(x.t));403    Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')');404  }405  void Unparse(const ComponentSpec &x) { // R757406    Walk(std::get<std::optional<Keyword>>(x.t), "=");407    Walk(std::get<ComponentDataSource>(x.t));408  }409  void Unparse(const EnumDefStmt &) { // R760410    Word("ENUM, BIND(C)"), Indent();411  }412  void Unparse(const EnumeratorDefStmt &x) { // R761413    Word("ENUMERATOR :: "), Walk(x.v, ", ");414  }415  void Unparse(const Enumerator &x) { // R762416    Walk(std::get<NamedConstant>(x.t));417    Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t));418  }419  void Post(const EndEnumStmt &) { // R763420    Outdent(), Word("END ENUM");421  }422  void Unparse(const BOZLiteralConstant &x) { // R764 - R767423    Put(x.v);424  }425  void Unparse(const AcValue::Triplet &x) { // R773426    Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));427    Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));428  }429  void Unparse(const ArrayConstructor &x) { // R769430    Put('['), Walk(x.v), Put(']');431  }432  void Unparse(const AcSpec &x) { // R770433    Walk(x.type, "::"), Walk(x.values, ", ");434  }435  template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) {436    Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);437    Walk(",", x.step);438  }439  void Unparse(const AcImpliedDo &x) { // R774440    Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", ");441    Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')');442  }443  void Unparse(const AcImpliedDoControl &x) { // R775444    Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");445    Walk(std::get<AcImpliedDoControl::Bounds>(x.t));446  }447 448  void Unparse(const TypeDeclarationStmt &x) { // R801449    const auto &dts{std::get<DeclarationTypeSpec>(x.t)};450    const auto &attrs{std::get<std::list<AttrSpec>>(x.t)};451    const auto &decls{std::get<std::list<EntityDecl>>(x.t)};452    Walk(dts), Walk(", ", attrs, ", ");453 454    static const auto isInitializerOldStyle{[](const Initialization &i) {455      return std::holds_alternative<456          std::list<common::Indirection<DataStmtValue>>>(i.u);457    }};458    static const auto hasAssignmentInitializer{[](const EntityDecl &d) {459      // Does a declaration have a new-style =x initializer?460      const auto &init{std::get<std::optional<Initialization>>(d.t)};461      return init && !isInitializerOldStyle(*init);462    }};463    static const auto hasSlashDelimitedInitializer{[](const EntityDecl &d) {464      // Does a declaration have an old-style /x/ initializer?465      const auto &init{std::get<std::optional<Initialization>>(d.t)};466      return init && isInitializerOldStyle(*init);467    }};468    const auto useDoubledColons{[&]() {469      bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)};470      if (!attrs.empty()) {471        // Attributes after the type require :: before the entities.472        CHECK(!isRecord);473        return true;474      }475      if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) {476        // Always use :: with new style standard initializers (=x),477        // since the standard requires them to appear (even in free form,478        // where mandatory spaces already disambiguate INTEGER J=666).479        CHECK(!isRecord);480        return true;481      }482      if (isRecord) {483        // Never put :: in a legacy extension RECORD// statement.484        return false;485      }486      // The :: is optional for this declaration.  Avoid usage that can487      // crash the pgf90 compiler.488      if (std::any_of(489              decls.begin(), decls.end(), hasSlashDelimitedInitializer)) {490        // Don't use :: when a declaration uses legacy DATA-statement-like491        // /x/ initialization.492        return false;493      }494      // Don't use :: with intrinsic types.  Otherwise, use it.495      return !std::holds_alternative<IntrinsicTypeSpec>(dts.u);496    }};497 498    if (useDoubledColons()) {499      Put(" ::");500    }501    Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", ");502  }503  void Before(const AttrSpec &x) { // R802504    common::visit(common::visitors{505                      [&](const CoarraySpec &) { Word("CODIMENSION["); },506                      [&](const ArraySpec &) { Word("DIMENSION("); },507                      [](const auto &) {},508                  },509        x.u);510  }511  void Post(const AttrSpec &x) {512    common::visit(common::visitors{513                      [&](const CoarraySpec &) { Put(']'); },514                      [&](const ArraySpec &) { Put(')'); },515                      [](const auto &) {},516                  },517        x.u);518  }519  void Unparse(const EntityDecl &x) { // R803520    Walk(std::get<ObjectName>(x.t));521    Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");522    Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");523    Walk("*", std::get<std::optional<CharLength>>(x.t));524    Walk(std::get<std::optional<Initialization>>(x.t));525  }526  void Unparse(const NullInit &) { // R806527    Word("NULL()");528  }529  void Unparse(const LanguageBindingSpec &x) { // R808 & R1528530    Word("BIND(C");531    Walk(532        ", NAME=", std::get<std::optional<ScalarDefaultCharConstantExpr>>(x.t));533    if (std::get<bool>(x.t)) {534      Word(", CDEFINED");535    }536    Put(')');537  }538  void Unparse(const CoarraySpec &x) { // R809539    common::visit(common::visitors{540                      [&](const DeferredCoshapeSpecList &y) { Walk(y); },541                      [&](const ExplicitCoshapeSpec &y) { Walk(y); },542                  },543        x.u);544  }545  void Unparse(const DeferredCoshapeSpecList &x) { // R810546    for (auto j{x.v}; j > 0; --j) {547      Put(':');548      if (j > 1) {549        Put(',');550      }551    }552  }553  void Unparse(const ExplicitCoshapeSpec &x) { // R811554    Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");555    Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*');556  }557  void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818558    Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":");559    Walk(std::get<SpecificationExpr>(x.t));560  }561  void Unparse(const ArraySpec &x) { // R815562    common::visit(563        common::visitors{564            [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },565            [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },566            [&](const DeferredShapeSpecList &y) { Walk(y); },567            [&](const AssumedSizeSpec &y) { Walk(y); },568            [&](const ImpliedShapeSpec &y) { Walk(y); },569            [&](const AssumedRankSpec &y) { Walk(y); },570        },571        x.u);572  }573  void Post(const AssumedShapeSpec &) { Put(':'); } // R819574  void Unparse(const DeferredShapeSpecList &x) { // R820575    for (auto j{x.v}; j > 0; --j) {576      Put(':');577      if (j > 1) {578        Put(',');579      }580    }581  }582  void Unparse(const AssumedImpliedSpec &x) { // R821583    Walk(x.v, ":");584    Put('*');585  }586  void Unparse(const AssumedSizeSpec &x) { // R822587    Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");588    Walk(std::get<AssumedImpliedSpec>(x.t));589  }590  void Unparse(const ImpliedShapeSpec &x) { // R823591    Walk(x.v, ",");592  }593  void Post(const AssumedRankSpec &) { Put(".."); } // R825594  void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); }595  void Post(const External &) { Word("EXTERNAL"); }596  void Post(const Intrinsic &) { Word("INTRINSIC"); }597  void Post(const Optional &) { Word("OPTIONAL"); }598  void Post(const Parameter &) { Word("PARAMETER"); }599  void Post(const Protected &) { Word("PROTECTED"); }600  void Post(const Save &) { Word("SAVE"); }601  void Post(const Target &) { Word("TARGET"); }602  void Post(const Value &) { Word("VALUE"); }603  void Post(const Volatile &) { Word("VOLATILE"); }604  void Unparse(const IntentSpec &x) { // R826605    Word("INTENT("), Walk(x.v), Put(")");606  }607  void Unparse(const AccessStmt &x) { // R827608    Walk(std::get<AccessSpec>(x.t));609    Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", ");610  }611  void Unparse(const AllocatableStmt &x) { // R829612    Word("ALLOCATABLE :: "), Walk(x.v, ", ");613  }614  void Unparse(const ObjectDecl &x) { // R830 & R860615    Walk(std::get<ObjectName>(x.t));616    Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");617    Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");618  }619  void Unparse(const AsynchronousStmt &x) { // R831620    Word("ASYNCHRONOUS :: "), Walk(x.v, ", ");621  }622  void Unparse(const BindStmt &x) { // R832623    Walk(x.t, " :: ");624  }625  void Unparse(const BindEntity &x) { // R833626    bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common};627    const char *slash{isCommon ? "/" : ""};628    Put(slash), Walk(std::get<Name>(x.t)), Put(slash);629  }630  void Unparse(const CodimensionStmt &x) { // R834631    Word("CODIMENSION :: "), Walk(x.v, ", ");632  }633  void Unparse(const CodimensionDecl &x) { // R835634    Walk(std::get<Name>(x.t));635    Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']');636  }637  void Unparse(const ContiguousStmt &x) { // R836638    Word("CONTIGUOUS :: "), Walk(x.v, ", ");639  }640  void Unparse(const DataStmt &x) { // R837641    Word("DATA "), Walk(x.v, ", ");642  }643  void Unparse(const DataStmtSet &x) { // R838644    Walk(std::get<std::list<DataStmtObject>>(x.t), ", ");645    Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/');646  }647  void Unparse(const DataImpliedDo &x) { // R840, R842648    Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');649    Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");650    Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')');651  }652  void Unparse(const DataStmtValue &x) { // R843653    Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");654    Walk(std::get<DataStmtConstant>(x.t));655  }656  void Unparse(const DimensionStmt &x) { // R848657    Word("DIMENSION :: "), Walk(x.v, ", ");658  }659  void Unparse(const DimensionStmt::Declaration &x) {660    Walk(std::get<Name>(x.t));661    Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')');662  }663  void Unparse(const IntentStmt &x) { // R849664    Walk(x.t, " :: ");665  }666  void Unparse(const OptionalStmt &x) { // R850667    Word("OPTIONAL :: "), Walk(x.v, ", ");668  }669  void Unparse(const ParameterStmt &x) { // R851670    Word("PARAMETER("), Walk(x.v, ", "), Put(')');671  }672  void Unparse(const NamedConstantDef &x) { // R852673    Walk(x.t, "=");674  }675  void Unparse(const PointerStmt &x) { // R853676    Word("POINTER :: "), Walk(x.v, ", ");677  }678  void Unparse(const PointerDecl &x) { // R854679    Walk(std::get<Name>(x.t));680    Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")");681  }682  void Unparse(const ProtectedStmt &x) { // R855683    Word("PROTECTED :: "), Walk(x.v, ", ");684  }685  void Unparse(const SaveStmt &x) { // R856686    Word("SAVE"), Walk(" :: ", x.v, ", ");687  }688  void Unparse(const SavedEntity &x) { // R857, R858689    bool isCommon{690        std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common};691    const char *slash{isCommon ? "/" : ""};692    Put(slash), Walk(std::get<Name>(x.t)), Put(slash);693  }694  void Unparse(const TargetStmt &x) { // R859695    Word("TARGET :: "), Walk(x.v, ", ");696  }697  void Unparse(const ValueStmt &x) { // R861698    Word("VALUE :: "), Walk(x.v, ", ");699  }700  void Unparse(const VolatileStmt &x) { // R862701    Word("VOLATILE :: "), Walk(x.v, ", ");702  }703  void Unparse(const ImplicitStmt &x) { // R863704    Word("IMPLICIT ");705    common::visit(706        common::visitors{707            [&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); },708            [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) {709              Word("NONE"), Walk(" (", y, ", ", ")");710            },711        },712        x.u);713  }714  void Unparse(const ImplicitSpec &x) { // R864715    Walk(std::get<DeclarationTypeSpec>(x.t));716    Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')');717  }718  void Unparse(const LetterSpec &x) { // R865719    Put(*std::get<const char *>(x.t));720    auto second{std::get<std::optional<const char *>>(x.t)};721    if (second) {722      Put('-'), Put(**second);723    }724  }725  void Unparse(const ImportStmt &x) { // R867726    Word("IMPORT");727    switch (x.kind) {728    case common::ImportKind::Default:729      Walk(" :: ", x.names, ", ");730      break;731    case common::ImportKind::Only:732      Put(", "), Word("ONLY: ");733      Walk(x.names, ", ");734      break;735    case common::ImportKind::None:736      Word(", NONE");737      break;738    case common::ImportKind::All:739      Word(", ALL");740      break;741    }742  }743  void Unparse(const NamelistStmt &x) { // R868744    Word("NAMELIST"), Walk(x.v, ", ");745  }746  void Unparse(const NamelistStmt::Group &x) {747    Put('/'), Walk(std::get<Name>(x.t)), Put('/');748    Walk(std::get<std::list<Name>>(x.t), ", ");749  }750  void Unparse(const EquivalenceStmt &x) { // R870, R871751    Word("EQUIVALENCE");752    const char *separator{" "};753    for (const std::list<EquivalenceObject> &y : x.v) {754      Put(separator), Put('('), Walk(y), Put(')');755      separator = ", ";756    }757  }758  void Unparse(const CommonStmt &x) { // R873759    Word("COMMON ");760    Walk(x.blocks);761  }762  void Unparse(const CommonBlockObject &x) { // R874763    Walk(std::get<Name>(x.t));764    Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");765  }766  void Unparse(const CommonStmt::Block &x) {767    Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/");768    Walk(std::get<std::list<CommonBlockObject>>(x.t));769  }770 771  void Unparse(const Substring &x) { // R908, R909772    Walk(std::get<DataRef>(x.t));773    Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');774  }775  void Unparse(const CharLiteralConstantSubstring &x) {776    Walk(std::get<CharLiteralConstant>(x.t));777    Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');778  }779  void Unparse(const SubstringInquiry &x) {780    Walk(x.v);781    Put(x.source.back() == 'n' ? "%LEN" : "%KIND");782  }783  void Unparse(const SubstringRange &x) { // R910784    Walk(x.t, ":");785  }786  void Unparse(const PartRef &x) { // R912787    Walk(x.name);788    Walk("(", x.subscripts, ",", ")");789    Walk(x.imageSelector);790  }791  void Unparse(const StructureComponent &x) { // R913792    Walk(x.base);793    if (structureComponents_.find(x.component.source) !=794        structureComponents_.end()) {795      Put('.');796    } else {797      Put('%');798    }799    Walk(x.component);800  }801  void Unparse(const ArrayElement &x) { // R917802    Walk(x.base);803    Put('('), Walk(x.subscripts, ","), Put(')');804  }805  void Unparse(const SubscriptTriplet &x) { // R921806    Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));807    Walk(":", std::get<2>(x.t));808  }809  void Unparse(const ImageSelector &x) { // R924810    Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ",");811    Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']');812  }813  void Before(const ImageSelectorSpec::Stat &) { // R926814    Word("STAT=");815  }816  void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); }817  void Before(const ImageSelectorSpec &x) {818    if (std::holds_alternative<TeamValue>(x.u)) {819      Word("TEAM=");820    }821  }822  void Before(const ImageSelectorSpec::Notify &) { Word("NOTIFY="); }823  void Unparse(const AllocateStmt &x) { // R927824    Word("ALLOCATE(");825    Walk(std::get<std::optional<TypeSpec>>(x.t), "::");826    Walk(std::get<std::list<Allocation>>(x.t), ", ");827    Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')');828  }829  void Before(const AllocOpt &x) { // R928, R931830    common::visit(common::visitors{831                      [&](const AllocOpt::Mold &) { Word("MOLD="); },832                      [&](const AllocOpt::Source &) { Word("SOURCE="); },833                      [&](const AllocOpt::Stream &) { Word("STREAM="); },834                      [&](const AllocOpt::Pinned &) { Word("PINNED="); },835                      [](const StatOrErrmsg &) {},836                  },837        x.u);838  }839  void Unparse(const Allocation &x) { // R932840    Walk(std::get<AllocateObject>(x.t));841    Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")");842    Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]");843  }844  void Unparse(const AllocateShapeSpec &x) { // R934 & R938845    Walk(std::get<std::optional<BoundExpr>>(x.t), ":");846    Walk(std::get<BoundExpr>(x.t));847  }848  void Unparse(const AllocateCoarraySpec &x) { // R937849    Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ",");850    Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*');851  }852  void Unparse(const NullifyStmt &x) { // R939853    Word("NULLIFY("), Walk(x.v, ", "), Put(')');854  }855  void Unparse(const DeallocateStmt &x) { // R941856    Word("DEALLOCATE(");857    Walk(std::get<std::list<AllocateObject>>(x.t), ", ");858    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');859  }860  void Before(const StatOrErrmsg &x) { // R942 & R1165861    common::visit(common::visitors{862                      [&](const StatVariable &) { Word("STAT="); },863                      [&](const MsgVariable &) { Word("ERRMSG="); },864                  },865        x.u);866  }867 868  // R1001 - R1022869  void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); }870  void Before(const Expr::UnaryPlus &) { Put("+"); }871  void Before(const Expr::Negate &) { Put("-"); }872  void Before(const Expr::NOT &) { Word(".NOT."); }873  void Unparse(const Expr::PercentLoc &x) {874    Word("%LOC("), Walk(x.v), Put(')');875  }876  void Unparse(const Expr::Power &x) { Walk(x.t, "**"); }877  void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); }878  void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); }879  void Unparse(const Expr::Add &x) { Walk(x.t, "+"); }880  void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); }881  void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); }882  void Unparse(const Expr::LT &x) { Walk(x.t, "<"); }883  void Unparse(const Expr::LE &x) { Walk(x.t, "<="); }884  void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); }885  void Unparse(const Expr::NE &x) { Walk(x.t, "/="); }886  void Unparse(const Expr::GE &x) { Walk(x.t, ">="); }887  void Unparse(const Expr::GT &x) { Walk(x.t, ">"); }888  void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); }889  void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); }890  void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); }891  void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); }892  void Unparse(const Expr::ComplexConstructor &x) {893    Put('('), Walk(x.t, ","), Put(')');894  }895  void Unparse(const Expr::DefinedBinary &x) {896    Walk(std::get<1>(x.t)); // left897    Walk(std::get<DefinedOpName>(x.t));898    Walk(std::get<2>(x.t)); // right899  }900  void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415901    Walk(x.v);902  }903  void Unparse(const AssignmentStmt &x) { // R1032904    if (asFortran_ && x.typedAssignment.get()) {905      Put(' ');906      asFortran_->assignment(out_, *x.typedAssignment);907      Put('\n');908    } else {909      Walk(x.t, " = ");910    }911  }912  void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038913    if (asFortran_ && x.typedAssignment.get()) {914      Put(' ');915      asFortran_->assignment(out_, *x.typedAssignment);916      Put('\n');917    } else {918      Walk(std::get<DataRef>(x.t));919      common::visit(920          common::visitors{921              [&](const std::list<BoundsRemapping> &y) {922                Put('('), Walk(y), Put(')');923              },924              [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); },925          },926          std::get<PointerAssignmentStmt::Bounds>(x.t).u);927      Put(" => "), Walk(std::get<Expr>(x.t));928    }929  }930  void Post(const BoundsSpec &) { // R1035931    Put(':');932  }933  void Unparse(const BoundsRemapping &x) { // R1036934    Walk(x.t, ":");935  }936  void Unparse(const WhereStmt &x) { // R1041, R1045, R1046937    Word("WHERE ("), Walk(x.t, ") ");938  }939  void Unparse(const WhereConstructStmt &x) { // R1043940    Walk(std::get<std::optional<Name>>(x.t), ": ");941    Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');942    Indent();943  }944  void Unparse(const MaskedElsewhereStmt &x) { // R1047945    Outdent();946    Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');947    Walk(" ", std::get<std::optional<Name>>(x.t));948    Indent();949  }950  void Unparse(const ElsewhereStmt &x) { // R1048951    Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent();952  }953  void Unparse(const EndWhereStmt &x) { // R1049954    Outdent(), Word("END WHERE"), Walk(" ", x.v);955  }956  void Unparse(const ForallConstructStmt &x) { // R1051957    Walk(std::get<std::optional<Name>>(x.t), ": ");958    Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t));959    Indent();960  }961  void Unparse(const EndForallStmt &x) { // R1054962    Outdent(), Word("END FORALL"), Walk(" ", x.v);963  }964  void Before(const ForallStmt &) { // R1055965    Word("FORALL");966  }967 968  void Unparse(const AssociateStmt &x) { // R1103969    Walk(std::get<std::optional<Name>>(x.t), ": ");970    Word("ASSOCIATE (");971    Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent();972  }973  void Unparse(const Association &x) { // R1104974    Walk(x.t, " => ");975  }976  void Unparse(const EndAssociateStmt &x) { // R1106977    Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v);978  }979  void Unparse(const BlockStmt &x) { // R1108980    Walk(x.v, ": "), Word("BLOCK"), Indent();981  }982  void Unparse(const EndBlockStmt &x) { // R1110983    Outdent(), Word("END BLOCK"), Walk(" ", x.v);984  }985  void Unparse(const ChangeTeamStmt &x) { // R1112986    Walk(std::get<std::optional<Name>>(x.t), ": ");987    Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t));988    Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", ");989    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');990    Indent();991  }992  void Unparse(const CoarrayAssociation &x) { // R1113993    Walk(x.t, " => ");994  }995  void Unparse(const EndChangeTeamStmt &x) { // R1114996    Outdent(), Word("END TEAM (");997    Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");998    Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t));999  }1000  void Unparse(const CriticalStmt &x) { // R11171001    Walk(std::get<std::optional<Name>>(x.t), ": ");1002    Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");1003    Put(')'), Indent();1004  }1005  void Unparse(const EndCriticalStmt &x) { // R11181006    Outdent(), Word("END CRITICAL"), Walk(" ", x.v);1007  }1008  void Unparse(const DoConstruct &x) { // R1119, R11201009    Walk(std::get<Statement<NonLabelDoStmt>>(x.t));1010    Indent(), Walk(std::get<Block>(x.t), ""), Outdent();1011    Walk(std::get<Statement<EndDoStmt>>(x.t));1012  }1013  void Unparse(const LabelDoStmt &x) { // R11211014    Word("DO "), Walk(std::get<Label>(x.t));1015    Walk(" ", std::get<std::optional<LoopControl>>(x.t));1016  }1017  void Unparse(const NonLabelDoStmt &x) { // R11221018    Walk(std::get<std::optional<Name>>(x.t), ": ");1019    Word("DO ");1020    Walk(std::get<std::optional<Label>>(x.t), " ");1021    Walk(std::get<std::optional<LoopControl>>(x.t));1022  }1023  void Unparse(const LoopControl &x) { // R11231024    common::visit(common::visitors{1025                      [&](const ScalarLogicalExpr &y) {1026                        Word("WHILE ("), Walk(y), Put(')');1027                      },1028                      [&](const auto &y) { Walk(y); },1029                  },1030        x.u);1031  }1032  void Unparse(const ConcurrentHeader &x) { // R11251033    Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");1034    Walk(std::get<std::list<ConcurrentControl>>(x.t), ", ");1035    Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')');1036  }1037  void Unparse(const ConcurrentControl &x) { // R1126 - R11281038    Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t));1039    Put(':'), Walk(std::get<2>(x.t));1040    Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));1041  }1042  void Before(const LoopControl::Concurrent &) { // R11291043    Word("CONCURRENT");1044  }1045  void Unparse(const LocalitySpec::Local &x) {1046    Word("LOCAL("), Walk(x.v, ", "), Put(')');1047  }1048  void Unparse(const LocalitySpec::LocalInit &x) {1049    Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')');1050  }1051  void Unparse(const LocalitySpec::Reduce &x) {1052    Word("REDUCE("), Walk(std::get<parser::ReductionOperator>(x.t));1053    Walk(":", std::get<std::list<parser::Name>>(x.t), ",", ")");1054  }1055  void Unparse(const LocalitySpec::Shared &x) {1056    Word("SHARED("), Walk(x.v, ", "), Put(')');1057  }1058  void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); }1059  void Unparse(const EndDoStmt &x) { // R11321060    Word("END DO"), Walk(" ", x.v);1061  }1062  void Unparse(const CycleStmt &x) { // R11331063    Word("CYCLE"), Walk(" ", x.v);1064  }1065  void Unparse(const IfThenStmt &x) { // R11351066    Walk(std::get<std::optional<Name>>(x.t), ": ");1067    Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t));1068    Put(") "), Word("THEN"), Indent();1069  }1070  void Unparse(const ElseIfStmt &x) { // R11361071    Outdent(), Word("ELSE IF (");1072    Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN");1073    Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();1074  }1075  void Unparse(const ElseStmt &x) { // R11371076    Outdent(), Word("ELSE"), Walk(" ", x.v), Indent();1077  }1078  void Unparse(const EndIfStmt &x) { // R11381079    Outdent(), Word("END IF"), Walk(" ", x.v);1080  }1081  void Unparse(const IfStmt &x) { // R11391082    Word("IF ("), Walk(x.t, ") ");1083  }1084  void Unparse(const SelectCaseStmt &x) { // R1141, R11441085    Walk(std::get<std::optional<Name>>(x.t), ": ");1086    Word("SELECT CASE (");1087    Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent();1088  }1089  void Unparse(const CaseStmt &x) { // R11421090    Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t));1091    Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();1092  }1093  void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R11551094    Outdent(), Word("END SELECT"), Walk(" ", x.v);1095  }1096  void Unparse(const CaseSelector &x) { // R11451097    common::visit(common::visitors{1098                      [&](const std::list<CaseValueRange> &y) {1099                        Put('('), Walk(y), Put(')');1100                      },1101                      [&](const Default &) { Word("DEFAULT"); },1102                  },1103        x.u);1104  }1105  void Unparse(const CaseValueRange::Range &x) { // R11461106    Walk(x.lower), Put(':'), Walk(x.upper);1107  }1108  void Unparse(const SelectRankStmt &x) { // R11491109    Walk(std::get<0>(x.t), ": ");1110    Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => ");1111    Walk(std::get<Selector>(x.t)), Put(')'), Indent();1112  }1113  void Unparse(const SelectRankCaseStmt &x) { // R11501114    Outdent(), Word("RANK ");1115    common::visit(common::visitors{1116                      [&](const ScalarIntConstantExpr &y) {1117                        Put('('), Walk(y), Put(')');1118                      },1119                      [&](const Star &) { Put("(*)"); },1120                      [&](const Default &) { Word("DEFAULT"); },1121                  },1122        std::get<SelectRankCaseStmt::Rank>(x.t).u);1123    Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();1124  }1125  void Unparse(const SelectTypeStmt &x) { // R11531126    Walk(std::get<0>(x.t), ": ");1127    Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => ");1128    Walk(std::get<Selector>(x.t)), Put(')'), Indent();1129  }1130  void Unparse(const TypeGuardStmt &x) { // R11541131    Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t));1132    Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();1133  }1134  void Unparse(const TypeGuardStmt::Guard &x) {1135    common::visit(1136        common::visitors{1137            [&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); },1138            [&](const DerivedTypeSpec &y) {1139              Word("CLASS IS ("), Walk(y), Put(')');1140            },1141            [&](const Default &) { Word("CLASS DEFAULT"); },1142        },1143        x.u);1144  }1145  void Unparse(const ExitStmt &x) { // R11561146    Word("EXIT"), Walk(" ", x.v);1147  }1148  void Before(const GotoStmt &) { // R11571149    Word("GO TO ");1150  }1151  void Unparse(const ComputedGotoStmt &x) { // R11581152    Word("GO TO ("), Walk(x.t, "), ");1153  }1154  void Unparse(const ContinueStmt &) { // R11591155    Word("CONTINUE");1156  }1157  void Unparse(const StopStmt &x) { // R1160, R11611158    if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) {1159      Word("ERROR ");1160    }1161    Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t));1162    Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t));1163  }1164  void Unparse(const FailImageStmt &) { // R11631165    Word("FAIL IMAGE");1166  }1167  void Unparse(const NotifyWaitStmt &x) { // F2023: R11661168    Word("NOTIFY WAIT ("), Walk(std::get<Scalar<Variable>>(x.t));1169    Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", ");1170    Put(')');1171  }1172  void Unparse(const SyncAllStmt &x) { // R11641173    Word("SYNC ALL ("), Walk(x.v, ", "), Put(')');1174  }1175  void Unparse(const SyncImagesStmt &x) { // R11661176    Word("SYNC IMAGES (");1177    Walk(std::get<SyncImagesStmt::ImageSet>(x.t));1178    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');1179  }1180  void Unparse(const SyncMemoryStmt &x) { // R11681181    Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')');1182  }1183  void Unparse(const SyncTeamStmt &x) { // R11691184    Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t));1185    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');1186  }1187  void Unparse(const EventPostStmt &x) { // R11701188    Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t));1189    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');1190  }1191  void Before(const EventWaitSpec &x) { // R1173, R11741192    common::visit(common::visitors{1193                      [&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); },1194                      [](const StatOrErrmsg &) {},1195                  },1196        x.u);1197  }1198  void Unparse(const EventWaitStmt &x) { // R11701199    Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t));1200    Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", ");1201    Put(')');1202  }1203  void Unparse(const FormTeamStmt &x) { // R1175, R11771204    Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));1205    Put(','), Walk(std::get<TeamVariable>(x.t));1206    Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");1207    Put(')');1208  }1209  void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R11781210    common::visit(common::visitors{1211                      [&](const ScalarIntExpr &) { Word("NEW_INDEX="); },1212                      [](const StatOrErrmsg &) {},1213                  },1214        x.u);1215  }1216  void Unparse(const LockStmt &x) { // R11791217    Word("LOCK ("), Walk(std::get<LockVariable>(x.t));1218    Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");1219    Put(')');1220  }1221  void Before(const LockStmt::LockStat &x) { // R11801222    common::visit(1223        common::visitors{1224            [&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },1225            [](const StatOrErrmsg &) {},1226        },1227        x.u);1228  }1229  void Unparse(const UnlockStmt &x) { // R11811230    Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));1231    Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");1232    Put(')');1233  }1234 1235  void Unparse(const OpenStmt &x) { // R12041236    Word("OPEN ("), Walk(x.v, ", "), Put(')');1237  }1238  bool Pre(const ConnectSpec &x) { // R12051239    return common::visit(common::visitors{1240                             [&](const FileUnitNumber &) {1241                               Word("UNIT=");1242                               return true;1243                             },1244                             [&](const FileNameExpr &) {1245                               Word("FILE=");1246                               return true;1247                             },1248                             [&](const ConnectSpec::CharExpr &y) {1249                               Walk(y.t, "=");1250                               return false;1251                             },1252                             [&](const MsgVariable &) {1253                               Word("IOMSG=");1254                               return true;1255                             },1256                             [&](const StatVariable &) {1257                               Word("IOSTAT=");1258                               return true;1259                             },1260                             [&](const ConnectSpec::Recl &) {1261                               Word("RECL=");1262                               return true;1263                             },1264                             [&](const ConnectSpec::Newunit &) {1265                               Word("NEWUNIT=");1266                               return true;1267                             },1268                             [&](const ErrLabel &) {1269                               Word("ERR=");1270                               return true;1271                             },1272                             [&](const StatusExpr &) {1273                               Word("STATUS=");1274                               return true;1275                             },1276                         },1277        x.u);1278  }1279  void Unparse(const CloseStmt &x) { // R12081280    Word("CLOSE ("), Walk(x.v, ", "), Put(')');1281  }1282  void Before(const CloseStmt::CloseSpec &x) { // R12091283    common::visit(common::visitors{1284                      [&](const FileUnitNumber &) { Word("UNIT="); },1285                      [&](const StatVariable &) { Word("IOSTAT="); },1286                      [&](const MsgVariable &) { Word("IOMSG="); },1287                      [&](const ErrLabel &) { Word("ERR="); },1288                      [&](const StatusExpr &) { Word("STATUS="); },1289                  },1290        x.u);1291  }1292  void Unparse(const ReadStmt &x) { // R12101293    Word("READ ");1294    if (x.iounit) {1295      Put('('), Walk(x.iounit);1296      if (x.format) {1297        Put(", "), Walk(x.format);1298      }1299      Walk(", ", x.controls, ", ");1300      Put(')');1301    } else if (x.format) {1302      Walk(x.format);1303      if (!x.items.empty()) {1304        Put(", ");1305      }1306    } else {1307      Put('('), Walk(x.controls, ", "), Put(')');1308    }1309    Walk(" ", x.items, ", ");1310  }1311  void Unparse(const WriteStmt &x) { // R12111312    Word("WRITE (");1313    if (x.iounit) {1314      Walk(x.iounit);1315      if (x.format) {1316        Put(", "), Walk(x.format);1317      }1318      Walk(", ", x.controls, ", ");1319    } else {1320      Walk(x.controls, ", ");1321    }1322    Put(')'), Walk(" ", x.items, ", ");1323  }1324  void Unparse(const PrintStmt &x) { // R12121325    Word("PRINT "), Walk(std::get<Format>(x.t));1326    Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");1327  }1328  bool Pre(const IoControlSpec &x) { // R12131329    return common::visit(common::visitors{1330                             [&](const IoUnit &) {1331                               Word("UNIT=");1332                               return true;1333                             },1334                             [&](const Format &) {1335                               Word("FMT=");1336                               return true;1337                             },1338                             [&](const Name &) {1339                               Word("NML=");1340                               return true;1341                             },1342                             [&](const IoControlSpec::CharExpr &y) {1343                               Walk(y.t, "=");1344                               return false;1345                             },1346                             [&](const IoControlSpec::Asynchronous &) {1347                               Word("ASYNCHRONOUS=");1348                               return true;1349                             },1350                             [&](const EndLabel &) {1351                               Word("END=");1352                               return true;1353                             },1354                             [&](const EorLabel &) {1355                               Word("EOR=");1356                               return true;1357                             },1358                             [&](const ErrLabel &) {1359                               Word("ERR=");1360                               return true;1361                             },1362                             [&](const IdVariable &) {1363                               Word("ID=");1364                               return true;1365                             },1366                             [&](const MsgVariable &) {1367                               Word("IOMSG=");1368                               return true;1369                             },1370                             [&](const StatVariable &) {1371                               Word("IOSTAT=");1372                               return true;1373                             },1374                             [&](const IoControlSpec::Pos &) {1375                               Word("POS=");1376                               return true;1377                             },1378                             [&](const IoControlSpec::Rec &) {1379                               Word("REC=");1380                               return true;1381                             },1382                             [&](const IoControlSpec::Size &) {1383                               Word("SIZE=");1384                               return true;1385                             },1386                         },1387        x.u);1388  }1389  void Unparse(const InputImpliedDo &x) { // R12181390    Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");1391    Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');1392  }1393  void Unparse(const OutputImpliedDo &x) { // R12191394    Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");1395    Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');1396  }1397  void Unparse(const WaitStmt &x) { // R12221398    Word("WAIT ("), Walk(x.v, ", "), Put(')');1399  }1400  void Before(const WaitSpec &x) { // R12231401    common::visit(common::visitors{1402                      [&](const FileUnitNumber &) { Word("UNIT="); },1403                      [&](const EndLabel &) { Word("END="); },1404                      [&](const EorLabel &) { Word("EOR="); },1405                      [&](const ErrLabel &) { Word("ERR="); },1406                      [&](const IdExpr &) { Word("ID="); },1407                      [&](const MsgVariable &) { Word("IOMSG="); },1408                      [&](const StatVariable &) { Word("IOSTAT="); },1409                  },1410        x.u);1411  }1412  void Unparse(const BackspaceStmt &x) { // R12241413    Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');1414  }1415  void Unparse(const EndfileStmt &x) { // R12251416    Word("ENDFILE ("), Walk(x.v, ", "), Put(')');1417  }1418  void Unparse(const RewindStmt &x) { // R12261419    Word("REWIND ("), Walk(x.v, ", "), Put(')');1420  }1421  void Before(const PositionOrFlushSpec &x) { // R1227 & R12291422    common::visit(common::visitors{1423                      [&](const FileUnitNumber &) { Word("UNIT="); },1424                      [&](const MsgVariable &) { Word("IOMSG="); },1425                      [&](const StatVariable &) { Word("IOSTAT="); },1426                      [&](const ErrLabel &) { Word("ERR="); },1427                  },1428        x.u);1429  }1430  void Unparse(const FlushStmt &x) { // R12281431    Word("FLUSH ("), Walk(x.v, ", "), Put(')');1432  }1433  void Unparse(const InquireStmt &x) { // R12301434    Word("INQUIRE (");1435    common::visit(1436        common::visitors{1437            [&](const InquireStmt::Iolength &y) {1438              Word("IOLENGTH="), Walk(y.t, ") ");1439            },1440            [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); },1441        },1442        x.u);1443  }1444  bool Pre(const InquireSpec &x) { // R12311445    return common::visit(common::visitors{1446                             [&](const FileUnitNumber &) {1447                               Word("UNIT=");1448                               return true;1449                             },1450                             [&](const FileNameExpr &) {1451                               Word("FILE=");1452                               return true;1453                             },1454                             [&](const InquireSpec::CharVar &y) {1455                               Walk(y.t, "=");1456                               return false;1457                             },1458                             [&](const InquireSpec::IntVar &y) {1459                               Walk(y.t, "=");1460                               return false;1461                             },1462                             [&](const InquireSpec::LogVar &y) {1463                               Walk(y.t, "=");1464                               return false;1465                             },1466                             [&](const IdExpr &) {1467                               Word("ID=");1468                               return true;1469                             },1470                             [&](const ErrLabel &) {1471                               Word("ERR=");1472                               return true;1473                             },1474                         },1475        x.u);1476  }1477 1478  void Before(const FormatStmt &) { // R13011479    Word("FORMAT");1480  }1481  void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R13051482    Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");1483    Walk("*(", x.unlimitedItems, ",", ")"), Put(')');1484  }1485  void Unparse(const format::FormatItem &x) { // R1304, R1306, R13211486    if (x.repeatCount) {1487      Walk(*x.repeatCount);1488    }1489    common::visit(common::visitors{1490                      [&](const std::string &y) { PutNormalized(y); },1491                      [&](const std::list<format::FormatItem> &y) {1492                        Walk("(", y, ",", ")");1493                      },1494                      [&](const auto &y) { Walk(y); },1495                  },1496        x.u);1497  }1498  void Unparse(1499      const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R13111500    switch (x.kind) {1501#define FMT(x) \1502  case format::IntrinsicTypeDataEditDesc::Kind::x: \1503    Put(#x); \1504    break1505      FMT(I);1506      FMT(B);1507      FMT(O);1508      FMT(Z);1509      FMT(F);1510      FMT(E);1511      FMT(EN);1512      FMT(ES);1513      FMT(EX);1514      FMT(G);1515      FMT(L);1516      FMT(A);1517      FMT(D);1518#undef FMT1519    }1520    Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);1521  }1522  void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R13121523    Word("DT");1524    if (!x.type.empty()) {1525      Put('"'), Put(x.type), Put('"');1526    }1527    Walk("(", x.parameters, ",", ")");1528  }1529  void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R13201530    switch (x.kind) {1531    case format::ControlEditDesc::Kind::T:1532      Word("T");1533      Walk(x.count);1534      break;1535    case format::ControlEditDesc::Kind::TL:1536      Word("TL");1537      Walk(x.count);1538      break;1539    case format::ControlEditDesc::Kind::TR:1540      Word("TR");1541      Walk(x.count);1542      break;1543    case format::ControlEditDesc::Kind::X:1544      if (x.count != 1) {1545        Walk(x.count);1546      }1547      Word("X");1548      break;1549    case format::ControlEditDesc::Kind::Slash:1550      if (x.count != 1) {1551        Walk(x.count);1552      }1553      Put('/');1554      break;1555    case format::ControlEditDesc::Kind::Colon:1556      Put(':');1557      break;1558    case format::ControlEditDesc::Kind::P:1559      Walk(x.count);1560      Word("P");1561      break;1562#define FMT(x) \1563  case format::ControlEditDesc::Kind::x: \1564    Put(#x); \1565    break1566      FMT(SS);1567      FMT(SP);1568      FMT(S);1569      FMT(BN);1570      FMT(BZ);1571      FMT(RU);1572      FMT(RD);1573      FMT(RZ);1574      FMT(RN);1575      FMT(RC);1576      FMT(RP);1577      FMT(DC);1578      FMT(DP);1579#undef FMT1580    case format::ControlEditDesc::Kind::Dollar:1581      Put('$');1582      break;1583    case format::ControlEditDesc::Kind::Backslash:1584      Put('\\');1585      break;1586    }1587  }1588 1589  void Before(const MainProgram &x) { // R14011590    if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {1591      Indent();1592    }1593  }1594  void Before(const ProgramStmt &) { // R14021595    Word("PROGRAM "), Indent();1596  }1597  void Unparse(const EndProgramStmt &x) { // R14031598    EndSubprogram("PROGRAM", x.v);1599  }1600  void Before(const ModuleStmt &) { // R14051601    Word("MODULE "), Indent();1602  }1603  void Unparse(const EndModuleStmt &x) { // R14061604    EndSubprogram("MODULE", x.v);1605  }1606  void Unparse(const UseStmt &x) { // R14091607    Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);1608    common::visit(1609        common::visitors{1610            [&](const std::list<Rename> &y) { Walk(", ", y, ", "); },1611            [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); },1612        },1613        x.u);1614  }1615  void Unparse(const Rename &x) { // R14111616    common::visit(common::visitors{1617                      [&](const Rename::Names &y) { Walk(y.t, " => "); },1618                      [&](const Rename::Operators &y) {1619                        Word("OPERATOR("), Walk(y.t, ") => OPERATOR("),1620                            Put(")");1621                      },1622                  },1623        x.u);1624  }1625  void Unparse(const SubmoduleStmt &x) { // R14171626    Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent();1627  }1628  void Unparse(const ParentIdentifier &x) { // R14181629    Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));1630  }1631  void Unparse(const EndSubmoduleStmt &x) { // R14191632    EndSubprogram("SUBMODULE", x.v);1633  }1634  void Unparse(const BlockDataStmt &x) { // R14211635    Word("BLOCK DATA"), Walk(" ", x.v), Indent();1636  }1637  void Unparse(const EndBlockDataStmt &x) { // R14221638    EndSubprogram("BLOCK DATA", x.v);1639  }1640 1641  void Unparse(const InterfaceStmt &x) { // R15031642    common::visit(common::visitors{1643                      [&](const std::optional<GenericSpec> &y) {1644                        Word("INTERFACE"), Walk(" ", y);1645                      },1646                      [&](const Abstract &) { Word("ABSTRACT INTERFACE"); },1647                  },1648        x.u);1649    Indent();1650  }1651  void Unparse(const EndInterfaceStmt &x) { // R15041652    Outdent(), Word("END INTERFACE"), Walk(" ", x.v);1653  }1654  void Unparse(const ProcedureStmt &x) { // R15061655    if (std::get<ProcedureStmt::Kind>(x.t) ==1656        ProcedureStmt::Kind::ModuleProcedure) {1657      Word("MODULE ");1658    }1659    Word("PROCEDURE :: ");1660    Walk(std::get<std::list<Name>>(x.t), ", ");1661  }1662  void Before(const GenericSpec &x) { // R1508, R15091663    common::visit(1664        common::visitors{1665            [&](const DefinedOperator &) { Word("OPERATOR("); },1666            [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },1667            [&](const GenericSpec::ReadFormatted &) {1668              Word("READ(FORMATTED)");1669            },1670            [&](const GenericSpec::ReadUnformatted &) {1671              Word("READ(UNFORMATTED)");1672            },1673            [&](const GenericSpec::WriteFormatted &) {1674              Word("WRITE(FORMATTED)");1675            },1676            [&](const GenericSpec::WriteUnformatted &) {1677              Word("WRITE(UNFORMATTED)");1678            },1679            [](const auto &) {},1680        },1681        x.u);1682  }1683  void Post(const GenericSpec &x) {1684    common::visit(common::visitors{1685                      [&](const DefinedOperator &) { Put(')'); },1686                      [](const auto &) {},1687                  },1688        x.u);1689  }1690  void Unparse(const GenericStmt &x) { // R15101691    Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));1692    Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");1693    Walk(std::get<std::list<Name>>(x.t), ", ");1694  }1695  void Unparse(const ExternalStmt &x) { // R15111696    Word("EXTERNAL :: "), Walk(x.v, ", ");1697  }1698  void Unparse(const ProcedureDeclarationStmt &x) { // R15121699    Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t));1700    Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");1701    Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");1702  }1703  void Unparse(const ProcDecl &x) { // R15151704    Walk(std::get<Name>(x.t));1705    Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));1706  }1707  void Unparse(const IntrinsicStmt &x) { // R15191708    Word("INTRINSIC :: "), Walk(x.v, ", ");1709  }1710  void Unparse(const CallStmt::StarOrExpr &x) {1711    if (x.v) {1712      Walk(*x.v);1713    } else {1714      Word("*");1715    }1716  }1717  void Unparse(const CallStmt::Chevrons &x) { // CUDA1718    Walk(std::get<0>(x.t)); // grid1719    Word(","), Walk(std::get<1>(x.t)); // block1720    Walk(",", std::get<2>(x.t)); // bytes1721    Walk(",", std::get<3>(x.t)); // stream1722  }1723  void Unparse(const FunctionReference &x) { // R15201724    Walk(std::get<ProcedureDesignator>(x.v.t));1725    Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');1726  }1727  void Unparse(const CallStmt &x) { // R15211728    if (asFortran_ && x.typedCall.get()) {1729      Put(' ');1730      asFortran_->call(out_, *x.typedCall);1731      Put('\n');1732    } else {1733      const auto &pd{std::get<ProcedureDesignator>(x.call.t)};1734      Word("CALL "), Walk(pd);1735      Walk("<<<", x.chevrons, ">>>");1736      const auto &args{std::get<std::list<ActualArgSpec>>(x.call.t)};1737      if (args.empty()) {1738        if (std::holds_alternative<ProcComponentRef>(pd.u)) {1739          Put("()"); // pgf90 crashes on CALL to tbp without parentheses1740        }1741      } else {1742        Walk("(", args, ", ", ")");1743      }1744    }1745  }1746  void Unparse(const ActualArgSpec &x) { // R15231747    Walk(std::get<std::optional<Keyword>>(x.t), "=");1748    Walk(std::get<ActualArg>(x.t));1749  }1750  void Unparse(const ActualArg::PercentRef &x) { // R15241751    Word("%REF("), Walk(x.v), Put(')');1752  }1753  void Unparse(const ActualArg::PercentVal &x) {1754    Word("%VAL("), Walk(x.v), Put(')');1755  }1756  void Before(const AltReturnSpec &) { // R15251757    Put('*');1758  }1759  void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R15271760  void Post(const PrefixSpec::Impure) { Word("IMPURE"); }1761  void Post(const PrefixSpec::Module) { Word("MODULE"); }1762  void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }1763  void Post(const PrefixSpec::Pure) { Word("PURE"); }1764  void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }1765  void Unparse(const PrefixSpec::Attributes &x) {1766    Word("ATTRIBUTES("), Walk(x.v), Word(")");1767  }1768  void Unparse(const PrefixSpec::Launch_Bounds &x) {1769    Word("LAUNCH_BOUNDS("), Walk(x.v), Word(")");1770  }1771  void Unparse(const PrefixSpec::Cluster_Dims &x) {1772    Word("CLUSTER_DIMS("), Walk(x.v), Word(")");1773  }1774  void Unparse(const FunctionStmt &x) { // R15301775    Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");1776    Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");1777    Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');1778    Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();1779  }1780  void Unparse(const Suffix &x) { // R15321781    if (x.resultName) {1782      Word("RESULT("), Walk(x.resultName), Put(')');1783      Walk(" ", x.binding);1784    } else {1785      Walk(x.binding);1786    }1787  }1788  void Unparse(const EndFunctionStmt &x) { // R15331789    EndSubprogram("FUNCTION", x.v);1790  }1791  void Unparse(const SubroutineStmt &x) { // R15351792    Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");1793    Word("SUBROUTINE "), Walk(std::get<Name>(x.t));1794    const auto &args{std::get<std::list<DummyArg>>(x.t)};1795    const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)};1796    if (args.empty()) {1797      Walk(" () ", bind);1798    } else {1799      Walk(" (", args, ", ", ")");1800      Walk(" ", bind);1801    }1802    Indent();1803  }1804  void Unparse(const EndSubroutineStmt &x) { // R15371805    EndSubprogram("SUBROUTINE", x.v);1806  }1807  void Before(const MpSubprogramStmt &) { // R15391808    Word("MODULE PROCEDURE "), Indent();1809  }1810  void Unparse(const EndMpSubprogramStmt &x) { // R15401811    EndSubprogram("PROCEDURE", x.v);1812  }1813  void Unparse(const EntryStmt &x) { // R15411814    Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("(");1815    Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")");1816    Walk(" ", std::get<std::optional<Suffix>>(x.t));1817  }1818  void Unparse(const ReturnStmt &x) { // R15421819    Word("RETURN"), Walk(" ", x.v);1820  }1821  void Unparse(const ContainsStmt &) { // R15431822    Outdent();1823    Word("CONTAINS");1824    Indent();1825  }1826  void Unparse(const StmtFunctionStmt &x) { // R15441827    Walk(std::get<Name>(x.t)), Put('(');1828    Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");1829    Walk(std::get<Scalar<Expr>>(x.t));1830  }1831 1832  // Directives, extensions, and deprecated constructs1833  void Unparse(const CompilerDirective &x) {1834    common::visit(1835        common::visitors{1836            [&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {1837              Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty1838              Walk(" ", tkr, ", ");1839            },1840            [&](const CompilerDirective::LoopCount &lcount) {1841              Walk("!DIR$ LOOP COUNT (", lcount.v, ", ", ")");1842            },1843            [&](const std::list<CompilerDirective::AssumeAligned>1844                    &assumeAligned) {1845              Word("!DIR$ ASSUME_ALIGNED ");1846              Walk(" ", assumeAligned, ", ");1847            },1848            [&](const CompilerDirective::VectorAlways &valways) {1849              Word("!DIR$ VECTOR ALWAYS");1850            },1851            [&](const std::list<CompilerDirective::NameValue> &names) {1852              Walk("!DIR$ ", names, " ");1853            },1854            [&](const CompilerDirective::Unroll &unroll) {1855              Word("!DIR$ UNROLL");1856              Walk(" ", unroll.v);1857            },1858            [&](const CompilerDirective::Prefetch &prefetch) {1859              Word("!DIR$ PREFETCH");1860              Walk(" ", prefetch.v);1861            },1862            [&](const CompilerDirective::UnrollAndJam &unrollAndJam) {1863              Word("!DIR$ UNROLL_AND_JAM");1864              Walk(" ", unrollAndJam.v);1865            },1866            [&](const CompilerDirective::NoVector &) {1867              Word("!DIR$ NOVECTOR");1868            },1869            [&](const CompilerDirective::NoUnroll &) {1870              Word("!DIR$ NOUNROLL");1871            },1872            [&](const CompilerDirective::NoUnrollAndJam &) {1873              Word("!DIR$ NOUNROLL_AND_JAM");1874            },1875            [&](const CompilerDirective::ForceInline &) {1876              Word("!DIR$ FORCEINLINE");1877            },1878            [&](const CompilerDirective::Inline &) { Word("!DIR$ INLINE"); },1879            [&](const CompilerDirective::NoInline &) {1880              Word("!DIR$ NOINLINE");1881            },1882            [&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },1883            [&](const CompilerDirective::Unrecognized &) {1884              Word("!DIR$ ");1885              Word(x.source.ToString());1886            },1887        },1888        x.u);1889    Put('\n');1890  }1891  void Unparse(const CompilerDirective::IgnoreTKR &x) {1892    if (const auto &maybeList{1893            std::get<std::optional<std::list<const char *>>>(x.t)}) {1894      Put("(");1895      for (const char *tkr : *maybeList) {1896        Put(*tkr);1897      }1898      Put(") ");1899    }1900    Walk(std::get<Name>(x.t));1901  }1902  void Unparse(const CompilerDirective::NameValue &x) {1903    Walk(std::get<Name>(x.t));1904    Walk("=", std::get<std::optional<std::uint64_t>>(x.t));1905  }1906  void Unparse(const CompilerDirective::AssumeAligned &x) {1907    Walk(std::get<common::Indirection<Designator>>(x.t));1908    Put(":");1909    Walk(std::get<uint64_t>(x.t));1910  }1911 1912  // OpenACC Directives & Clauses1913  void Unparse(const AccAtomicCapture &x) {1914    BeginOpenACC();1915    Word("!$ACC CAPTURE");1916    Put("\n");1917    EndOpenACC();1918    Walk(std::get<AccAtomicCapture::Stmt1>(x.t));1919    Put("\n");1920    Walk(std::get<AccAtomicCapture::Stmt2>(x.t));1921    BeginOpenACC();1922    Word("!$ACC END ATOMIC\n");1923    EndOpenACC();1924  }1925  void Unparse(const AccAtomicRead &x) {1926    BeginOpenACC();1927    Word("!$ACC ATOMIC READ");1928    Put("\n");1929    EndOpenACC();1930    Walk(std::get<Statement<AssignmentStmt>>(x.t));1931    BeginOpenACC();1932    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");1933    EndOpenACC();1934  }1935  void Unparse(const AccAtomicWrite &x) {1936    BeginOpenACC();1937    Word("!$ACC ATOMIC WRITE");1938    Put("\n");1939    EndOpenACC();1940    Walk(std::get<Statement<AssignmentStmt>>(x.t));1941    BeginOpenACC();1942    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");1943    EndOpenACC();1944  }1945  void Unparse(const AccAtomicUpdate &x) {1946    BeginOpenACC();1947    Word("!$ACC ATOMIC UPDATE");1948    Put("\n");1949    EndOpenACC();1950    Walk(std::get<Statement<AssignmentStmt>>(x.t));1951    BeginOpenACC();1952    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");1953    EndOpenACC();1954  }1955  void Unparse(const llvm::acc::Directive &x) {1956    Word(llvm::acc::getOpenACCDirectiveName(x).str());1957  }1958#define GEN_FLANG_CLAUSE_UNPARSE1959#include "llvm/Frontend/OpenACC/ACC.inc"1960  void Unparse(const AccObjectListWithModifier &x) {1961    Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");1962    Walk(std::get<AccObjectList>(x.t));1963  }1964  void Unparse(const AccBindClause &x) {1965    common::visit(common::visitors{1966                      [&](const Name &y) { Walk(y); },1967                      [&](const ScalarDefaultCharExpr &y) { Walk(y); },1968                  },1969        x.u);1970  }1971  void Unparse(const AccDefaultClause &x) {1972    switch (x.v) {1973    case llvm::acc::DefaultValue::ACC_Default_none:1974      Put("NONE");1975      break;1976    case llvm::acc::DefaultValue::ACC_Default_present:1977      Put("PRESENT");1978      break;1979    }1980  }1981  void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }1982  void Unparse(const AccGangArgList &x) { Walk(x.v, ","); }1983  void Before(const AccSizeExpr &x) {1984    if (!x.v)1985      Put("*");1986  }1987  void Before(const AccGangArg &x) {1988    common::visit(common::visitors{1989                      [&](const AccGangArg::Num &) { Word("NUM:"); },1990                      [&](const AccGangArg::Dim &) { Word("DIM:"); },1991                      [&](const AccGangArg::Static &) { Word("STATIC:"); },1992                      [](const StatOrErrmsg &) {},1993                  },1994        x.u);1995  }1996  void Unparse(const AccCollapseArg &x) {1997    const auto &force{std::get<bool>(x.t)};1998    const auto &collapseValue{std::get<parser::ScalarIntConstantExpr>(x.t)};1999    if (force) {2000      Put("FORCE:");2001    }2002    Walk(collapseValue);2003  }2004  void Unparse(const OpenACCBlockConstruct &x) {2005    BeginOpenACC();2006    Word("!$ACC ");2007    Walk(std::get<AccBeginBlockDirective>(x.t));2008    Put("\n");2009    EndOpenACC();2010    Walk(std::get<Block>(x.t), "");2011    BeginOpenACC();2012    Word("!$ACC END ");2013    Walk(std::get<AccEndBlockDirective>(x.t));2014    Put("\n");2015    EndOpenACC();2016  }2017  void Unparse(const OpenACCLoopConstruct &x) {2018    BeginOpenACC();2019    Word("!$ACC ");2020    Walk(std::get<AccBeginLoopDirective>(x.t));2021    Put("\n");2022    EndOpenACC();2023    Walk(std::get<std::optional<DoConstruct>>(x.t));2024  }2025  void Unparse(const AccBeginLoopDirective &x) {2026    Walk(std::get<AccLoopDirective>(x.t));2027    Walk(std::get<AccClauseList>(x.t));2028  }2029  void Unparse(const OpenACCStandaloneConstruct &x) {2030    BeginOpenACC();2031    Word("!$ACC ");2032    Walk(std::get<AccStandaloneDirective>(x.t));2033    Walk(std::get<AccClauseList>(x.t));2034    Put("\n");2035    EndOpenACC();2036  }2037  void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {2038    BeginOpenACC();2039    Word("!$ACC ");2040    Walk(std::get<AccDeclarativeDirective>(x.t));2041    Walk(std::get<AccClauseList>(x.t));2042    Put("\n");2043    EndOpenACC();2044  }2045  void Unparse(const OpenACCCombinedConstruct &x) {2046    BeginOpenACC();2047    Word("!$ACC ");2048    Walk(std::get<AccBeginCombinedDirective>(x.t));2049    Put("\n");2050    EndOpenACC();2051    Walk(std::get<std::optional<DoConstruct>>(x.t));2052    BeginOpenACC();2053    Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),2054        "\n");2055    EndOpenACC();2056  }2057  void Unparse(const OpenACCRoutineConstruct &x) {2058    BeginOpenACC();2059    Word("!$ACC ROUTINE");2060    Walk("(", std::get<std::optional<Name>>(x.t), ")");2061    Walk(std::get<AccClauseList>(x.t));2062    Put("\n");2063    EndOpenACC();2064  }2065  void Unparse(const AccObject &x) {2066    common::visit(common::visitors{2067                      [&](const Designator &y) { Walk(y); },2068                      [&](const Name &y) { Put("/"), Walk(y), Put("/"); },2069                  },2070        x.u);2071  }2072  void Unparse(const AccObjectList &x) { Walk(x.v, ","); }2073  void Unparse(const AccObjectListWithReduction &x) {2074    Walk(std::get<ReductionOperator>(x.t));2075    Put(":");2076    Walk(std::get<AccObjectList>(x.t));2077  }2078  void Unparse(const OpenACCCacheConstruct &x) {2079    BeginOpenACC();2080    Word("!$ACC ");2081    Word("CACHE(");2082    Walk(std::get<AccObjectListWithModifier>(x.t));2083    Put(")");2084    Put("\n");2085    EndOpenACC();2086  }2087  void Unparse(const AccWaitArgument &x) {2088    Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");2089    Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");2090  }2091  void Unparse(const OpenACCWaitConstruct &x) {2092    BeginOpenACC();2093    Word("!$ACC ");2094    Word("WAIT(");2095    Walk(std::get<std::optional<AccWaitArgument>>(x.t));2096    Walk(std::get<AccClauseList>(x.t));2097    Put(")");2098    Put("\n");2099    EndOpenACC();2100  }2101 2102  // OpenMP Clauses & Directives2103  void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }2104  void Unparse(const OmpTypeNameList &x) { Walk(x.v, ", "); }2105 2106  void Unparse(const OmpBaseVariantNames &x) {2107    Walk(std::get<0>(x.t)); // OmpObject2108    Put(":");2109    Walk(std::get<1>(x.t)); // OmpObject2110  }2111  void Unparse(const OmpMapperSpecifier &x) {2112    const auto &mapperName{std::get<std::string>(x.t)};2113    if (mapperName.find(llvm::omp::OmpDefaultMapperName) == std::string::npos) {2114      Walk(mapperName);2115      Put(":");2116    }2117    Walk(std::get<TypeSpec>(x.t));2118    Put("::");2119    Walk(std::get<Name>(x.t));2120  }2121  void Unparse(const OmpReductionSpecifier &x) {2122    Walk(std::get<OmpReductionIdentifier>(x.t));2123    Put(":");2124    Walk(std::get<OmpTypeNameList>(x.t));2125    Walk(": ", std::get<std::optional<OmpCombinerExpression>>(x.t));2126  }2127  void Unparse(const llvm::omp::Directive &x) {2128    unsigned ompVersion{langOpts_.OpenMPVersion};2129    Word(llvm::omp::getOpenMPDirectiveName(x, ompVersion).str());2130  }2131  void Unparse(const OmpDirectiveSpecification &x) {2132    auto unparseArgs{[&]() {2133      if (auto &args{std::get<std::optional<OmpArgumentList>>(x.t)}) {2134        Put("(");2135        Walk(*args);2136        Put(")");2137      }2138    }};2139    auto unparseClauses{[&]() { //2140      Walk(std::get<std::optional<OmpClauseList>>(x.t));2141    }};2142 2143    Walk(std::get<OmpDirectiveName>(x.t));2144    auto flags{std::get<OmpDirectiveSpecification::Flags>(x.t)};2145    if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {2146      if (x.DirId() == llvm::omp::Directive::OMPD_flush) {2147        // FLUSH clause arglist2148        unparseClauses();2149        unparseArgs();2150      }2151    } else {2152      unparseArgs();2153      unparseClauses();2154    }2155  }2156  void Unparse(const OmpTraitScore &x) {2157    Word("SCORE(");2158    Walk(x.v);2159    Put(")");2160  }2161  void Unparse(const OmpTraitPropertyExtension::Complex &x) {2162    using PropList = std::list<common::Indirection<OmpTraitPropertyExtension>>;2163    Walk(std::get<OmpTraitPropertyName>(x.t));2164    Put("(");2165    Walk(std::get<PropList>(x.t), ",");2166    Put(")");2167  }2168  void Unparse(const OmpTraitSelector &x) {2169    Walk(std::get<OmpTraitSelectorName>(x.t));2170    Walk(std::get<std::optional<OmpTraitSelector::Properties>>(x.t));2171  }2172  void Unparse(const OmpTraitSelector::Properties &x) {2173    Put("(");2174    Walk(std::get<std::optional<OmpTraitScore>>(x.t), ": ");2175    Walk(std::get<std::list<OmpTraitProperty>>(x.t));2176    Put(")");2177  }2178  void Unparse(const OmpTraitSetSelector &x) {2179    Walk(std::get<OmpTraitSetSelectorName>(x.t));2180    Put("={");2181    Walk(std::get<std::list<OmpTraitSelector>>(x.t));2182    Put("}");2183  }2184  void Unparse(const OmpContextSelectorSpecification &x) { Walk(x.v, ", "); }2185 2186  void Unparse(const OmpObject &x) {2187    common::visit( //2188        common::visitors{2189            [&](const Designator &y) { Walk(y); },2190            [&](const Name &y) {2191              Put("/");2192              Walk(y);2193              Put("/");2194            },2195            [&](const OmpObject::Invalid &y) {2196              switch (y.v) {2197              case OmpObject::Invalid::Kind::BlankCommonBlock:2198                Put("//");2199                break;2200              }2201            },2202        },2203        x.u);2204  }2205  void Unparse(const OmpDirectiveNameModifier &x) {2206    unsigned ompVersion{langOpts_.OpenMPVersion};2207    Word(llvm::omp::getOpenMPDirectiveName(x.v, ompVersion));2208  }2209  void Unparse(const OmpStylizedDeclaration &x) {2210    // empty2211  }2212  void Unparse(const OmpStylizedExpression &x) { //2213    Put(x.source.ToString());2214  }2215  void Unparse(const OmpStylizedInstance &x) {2216    // empty2217  }2218  void Unparse(const OmpIteratorSpecifier &x) {2219    Walk(std::get<TypeDeclarationStmt>(x.t));2220    Put(" = ");2221    Walk(std::get<SubscriptTriplet>(x.t));2222  }2223  void Unparse(const OmpIterator &x) {2224    Word("ITERATOR(");2225    Walk(x.v);2226    Put(")");2227  }2228  void Unparse(const OmpMapper &x) {2229    Word("MAPPER(");2230    Walk(x.v);2231    Put(")");2232  }2233  void Unparse(const OmpLastprivateClause &x) {2234    using Modifier = OmpLastprivateClause::Modifier;2235    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2236    Walk(std::get<OmpObjectList>(x.t));2237  }2238  void Unparse(const OmpInteropPreference &x) { Walk(x.v, ","); }2239  void Unparse(const OmpInitClause &x) {2240    using Modifier = OmpInitClause::Modifier;2241    auto &modifiers{std::get<std::optional<std::list<Modifier>>>(x.t)};2242    bool isTypeStart{true};2243    for (const Modifier &m : *modifiers) {2244      if (auto *interopPreferenceMod{2245              std::get_if<parser::OmpInteropPreference>(&m.u)}) {2246        Put("PREFER_TYPE(");2247        Walk(*interopPreferenceMod);2248        Put("),");2249      } else if (auto *interopTypeMod{2250                     std::get_if<parser::OmpInteropType>(&m.u)}) {2251        if (isTypeStart) {2252          isTypeStart = false;2253        } else {2254          Put(",");2255        }2256        Walk(*interopTypeMod);2257      }2258    }2259    Put(": ");2260    Walk(std::get<OmpObject>(x.t));2261  }2262  void Unparse(const OmpMapClause &x) {2263    using Modifier = OmpMapClause::Modifier;2264    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2265    Walk(std::get<OmpObjectList>(x.t));2266  }2267  void Unparse(const OmpScheduleClause &x) {2268    using Modifier = OmpScheduleClause::Modifier;2269    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":");2270    Walk(std::get<OmpScheduleClause::Kind>(x.t));2271    Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));2272  }2273  void Unparse(const OmpDeviceClause &x) {2274    using Modifier = OmpDeviceClause::Modifier;2275    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2276    Walk(std::get<ScalarIntExpr>(x.t));2277  }2278  void Unparse(const OmpAbsentClause &x) { Walk("", x.v, ","); }2279  void Unparse(const OmpContainsClause &x) { Walk("", x.v, ","); }2280  void Unparse(const OmpAffinityClause &x) {2281    using Modifier = OmpAffinityClause::Modifier;2282    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2283    Walk(std::get<OmpObjectList>(x.t));2284  }2285  void Unparse(const OmpAlignedClause &x) {2286    using Modifier = OmpAlignedClause::Modifier;2287    Walk(std::get<OmpObjectList>(x.t));2288    Walk(": ", std::get<std::optional<std::list<Modifier>>>(x.t));2289  }2290  void Unparse(const OmpFallbackModifier &x) {2291    Word("FALLBACK(");2292    Walk(x.v);2293    Put(")");2294  }2295  void Unparse(const OmpDynGroupprivateClause &x) {2296    using Modifier = OmpDynGroupprivateClause::Modifier;2297    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2298    Walk(std::get<ScalarIntExpr>(x.t));2299  }2300  void Unparse(const OmpEnterClause &x) {2301    using Modifier = OmpEnterClause::Modifier;2302    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2303    Walk(std::get<OmpObjectList>(x.t));2304  }2305  void Unparse(const OmpFromClause &x) {2306    using Modifier = OmpFromClause::Modifier;2307    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2308    Walk(std::get<OmpObjectList>(x.t));2309  }2310  void Unparse(const OmpIfClause &x) {2311    using Modifier = OmpIfClause::Modifier;2312    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2313    Walk(std::get<ScalarLogicalExpr>(x.t));2314  }2315  void Unparse(const OmpStepSimpleModifier &x) { Walk(x.v); }2316  void Unparse(const OmpStepComplexModifier &x) {2317    Word("STEP(");2318    Walk(x.v);2319    Put(")");2320  }2321  void Unparse(const OmpLinearClause &x) {2322    using Modifier = OmpLinearClause::Modifier;2323    auto &modifiers{std::get<std::optional<std::list<Modifier>>>(x.t)};2324    if (std::get<bool>(x.t)) { // PostModified2325      Walk(std::get<OmpObjectList>(x.t));2326      Walk(": ", modifiers);2327    } else {2328      // Unparse using pre-5.2 syntax.2329      bool HasStepModifier{false}, HasLinearModifier{false};2330 2331      if (modifiers) {2332        bool NeedComma{false};2333        for (const Modifier &m : *modifiers) {2334          // Print all linear modifiers in case we need to unparse an2335          // incorrect tree.2336          if (auto *lmod{std::get_if<parser::OmpLinearModifier>(&m.u)}) {2337            if (NeedComma) {2338              Put(",");2339            }2340            Walk(*lmod);2341            HasLinearModifier = true;2342            NeedComma = true;2343          } else {2344            // If not linear-modifier, then it has to be step modifier.2345            HasStepModifier = true;2346          }2347        }2348      }2349 2350      if (HasLinearModifier) {2351        Put("(");2352      }2353      Walk(std::get<OmpObjectList>(x.t));2354      if (HasLinearModifier) {2355        Put(")");2356      }2357 2358      if (HasStepModifier) {2359        Put(": ");2360        bool NeedComma{false};2361        for (const Modifier &m : *modifiers) {2362          if (!std::holds_alternative<parser::OmpLinearModifier>(m.u)) {2363            if (NeedComma) {2364              Put(",");2365            }2366            common::visit([&](auto &&s) { Walk(s); }, m.u);2367            NeedComma = true;2368          }2369        }2370      }2371    }2372  }2373  void Unparse(const OmpLoopRangeClause &x) {2374    Word("LOOPRANGE(");2375    Walk(std::get<0>(x.t));2376    Put(", ");2377    Walk(std::get<1>(x.t));2378    Put(")");2379  }2380  void Unparse(const OmpReductionClause &x) {2381    using Modifier = OmpReductionClause::Modifier;2382    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2383    Walk(std::get<OmpObjectList>(x.t));2384  }2385  void Unparse(const OmpDetachClause &x) { Walk(x.v); }2386  void Unparse(const OmpInReductionClause &x) {2387    using Modifier = OmpInReductionClause::Modifier;2388    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2389    Walk(std::get<OmpObjectList>(x.t));2390  }2391  void Unparse(const OmpTaskReductionClause &x) {2392    using Modifier = OmpTaskReductionClause::Modifier;2393    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2394    Walk(std::get<OmpObjectList>(x.t));2395  }2396  void Unparse(const OmpAllocateClause &x) {2397    using Modifier = OmpAllocateClause::Modifier;2398    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2399    Walk(std::get<OmpObjectList>(x.t));2400  }2401  void Unparse(const OmpAlignModifier &x) {2402    Word("ALIGN(");2403    Walk(x.v);2404    Put(")");2405  }2406  void Unparse(const OmpAllocatorSimpleModifier &x) { Walk(x.v); }2407  void Unparse(const OmpAllocatorComplexModifier &x) {2408    Word("ALLOCATOR(");2409    Walk(x.v);2410    Put(")");2411  }2412  void Unparse(const OmpAttachModifier &x) {2413    Word("ATTACH(");2414    Walk(x.v);2415    Put(")");2416  }2417  void Unparse(const OmpOrderClause &x) {2418    using Modifier = OmpOrderClause::Modifier;2419    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":");2420    Walk(std::get<OmpOrderClause::Ordering>(x.t));2421  }2422  void Unparse(const OmpGrainsizeClause &x) {2423    using Modifier = OmpGrainsizeClause::Modifier;2424    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2425    Walk(std::get<ScalarIntExpr>(x.t));2426  }2427  void Unparse(const OmpNumTasksClause &x) {2428    using Modifier = OmpNumTasksClause::Modifier;2429    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2430    Walk(std::get<ScalarIntExpr>(x.t));2431  }2432  void Unparse(const OmpDoacross::Sink &x) {2433    Word("SINK: ");2434    Walk(x.v.v);2435  }2436  void Unparse(const OmpDoacross::Source &) { Word("SOURCE"); }2437  void Unparse(const OmpDependClause::TaskDep &x) {2438    using Modifier = OmpDependClause::TaskDep::Modifier;2439    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2440    Walk(std::get<OmpObjectList>(x.t));2441  }2442  void Unparse(const OmpDefaultmapClause &x) {2443    using Modifier = OmpDefaultmapClause::Modifier;2444    Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));2445    Walk(":", std::get<std::optional<std::list<Modifier>>>(x.t));2446  }2447  void Unparse(const OmpToClause &x) {2448    using Modifier = OmpToClause::Modifier;2449    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2450    Walk(std::get<OmpObjectList>(x.t));2451  }2452  void Unparse(const OmpWhenClause &x) {2453    using Modifier = OmpWhenClause::Modifier;2454    using Directive = common::Indirection<OmpDirectiveSpecification>;2455    Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");2456    Walk(std::get<std::optional<Directive>>(x.t));2457  }2458#define GEN_FLANG_CLAUSE_UNPARSE2459#include "llvm/Frontend/OpenMP/OMP.inc"2460  void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }2461 2462  void Unparse(const common::OmpMemoryOrderType &x) {2463    Word(ToUpperCaseLetters(common::EnumToString(x)));2464  }2465 2466  void Unparse(const OmpBeginDirective &x) {2467    BeginOpenMP();2468    Word("!$OMP ");2469    Walk(static_cast<const OmpDirectiveSpecification &>(x));2470    Put("\n");2471    EndOpenMP();2472  }2473 2474  void Unparse(const OmpEndDirective &x) {2475    BeginOpenMP();2476    Word("!$OMP END ");2477    Walk(static_cast<const OmpDirectiveSpecification &>(x));2478    Put("\n");2479    EndOpenMP();2480  }2481 2482  void Unparse(const OmpBlockConstruct &x) {2483    Walk(std::get<OmpBeginDirective>(x.t));2484    Walk(std::get<Block>(x.t), "");2485    if (auto &end{std::get<std::optional<OmpEndDirective>>(x.t)}) {2486      Walk(*end);2487    } else {2488      Put("\n");2489    }2490  }2491 2492  void Unparse(const OpenMPAtomicConstruct &x) { //2493    Unparse(static_cast<const OmpBlockConstruct &>(x));2494  }2495 2496  void Unparse(const OmpAllocateDirective &x) {2497    Unparse(static_cast<const OmpBlockConstruct &>(x));2498  }2499  void Unparse(const OpenMPAllocatorsConstruct &x) {2500    Unparse(static_cast<const OmpBlockConstruct &>(x));2501  }2502  void Unparse(const OpenMPAssumeConstruct &x) {2503    Unparse(static_cast<const OmpBlockConstruct &>(x));2504  }2505  void Unparse(const OpenMPCriticalConstruct &x) {2506    Unparse(static_cast<const OmpBlockConstruct &>(x));2507  }2508  void Unparse(const OmpInitializerExpression &x) {2509    Unparse(static_cast<const OmpStylizedExpression &>(x));2510  }2511  void Unparse(const OmpCombinerExpression &x) {2512    Unparse(static_cast<const OmpStylizedExpression &>(x));2513  }2514  void Unparse(const OpenMPDeclareReductionConstruct &x) {2515    BeginOpenMP();2516    Word("!$OMP ");2517    Walk(x.v);2518    Put("\n");2519    EndOpenMP();2520  }2521  void Unparse(const OmpAppendArgsClause::OmpAppendOp &x) {2522    Put("INTEROP(");2523    Walk(x.v, ",");2524    Put(")");2525  }2526  void Unparse(const OmpAppendArgsClause &x) { Walk(x.v, ","); }2527  void Unparse(const OmpAdjustArgsClause &x) {2528    Walk(std::get<OmpAdjustArgsClause::OmpAdjustOp>(x.t).v);2529    Put(":");2530    Walk(std::get<parser::OmpObjectList>(x.t));2531  }2532  void Unparse(const OmpDeclareVariantDirective &x) {2533    BeginOpenMP();2534    Word("!$OMP ");2535    Walk(x.v);2536    Put("\n");2537    EndOpenMP();2538  }2539  void Unparse(const OpenMPInteropConstruct &x) {2540    BeginOpenMP();2541    Word("!$OMP INTEROP");2542    auto flags{std::get<OmpDirectiveSpecification::Flags>(x.v.t)};2543    if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {2544      Walk("(", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");2545      Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));2546    } else {2547      Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));2548      Walk(" (", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");2549    }2550    Put("\n");2551    EndOpenMP();2552  }2553 2554  void Unparse(const OpenMPDeclarativeAssumes &x) {2555    BeginOpenMP();2556    Word("!$OMP ");2557    Walk(x.v);2558    Put("\n");2559    EndOpenMP();2560  }2561  void Unparse(const OpenMPDeclareMapperConstruct &x) {2562    BeginOpenMP();2563    Word("!$OMP ");2564    Walk(x.v);2565    Put("\n");2566    EndOpenMP();2567  }2568  void Unparse(const OpenMPDeclareSimdConstruct &x) {2569    BeginOpenMP();2570    Word("!$OMP ");2571    Walk(x.v);2572    Put("\n");2573    EndOpenMP();2574  }2575  void Unparse(const OpenMPDeclareTargetConstruct &x) {2576    BeginOpenMP();2577    Word("!$OMP ");2578    Walk(x.v);2579    Put("\n");2580    EndOpenMP();2581  }2582  void Unparse(const OpenMPDispatchConstruct &x) { //2583    Unparse(static_cast<const OmpBlockConstruct &>(x));2584  }2585  void Unparse(const OpenMPGroupprivate &x) {2586    BeginOpenMP();2587    Word("!$OMP ");2588    Walk(x.v);2589    Put("\n");2590    EndOpenMP();2591  }2592  void Unparse(const OpenMPRequiresConstruct &x) {2593    BeginOpenMP();2594    Word("!$OMP ");2595    Walk(x.v);2596    Put("\n");2597    EndOpenMP();2598  }2599  void Unparse(const OpenMPThreadprivate &x) {2600    BeginOpenMP();2601    Word("!$OMP ");2602    Walk(x.v);2603    Put("\n");2604    EndOpenMP();2605  }2606  bool Pre(const OmpMessageClause &x) {2607    Walk(x.v);2608    return false;2609  }2610  void Unparse(const OmpErrorDirective &x) {2611    BeginOpenMP();2612    Word("!$OMP ");2613    Walk(x.v);2614    Put("\n");2615    EndOpenMP();2616  }2617  void Unparse(const OmpNothingDirective &x) {2618    BeginOpenMP();2619    Word("!$OMP ");2620    Walk(x.v);2621    Put("\n");2622    EndOpenMP();2623  }2624  void Unparse(const OpenMPSectionConstruct &x) {2625    if (auto &&dirSpec{2626            std::get<std::optional<OmpDirectiveSpecification>>(x.t)}) {2627      BeginOpenMP();2628      Word("!$OMP ");2629      Walk(*dirSpec);2630      Put("\n");2631      EndOpenMP();2632    }2633    Walk(std::get<Block>(x.t), "");2634  }2635  void Unparse(const OmpBeginSectionsDirective &x) {2636    Unparse(static_cast<const OmpBeginDirective &>(x));2637  }2638  void Unparse(const OmpEndSectionsDirective &x) {2639    Unparse(static_cast<const OmpEndDirective &>(x));2640  }2641  void Unparse(const OpenMPSectionsConstruct &x) {2642    Walk(std::get<OmpBeginSectionsDirective>(x.t));2643    Walk(std::get<std::list<OpenMPConstruct>>(x.t), "");2644    Walk(std::get<std::optional<OmpEndSectionsDirective>>(x.t));2645  }2646  // Clause unparsers are usually generated by tablegen in the form2647  // CLAUSE(VALUE). Here we only want to print VALUE so a custom unparser is2648  // needed.2649  void Unparse(const OmpClause::CancellationConstructType &x) { Walk(x.v); }2650  void Unparse(const OpenMPCancellationPointConstruct &x) {2651    BeginOpenMP();2652    Word("!$OMP ");2653    Walk(x.v);2654    Put("\n");2655    EndOpenMP();2656  }2657  void Unparse(const OpenMPCancelConstruct &x) {2658    BeginOpenMP();2659    Word("!$OMP ");2660    Walk(x.v);2661    Put("\n");2662    EndOpenMP();2663  }2664  void Unparse(const OmpFailClause &x) { Walk(x.v); }2665  void Unparse(const OmpMetadirectiveDirective &x) {2666    BeginOpenMP();2667    Word("!$OMP ");2668    Walk(x.v);2669    Put("\n");2670    EndOpenMP();2671  }2672  void Unparse(const OpenMPDepobjConstruct &x) {2673    BeginOpenMP();2674    Word("!$OMP ");2675    Walk(x.v);2676    Put("\n");2677    EndOpenMP();2678  }2679  void Unparse(const OpenMPFlushConstruct &x) {2680    BeginOpenMP();2681    Word("!$OMP FLUSH");2682    auto flags{std::get<OmpDirectiveSpecification::Flags>(x.v.t)};2683    if (flags.test(OmpDirectiveSpecification::Flag::DeprecatedSyntax)) {2684      Walk("(", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");2685      Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));2686    } else {2687      Walk(" ", std::get<std::optional<OmpClauseList>>(x.v.t));2688      Walk(" (", std::get<std::optional<OmpArgumentList>>(x.v.t), ")");2689    }2690    Put("\n");2691    EndOpenMP();2692  }2693  void Unparse(const OmpBeginLoopDirective &x) {2694    Unparse(static_cast<const OmpBeginDirective &>(x));2695  }2696  void Unparse(const OmpEndLoopDirective &x) {2697    Unparse(static_cast<const OmpEndDirective &>(x));2698  }2699  void Unparse(const OmpClauseList &x, const char *sep = " ") {2700    Walk(" ", x.v, sep);2701  }2702  void Unparse(const OpenMPSimpleStandaloneConstruct &x) {2703    BeginOpenMP();2704    Word("!$OMP ");2705    Walk(x.v);2706    Put("\n");2707    EndOpenMP();2708  }2709  void Unparse(const OpenMPMisplacedEndDirective &x) {2710    Unparse(static_cast<const OmpEndDirective &>(x));2711  }2712  void Unparse(const OpenMPInvalidDirective &x) {2713    BeginOpenMP();2714    Word("!$OMP ");2715    Put(parser::ToUpperCaseLetters(x.source.ToString()));2716    Put("\n");2717    EndOpenMP();2718  }2719  void Unparse(const BasedPointer &x) {2720    Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));2721    Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');2722  }2723  void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }2724  void Unparse(const CUDAAttributesStmt &x) {2725    Word("ATTRIBUTES("), Walk(std::get<common::CUDADataAttr>(x.t));2726    Word(") "), Walk(std::get<std::list<Name>>(x.t), ", ");2727  }2728  void Post(const StructureField &x) {2729    if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {2730      for (const auto &item :2731          std::get<std::list<ComponentOrFill>>(def->statement.t)) {2732        if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) {2733          structureComponents_.insert(std::get<Name>(comp->t).source);2734        }2735      }2736    }2737  }2738  void Unparse(const StructureStmt &x) {2739    Word("STRUCTURE ");2740    // The name, if present, includes the /slashes/2741    Walk(std::get<std::optional<Name>>(x.t));2742    Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");2743    Indent();2744  }2745  void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }2746  void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }2747  void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }2748  void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }2749  void Post(const StructureDef::EndStructureStmt &) {2750    Outdent(), Word("END STRUCTURE");2751  }2752  void Unparse(const OldParameterStmt &x) {2753    Word("PARAMETER "), Walk(x.v, ", ");2754  }2755  void Unparse(const ArithmeticIfStmt &x) {2756    Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");2757    Walk(std::get<1>(x.t)), Put(", ");2758    Walk(std::get<2>(x.t)), Put(", ");2759    Walk(std::get<3>(x.t));2760  }2761  void Unparse(const AssignStmt &x) {2762    Word("ASSIGN "), Walk(std::get<Label>(x.t));2763    Word(" TO "), Walk(std::get<Name>(x.t));2764  }2765  void Unparse(const AssignedGotoStmt &x) {2766    Word("GO TO "), Walk(std::get<Name>(x.t));2767    Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");2768  }2769  void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }2770 2771#define WALK_NESTED_ENUM(CLASS, ENUM) \2772  void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }2773  WALK_NESTED_ENUM(AccDataModifier, Modifier)2774  WALK_NESTED_ENUM(AccessSpec, Kind) // R8072775  WALK_NESTED_ENUM(common, TypeParamAttr) // R7342776  WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA2777  WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA2778  WALK_NESTED_ENUM(IntentSpec, Intent) // R8262779  WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R8662780  WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R12052781  WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)2782  WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)2783  WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)2784  WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)2785  WALK_NESTED_ENUM(ProcedureStmt, Kind) // R15062786  WALK_NESTED_ENUM(UseStmt, ModuleNature) // R14102787  WALK_NESTED_ENUM(OmpAdjustArgsClause::OmpAdjustOp, Value) // OMP adjustop2788  WALK_NESTED_ENUM(OmpAtClause, ActionTime) // OMP at2789  WALK_NESTED_ENUM(OmpAutomapModifier, Value) // OMP automap-modifier2790  WALK_NESTED_ENUM(OmpBindClause, Binding) // OMP bind2791  WALK_NESTED_ENUM(OmpProcBindClause, AffinityPolicy) // OMP proc_bind2792  WALK_NESTED_ENUM(OmpDefaultClause, DataSharingAttribute) // OMP default2793  WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP defaultmap2794  WALK_NESTED_ENUM(OmpVariableCategory, Value) // OMP variable-category2795  WALK_NESTED_ENUM(OmpLastprivateModifier, Value) // OMP lastprivate-modifier2796  WALK_NESTED_ENUM(OmpChunkModifier, Value) // OMP chunk-modifier2797  WALK_NESTED_ENUM(OmpLinearModifier, Value) // OMP linear-modifier2798  WALK_NESTED_ENUM(OmpOrderingModifier, Value) // OMP ordering-modifier2799  WALK_NESTED_ENUM(OmpTaskDependenceType, Value) // OMP task-dependence-type2800  WALK_NESTED_ENUM(OmpScheduleClause, Kind) // OMP schedule-kind2801  WALK_NESTED_ENUM(OmpSeverityClause, Severity) // OMP severity2802  WALK_NESTED_ENUM(OmpAccessGroup, Value)2803  WALK_NESTED_ENUM(OmpDeviceModifier, Value) // OMP device modifier2804  WALK_NESTED_ENUM(2805      OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type2806  WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier2807  WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation2808  WALK_NESTED_ENUM(OmpFallbackModifier, Value) // OMP fallback-modifier2809  WALK_NESTED_ENUM(OmpInteropType, Value) // OMP InteropType2810  WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering2811  WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier2812  WALK_NESTED_ENUM(OmpPrescriptiveness, Value) // OMP prescriptiveness2813  WALK_NESTED_ENUM(OmpMapType, Value) // OMP map-type2814  WALK_NESTED_ENUM(OmpMapTypeModifier, Value) // OMP map-type-modifier2815  WALK_NESTED_ENUM(OmpAlwaysModifier, Value)2816  WALK_NESTED_ENUM(OmpAttachModifier, Value)2817  WALK_NESTED_ENUM(OmpCloseModifier, Value)2818  WALK_NESTED_ENUM(OmpDeleteModifier, Value)2819  WALK_NESTED_ENUM(OmpPresentModifier, Value)2820  WALK_NESTED_ENUM(OmpRefModifier, Value)2821  WALK_NESTED_ENUM(OmpSelfModifier, Value)2822  WALK_NESTED_ENUM(OmpTraitSelectorName, Value)2823  WALK_NESTED_ENUM(OmpTraitSetSelectorName, Value)2824  WALK_NESTED_ENUM(OmpxHoldModifier, Value)2825 2826#undef WALK_NESTED_ENUM2827  void Unparse(const ReductionOperator::Operator x) {2828    switch (x) {2829    case ReductionOperator::Operator::Plus:2830      Word("+");2831      break;2832    case ReductionOperator::Operator::Multiply:2833      Word("*");2834      break;2835    case ReductionOperator::Operator::And:2836      Word(".AND.");2837      break;2838    case ReductionOperator::Operator::Or:2839      Word(".OR.");2840      break;2841    case ReductionOperator::Operator::Eqv:2842      Word(".EQV.");2843      break;2844    case ReductionOperator::Operator::Neqv:2845      Word(".NEQV.");2846      break;2847    default:2848      Word(ReductionOperator::EnumToString(x));2849      break;2850    }2851  }2852 2853  void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) {2854    if (x.v) {2855      Walk(*x.v);2856    } else {2857      Word("*");2858    }2859  }2860  void Unparse(const CUFKernelDoConstruct::LaunchConfiguration &x) {2861    Word(" <<<");2862    const auto &grid{std::get<0>(x.t)};2863    if (grid.empty()) {2864      Word("*");2865    } else if (grid.size() == 1) {2866      Walk(grid.front());2867    } else {2868      Walk("(", grid, ",", ")");2869    }2870    Word(",");2871    const auto &block{std::get<1>(x.t)};2872    if (block.empty()) {2873      Word("*");2874    } else if (block.size() == 1) {2875      Walk(block.front());2876    } else {2877      Walk("(", block, ",", ")");2878    }2879    if (const auto &stream{std::get<2>(x.t)}) {2880      Word(",STREAM="), Walk(*stream);2881    }2882    Word(">>>");2883  }2884  void Unparse(const CUFKernelDoConstruct::Directive &x) {2885    Word("!$CUF KERNEL DO");2886    Walk(" (", std::get<std::optional<ScalarIntConstantExpr>>(x.t), ")");2887    Walk(std::get<std::optional<CUFKernelDoConstruct::LaunchConfiguration>>(2888        x.t));2889    Walk(" ", std::get<std::list<CUFReduction>>(x.t), " ");2890    Word("\n");2891  }2892  void Unparse(const CUFKernelDoConstruct &x) {2893    Walk(std::get<CUFKernelDoConstruct::Directive>(x.t));2894    Walk(std::get<std::optional<DoConstruct>>(x.t));2895  }2896  void Unparse(const CUFReduction &x) {2897    Word("REDUCE(");2898    Walk(std::get<CUFReduction::Operator>(x.t));2899    Walk(":", std::get<std::list<Scalar<Variable>>>(x.t), ",", ")");2900  }2901 2902  void Done() const { CHECK(indent_ == 0); }2903 2904private:2905  void Put(char);2906  void Put(const char *);2907  void Put(const std::string &);2908  void PutNormalized(const std::string &);2909  void PutKeywordLetter(char);2910  void Word(const char *);2911  void Word(const std::string &);2912  void Word(const std::string_view &);2913  void Indent() { indent_ += indentationAmount_; }2914  void Outdent() {2915    CHECK(indent_ >= indentationAmount_);2916    indent_ -= indentationAmount_;2917  }2918  void BeginOpenMP() { openmpDirective_ = true; }2919  void EndOpenMP() { openmpDirective_ = false; }2920  void BeginOpenACC() { openaccDirective_ = true; }2921  void EndOpenACC() { openaccDirective_ = false; }2922 2923  // Call back to the traversal framework.2924  template <typename T> void Walk(const T &x) {2925    Fortran::parser::Walk(x, *this);2926  }2927 2928  // Traverse a std::optional<> value.  Emit a prefix and/or a suffix string2929  // only when it contains a value.2930  template <typename A>2931  void Walk(2932      const char *prefix, const std::optional<A> &x, const char *suffix = "") {2933    if (x) {2934      Word(prefix), Walk(*x), Word(suffix);2935    }2936  }2937  template <typename A>2938  void Walk(const std::optional<A> &x, const char *suffix = "") {2939    return Walk("", x, suffix);2940  }2941 2942  // Traverse a std::list<>.  Separate the elements with an optional string.2943  // Emit a prefix and/or a suffix string only when the list is not empty.2944  template <typename A>2945  void Walk(const char *prefix, const std::list<A> &list,2946      const char *comma = ", ", const char *suffix = "") {2947    if (!list.empty()) {2948      const char *str{prefix};2949      for (const auto &x : list) {2950        Word(str), Walk(x);2951        str = comma;2952      }2953      Word(suffix);2954    }2955  }2956  template <typename A>2957  void Walk(const std::list<A> &list, const char *comma = ", ",2958      const char *suffix = "") {2959    return Walk("", list, comma, suffix);2960  }2961 2962  // Traverse a std::tuple<>, with an optional separator.2963  template <std::size_t J = 0, typename T>2964  void WalkTupleElements(const T &tuple, const char *separator) {2965    if (J > 0 && J < std::tuple_size_v<T>) {2966      Word(separator); // this usage dodges "unused parameter" warning2967    }2968    if constexpr (J < std::tuple_size_v<T>) {2969      Walk(std::get<J>(tuple));2970      WalkTupleElements<J + 1>(tuple, separator);2971    }2972  }2973  template <typename... A>2974  void Walk(const std::tuple<A...> &tuple, const char *separator = "") {2975    WalkTupleElements(tuple, separator);2976  }2977 2978  void EndSubprogram(const char *kind, const std::optional<Name> &name) {2979    Outdent(), Word("END "), Word(kind), Walk(" ", name);2980    structureComponents_.clear();2981  }2982 2983  llvm::raw_ostream &out_;2984  const common::LangOptions &langOpts_;2985  int indent_{0};2986  const int indentationAmount_{1};2987  int column_{1};2988  const int maxColumns_{80};2989  std::set<CharBlock> structureComponents_;2990  Encoding encoding_{Encoding::UTF_8};2991  bool capitalizeKeywords_{true};2992  bool openaccDirective_{false};2993  bool openmpDirective_{false};2994  bool backslashEscapes_{false};2995  preStatementType *preStatement_{nullptr};2996  AnalyzedObjectsAsFortran *asFortran_{nullptr};2997};2998 2999void UnparseVisitor::Put(char ch) {3000  int sav = indent_;3001  if (openmpDirective_ || openaccDirective_) {3002    indent_ = 0;3003  }3004  if (column_ <= 1) {3005    if (ch == '\n') {3006      return;3007    }3008    for (int j{0}; j < indent_; ++j) {3009      out_ << ' ';3010    }3011    column_ = indent_ + 2;3012  } else if (ch == '\n') {3013    column_ = 1;3014  } else if (++column_ >= maxColumns_) {3015    out_ << "&\n";3016    for (int j{0}; j < indent_; ++j) {3017      out_ << ' ';3018    }3019    if (openmpDirective_) {3020      out_ << "!$OMP&";3021      column_ = 8;3022    } else if (openaccDirective_) {3023      out_ << "!$ACC&";3024      column_ = 8;3025    } else {3026      out_ << '&';3027      column_ = indent_ + 3;3028    }3029  }3030  out_ << ch;3031  if (openmpDirective_ || openaccDirective_) {3032    indent_ = sav;3033  }3034}3035 3036void UnparseVisitor::Put(const char *str) {3037  for (; *str != '\0'; ++str) {3038    Put(*str);3039  }3040}3041 3042void UnparseVisitor::Put(const std::string &str) {3043  for (char ch : str) {3044    Put(ch);3045  }3046}3047 3048void UnparseVisitor::PutNormalized(const std::string &str) {3049  auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};3050  std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};3051  Put(QuoteCharacterLiteral(encoded, backslashEscapes_));3052}3053 3054void UnparseVisitor::PutKeywordLetter(char ch) {3055  if (capitalizeKeywords_) {3056    Put(ToUpperCaseLetter(ch));3057  } else {3058    Put(ToLowerCaseLetter(ch));3059  }3060}3061 3062void UnparseVisitor::Word(const char *str) {3063  for (; *str != '\0'; ++str) {3064    PutKeywordLetter(*str);3065  }3066}3067 3068void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }3069 3070void UnparseVisitor::Word(const std::string_view &str) {3071  for (std::size_t j{0}; j < str.length(); ++j) {3072    PutKeywordLetter(str[j]);3073  }3074}3075 3076template <typename A>3077void Unparse(llvm::raw_ostream &out, const A &root,3078    const common::LangOptions &langOpts, Encoding encoding,3079    bool capitalizeKeywords, bool backslashEscapes,3080    preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {3081  UnparseVisitor visitor{out, langOpts, 1, encoding, capitalizeKeywords,3082      backslashEscapes, preStatement, asFortran};3083  Walk(root, visitor);3084  visitor.Done();3085}3086 3087template void Unparse<Program>(llvm::raw_ostream &, const Program &,3088    const common::LangOptions &, Encoding, bool, bool, preStatementType *,3089    AnalyzedObjectsAsFortran *);3090template void Unparse<Expr>(llvm::raw_ostream &, const Expr &,3091    const common::LangOptions &, Encoding, bool, bool, preStatementType *,3092    AnalyzedObjectsAsFortran *);3093 3094template void Unparse<parser::OpenMPDeclarativeConstruct>(llvm::raw_ostream &,3095    const parser::OpenMPDeclarativeConstruct &, const common::LangOptions &,3096    Encoding, bool, bool, preStatementType *, AnalyzedObjectsAsFortran *);3097} // namespace Fortran::parser3098