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