1 //===-- lib/Parser/unparse.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // Generates Fortran from the content of a parse tree, using the 10 // traversal templates in parse-tree-visitor.h. 11 12 #include "flang/Parser/unparse.h" 13 #include "flang/Common/Fortran.h" 14 #include "flang/Common/idioms.h" 15 #include "flang/Common/indirection.h" 16 #include "flang/Parser/characters.h" 17 #include "flang/Parser/parse-tree-visitor.h" 18 #include "flang/Parser/parse-tree.h" 19 #include "flang/Parser/tools.h" 20 #include "llvm/Support/raw_ostream.h" 21 #include <algorithm> 22 #include <cinttypes> 23 #include <cstddef> 24 #include <set> 25 26 namespace Fortran::parser { 27 28 class UnparseVisitor { 29 public: UnparseVisitor(llvm::raw_ostream & out,int indentationAmount,Encoding encoding,bool capitalize,bool backslashEscapes,preStatementType * preStatement,AnalyzedObjectsAsFortran * asFortran)30 UnparseVisitor(llvm::raw_ostream &out, int indentationAmount, 31 Encoding encoding, bool capitalize, bool backslashEscapes, 32 preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) 33 : out_{out}, indentationAmount_{indentationAmount}, encoding_{encoding}, 34 capitalizeKeywords_{capitalize}, backslashEscapes_{backslashEscapes}, 35 preStatement_{preStatement}, asFortran_{asFortran} {} 36 37 // In nearly all cases, this code avoids defining Boolean-valued Pre() 38 // callbacks for the parse tree walking framework in favor of two void 39 // functions, Before() and Unparse(), which imply true and false return 40 // values for Pre() respectively. Before(const T &)41 template <typename T> void Before(const T &) {} 42 template <typename T> double Unparse(const T &); // not void, never used 43 Pre(const T & x)44 template <typename T> bool Pre(const T &x) { 45 if constexpr (std::is_void_v<decltype(Unparse(x))>) { 46 // There is a local definition of Unparse() for this type. It 47 // overrides the parse tree walker's default Walk() over the descendents. 48 Before(x); 49 Unparse(x); 50 Post(x); 51 return false; // Walk() does not visit descendents 52 } else if constexpr (HasTypedExpr<T>::value) { 53 // Format the expression representation from semantics 54 if (asFortran_ && x.typedExpr) { 55 asFortran_->expr(out_, *x.typedExpr); 56 return false; 57 } else { 58 return true; 59 } 60 } else { 61 Before(x); 62 return true; // there's no Unparse() defined here, Walk() the descendents 63 } 64 } Post(const T &)65 template <typename T> void Post(const T &) {} 66 67 // Emit simple types as-is. Unparse(const std::string & x)68 void Unparse(const std::string &x) { Put(x); } Unparse(int x)69 void Unparse(int x) { Put(std::to_string(x)); } Unparse(unsigned int x)70 void Unparse(unsigned int x) { Put(std::to_string(x)); } Unparse(long x)71 void Unparse(long x) { Put(std::to_string(x)); } Unparse(unsigned long x)72 void Unparse(unsigned long x) { Put(std::to_string(x)); } Unparse(long long x)73 void Unparse(long long x) { Put(std::to_string(x)); } Unparse(unsigned long long x)74 void Unparse(unsigned long long x) { Put(std::to_string(x)); } Unparse(char x)75 void Unparse(char x) { Put(x); } 76 77 // Statement labels and ends of lines Before(const Statement<T> & x)78 template <typename T> void Before(const Statement<T> &x) { 79 if (preStatement_) { 80 (*preStatement_)(x.source, out_, indent_); 81 } 82 Walk(x.label, " "); 83 } Post(const Statement<T> &)84 template <typename T> void Post(const Statement<T> &) { Put('\n'); } 85 86 // The special-case formatting functions for these productions are 87 // ordered to correspond roughly to their order of appearance in 88 // the Fortran 2018 standard (and parse-tree.h). 89 Unparse(const Program & x)90 void Unparse(const Program &x) { // R501 91 Walk("", x.v, "\n"); // put blank lines between ProgramUnits 92 } 93 Unparse(const Name & x)94 void Unparse(const Name &x) { // R603 95 Put(x.ToString()); 96 } Unparse(const DefinedOperator::IntrinsicOperator & x)97 void Unparse(const DefinedOperator::IntrinsicOperator &x) { // R608 98 switch (x) { 99 case DefinedOperator::IntrinsicOperator::Power: 100 Put("**"); 101 break; 102 case DefinedOperator::IntrinsicOperator::Multiply: 103 Put('*'); 104 break; 105 case DefinedOperator::IntrinsicOperator::Divide: 106 Put('/'); 107 break; 108 case DefinedOperator::IntrinsicOperator::Add: 109 Put('+'); 110 break; 111 case DefinedOperator::IntrinsicOperator::Subtract: 112 Put('-'); 113 break; 114 case DefinedOperator::IntrinsicOperator::Concat: 115 Put("//"); 116 break; 117 case DefinedOperator::IntrinsicOperator::LT: 118 Put('<'); 119 break; 120 case DefinedOperator::IntrinsicOperator::LE: 121 Put("<="); 122 break; 123 case DefinedOperator::IntrinsicOperator::EQ: 124 Put("=="); 125 break; 126 case DefinedOperator::IntrinsicOperator::NE: 127 Put("/="); 128 break; 129 case DefinedOperator::IntrinsicOperator::GE: 130 Put(">="); 131 break; 132 case DefinedOperator::IntrinsicOperator::GT: 133 Put('>'); 134 break; 135 default: 136 Put('.'), Word(DefinedOperator::EnumToString(x)), Put('.'); 137 } 138 } Post(const Star &)139 void Post(const Star &) { Put('*'); } // R701 &c. Post(const TypeParamValue::Deferred &)140 void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701 Unparse(const DeclarationTypeSpec::Type & x)141 void Unparse(const DeclarationTypeSpec::Type &x) { // R703 142 Word("TYPE("), Walk(x.derived), Put(')'); 143 } Unparse(const DeclarationTypeSpec::Class & x)144 void Unparse(const DeclarationTypeSpec::Class &x) { 145 Word("CLASS("), Walk(x.derived), Put(')'); 146 } Post(const DeclarationTypeSpec::ClassStar &)147 void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); } Post(const DeclarationTypeSpec::TypeStar &)148 void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); } Unparse(const DeclarationTypeSpec::Record & x)149 void Unparse(const DeclarationTypeSpec::Record &x) { 150 Word("RECORD/"), Walk(x.v), Put('/'); 151 } Before(const IntrinsicTypeSpec::Real &)152 void Before(const IntrinsicTypeSpec::Real &) { // R704 153 Word("REAL"); 154 } Before(const IntrinsicTypeSpec::Complex &)155 void Before(const IntrinsicTypeSpec::Complex &) { Word("COMPLEX"); } Post(const IntrinsicTypeSpec::DoublePrecision &)156 void Post(const IntrinsicTypeSpec::DoublePrecision &) { 157 Word("DOUBLE PRECISION"); 158 } Before(const IntrinsicTypeSpec::Character &)159 void Before(const IntrinsicTypeSpec::Character &) { Word("CHARACTER"); } Before(const IntrinsicTypeSpec::Logical &)160 void Before(const IntrinsicTypeSpec::Logical &) { Word("LOGICAL"); } Post(const IntrinsicTypeSpec::DoubleComplex &)161 void Post(const IntrinsicTypeSpec::DoubleComplex &) { 162 Word("DOUBLE COMPLEX"); 163 } Before(const IntegerTypeSpec &)164 void Before(const IntegerTypeSpec &) { // R705 165 Word("INTEGER"); 166 } Unparse(const KindSelector & x)167 void Unparse(const KindSelector &x) { // R706 168 common::visit( 169 common::visitors{ 170 [&](const ScalarIntConstantExpr &y) { 171 Put('('), Word("KIND="), Walk(y), Put(')'); 172 }, 173 [&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); }, 174 }, 175 x.u); 176 } Unparse(const SignedIntLiteralConstant & x)177 void Unparse(const SignedIntLiteralConstant &x) { // R707 178 Put(std::get<CharBlock>(x.t).ToString()); 179 Walk("_", std::get<std::optional<KindParam>>(x.t)); 180 } Unparse(const IntLiteralConstant & x)181 void Unparse(const IntLiteralConstant &x) { // R708 182 Put(std::get<CharBlock>(x.t).ToString()); 183 Walk("_", std::get<std::optional<KindParam>>(x.t)); 184 } Unparse(const Sign & x)185 void Unparse(const Sign &x) { // R712 186 Put(x == Sign::Negative ? '-' : '+'); 187 } Unparse(const RealLiteralConstant & x)188 void Unparse(const RealLiteralConstant &x) { // R714, R715 189 Put(x.real.source.ToString()), Walk("_", x.kind); 190 } Unparse(const ComplexLiteralConstant & x)191 void Unparse(const ComplexLiteralConstant &x) { // R718 - R720 192 Put('('), Walk(x.t, ","), Put(')'); 193 } Unparse(const CharSelector::LengthAndKind & x)194 void Unparse(const CharSelector::LengthAndKind &x) { // R721 195 Put('('), Word("KIND="), Walk(x.kind); 196 Walk(", LEN=", x.length), Put(')'); 197 } Unparse(const LengthSelector & x)198 void Unparse(const LengthSelector &x) { // R722 199 common::visit(common::visitors{ 200 [&](const TypeParamValue &y) { 201 Put('('), Word("LEN="), Walk(y), Put(')'); 202 }, 203 [&](const CharLength &y) { Put('*'), Walk(y); }, 204 }, 205 x.u); 206 } Unparse(const CharLength & x)207 void Unparse(const CharLength &x) { // R723 208 common::visit( 209 common::visitors{ 210 [&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); }, 211 [&](const std::int64_t &y) { Walk(y); }, 212 }, 213 x.u); 214 } Unparse(const CharLiteralConstant & x)215 void Unparse(const CharLiteralConstant &x) { // R724 216 const auto &str{std::get<std::string>(x.t)}; 217 if (const auto &k{std::get<std::optional<KindParam>>(x.t)}) { 218 Walk(*k), Put('_'); 219 } 220 PutNormalized(str); 221 } Unparse(const HollerithLiteralConstant & x)222 void Unparse(const HollerithLiteralConstant &x) { 223 auto ucs{DecodeString<std::u32string, Encoding::UTF_8>(x.v, false)}; 224 Unparse(ucs.size()); 225 Put('H'); 226 for (char32_t ch : ucs) { 227 EncodedCharacter encoded{EncodeCharacter(encoding_, ch)}; 228 for (int j{0}; j < encoded.bytes; ++j) { 229 Put(encoded.buffer[j]); 230 } 231 } 232 } Unparse(const LogicalLiteralConstant & x)233 void Unparse(const LogicalLiteralConstant &x) { // R725 234 Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE."); 235 Walk("_", std::get<std::optional<KindParam>>(x.t)); 236 } Unparse(const DerivedTypeStmt & x)237 void Unparse(const DerivedTypeStmt &x) { // R727 238 Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", "); 239 Put(" :: "), Walk(std::get<Name>(x.t)); 240 Walk("(", std::get<std::list<Name>>(x.t), ", ", ")"); 241 Indent(); 242 } Unparse(const Abstract &)243 void Unparse(const Abstract &) { // R728, &c. 244 Word("ABSTRACT"); 245 } Post(const TypeAttrSpec::BindC &)246 void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); } Unparse(const TypeAttrSpec::Extends & x)247 void Unparse(const TypeAttrSpec::Extends &x) { 248 Word("EXTENDS("), Walk(x.v), Put(')'); 249 } Unparse(const EndTypeStmt & x)250 void Unparse(const EndTypeStmt &x) { // R730 251 Outdent(), Word("END TYPE"), Walk(" ", x.v); 252 } Unparse(const SequenceStmt &)253 void Unparse(const SequenceStmt &) { // R731 254 Word("SEQUENCE"); 255 } Unparse(const TypeParamDefStmt & x)256 void Unparse(const TypeParamDefStmt &x) { // R732 257 Walk(std::get<IntegerTypeSpec>(x.t)); 258 Put(", "), Walk(std::get<common::TypeParamAttr>(x.t)); 259 Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", "); 260 } Unparse(const TypeParamDecl & x)261 void Unparse(const TypeParamDecl &x) { // R733 262 Walk(std::get<Name>(x.t)); 263 Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t)); 264 } Unparse(const DataComponentDefStmt & x)265 void Unparse(const DataComponentDefStmt &x) { // R737 266 const auto &dts{std::get<DeclarationTypeSpec>(x.t)}; 267 const auto &attrs{std::get<std::list<ComponentAttrSpec>>(x.t)}; 268 const auto &decls{std::get<std::list<ComponentOrFill>>(x.t)}; 269 Walk(dts), Walk(", ", attrs, ", "); 270 if (!attrs.empty() || 271 (!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) && 272 std::none_of( 273 decls.begin(), decls.end(), [](const ComponentOrFill &c) { 274 return common::visit( 275 common::visitors{ 276 [](const ComponentDecl &d) { 277 const auto &init{ 278 std::get<std::optional<Initialization>>(d.t)}; 279 return init && 280 std::holds_alternative<std::list< 281 common::Indirection<DataStmtValue>>>( 282 init->u); 283 }, 284 [](const FillDecl &) { return false; }, 285 }, 286 c.u); 287 }))) { 288 Put(" ::"); 289 } 290 Put(' '), Walk(decls, ", "); 291 } Unparse(const Allocatable &)292 void Unparse(const Allocatable &) { // R738 293 Word("ALLOCATABLE"); 294 } Unparse(const Pointer &)295 void Unparse(const Pointer &) { Word("POINTER"); } Unparse(const Contiguous &)296 void Unparse(const Contiguous &) { Word("CONTIGUOUS"); } Before(const ComponentAttrSpec & x)297 void Before(const ComponentAttrSpec &x) { 298 common::visit(common::visitors{ 299 [&](const CoarraySpec &) { Word("CODIMENSION["); }, 300 [&](const ComponentArraySpec &) { Word("DIMENSION("); }, 301 [](const auto &) {}, 302 }, 303 x.u); 304 } Post(const ComponentAttrSpec & x)305 void Post(const ComponentAttrSpec &x) { 306 common::visit(common::visitors{ 307 [&](const CoarraySpec &) { Put(']'); }, 308 [&](const ComponentArraySpec &) { Put(')'); }, 309 [](const auto &) {}, 310 }, 311 x.u); 312 } Unparse(const ComponentDecl & x)313 void Unparse(const ComponentDecl &x) { // R739 314 Walk(std::get<ObjectName>(x.t)); 315 Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")"); 316 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 317 Walk("*", std::get<std::optional<CharLength>>(x.t)); 318 Walk(std::get<std::optional<Initialization>>(x.t)); 319 } Unparse(const FillDecl & x)320 void Unparse(const FillDecl &x) { // DEC extension 321 Put("%FILL"); 322 Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")"); 323 Walk("*", std::get<std::optional<CharLength>>(x.t)); 324 } Unparse(const ComponentArraySpec & x)325 void Unparse(const ComponentArraySpec &x) { // R740 326 common::visit( 327 common::visitors{ 328 [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); }, 329 [&](const DeferredShapeSpecList &y) { Walk(y); }, 330 }, 331 x.u); 332 } Unparse(const ProcComponentDefStmt & x)333 void Unparse(const ProcComponentDefStmt &x) { // R741 334 Word("PROCEDURE("); 335 Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')'); 336 Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", "); 337 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", "); 338 } Unparse(const NoPass &)339 void Unparse(const NoPass &) { // R742 340 Word("NOPASS"); 341 } Unparse(const Pass & x)342 void Unparse(const Pass &x) { Word("PASS"), Walk("(", x.v, ")"); } Unparse(const Initialization & x)343 void Unparse(const Initialization &x) { // R743 & R805 344 common::visit( 345 common::visitors{ 346 [&](const ConstantExpr &y) { Put(" = "), Walk(y); }, 347 [&](const NullInit &y) { Put(" => "), Walk(y); }, 348 [&](const InitialDataTarget &y) { Put(" => "), Walk(y); }, 349 [&](const std::list<common::Indirection<DataStmtValue>> &y) { 350 Walk("/", y, ", ", "/"); 351 }, 352 }, 353 x.u); 354 } Unparse(const PrivateStmt &)355 void Unparse(const PrivateStmt &) { // R745 356 Word("PRIVATE"); 357 } Unparse(const TypeBoundProcedureStmt::WithoutInterface & x)358 void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749 359 Word("PROCEDURE"), Walk(", ", x.attributes, ", "); 360 Put(" :: "), Walk(x.declarations, ", "); 361 } Unparse(const TypeBoundProcedureStmt::WithInterface & x)362 void Unparse(const TypeBoundProcedureStmt::WithInterface &x) { 363 Word("PROCEDURE("), Walk(x.interfaceName), Put("), "); 364 Walk(x.attributes); 365 Put(" :: "), Walk(x.bindingNames, ", "); 366 } Unparse(const TypeBoundProcDecl & x)367 void Unparse(const TypeBoundProcDecl &x) { // R750 368 Walk(std::get<Name>(x.t)); 369 Walk(" => ", std::get<std::optional<Name>>(x.t)); 370 } Unparse(const TypeBoundGenericStmt & x)371 void Unparse(const TypeBoundGenericStmt &x) { // R751 372 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t)); 373 Put(" :: "), Walk(std::get<common::Indirection<GenericSpec>>(x.t)); 374 Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", "); 375 } Post(const BindAttr::Deferred &)376 void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752 Post(const BindAttr::Non_Overridable &)377 void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); } Unparse(const FinalProcedureStmt & x)378 void Unparse(const FinalProcedureStmt &x) { // R753 379 Word("FINAL :: "), Walk(x.v, ", "); 380 } Unparse(const DerivedTypeSpec & x)381 void Unparse(const DerivedTypeSpec &x) { // R754 382 Walk(std::get<Name>(x.t)); 383 Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")"); 384 } Unparse(const TypeParamSpec & x)385 void Unparse(const TypeParamSpec &x) { // R755 386 Walk(std::get<std::optional<Keyword>>(x.t), "="); 387 Walk(std::get<TypeParamValue>(x.t)); 388 } Unparse(const StructureConstructor & x)389 void Unparse(const StructureConstructor &x) { // R756 390 Walk(std::get<DerivedTypeSpec>(x.t)); 391 Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')'); 392 } Unparse(const ComponentSpec & x)393 void Unparse(const ComponentSpec &x) { // R757 394 Walk(std::get<std::optional<Keyword>>(x.t), "="); 395 Walk(std::get<ComponentDataSource>(x.t)); 396 } Unparse(const EnumDefStmt &)397 void Unparse(const EnumDefStmt &) { // R760 398 Word("ENUM, BIND(C)"), Indent(); 399 } Unparse(const EnumeratorDefStmt & x)400 void Unparse(const EnumeratorDefStmt &x) { // R761 401 Word("ENUMERATOR :: "), Walk(x.v, ", "); 402 } Unparse(const Enumerator & x)403 void Unparse(const Enumerator &x) { // R762 404 Walk(std::get<NamedConstant>(x.t)); 405 Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t)); 406 } Post(const EndEnumStmt &)407 void Post(const EndEnumStmt &) { // R763 408 Outdent(), Word("END ENUM"); 409 } Unparse(const BOZLiteralConstant & x)410 void Unparse(const BOZLiteralConstant &x) { // R764 - R767 411 Put(x.v); 412 } Unparse(const AcValue::Triplet & x)413 void Unparse(const AcValue::Triplet &x) { // R773 414 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t)); 415 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t)); 416 } Unparse(const ArrayConstructor & x)417 void Unparse(const ArrayConstructor &x) { // R769 418 Put('['), Walk(x.v), Put(']'); 419 } Unparse(const AcSpec & x)420 void Unparse(const AcSpec &x) { // R770 421 Walk(x.type, "::"), Walk(x.values, ", "); 422 } Unparse(const LoopBounds<A,B> & x)423 template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) { 424 Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper); 425 Walk(",", x.step); 426 } Unparse(const AcImpliedDo & x)427 void Unparse(const AcImpliedDo &x) { // R774 428 Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", "); 429 Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')'); 430 } Unparse(const AcImpliedDoControl & x)431 void Unparse(const AcImpliedDoControl &x) { // R775 432 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 433 Walk(std::get<AcImpliedDoControl::Bounds>(x.t)); 434 } 435 Unparse(const TypeDeclarationStmt & x)436 void Unparse(const TypeDeclarationStmt &x) { // R801 437 const auto &dts{std::get<DeclarationTypeSpec>(x.t)}; 438 const auto &attrs{std::get<std::list<AttrSpec>>(x.t)}; 439 const auto &decls{std::get<std::list<EntityDecl>>(x.t)}; 440 Walk(dts), Walk(", ", attrs, ", "); 441 442 static const auto isInitializerOldStyle{[](const Initialization &i) { 443 return std::holds_alternative< 444 std::list<common::Indirection<DataStmtValue>>>(i.u); 445 }}; 446 static const auto hasAssignmentInitializer{[](const EntityDecl &d) { 447 // Does a declaration have a new-style =x initializer? 448 const auto &init{std::get<std::optional<Initialization>>(d.t)}; 449 return init && !isInitializerOldStyle(*init); 450 }}; 451 static const auto hasSlashDelimitedInitializer{[](const EntityDecl &d) { 452 // Does a declaration have an old-style /x/ initializer? 453 const auto &init{std::get<std::optional<Initialization>>(d.t)}; 454 return init && isInitializerOldStyle(*init); 455 }}; 456 const auto useDoubledColons{[&]() { 457 bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)}; 458 if (!attrs.empty()) { 459 // Attributes after the type require :: before the entities. 460 CHECK(!isRecord); 461 return true; 462 } 463 if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) { 464 // Always use :: with new style standard initializers (=x), 465 // since the standard requires them to appear (even in free form, 466 // where mandatory spaces already disambiguate INTEGER J=666). 467 CHECK(!isRecord); 468 return true; 469 } 470 if (isRecord) { 471 // Never put :: in a legacy extension RECORD// statement. 472 return false; 473 } 474 // The :: is optional for this declaration. Avoid usage that can 475 // crash the pgf90 compiler. 476 if (std::any_of( 477 decls.begin(), decls.end(), hasSlashDelimitedInitializer)) { 478 // Don't use :: when a declaration uses legacy DATA-statement-like 479 // /x/ initialization. 480 return false; 481 } 482 // Don't use :: with intrinsic types. Otherwise, use it. 483 return !std::holds_alternative<IntrinsicTypeSpec>(dts.u); 484 }}; 485 486 if (useDoubledColons()) { 487 Put(" ::"); 488 } 489 Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", "); 490 } Before(const AttrSpec & x)491 void Before(const AttrSpec &x) { // R802 492 common::visit(common::visitors{ 493 [&](const CoarraySpec &) { Word("CODIMENSION["); }, 494 [&](const ArraySpec &) { Word("DIMENSION("); }, 495 [](const auto &) {}, 496 }, 497 x.u); 498 } Post(const AttrSpec & x)499 void Post(const AttrSpec &x) { 500 common::visit(common::visitors{ 501 [&](const CoarraySpec &) { Put(']'); }, 502 [&](const ArraySpec &) { Put(')'); }, 503 [](const auto &) {}, 504 }, 505 x.u); 506 } Unparse(const EntityDecl & x)507 void Unparse(const EntityDecl &x) { // R803 508 Walk(std::get<ObjectName>(x.t)); 509 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 510 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 511 Walk("*", std::get<std::optional<CharLength>>(x.t)); 512 Walk(std::get<std::optional<Initialization>>(x.t)); 513 } Unparse(const NullInit &)514 void Unparse(const NullInit &) { // R806 515 Word("NULL()"); 516 } Unparse(const LanguageBindingSpec & x)517 void Unparse(const LanguageBindingSpec &x) { // R808 & R1528 518 Word("BIND(C"), Walk(", NAME=", x.v), Put(')'); 519 } Unparse(const CoarraySpec & x)520 void Unparse(const CoarraySpec &x) { // R809 521 common::visit(common::visitors{ 522 [&](const DeferredCoshapeSpecList &y) { Walk(y); }, 523 [&](const ExplicitCoshapeSpec &y) { Walk(y); }, 524 }, 525 x.u); 526 } Unparse(const DeferredCoshapeSpecList & x)527 void Unparse(const DeferredCoshapeSpecList &x) { // R810 528 for (auto j{x.v}; j > 0; --j) { 529 Put(':'); 530 if (j > 1) { 531 Put(','); 532 } 533 } 534 } Unparse(const ExplicitCoshapeSpec & x)535 void Unparse(const ExplicitCoshapeSpec &x) { // R811 536 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ","); 537 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*'); 538 } Unparse(const ExplicitShapeSpec & x)539 void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818 540 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"); 541 Walk(std::get<SpecificationExpr>(x.t)); 542 } Unparse(const ArraySpec & x)543 void Unparse(const ArraySpec &x) { // R815 544 common::visit( 545 common::visitors{ 546 [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); }, 547 [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); }, 548 [&](const DeferredShapeSpecList &y) { Walk(y); }, 549 [&](const AssumedSizeSpec &y) { Walk(y); }, 550 [&](const ImpliedShapeSpec &y) { Walk(y); }, 551 [&](const AssumedRankSpec &y) { Walk(y); }, 552 }, 553 x.u); 554 } Post(const AssumedShapeSpec &)555 void Post(const AssumedShapeSpec &) { Put(':'); } // R819 Unparse(const DeferredShapeSpecList & x)556 void Unparse(const DeferredShapeSpecList &x) { // R820 557 for (auto j{x.v}; j > 0; --j) { 558 Put(':'); 559 if (j > 1) { 560 Put(','); 561 } 562 } 563 } Unparse(const AssumedImpliedSpec & x)564 void Unparse(const AssumedImpliedSpec &x) { // R821 565 Walk(x.v, ":"); 566 Put('*'); 567 } Unparse(const AssumedSizeSpec & x)568 void Unparse(const AssumedSizeSpec &x) { // R822 569 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ","); 570 Walk(std::get<AssumedImpliedSpec>(x.t)); 571 } Unparse(const ImpliedShapeSpec & x)572 void Unparse(const ImpliedShapeSpec &x) { // R823 573 Walk(x.v, ","); 574 } Post(const AssumedRankSpec &)575 void Post(const AssumedRankSpec &) { Put(".."); } // R825 Post(const Asynchronous &)576 void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); } Post(const External &)577 void Post(const External &) { Word("EXTERNAL"); } Post(const Intrinsic &)578 void Post(const Intrinsic &) { Word("INTRINSIC"); } Post(const Optional &)579 void Post(const Optional &) { Word("OPTIONAL"); } Post(const Parameter &)580 void Post(const Parameter &) { Word("PARAMETER"); } Post(const Protected &)581 void Post(const Protected &) { Word("PROTECTED"); } Post(const Save &)582 void Post(const Save &) { Word("SAVE"); } Post(const Target &)583 void Post(const Target &) { Word("TARGET"); } Post(const Value &)584 void Post(const Value &) { Word("VALUE"); } Post(const Volatile &)585 void Post(const Volatile &) { Word("VOLATILE"); } Unparse(const IntentSpec & x)586 void Unparse(const IntentSpec &x) { // R826 587 Word("INTENT("), Walk(x.v), Put(")"); 588 } Unparse(const AccessStmt & x)589 void Unparse(const AccessStmt &x) { // R827 590 Walk(std::get<AccessSpec>(x.t)); 591 Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", "); 592 } Unparse(const AllocatableStmt & x)593 void Unparse(const AllocatableStmt &x) { // R829 594 Word("ALLOCATABLE :: "), Walk(x.v, ", "); 595 } Unparse(const ObjectDecl & x)596 void Unparse(const ObjectDecl &x) { // R830 & R860 597 Walk(std::get<ObjectName>(x.t)); 598 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 599 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]"); 600 } Unparse(const AsynchronousStmt & x)601 void Unparse(const AsynchronousStmt &x) { // R831 602 Word("ASYNCHRONOUS :: "), Walk(x.v, ", "); 603 } Unparse(const BindStmt & x)604 void Unparse(const BindStmt &x) { // R832 605 Walk(x.t, " :: "); 606 } Unparse(const BindEntity & x)607 void Unparse(const BindEntity &x) { // R833 608 bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common}; 609 const char *slash{isCommon ? "/" : ""}; 610 Put(slash), Walk(std::get<Name>(x.t)), Put(slash); 611 } Unparse(const CodimensionStmt & x)612 void Unparse(const CodimensionStmt &x) { // R834 613 Word("CODIMENSION :: "), Walk(x.v, ", "); 614 } Unparse(const CodimensionDecl & x)615 void Unparse(const CodimensionDecl &x) { // R835 616 Walk(std::get<Name>(x.t)); 617 Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']'); 618 } Unparse(const ContiguousStmt & x)619 void Unparse(const ContiguousStmt &x) { // R836 620 Word("CONTIGUOUS :: "), Walk(x.v, ", "); 621 } Unparse(const DataStmt & x)622 void Unparse(const DataStmt &x) { // R837 623 Word("DATA "), Walk(x.v, ", "); 624 } Unparse(const DataStmtSet & x)625 void Unparse(const DataStmtSet &x) { // R838 626 Walk(std::get<std::list<DataStmtObject>>(x.t), ", "); 627 Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/'); 628 } Unparse(const DataImpliedDo & x)629 void Unparse(const DataImpliedDo &x) { // R840, R842 630 Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(','); 631 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 632 Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')'); 633 } Unparse(const DataStmtValue & x)634 void Unparse(const DataStmtValue &x) { // R843 635 Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*"); 636 Walk(std::get<DataStmtConstant>(x.t)); 637 } Unparse(const DimensionStmt & x)638 void Unparse(const DimensionStmt &x) { // R848 639 Word("DIMENSION :: "), Walk(x.v, ", "); 640 } Unparse(const DimensionStmt::Declaration & x)641 void Unparse(const DimensionStmt::Declaration &x) { 642 Walk(std::get<Name>(x.t)); 643 Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')'); 644 } Unparse(const IntentStmt & x)645 void Unparse(const IntentStmt &x) { // R849 646 Walk(x.t, " :: "); 647 } Unparse(const OptionalStmt & x)648 void Unparse(const OptionalStmt &x) { // R850 649 Word("OPTIONAL :: "), Walk(x.v, ", "); 650 } Unparse(const ParameterStmt & x)651 void Unparse(const ParameterStmt &x) { // R851 652 Word("PARAMETER("), Walk(x.v, ", "), Put(')'); 653 } Unparse(const NamedConstantDef & x)654 void Unparse(const NamedConstantDef &x) { // R852 655 Walk(x.t, "="); 656 } Unparse(const PointerStmt & x)657 void Unparse(const PointerStmt &x) { // R853 658 Word("POINTER :: "), Walk(x.v, ", "); 659 } Unparse(const PointerDecl & x)660 void Unparse(const PointerDecl &x) { // R854 661 Walk(std::get<Name>(x.t)); 662 Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")"); 663 } Unparse(const ProtectedStmt & x)664 void Unparse(const ProtectedStmt &x) { // R855 665 Word("PROTECTED :: "), Walk(x.v, ", "); 666 } Unparse(const SaveStmt & x)667 void Unparse(const SaveStmt &x) { // R856 668 Word("SAVE"), Walk(" :: ", x.v, ", "); 669 } Unparse(const SavedEntity & x)670 void Unparse(const SavedEntity &x) { // R857, R858 671 bool isCommon{ 672 std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common}; 673 const char *slash{isCommon ? "/" : ""}; 674 Put(slash), Walk(std::get<Name>(x.t)), Put(slash); 675 } Unparse(const TargetStmt & x)676 void Unparse(const TargetStmt &x) { // R859 677 Word("TARGET :: "), Walk(x.v, ", "); 678 } Unparse(const ValueStmt & x)679 void Unparse(const ValueStmt &x) { // R861 680 Word("VALUE :: "), Walk(x.v, ", "); 681 } Unparse(const VolatileStmt & x)682 void Unparse(const VolatileStmt &x) { // R862 683 Word("VOLATILE :: "), Walk(x.v, ", "); 684 } Unparse(const ImplicitStmt & x)685 void Unparse(const ImplicitStmt &x) { // R863 686 Word("IMPLICIT "); 687 common::visit( 688 common::visitors{ 689 [&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); }, 690 [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) { 691 Word("NONE"), Walk(" (", y, ", ", ")"); 692 }, 693 }, 694 x.u); 695 } Unparse(const ImplicitSpec & x)696 void Unparse(const ImplicitSpec &x) { // R864 697 Walk(std::get<DeclarationTypeSpec>(x.t)); 698 Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')'); 699 } Unparse(const LetterSpec & x)700 void Unparse(const LetterSpec &x) { // R865 701 Put(*std::get<const char *>(x.t)); 702 auto second{std::get<std::optional<const char *>>(x.t)}; 703 if (second) { 704 Put('-'), Put(**second); 705 } 706 } Unparse(const ImportStmt & x)707 void Unparse(const ImportStmt &x) { // R867 708 Word("IMPORT"); 709 switch (x.kind) { 710 case common::ImportKind::Default: 711 Walk(" :: ", x.names, ", "); 712 break; 713 case common::ImportKind::Only: 714 Put(", "), Word("ONLY: "); 715 Walk(x.names, ", "); 716 break; 717 case common::ImportKind::None: 718 Word(", NONE"); 719 break; 720 case common::ImportKind::All: 721 Word(", ALL"); 722 break; 723 } 724 } Unparse(const NamelistStmt & x)725 void Unparse(const NamelistStmt &x) { // R868 726 Word("NAMELIST"), Walk(x.v, ", "); 727 } Unparse(const NamelistStmt::Group & x)728 void Unparse(const NamelistStmt::Group &x) { 729 Put('/'), Walk(std::get<Name>(x.t)), Put('/'); 730 Walk(std::get<std::list<Name>>(x.t), ", "); 731 } Unparse(const EquivalenceStmt & x)732 void Unparse(const EquivalenceStmt &x) { // R870, R871 733 Word("EQUIVALENCE"); 734 const char *separator{" "}; 735 for (const std::list<EquivalenceObject> &y : x.v) { 736 Put(separator), Put('('), Walk(y), Put(')'); 737 separator = ", "; 738 } 739 } Unparse(const CommonStmt & x)740 void Unparse(const CommonStmt &x) { // R873 741 Word("COMMON "); 742 Walk(x.blocks); 743 } Unparse(const CommonBlockObject & x)744 void Unparse(const CommonBlockObject &x) { // R874 745 Walk(std::get<Name>(x.t)); 746 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"); 747 } Unparse(const CommonStmt::Block & x)748 void Unparse(const CommonStmt::Block &x) { 749 Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/"); 750 Walk(std::get<std::list<CommonBlockObject>>(x.t)); 751 } 752 Unparse(const Substring & x)753 void Unparse(const Substring &x) { // R908, R909 754 Walk(std::get<DataRef>(x.t)); 755 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')'); 756 } Unparse(const CharLiteralConstantSubstring & x)757 void Unparse(const CharLiteralConstantSubstring &x) { 758 Walk(std::get<CharLiteralConstant>(x.t)); 759 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')'); 760 } Unparse(const SubstringInquiry & x)761 void Unparse(const SubstringInquiry &x) { 762 Walk(x.v); 763 Put(x.source.end()[-1] == 'n' ? "%LEN" : "%KIND"); 764 } Unparse(const SubstringRange & x)765 void Unparse(const SubstringRange &x) { // R910 766 Walk(x.t, ":"); 767 } Unparse(const PartRef & x)768 void Unparse(const PartRef &x) { // R912 769 Walk(x.name); 770 Walk("(", x.subscripts, ",", ")"); 771 Walk(x.imageSelector); 772 } Unparse(const StructureComponent & x)773 void Unparse(const StructureComponent &x) { // R913 774 Walk(x.base); 775 if (structureComponents_.find(x.component.source) != 776 structureComponents_.end()) { 777 Put('.'); 778 } else { 779 Put('%'); 780 } 781 Walk(x.component); 782 } Unparse(const ArrayElement & x)783 void Unparse(const ArrayElement &x) { // R917 784 Walk(x.base); 785 Put('('), Walk(x.subscripts, ","), Put(')'); 786 } Unparse(const SubscriptTriplet & x)787 void Unparse(const SubscriptTriplet &x) { // R921 788 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t)); 789 Walk(":", std::get<2>(x.t)); 790 } Unparse(const ImageSelector & x)791 void Unparse(const ImageSelector &x) { // R924 792 Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ","); 793 Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']'); 794 } Before(const ImageSelectorSpec::Stat &)795 void Before(const ImageSelectorSpec::Stat &) { // R926 796 Word("STAT="); 797 } Before(const ImageSelectorSpec::Team_Number &)798 void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); } Before(const ImageSelectorSpec & x)799 void Before(const ImageSelectorSpec &x) { 800 if (std::holds_alternative<TeamValue>(x.u)) { 801 Word("TEAM="); 802 } 803 } Unparse(const AllocateStmt & x)804 void Unparse(const AllocateStmt &x) { // R927 805 Word("ALLOCATE("); 806 Walk(std::get<std::optional<TypeSpec>>(x.t), "::"); 807 Walk(std::get<std::list<Allocation>>(x.t), ", "); 808 Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')'); 809 } Before(const AllocOpt & x)810 void Before(const AllocOpt &x) { // R928, R931 811 common::visit(common::visitors{ 812 [&](const AllocOpt::Mold &) { Word("MOLD="); }, 813 [&](const AllocOpt::Source &) { Word("SOURCE="); }, 814 [](const StatOrErrmsg &) {}, 815 }, 816 x.u); 817 } Unparse(const Allocation & x)818 void Unparse(const Allocation &x) { // R932 819 Walk(std::get<AllocateObject>(x.t)); 820 Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")"); 821 Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]"); 822 } Unparse(const AllocateShapeSpec & x)823 void Unparse(const AllocateShapeSpec &x) { // R934 & R938 824 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"); 825 Walk(std::get<BoundExpr>(x.t)); 826 } Unparse(const AllocateCoarraySpec & x)827 void Unparse(const AllocateCoarraySpec &x) { // R937 828 Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ","); 829 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*'); 830 } Unparse(const NullifyStmt & x)831 void Unparse(const NullifyStmt &x) { // R939 832 Word("NULLIFY("), Walk(x.v, ", "), Put(')'); 833 } Unparse(const DeallocateStmt & x)834 void Unparse(const DeallocateStmt &x) { // R941 835 Word("DEALLOCATE("); 836 Walk(std::get<std::list<AllocateObject>>(x.t), ", "); 837 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 838 } Before(const StatOrErrmsg & x)839 void Before(const StatOrErrmsg &x) { // R942 & R1165 840 common::visit(common::visitors{ 841 [&](const StatVariable &) { Word("STAT="); }, 842 [&](const MsgVariable &) { Word("ERRMSG="); }, 843 }, 844 x.u); 845 } 846 847 // R1001 - R1022 Unparse(const Expr::Parentheses & x)848 void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); } Before(const Expr::UnaryPlus &)849 void Before(const Expr::UnaryPlus &) { Put("+"); } Before(const Expr::Negate &)850 void Before(const Expr::Negate &) { Put("-"); } Before(const Expr::NOT &)851 void Before(const Expr::NOT &) { Word(".NOT."); } Unparse(const Expr::PercentLoc & x)852 void Unparse(const Expr::PercentLoc &x) { 853 Word("%LOC("), Walk(x.v), Put(')'); 854 } Unparse(const Expr::Power & x)855 void Unparse(const Expr::Power &x) { Walk(x.t, "**"); } Unparse(const Expr::Multiply & x)856 void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); } Unparse(const Expr::Divide & x)857 void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); } Unparse(const Expr::Add & x)858 void Unparse(const Expr::Add &x) { Walk(x.t, "+"); } Unparse(const Expr::Subtract & x)859 void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); } Unparse(const Expr::Concat & x)860 void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); } Unparse(const Expr::LT & x)861 void Unparse(const Expr::LT &x) { Walk(x.t, "<"); } Unparse(const Expr::LE & x)862 void Unparse(const Expr::LE &x) { Walk(x.t, "<="); } Unparse(const Expr::EQ & x)863 void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); } Unparse(const Expr::NE & x)864 void Unparse(const Expr::NE &x) { Walk(x.t, "/="); } Unparse(const Expr::GE & x)865 void Unparse(const Expr::GE &x) { Walk(x.t, ">="); } Unparse(const Expr::GT & x)866 void Unparse(const Expr::GT &x) { Walk(x.t, ">"); } Unparse(const Expr::AND & x)867 void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); } Unparse(const Expr::OR & x)868 void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); } Unparse(const Expr::EQV & x)869 void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); } Unparse(const Expr::NEQV & x)870 void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); } Unparse(const Expr::ComplexConstructor & x)871 void Unparse(const Expr::ComplexConstructor &x) { 872 Put('('), Walk(x.t, ","), Put(')'); 873 } Unparse(const Expr::DefinedBinary & x)874 void Unparse(const Expr::DefinedBinary &x) { 875 Walk(std::get<1>(x.t)); // left 876 Walk(std::get<DefinedOpName>(x.t)); 877 Walk(std::get<2>(x.t)); // right 878 } Unparse(const DefinedOpName & x)879 void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415 880 Walk(x.v); 881 } Unparse(const AssignmentStmt & x)882 void Unparse(const AssignmentStmt &x) { // R1032 883 if (asFortran_ && x.typedAssignment.get()) { 884 Put(' '); 885 asFortran_->assignment(out_, *x.typedAssignment); 886 Put('\n'); 887 } else { 888 Walk(x.t, " = "); 889 } 890 } Unparse(const PointerAssignmentStmt & x)891 void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038 892 if (asFortran_ && x.typedAssignment.get()) { 893 Put(' '); 894 asFortran_->assignment(out_, *x.typedAssignment); 895 Put('\n'); 896 } else { 897 Walk(std::get<DataRef>(x.t)); 898 common::visit( 899 common::visitors{ 900 [&](const std::list<BoundsRemapping> &y) { 901 Put('('), Walk(y), Put(')'); 902 }, 903 [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); }, 904 }, 905 std::get<PointerAssignmentStmt::Bounds>(x.t).u); 906 Put(" => "), Walk(std::get<Expr>(x.t)); 907 } 908 } Post(const BoundsSpec &)909 void Post(const BoundsSpec &) { // R1035 910 Put(':'); 911 } Unparse(const BoundsRemapping & x)912 void Unparse(const BoundsRemapping &x) { // R1036 913 Walk(x.t, ":"); 914 } Unparse(const WhereStmt & x)915 void Unparse(const WhereStmt &x) { // R1041, R1045, R1046 916 Word("WHERE ("), Walk(x.t, ") "); 917 } Unparse(const WhereConstructStmt & x)918 void Unparse(const WhereConstructStmt &x) { // R1043 919 Walk(std::get<std::optional<Name>>(x.t), ": "); 920 Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')'); 921 Indent(); 922 } Unparse(const MaskedElsewhereStmt & x)923 void Unparse(const MaskedElsewhereStmt &x) { // R1047 924 Outdent(); 925 Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')'); 926 Walk(" ", std::get<std::optional<Name>>(x.t)); 927 Indent(); 928 } Unparse(const ElsewhereStmt & x)929 void Unparse(const ElsewhereStmt &x) { // R1048 930 Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent(); 931 } Unparse(const EndWhereStmt & x)932 void Unparse(const EndWhereStmt &x) { // R1049 933 Outdent(), Word("END WHERE"), Walk(" ", x.v); 934 } Unparse(const ForallConstructStmt & x)935 void Unparse(const ForallConstructStmt &x) { // R1051 936 Walk(std::get<std::optional<Name>>(x.t), ": "); 937 Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t)); 938 Indent(); 939 } Unparse(const EndForallStmt & x)940 void Unparse(const EndForallStmt &x) { // R1054 941 Outdent(), Word("END FORALL"), Walk(" ", x.v); 942 } Before(const ForallStmt &)943 void Before(const ForallStmt &) { // R1055 944 Word("FORALL"); 945 } 946 Unparse(const AssociateStmt & x)947 void Unparse(const AssociateStmt &x) { // R1103 948 Walk(std::get<std::optional<Name>>(x.t), ": "); 949 Word("ASSOCIATE ("); 950 Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent(); 951 } Unparse(const Association & x)952 void Unparse(const Association &x) { // R1104 953 Walk(x.t, " => "); 954 } Unparse(const EndAssociateStmt & x)955 void Unparse(const EndAssociateStmt &x) { // R1106 956 Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v); 957 } Unparse(const BlockStmt & x)958 void Unparse(const BlockStmt &x) { // R1108 959 Walk(x.v, ": "), Word("BLOCK"), Indent(); 960 } Unparse(const EndBlockStmt & x)961 void Unparse(const EndBlockStmt &x) { // R1110 962 Outdent(), Word("END BLOCK"), Walk(" ", x.v); 963 } Unparse(const ChangeTeamStmt & x)964 void Unparse(const ChangeTeamStmt &x) { // R1112 965 Walk(std::get<std::optional<Name>>(x.t), ": "); 966 Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t)); 967 Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", "); 968 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 969 Indent(); 970 } Unparse(const CoarrayAssociation & x)971 void Unparse(const CoarrayAssociation &x) { // R1113 972 Walk(x.t, " => "); 973 } Unparse(const EndChangeTeamStmt & x)974 void Unparse(const EndChangeTeamStmt &x) { // R1114 975 Outdent(), Word("END TEAM ("); 976 Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", "); 977 Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t)); 978 } Unparse(const CriticalStmt & x)979 void Unparse(const CriticalStmt &x) { // R1117 980 Walk(std::get<std::optional<Name>>(x.t), ": "); 981 Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", "); 982 Put(')'), Indent(); 983 } Unparse(const EndCriticalStmt & x)984 void Unparse(const EndCriticalStmt &x) { // R1118 985 Outdent(), Word("END CRITICAL"), Walk(" ", x.v); 986 } Unparse(const DoConstruct & x)987 void Unparse(const DoConstruct &x) { // R1119, R1120 988 Walk(std::get<Statement<NonLabelDoStmt>>(x.t)); 989 Indent(), Walk(std::get<Block>(x.t), ""), Outdent(); 990 Walk(std::get<Statement<EndDoStmt>>(x.t)); 991 } Unparse(const LabelDoStmt & x)992 void Unparse(const LabelDoStmt &x) { // R1121 993 Walk(std::get<std::optional<Name>>(x.t), ": "); 994 Word("DO "), Walk(std::get<Label>(x.t)); 995 Walk(" ", std::get<std::optional<LoopControl>>(x.t)); 996 } Unparse(const NonLabelDoStmt & x)997 void Unparse(const NonLabelDoStmt &x) { // R1122 998 Walk(std::get<std::optional<Name>>(x.t), ": "); 999 Word("DO "), Walk(std::get<std::optional<LoopControl>>(x.t)); 1000 } Unparse(const LoopControl & x)1001 void Unparse(const LoopControl &x) { // R1123 1002 common::visit(common::visitors{ 1003 [&](const ScalarLogicalExpr &y) { 1004 Word("WHILE ("), Walk(y), Put(')'); 1005 }, 1006 [&](const auto &y) { Walk(y); }, 1007 }, 1008 x.u); 1009 } Unparse(const ConcurrentHeader & x)1010 void Unparse(const ConcurrentHeader &x) { // R1125 1011 Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::"); 1012 Walk(std::get<std::list<ConcurrentControl>>(x.t), ", "); 1013 Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')'); 1014 } Unparse(const ConcurrentControl & x)1015 void Unparse(const ConcurrentControl &x) { // R1126 - R1128 1016 Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t)); 1017 Put(':'), Walk(std::get<2>(x.t)); 1018 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t)); 1019 } Before(const LoopControl::Concurrent &)1020 void Before(const LoopControl::Concurrent &) { // R1129 1021 Word("CONCURRENT"); 1022 } Unparse(const LocalitySpec::Local & x)1023 void Unparse(const LocalitySpec::Local &x) { 1024 Word("LOCAL("), Walk(x.v, ", "), Put(')'); 1025 } Unparse(const LocalitySpec::LocalInit & x)1026 void Unparse(const LocalitySpec::LocalInit &x) { 1027 Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')'); 1028 } Unparse(const LocalitySpec::Shared & x)1029 void Unparse(const LocalitySpec::Shared &x) { 1030 Word("SHARED("), Walk(x.v, ", "), Put(')'); 1031 } Post(const LocalitySpec::DefaultNone &)1032 void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); } Unparse(const EndDoStmt & x)1033 void Unparse(const EndDoStmt &x) { // R1132 1034 Word("END DO"), Walk(" ", x.v); 1035 } Unparse(const CycleStmt & x)1036 void Unparse(const CycleStmt &x) { // R1133 1037 Word("CYCLE"), Walk(" ", x.v); 1038 } Unparse(const IfThenStmt & x)1039 void Unparse(const IfThenStmt &x) { // R1135 1040 Walk(std::get<std::optional<Name>>(x.t), ": "); 1041 Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t)); 1042 Put(") "), Word("THEN"), Indent(); 1043 } Unparse(const ElseIfStmt & x)1044 void Unparse(const ElseIfStmt &x) { // R1136 1045 Outdent(), Word("ELSE IF ("); 1046 Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN"); 1047 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1048 } Unparse(const ElseStmt & x)1049 void Unparse(const ElseStmt &x) { // R1137 1050 Outdent(), Word("ELSE"), Walk(" ", x.v), Indent(); 1051 } Unparse(const EndIfStmt & x)1052 void Unparse(const EndIfStmt &x) { // R1138 1053 Outdent(), Word("END IF"), Walk(" ", x.v); 1054 } Unparse(const IfStmt & x)1055 void Unparse(const IfStmt &x) { // R1139 1056 Word("IF ("), Walk(x.t, ") "); 1057 } Unparse(const SelectCaseStmt & x)1058 void Unparse(const SelectCaseStmt &x) { // R1141, R1144 1059 Walk(std::get<std::optional<Name>>(x.t), ": "); 1060 Word("SELECT CASE ("); 1061 Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent(); 1062 } Unparse(const CaseStmt & x)1063 void Unparse(const CaseStmt &x) { // R1142 1064 Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t)); 1065 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1066 } Unparse(const EndSelectStmt & x)1067 void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R1155 1068 Outdent(), Word("END SELECT"), Walk(" ", x.v); 1069 } Unparse(const CaseSelector & x)1070 void Unparse(const CaseSelector &x) { // R1145 1071 common::visit(common::visitors{ 1072 [&](const std::list<CaseValueRange> &y) { 1073 Put('('), Walk(y), Put(')'); 1074 }, 1075 [&](const Default &) { Word("DEFAULT"); }, 1076 }, 1077 x.u); 1078 } Unparse(const CaseValueRange::Range & x)1079 void Unparse(const CaseValueRange::Range &x) { // R1146 1080 Walk(x.lower), Put(':'), Walk(x.upper); 1081 } Unparse(const SelectRankStmt & x)1082 void Unparse(const SelectRankStmt &x) { // R1149 1083 Walk(std::get<0>(x.t), ": "); 1084 Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => "); 1085 Walk(std::get<Selector>(x.t)), Put(')'), Indent(); 1086 } Unparse(const SelectRankCaseStmt & x)1087 void Unparse(const SelectRankCaseStmt &x) { // R1150 1088 Outdent(), Word("RANK "); 1089 common::visit(common::visitors{ 1090 [&](const ScalarIntConstantExpr &y) { 1091 Put('('), Walk(y), Put(')'); 1092 }, 1093 [&](const Star &) { Put("(*)"); }, 1094 [&](const Default &) { Word("DEFAULT"); }, 1095 }, 1096 std::get<SelectRankCaseStmt::Rank>(x.t).u); 1097 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1098 } Unparse(const SelectTypeStmt & x)1099 void Unparse(const SelectTypeStmt &x) { // R1153 1100 Walk(std::get<0>(x.t), ": "); 1101 Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => "); 1102 Walk(std::get<Selector>(x.t)), Put(')'), Indent(); 1103 } Unparse(const TypeGuardStmt & x)1104 void Unparse(const TypeGuardStmt &x) { // R1154 1105 Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t)); 1106 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent(); 1107 } Unparse(const TypeGuardStmt::Guard & x)1108 void Unparse(const TypeGuardStmt::Guard &x) { 1109 common::visit( 1110 common::visitors{ 1111 [&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); }, 1112 [&](const DerivedTypeSpec &y) { 1113 Word("CLASS IS ("), Walk(y), Put(')'); 1114 }, 1115 [&](const Default &) { Word("CLASS DEFAULT"); }, 1116 }, 1117 x.u); 1118 } Unparse(const ExitStmt & x)1119 void Unparse(const ExitStmt &x) { // R1156 1120 Word("EXIT"), Walk(" ", x.v); 1121 } Before(const GotoStmt &)1122 void Before(const GotoStmt &) { // R1157 1123 Word("GO TO "); 1124 } Unparse(const ComputedGotoStmt & x)1125 void Unparse(const ComputedGotoStmt &x) { // R1158 1126 Word("GO TO ("), Walk(x.t, "), "); 1127 } Unparse(const ContinueStmt &)1128 void Unparse(const ContinueStmt &) { // R1159 1129 Word("CONTINUE"); 1130 } Unparse(const StopStmt & x)1131 void Unparse(const StopStmt &x) { // R1160, R1161 1132 if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) { 1133 Word("ERROR "); 1134 } 1135 Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t)); 1136 Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t)); 1137 } Unparse(const FailImageStmt &)1138 void Unparse(const FailImageStmt &) { // R1163 1139 Word("FAIL IMAGE"); 1140 } Unparse(const SyncAllStmt & x)1141 void Unparse(const SyncAllStmt &x) { // R1164 1142 Word("SYNC ALL ("), Walk(x.v, ", "), Put(')'); 1143 } Unparse(const SyncImagesStmt & x)1144 void Unparse(const SyncImagesStmt &x) { // R1166 1145 Word("SYNC IMAGES ("); 1146 Walk(std::get<SyncImagesStmt::ImageSet>(x.t)); 1147 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1148 } Unparse(const SyncMemoryStmt & x)1149 void Unparse(const SyncMemoryStmt &x) { // R1168 1150 Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')'); 1151 } Unparse(const SyncTeamStmt & x)1152 void Unparse(const SyncTeamStmt &x) { // R1169 1153 Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t)); 1154 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1155 } Unparse(const EventPostStmt & x)1156 void Unparse(const EventPostStmt &x) { // R1170 1157 Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t)); 1158 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')'); 1159 } Before(const EventWaitStmt::EventWaitSpec & x)1160 void Before(const EventWaitStmt::EventWaitSpec &x) { // R1173, R1174 1161 common::visit(common::visitors{ 1162 [&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); }, 1163 [](const StatOrErrmsg &) {}, 1164 }, 1165 x.u); 1166 } Unparse(const EventWaitStmt & x)1167 void Unparse(const EventWaitStmt &x) { // R1170 1168 Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t)); 1169 Walk(", ", std::get<std::list<EventWaitStmt::EventWaitSpec>>(x.t), ", "); 1170 Put(')'); 1171 } Unparse(const FormTeamStmt & x)1172