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