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   void Unparse(const FormTeamStmt &x) { // R1175, R1177
1173     Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));
1174     Put(','), Walk(std::get<TeamVariable>(x.t));
1175     Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");
1176     Put(')');
1177   }
Before(const FormTeamStmt::FormTeamSpec & x)1178   void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1178
1179     common::visit(common::visitors{
1180                       [&](const ScalarIntExpr &) { Word("NEW_INDEX="); },
1181                       [](const StatOrErrmsg &) {},
1182                   },
1183         x.u);
1184   }
Unparse(const LockStmt & x)1185   void Unparse(const LockStmt &x) { // R1179
1186     Word("LOCK ("), Walk(std::get<LockVariable>(x.t));
1187     Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");
1188     Put(')');
1189   }
Before(const LockStmt::LockStat & x)1190   void Before(const LockStmt::LockStat &x) { // R1180
1191     common::visit(
1192         common::visitors{
1193             [&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },
1194             [](const StatOrErrmsg &) {},
1195         },
1196         x.u);
1197   }
Unparse(const UnlockStmt & x)1198   void Unparse(const UnlockStmt &x) { // R1181
1199     Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));
1200     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");
1201     Put(')');
1202   }
1203 
Unparse(const OpenStmt & x)1204   void Unparse(const OpenStmt &x) { // R1204
1205     Word("OPEN ("), Walk(x.v, ", "), Put(')');
1206   }
Pre(const ConnectSpec & x)1207   bool Pre(const ConnectSpec &x) { // R1205
1208     return common::visit(common::visitors{
1209                              [&](const FileUnitNumber &) {
1210                                Word("UNIT=");
1211                                return true;
1212                              },
1213                              [&](const FileNameExpr &) {
1214                                Word("FILE=");
1215                                return true;
1216                              },
1217                              [&](const ConnectSpec::CharExpr &y) {
1218                                Walk(y.t, "=");
1219                                return false;
1220                              },
1221                              [&](const MsgVariable &) {
1222                                Word("IOMSG=");
1223                                return true;
1224                              },
1225                              [&](const StatVariable &) {
1226                                Word("IOSTAT=");
1227                                return true;
1228                              },
1229                              [&](const ConnectSpec::Recl &) {
1230                                Word("RECL=");
1231                                return true;
1232                              },
1233                              [&](const ConnectSpec::Newunit &) {
1234                                Word("NEWUNIT=");
1235                                return true;
1236                              },
1237                              [&](const ErrLabel &) {
1238                                Word("ERR=");
1239                                return true;
1240                              },
1241                              [&](const StatusExpr &) {
1242                                Word("STATUS=");
1243                                return true;
1244                              },
1245                          },
1246         x.u);
1247   }
Unparse(const CloseStmt & x)1248   void Unparse(const CloseStmt &x) { // R1208
1249     Word("CLOSE ("), Walk(x.v, ", "), Put(')');
1250   }
Before(const CloseStmt::CloseSpec & x)1251   void Before(const CloseStmt::CloseSpec &x) { // R1209
1252     common::visit(common::visitors{
1253                       [&](const FileUnitNumber &) { Word("UNIT="); },
1254                       [&](const StatVariable &) { Word("IOSTAT="); },
1255                       [&](const MsgVariable &) { Word("IOMSG="); },
1256                       [&](const ErrLabel &) { Word("ERR="); },
1257                       [&](const StatusExpr &) { Word("STATUS="); },
1258                   },
1259         x.u);
1260   }
Unparse(const ReadStmt & x)1261   void Unparse(const ReadStmt &x) { // R1210
1262     Word("READ ");
1263     if (x.iounit) {
1264       Put('('), Walk(x.iounit);
1265       if (x.format) {
1266         Put(", "), Walk(x.format);
1267       }
1268       Walk(", ", x.controls, ", ");
1269       Put(')');
1270     } else if (x.format) {
1271       Walk(x.format);
1272       if (!x.items.empty()) {
1273         Put(", ");
1274       }
1275     } else {
1276       Put('('), Walk(x.controls, ", "), Put(')');
1277     }
1278     Walk(" ", x.items, ", ");
1279   }
Unparse(const WriteStmt & x)1280   void Unparse(const WriteStmt &x) { // R1211
1281     Word("WRITE (");
1282     if (x.iounit) {
1283       Walk(x.iounit);
1284       if (x.format) {
1285         Put(", "), Walk(x.format);
1286       }
1287       Walk(", ", x.controls, ", ");
1288     } else {
1289       Walk(x.controls, ", ");
1290     }
1291     Put(')'), Walk(" ", x.items, ", ");
1292   }
Unparse(const PrintStmt & x)1293   void Unparse(const PrintStmt &x) { // R1212
1294     Word("PRINT "), Walk(std::get<Format>(x.t));
1295     Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");
1296   }
Pre(const IoControlSpec & x)1297   bool Pre(const IoControlSpec &x) { // R1213
1298     return common::visit(common::visitors{
1299                              [&](const IoUnit &) {
1300                                Word("UNIT=");
1301                                return true;
1302                              },
1303                              [&](const Format &) {
1304                                Word("FMT=");
1305                                return true;
1306                              },
1307                              [&](const Name &) {
1308                                Word("NML=");
1309                                return true;
1310                              },
1311                              [&](const IoControlSpec::CharExpr &y) {
1312                                Walk(y.t, "=");
1313                                return false;
1314                              },
1315                              [&](const IoControlSpec::Asynchronous &) {
1316                                Word("ASYNCHRONOUS=");
1317                                return true;
1318                              },
1319                              [&](const EndLabel &) {
1320                                Word("END=");
1321                                return true;
1322                              },
1323                              [&](const EorLabel &) {
1324                                Word("EOR=");
1325                                return true;
1326                              },
1327                              [&](const ErrLabel &) {
1328                                Word("ERR=");
1329                                return true;
1330                              },
1331                              [&](const IdVariable &) {
1332                                Word("ID=");
1333                                return true;
1334                              },
1335                              [&](const MsgVariable &) {
1336                                Word("IOMSG=");
1337                                return true;
1338                              },
1339                              [&](const StatVariable &) {
1340                                Word("IOSTAT=");
1341                                return true;
1342                              },
1343                              [&](const IoControlSpec::Pos &) {
1344                                Word("POS=");
1345                                return true;
1346                              },
1347                              [&](const IoControlSpec::Rec &) {
1348                                Word("REC=");
1349                                return true;
1350                              },
1351                              [&](const IoControlSpec::Size &) {
1352                                Word("SIZE=");
1353                                return true;
1354                              },
1355                          },
1356         x.u);
1357   }
Unparse(const InputImpliedDo & x)1358   void Unparse(const InputImpliedDo &x) { // R1218
1359     Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");
1360     Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1361   }
Unparse(const OutputImpliedDo & x)1362   void Unparse(const OutputImpliedDo &x) { // R1219
1363     Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");
1364     Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1365   }
Unparse(const WaitStmt & x)1366   void Unparse(const WaitStmt &x) { // R1222
1367     Word("WAIT ("), Walk(x.v, ", "), Put(')');
1368   }
Before(const WaitSpec & x)1369   void Before(const WaitSpec &x) { // R1223
1370     common::visit(common::visitors{
1371                       [&](const FileUnitNumber &) { Word("UNIT="); },
1372                       [&](const EndLabel &) { Word("END="); },
1373                       [&](const EorLabel &) { Word("EOR="); },
1374                       [&](const ErrLabel &) { Word("ERR="); },
1375                       [&](const IdExpr &) { Word("ID="); },
1376                       [&](const MsgVariable &) { Word("IOMSG="); },
1377                       [&](const StatVariable &) { Word("IOSTAT="); },
1378                   },
1379         x.u);
1380   }
Unparse(const BackspaceStmt & x)1381   void Unparse(const BackspaceStmt &x) { // R1224
1382     Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');
1383   }
Unparse(const EndfileStmt & x)1384   void Unparse(const EndfileStmt &x) { // R1225
1385     Word("ENDFILE ("), Walk(x.v, ", "), Put(')');
1386   }
Unparse(const RewindStmt & x)1387   void Unparse(const RewindStmt &x) { // R1226
1388     Word("REWIND ("), Walk(x.v, ", "), Put(')');
1389   }
Before(const PositionOrFlushSpec & x)1390   void Before(const PositionOrFlushSpec &x) { // R1227 & R1229
1391     common::visit(common::visitors{
1392                       [&](const FileUnitNumber &) { Word("UNIT="); },
1393                       [&](const MsgVariable &) { Word("IOMSG="); },
1394                       [&](const StatVariable &) { Word("IOSTAT="); },
1395                       [&](const ErrLabel &) { Word("ERR="); },
1396                   },
1397         x.u);
1398   }
Unparse(const FlushStmt & x)1399   void Unparse(const FlushStmt &x) { // R1228
1400     Word("FLUSH ("), Walk(x.v, ", "), Put(')');
1401   }
Unparse(const InquireStmt & x)1402   void Unparse(const InquireStmt &x) { // R1230
1403     Word("INQUIRE (");
1404     common::visit(
1405         common::visitors{
1406             [&](const InquireStmt::Iolength &y) {
1407               Word("IOLENGTH="), Walk(y.t, ") ");
1408             },
1409             [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); },
1410         },
1411         x.u);
1412   }
Pre(const InquireSpec & x)1413   bool Pre(const InquireSpec &x) { // R1231
1414     return common::visit(common::visitors{
1415                              [&](const FileUnitNumber &) {
1416                                Word("UNIT=");
1417                                return true;
1418                              },
1419                              [&](const FileNameExpr &) {
1420                                Word("FILE=");
1421                                return true;
1422                              },
1423                              [&](const InquireSpec::CharVar &y) {
1424                                Walk(y.t, "=");
1425                                return false;
1426                              },
1427                              [&](const InquireSpec::IntVar &y) {
1428                                Walk(y.t, "=");
1429                                return false;
1430                              },
1431                              [&](const InquireSpec::LogVar &y) {
1432                                Walk(y.t, "=");
1433                                return false;
1434                              },
1435                              [&](const IdExpr &) {
1436                                Word("ID=");
1437                                return true;
1438                              },
1439                              [&](const ErrLabel &) {
1440                                Word("ERR=");
1441                                return true;
1442                              },
1443                          },
1444         x.u);
1445   }
1446 
Before(const FormatStmt &)1447   void Before(const FormatStmt &) { // R1301
1448     Word("FORMAT");
1449   }
Unparse(const format::FormatSpecification & x)1450   void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R1305
1451     Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");
1452     Walk("*(", x.unlimitedItems, ",", ")"), Put(')');
1453   }
Unparse(const format::FormatItem & x)1454   void Unparse(const format::FormatItem &x) { // R1304, R1306, R1321
1455     if (x.repeatCount) {
1456       Walk(*x.repeatCount);
1457     }
1458     common::visit(common::visitors{
1459                       [&](const std::string &y) { PutNormalized(y); },
1460                       [&](const std::list<format::FormatItem> &y) {
1461                         Walk("(", y, ",", ")");
1462                       },
1463                       [&](const auto &y) { Walk(y); },
1464                   },
1465         x.u);
1466   }
Unparse(const format::IntrinsicTypeDataEditDesc & x)1467   void Unparse(
1468       const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311
1469     switch (x.kind) {
1470 #define FMT(x) \
1471   case format::IntrinsicTypeDataEditDesc::Kind::x: \
1472     Put(#x); \
1473     break
1474       FMT(I);
1475       FMT(B);
1476       FMT(O);
1477       FMT(Z);
1478       FMT(F);
1479       FMT(E);
1480       FMT(EN);
1481       FMT(ES);
1482       FMT(EX);
1483       FMT(G);
1484       FMT(L);
1485       FMT(A);
1486       FMT(D);
1487 #undef FMT
1488     }
1489     Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);
1490   }
Unparse(const format::DerivedTypeDataEditDesc & x)1491   void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312
1492     Word("DT");
1493     if (!x.type.empty()) {
1494       Put('"'), Put(x.type), Put('"');
1495     }
1496     Walk("(", x.parameters, ",", ")");
1497   }
Unparse(const format::ControlEditDesc & x)1498   void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R1320
1499     switch (x.kind) {
1500     case format::ControlEditDesc::Kind::T:
1501       Word("T");
1502       Walk(x.count);
1503       break;
1504     case format::ControlEditDesc::Kind::TL:
1505       Word("TL");
1506       Walk(x.count);
1507       break;
1508     case format::ControlEditDesc::Kind::TR:
1509       Word("TR");
1510       Walk(x.count);
1511       break;
1512     case format::ControlEditDesc::Kind::X:
1513       if (x.count != 1) {
1514         Walk(x.count);
1515       }
1516       Word("X");
1517       break;
1518     case format::ControlEditDesc::Kind::Slash:
1519       if (x.count != 1) {
1520         Walk(x.count);
1521       }
1522       Put('/');
1523       break;
1524     case format::ControlEditDesc::Kind::Colon:
1525       Put(':');
1526       break;
1527     case format::ControlEditDesc::Kind::P:
1528       Walk(x.count);
1529       Word("P");
1530       break;
1531 #define FMT(x) \
1532   case format::ControlEditDesc::Kind::x: \
1533     Put(#x); \
1534     break
1535       FMT(SS);
1536       FMT(SP);
1537       FMT(S);
1538       FMT(BN);
1539       FMT(BZ);
1540       FMT(RU);
1541       FMT(RD);
1542       FMT(RZ);
1543       FMT(RN);
1544       FMT(RC);
1545       FMT(RP);
1546       FMT(DC);
1547       FMT(DP);
1548 #undef FMT
1549     case format::ControlEditDesc::Kind::Dollar:
1550       Put('$');
1551       break;
1552     case format::ControlEditDesc::Kind::Backslash:
1553       Put('\\');
1554       break;
1555     }
1556   }
1557 
Before(const MainProgram & x)1558   void Before(const MainProgram &x) { // R1401
1559     if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {
1560       Indent();
1561     }
1562   }
Before(const ProgramStmt &)1563   void Before(const ProgramStmt &) { // R1402
1564     Word("PROGRAM "), Indent();
1565   }
Unparse(const EndProgramStmt & x)1566   void Unparse(const EndProgramStmt &x) { // R1403
1567     EndSubprogram("PROGRAM", x.v);
1568   }
Before(const ModuleStmt &)1569   void Before(const ModuleStmt &) { // R1405
1570     Word("MODULE "), Indent();
1571   }
Unparse(const EndModuleStmt & x)1572   void Unparse(const EndModuleStmt &x) { // R1406
1573     EndSubprogram("MODULE", x.v);
1574   }
Unparse(const UseStmt & x)1575   void Unparse(const UseStmt &x) { // R1409
1576     Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);
1577     common::visit(
1578         common::visitors{
1579             [&](const std::list<Rename> &y) { Walk(", ", y, ", "); },
1580             [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); },
1581         },
1582         x.u);
1583   }
Unparse(const Rename & x)1584   void Unparse(const Rename &x) { // R1411
1585     common::visit(common::visitors{
1586                       [&](const Rename::Names &y) { Walk(y.t, " => "); },
1587                       [&](const Rename::Operators &y) {
1588                         Word("OPERATOR("), Walk(y.t, ") => OPERATOR("),
1589                             Put(")");
1590                       },
1591                   },
1592         x.u);
1593   }
Unparse(const SubmoduleStmt & x)1594   void Unparse(const SubmoduleStmt &x) { // R1417
1595     Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent();
1596   }
Unparse(const ParentIdentifier & x)1597   void Unparse(const ParentIdentifier &x) { // R1418
1598     Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));
1599   }
Unparse(const EndSubmoduleStmt & x)1600   void Unparse(const EndSubmoduleStmt &x) { // R1419
1601     EndSubprogram("SUBMODULE", x.v);
1602   }
Unparse(const BlockDataStmt & x)1603   void Unparse(const BlockDataStmt &x) { // R1421
1604     Word("BLOCK DATA"), Walk(" ", x.v), Indent();
1605   }
Unparse(const EndBlockDataStmt & x)1606   void Unparse(const EndBlockDataStmt &x) { // R1422
1607     EndSubprogram("BLOCK DATA", x.v);
1608   }
1609 
Unparse(const InterfaceStmt & x)1610   void Unparse(const InterfaceStmt &x) { // R1503
1611     common::visit(common::visitors{
1612                       [&](const std::optional<GenericSpec> &y) {
1613                         Word("INTERFACE"), Walk(" ", y);
1614                       },
1615                       [&](const Abstract &) { Word("ABSTRACT INTERFACE"); },
1616                   },
1617         x.u);
1618     Indent();
1619   }
Unparse(const EndInterfaceStmt & x)1620   void Unparse(const EndInterfaceStmt &x) { // R1504
1621     Outdent(), Word("END INTERFACE"), Walk(" ", x.v);
1622   }
Unparse(const ProcedureStmt & x)1623   void Unparse(const ProcedureStmt &x) { // R1506
1624     if (std::get<ProcedureStmt::Kind>(x.t) ==
1625         ProcedureStmt::Kind::ModuleProcedure) {
1626       Word("MODULE ");
1627     }
1628     Word("PROCEDURE :: ");
1629     Walk(std::get<std::list<Name>>(x.t), ", ");
1630   }
Before(const GenericSpec & x)1631   void Before(const GenericSpec &x) { // R1508, R1509
1632     common::visit(
1633         common::visitors{
1634             [&](const DefinedOperator &) { Word("OPERATOR("); },
1635             [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },
1636             [&](const GenericSpec::ReadFormatted &) {
1637               Word("READ(FORMATTED)");
1638             },
1639             [&](const GenericSpec::ReadUnformatted &) {
1640               Word("READ(UNFORMATTED)");
1641             },
1642             [&](const GenericSpec::WriteFormatted &) {
1643               Word("WRITE(FORMATTED)");
1644             },
1645             [&](const GenericSpec::WriteUnformatted &) {
1646               Word("WRITE(UNFORMATTED)");
1647             },
1648             [](const auto &) {},
1649         },
1650         x.u);
1651   }
Post(const GenericSpec & x)1652   void Post(const GenericSpec &x) {
1653     common::visit(common::visitors{
1654                       [&](const DefinedOperator &) { Put(')'); },
1655                       [](const auto &) {},
1656                   },
1657         x.u);
1658   }
Unparse(const GenericStmt & x)1659   void Unparse(const GenericStmt &x) { // R1510
1660     Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
1661     Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");
1662     Walk(std::get<std::list<Name>>(x.t), ", ");
1663   }
Unparse(const ExternalStmt & x)1664   void Unparse(const ExternalStmt &x) { // R1511
1665     Word("EXTERNAL :: "), Walk(x.v, ", ");
1666   }
Unparse(const ProcedureDeclarationStmt & x)1667   void Unparse(const ProcedureDeclarationStmt &x) { // R1512
1668     Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t));
1669     Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");
1670     Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
1671   }
Unparse(const ProcDecl & x)1672   void Unparse(const ProcDecl &x) { // R1515
1673     Walk(std::get<Name>(x.t));
1674     Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));
1675   }
Unparse(const IntrinsicStmt & x)1676   void Unparse(const IntrinsicStmt &x) { // R1519
1677     Word("INTRINSIC :: "), Walk(x.v, ", ");
1678   }
Unparse(const FunctionReference & x)1679   void Unparse(const FunctionReference &x) { // R1520
1680     Walk(std::get<ProcedureDesignator>(x.v.t));
1681     Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
1682   }
Unparse(const CallStmt & x)1683   void Unparse(const CallStmt &x) { // R1521
1684     if (asFortran_ && x.typedCall.get()) {
1685       Put(' ');
1686       asFortran_->call(out_, *x.typedCall);
1687       Put('\n');
1688     } else {
1689       const auto &pd{std::get<ProcedureDesignator>(x.v.t)};
1690       const auto &args{std::get<std::list<ActualArgSpec>>(x.v.t)};
1691       Word("CALL "), Walk(pd);
1692       if (args.empty()) {
1693         if (std::holds_alternative<ProcComponentRef>(pd.u)) {
1694           Put("()"); // pgf90 crashes on CALL to tbp without parentheses
1695         }
1696       } else {
1697         Walk("(", args, ", ", ")");
1698       }
1699     }
1700   }
Unparse(const ActualArgSpec & x)1701   void Unparse(const ActualArgSpec &x) { // R1523
1702     Walk(std::get<std::optional<Keyword>>(x.t), "=");
1703     Walk(std::get<ActualArg>(x.t));
1704   }
Unparse(const ActualArg::PercentRef & x)1705   void Unparse(const ActualArg::PercentRef &x) { // R1524
1706     Word("%REF("), Walk(x.v), Put(')');
1707   }
Unparse(const ActualArg::PercentVal & x)1708   void Unparse(const ActualArg::PercentVal &x) {
1709     Word("%VAL("), Walk(x.v), Put(')');
1710   }
Before(const AltReturnSpec &)1711   void Before(const AltReturnSpec &) { // R1525
1712     Put('*');
1713   }
Post(const PrefixSpec::Elemental)1714   void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527
Post(const PrefixSpec::Impure)1715   void Post(const PrefixSpec::Impure) { Word("IMPURE"); }
Post(const PrefixSpec::Module)1716   void Post(const PrefixSpec::Module) { Word("MODULE"); }
Post(const PrefixSpec::Non_Recursive)1717   void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }
Post(const PrefixSpec::Pure)1718   void Post(const PrefixSpec::Pure) { Word("PURE"); }
Post(const PrefixSpec::Recursive)1719   void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }
Unparse(const FunctionStmt & x)1720   void Unparse(const FunctionStmt &x) { // R1530
1721     Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1722     Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");
1723     Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');
1724     Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
1725   }
Unparse(const Suffix & x)1726   void Unparse(const Suffix &x) { // R1532
1727     if (x.resultName) {
1728       Word("RESULT("), Walk(x.resultName), Put(')');
1729       Walk(" ", x.binding);
1730     } else {
1731       Walk(x.binding);
1732     }
1733   }
Unparse(const EndFunctionStmt & x)1734   void Unparse(const EndFunctionStmt &x) { // R1533
1735     EndSubprogram("FUNCTION", x.v);
1736   }
Unparse(const SubroutineStmt & x)1737   void Unparse(const SubroutineStmt &x) { // R1535
1738     Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1739     Word("SUBROUTINE "), Walk(std::get<Name>(x.t));
1740     const auto &args{std::get<std::list<DummyArg>>(x.t)};
1741     const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)};
1742     if (args.empty()) {
1743       Walk(" () ", bind);
1744     } else {
1745       Walk(" (", args, ", ", ")");
1746       Walk(" ", bind);
1747     }
1748     Indent();
1749   }
Unparse(const EndSubroutineStmt & x)1750   void Unparse(const EndSubroutineStmt &x) { // R1537
1751     EndSubprogram("SUBROUTINE", x.v);
1752   }
Before(const MpSubprogramStmt &)1753   void Before(const MpSubprogramStmt &) { // R1539
1754     Word("MODULE PROCEDURE "), Indent();
1755   }
Unparse(const EndMpSubprogramStmt & x)1756   void Unparse(const EndMpSubprogramStmt &x) { // R1540
1757     EndSubprogram("PROCEDURE", x.v);
1758   }
Unparse(const EntryStmt & x)1759   void Unparse(const EntryStmt &x) { // R1541
1760     Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("(");
1761     Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")");
1762     Walk(" ", std::get<std::optional<Suffix>>(x.t));
1763   }
Unparse(const ReturnStmt & x)1764   void Unparse(const ReturnStmt &x) { // R1542
1765     Word("RETURN"), Walk(" ", x.v);
1766   }
Unparse(const ContainsStmt &)1767   void Unparse(const ContainsStmt &) { // R1543
1768     Outdent();
1769     Word("CONTAINS");
1770     Indent();
1771   }
Unparse(const StmtFunctionStmt & x)1772   void Unparse(const StmtFunctionStmt &x) { // R1544
1773     Walk(std::get<Name>(x.t)), Put('(');
1774     Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");
1775     Walk(std::get<Scalar<Expr>>(x.t));
1776   }
1777 
1778   // Directives, extensions, and deprecated constructs
Unparse(const CompilerDirective & x)1779   void Unparse(const CompilerDirective &x) {
1780     common::visit(
1781         common::visitors{
1782             [&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {
1783               Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty
1784               Walk(" ", tkr, ", ");
1785             },
1786             [&](const std::list<CompilerDirective::NameValue> &names) {
1787               Walk("!DIR$ ", names, " ");
1788             },
1789         },
1790         x.u);
1791     Put('\n');
1792   }
Unparse(const CompilerDirective::IgnoreTKR & x)1793   void Unparse(const CompilerDirective::IgnoreTKR &x) {
1794     const auto &list{std::get<std::list<const char *>>(x.t)};
1795     if (!list.empty()) {
1796       Put("(");
1797       for (const char *tkr : list) {
1798         Put(*tkr);
1799       }
1800       Put(") ");
1801     }
1802     Walk(std::get<Name>(x.t));
1803   }
Unparse(const CompilerDirective::NameValue & x)1804   void Unparse(const CompilerDirective::NameValue &x) {
1805     Walk(std::get<Name>(x.t));
1806     Walk("=", std::get<std::optional<std::uint64_t>>(x.t));
1807   }
1808 
1809   // OpenACC Directives & Clauses
Unparse(const AccAtomicCapture & x)1810   void Unparse(const AccAtomicCapture &x) {
1811     BeginOpenACC();
1812     Word("!$ACC CAPTURE");
1813     Put("\n");
1814     EndOpenACC();
1815     Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
1816     Put("\n");
1817     Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
1818     BeginOpenACC();
1819     Word("!$ACC END ATOMIC\n");
1820     EndOpenACC();
1821   }
Unparse(const AccAtomicRead & x)1822   void Unparse(const AccAtomicRead &x) {
1823     BeginOpenACC();
1824     Word("!$ACC ATOMIC READ");
1825     Put("\n");
1826     EndOpenACC();
1827     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1828     BeginOpenACC();
1829     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1830     EndOpenACC();
1831   }
Unparse(const AccAtomicWrite & x)1832   void Unparse(const AccAtomicWrite &x) {
1833     BeginOpenACC();
1834     Word("!$ACC ATOMIC WRITE");
1835     Put("\n");
1836     EndOpenACC();
1837     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1838     BeginOpenACC();
1839     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1840     EndOpenACC();
1841   }
Unparse(const AccAtomicUpdate & x)1842   void Unparse(const AccAtomicUpdate &x) {
1843     BeginOpenACC();
1844     Word("!$ACC ATOMIC UPDATE");
1845     Put("\n");
1846     EndOpenACC();
1847     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1848     BeginOpenACC();
1849     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1850     EndOpenACC();
1851   }
Unparse(const llvm::acc::Directive & x)1852   void Unparse(const llvm::acc::Directive &x) {
1853     Word(llvm::acc::getOpenACCDirectiveName(x).str());
1854   }
1855 #define GEN_FLANG_CLAUSE_UNPARSE
1856 #include "llvm/Frontend/OpenACC/ACC.inc"
Unparse(const AccObjectListWithModifier & x)1857   void Unparse(const AccObjectListWithModifier &x) {
1858     Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
1859     Walk(std::get<AccObjectList>(x.t));
1860   }
Unparse(const AccDataModifier::Modifier & x)1861   void Unparse(const AccDataModifier::Modifier &x) {
1862     Word(AccDataModifier::EnumToString(x));
1863   }
Unparse(const AccBindClause & x)1864   void Unparse(const AccBindClause &x) {
1865     common::visit(common::visitors{
1866                       [&](const Name &y) { Put('('), Walk(y), Put(')'); },
1867                       [&](const ScalarDefaultCharExpr &y) {
1868                         Put('('), Walk(y), Put(')');
1869                       },
1870                   },
1871         x.u);
1872   }
Unparse(const AccDefaultClause & x)1873   void Unparse(const AccDefaultClause &x) {
1874     switch (x.v) {
1875     case llvm::acc::DefaultValue::ACC_Default_none:
1876       Put("NONE");
1877       break;
1878     case llvm::acc::DefaultValue::ACC_Default_present:
1879       Put("PRESENT");
1880       break;
1881     }
1882   }
Unparse(const AccClauseList & x)1883   void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
Unparse(const AccGangArgument & x)1884   void Unparse(const AccGangArgument &x) {
1885     Walk("NUM:", std::get<std::optional<ScalarIntExpr>>(x.t));
1886     Walk(", STATIC:", std::get<std::optional<AccSizeExpr>>(x.t));
1887   }
Unparse(const OpenACCBlockConstruct & x)1888   void Unparse(const OpenACCBlockConstruct &x) {
1889     BeginOpenACC();
1890     Word("!$ACC ");
1891     Walk(std::get<AccBeginBlockDirective>(x.t));
1892     Put("\n");
1893     EndOpenACC();
1894     Walk(std::get<Block>(x.t), "");
1895     BeginOpenACC();
1896     Word("!$ACC END ");
1897     Walk(std::get<AccEndBlockDirective>(x.t));
1898     Put("\n");
1899     EndOpenACC();
1900   }
Unparse(const OpenACCLoopConstruct & x)1901   void Unparse(const OpenACCLoopConstruct &x) {
1902     BeginOpenACC();
1903     Word("!$ACC ");
1904     Walk(std::get<AccBeginLoopDirective>(x.t));
1905     Put("\n");
1906     EndOpenACC();
1907     Walk(std::get<std::optional<DoConstruct>>(x.t));
1908   }
Unparse(const AccBeginLoopDirective & x)1909   void Unparse(const AccBeginLoopDirective &x) {
1910     Walk(std::get<AccLoopDirective>(x.t));
1911     Walk(std::get<AccClauseList>(x.t));
1912   }
Unparse(const OpenACCStandaloneConstruct & x)1913   void Unparse(const OpenACCStandaloneConstruct &x) {
1914     BeginOpenACC();
1915     Word("!$ACC ");
1916     Walk(std::get<AccStandaloneDirective>(x.t));
1917     Walk(std::get<AccClauseList>(x.t));
1918     Put("\n");
1919     EndOpenACC();
1920   }
Unparse(const OpenACCStandaloneDeclarativeConstruct & x)1921   void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
1922     BeginOpenACC();
1923     Word("!$ACC ");
1924     Walk(std::get<AccDeclarativeDirective>(x.t));
1925     Walk(std::get<AccClauseList>(x.t));
1926     Put("\n");
1927     EndOpenACC();
1928   }
Unparse(const OpenACCCombinedConstruct & x)1929   void Unparse(const OpenACCCombinedConstruct &x) {
1930     BeginOpenACC();
1931     Word("!$ACC ");
1932     Walk(std::get<AccBeginCombinedDirective>(x.t));
1933     Put("\n");
1934     EndOpenACC();
1935     Walk(std::get<std::optional<DoConstruct>>(x.t));
1936     BeginOpenACC();
1937     Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),
1938         "\n");
1939     EndOpenACC();
1940   }
Unparse(const OpenACCRoutineConstruct & x)1941   void Unparse(const OpenACCRoutineConstruct &x) {
1942     BeginOpenACC();
1943     Word("!$ACC ROUTINE");
1944     Walk("(", std::get<std::optional<Name>>(x.t), ")");
1945     Walk(std::get<AccClauseList>(x.t));
1946     Put("\n");
1947     EndOpenACC();
1948   }
Unparse(const AccObject & x)1949   void Unparse(const AccObject &x) {
1950     common::visit(common::visitors{
1951                       [&](const Designator &y) { Walk(y); },
1952                       [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
1953                   },
1954         x.u);
1955   }
Unparse(const AccObjectList & x)1956   void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
Unparse(const AccReductionOperator::Operator & x)1957   void Unparse(const AccReductionOperator::Operator &x) {
1958     Word(AccReductionOperator::EnumToString(x));
1959   }
Unparse(const AccObjectListWithReduction & x)1960   void Unparse(const AccObjectListWithReduction &x) {
1961     Walk(std::get<AccReductionOperator>(x.t));
1962     Put(":");
1963     Walk(std::get<AccObjectList>(x.t));
1964   }
Unparse(const OpenACCCacheConstruct & x)1965   void Unparse(const OpenACCCacheConstruct &x) {
1966     BeginOpenACC();
1967     Word("!$ACC ");
1968     Word("CACHE(");
1969     Walk(std::get<AccObjectListWithModifier>(x.t));
1970     Put(")");
1971     Put("\n");
1972     EndOpenACC();
1973   }
Unparse(const AccWaitArgument & x)1974   void Unparse(const AccWaitArgument &x) {
1975     Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");
1976     Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");
1977   }
Unparse(const OpenACCWaitConstruct & x)1978   void Unparse(const OpenACCWaitConstruct &x) {
1979     BeginOpenACC();
1980     Word("!$ACC ");
1981     Word("WAIT(");
1982     Walk(std::get<std::optional<AccWaitArgument>>(x.t));
1983     Walk(std::get<AccClauseList>(x.t));
1984     Put(")");
1985     Put("\n");
1986     EndOpenACC();
1987   }
1988 
1989   // OpenMP Clauses & Directives
Unparse(const OmpObject & x)1990   void Unparse(const OmpObject &x) {
1991     common::visit(common::visitors{
1992                       [&](const Designator &y) { Walk(y); },
1993                       [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
1994                   },
1995         x.u);
1996   }
Unparse(const OmpMapType::Always &)1997   void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
Unparse(const OmpMapClause & x)1998   void Unparse(const OmpMapClause &x) {
1999     Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
2000     Walk(std::get<OmpObjectList>(x.t));
2001   }
Unparse(const OmpScheduleModifier & x)2002   void Unparse(const OmpScheduleModifier &x) {
2003     Walk(std::get<OmpScheduleModifier::Modifier1>(x.t));
2004     Walk(",", std::get<std::optional<OmpScheduleModifier::Modifier2>>(x.t));
2005   }
Unparse(const OmpScheduleClause & x)2006   void Unparse(const OmpScheduleClause &x) {
2007     Walk(std::get<std::optional<OmpScheduleModifier>>(x.t), ":");
2008     Walk(std::get<OmpScheduleClause::ScheduleType>(x.t));
2009     Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
2010   }
Unparse(const OmpAlignedClause & x)2011   void Unparse(const OmpAlignedClause &x) {
2012     Walk(std::get<std::list<Name>>(x.t), ",");
2013     Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
2014   }
Unparse(const OmpIfClause & x)2015   void Unparse(const OmpIfClause &x) {
2016     Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
2017     Walk(std::get<ScalarLogicalExpr>(x.t));
2018   }
Unparse(const OmpLinearClause::WithoutModifier & x)2019   void Unparse(const OmpLinearClause::WithoutModifier &x) {
2020     Walk(x.names, ", ");
2021     Walk(":", x.step);
2022   }
Unparse(const OmpLinearClause::WithModifier & x)2023   void Unparse(const OmpLinearClause::WithModifier &x) {
2024     Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
2025     Walk(":", x.step);
2026   }
Unparse(const OmpReductionClause & x)2027   void Unparse(const OmpReductionClause &x) {
2028     Walk(std::get<OmpReductionOperator>(x.t));
2029     Put(":");
2030     Walk(std::get<OmpObjectList>(x.t));
2031   }
Unparse(const OmpInReductionClause & x)2032   void Unparse(const OmpInReductionClause &x) {
2033     Walk(std::get<OmpReductionOperator>(x.t));
2034     Put(":");
2035     Walk(std::get<OmpObjectList>(x.t));
2036   }
Unparse(const OmpAllocateClause & x)2037   void Unparse(const OmpAllocateClause &x) {
2038     Walk(std::get<std::optional<OmpAllocateClause::Allocator>>(x.t));
2039     Put(":");
2040     Walk(std::get<OmpObjectList>(x.t));
2041   }
Unparse(const OmpDependSinkVecLength & x)2042   void Unparse(const OmpDependSinkVecLength &x) {
2043     Walk(std::get<DefinedOperator>(x.t));
2044     Walk(std::get<ScalarIntConstantExpr>(x.t));
2045   }
Unparse(const OmpDependSinkVec & x)2046   void Unparse(const OmpDependSinkVec &x) {
2047     Walk(std::get<Name>(x.t));
2048     Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
2049   }
Unparse(const OmpDependClause::InOut & x)2050   void Unparse(const OmpDependClause::InOut &x) {
2051     Put("(");
2052     Walk(std::get<OmpDependenceType>(x.t));
2053     Put(":");
2054     Walk(std::get<std::list<Designator>>(x.t), ",");
2055     Put(")");
2056   }
Pre(const OmpDependClause & x)2057   bool Pre(const OmpDependClause &x) {
2058     return common::visit(
2059         common::visitors{
2060             [&](const OmpDependClause::Source &) {
2061               Word("SOURCE");
2062               return false;
2063             },
2064             [&](const OmpDependClause::Sink &y) {
2065               Word("SINK:");
2066               Walk(y.v);
2067               Put(")");
2068               return false;
2069             },
2070             [&](const OmpDependClause::InOut &) { return true; },
2071         },
2072         x.u);
2073   }
Unparse(const OmpDefaultmapClause & x)2074   void Unparse(const OmpDefaultmapClause &x) {
2075     Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
2076     Walk(":",
2077         std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
2078   }
2079 #define GEN_FLANG_CLAUSE_UNPARSE
2080 #include "llvm/Frontend/OpenMP/OMP.inc"
Unparse(const OmpLoopDirective & x)2081   void Unparse(const OmpLoopDirective &x) {
2082     switch (x.v) {
2083     case llvm::omp::Directive::OMPD_distribute:
2084       Word("DISTRIBUTE ");
2085       break;
2086     case llvm::omp::Directive::OMPD_distribute_parallel_do:
2087       Word("DISTRIBUTE PARALLEL DO ");
2088       break;
2089     case llvm::omp::Directive::OMPD_distribute_parallel_do_simd:
2090       Word("DISTRIBUTE PARALLEL DO SIMD ");
2091       break;
2092     case llvm::omp::Directive::OMPD_distribute_simd:
2093       Word("DISTRIBUTE SIMD ");
2094       break;
2095     case llvm::omp::Directive::OMPD_do:
2096       Word("DO ");
2097       break;
2098     case llvm::omp::Directive::OMPD_do_simd:
2099       Word("DO SIMD ");
2100       break;
2101     case llvm::omp::Directive::OMPD_parallel_do:
2102       Word("PARALLEL DO ");
2103       break;
2104     case llvm::omp::Directive::OMPD_parallel_do_simd:
2105       Word("PARALLEL DO SIMD ");
2106       break;
2107     case llvm::omp::Directive::OMPD_simd:
2108       Word("SIMD ");
2109       break;
2110     case llvm::omp::Directive::OMPD_target_parallel_do:
2111       Word("TARGET PARALLEL DO ");
2112       break;
2113     case llvm::omp::Directive::OMPD_target_parallel_do_simd:
2114       Word("TARGET PARALLEL DO SIMD ");
2115       break;
2116     case llvm::omp::Directive::OMPD_target_teams_distribute:
2117       Word("TARGET TEAMS DISTRIBUTE ");
2118       break;
2119     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
2120       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO ");
2121       break;
2122     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
2123       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2124       break;
2125     case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
2126       Word("TARGET TEAMS DISTRIBUTE SIMD ");
2127       break;
2128     case llvm::omp::Directive::OMPD_target_simd:
2129       Word("TARGET SIMD ");
2130       break;
2131     case llvm::omp::Directive::OMPD_taskloop:
2132       Word("TASKLOOP ");
2133       break;
2134     case llvm::omp::Directive::OMPD_taskloop_simd:
2135       Word("TASKLOOP SIMD ");
2136       break;
2137     case llvm::omp::Directive::OMPD_teams_distribute:
2138       Word("TEAMS DISTRIBUTE ");
2139       break;
2140     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do:
2141       Word("TEAMS DISTRIBUTE PARALLEL DO ");
2142       break;
2143     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd:
2144       Word("TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2145       break;
2146     case llvm::omp::Directive::OMPD_teams_distribute_simd:
2147       Word("TEAMS DISTRIBUTE SIMD ");
2148       break;
2149     default:
2150       break;
2151     }
2152   }
Unparse(const OmpObjectList & x)2153   void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
Unparse(const OmpSimpleStandaloneDirective & x)2154   void Unparse(const OmpSimpleStandaloneDirective &x) {
2155     switch (x.v) {
2156     case llvm::omp::Directive::OMPD_barrier:
2157       Word("BARRIER ");
2158       break;
2159     case llvm::omp::Directive::OMPD_taskwait:
2160       Word("TASKWAIT ");
2161       break;
2162     case llvm::omp::Directive::OMPD_taskyield:
2163       Word("TASKYIELD ");
2164       break;
2165     case llvm::omp::Directive::OMPD_target_enter_data:
2166       Word("TARGET ENTER DATA ");
2167       break;
2168     case llvm::omp::Directive::OMPD_target_exit_data:
2169       Word("TARGET EXIT DATA ");
2170       break;
2171     case llvm::omp::Directive::OMPD_target_update:
2172       Word("TARGET UPDATE ");
2173       break;
2174     case llvm::omp::Directive::OMPD_ordered:
2175       Word("ORDERED ");
2176       break;
2177     default:
2178       // Nothing to be done
2179       break;
2180     }
2181   }
Unparse(const OmpBlockDirective & x)2182   void Unparse(const OmpBlockDirective &x) {
2183     switch (x.v) {
2184     case llvm::omp::Directive::OMPD_master:
2185       Word("MASTER");
2186       break;
2187     case llvm::omp::Directive::OMPD_ordered:
2188       Word("ORDERED ");
2189       break;
2190     case llvm::omp::Directive::OMPD_parallel_workshare:
2191       Word("PARALLEL WORKSHARE ");
2192       break;
2193     case llvm::omp::Directive::OMPD_parallel:
2194       Word("PARALLEL ");
2195       break;
2196     case llvm::omp::Directive::OMPD_single:
2197       Word("SINGLE ");
2198       break;
2199     case llvm::omp::Directive::OMPD_target_data:
2200       Word("TARGET DATA ");
2201       break;
2202     case llvm::omp::Directive::OMPD_target_parallel:
2203       Word("TARGET PARALLEL ");
2204       break;
2205     case llvm::omp::Directive::OMPD_target_teams:
2206       Word("TARGET TEAMS ");
2207       break;
2208     case llvm::omp::Directive::OMPD_target:
2209       Word("TARGET ");
2210       break;
2211     case llvm::omp::Directive::OMPD_taskgroup:
2212       Word("TASKGROUP ");
2213       break;
2214     case llvm::omp::Directive::OMPD_task:
2215       Word("TASK ");
2216       break;
2217     case llvm::omp::Directive::OMPD_teams:
2218       Word("TEAMS ");
2219       break;
2220     case llvm::omp::Directive::OMPD_workshare:
2221       Word("WORKSHARE ");
2222       break;
2223     default:
2224       // Nothing to be done
2225       break;
2226     }
2227   }
Unparse(const OmpAtomicClauseList & x)2228   void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }
2229 
Unparse(const OmpAtomic & x)2230   void Unparse(const OmpAtomic &x) {
2231     BeginOpenMP();
2232     Word("!$OMP ATOMIC");
2233     Walk(std::get<OmpAtomicClauseList>(x.t));
2234     Put("\n");
2235     EndOpenMP();
2236     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2237     BeginOpenMP();
2238     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2239     EndOpenMP();
2240   }
Unparse(const OmpAtomicCapture & x)2241   void Unparse(const OmpAtomicCapture &x) {
2242     BeginOpenMP();
2243     Word("!$OMP ATOMIC");
2244     Walk(std::get<0>(x.t));
2245     Word(" CAPTURE");
2246     Walk(std::get<2>(x.t));
2247     Put("\n");
2248     EndOpenMP();
2249     Walk(std::get<OmpAtomicCapture::Stmt1>(x.t));
2250     Put("\n");
2251     Walk(std::get<OmpAtomicCapture::Stmt2>(x.t));
2252     BeginOpenMP();
2253     Word("!$OMP END ATOMIC\n");
2254     EndOpenMP();
2255   }
Unparse(const OmpAtomicRead & x)2256   void Unparse(const OmpAtomicRead &x) {
2257     BeginOpenMP();
2258     Word("!$OMP ATOMIC");
2259     Walk(std::get<0>(x.t));
2260     Word(" READ");
2261     Walk(std::get<2>(x.t));
2262     Put("\n");
2263     EndOpenMP();
2264     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2265     BeginOpenMP();
2266     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2267     EndOpenMP();
2268   }
Unparse(const OmpAtomicUpdate & x)2269   void Unparse(const OmpAtomicUpdate &x) {
2270     BeginOpenMP();
2271     Word("!$OMP ATOMIC");
2272     Walk(std::get<0>(x.t));
2273     Word(" UPDATE");
2274     Walk(std::get<2>(x.t));
2275     Put("\n");
2276     EndOpenMP();
2277     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2278     BeginOpenMP();
2279     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2280     EndOpenMP();
2281   }
Unparse(const OmpAtomicWrite & x)2282   void Unparse(const OmpAtomicWrite &x) {
2283     BeginOpenMP();
2284     Word("!$OMP ATOMIC");
2285     Walk(std::get<0>(x.t));
2286     Word(" WRITE");
2287     Walk(std::get<2>(x.t));
2288     Put("\n");
2289     EndOpenMP();
2290     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2291     BeginOpenMP();
2292     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2293     EndOpenMP();
2294   }
Unparse(const OpenMPExecutableAllocate & x)2295   void Unparse(const OpenMPExecutableAllocate &x) {
2296     BeginOpenMP();
2297     Word("!$OMP ALLOCATE");
2298     Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2299     Walk(std::get<OmpClauseList>(x.t));
2300     Put("\n");
2301     EndOpenMP();
2302     Walk(std::get<Statement<AllocateStmt>>(x.t));
2303   }
Unparse(const OpenMPDeclarativeAllocate & x)2304   void Unparse(const OpenMPDeclarativeAllocate &x) {
2305     BeginOpenMP();
2306     Word("!$OMP ALLOCATE");
2307     Put(" (");
2308     Walk(std::get<OmpObjectList>(x.t));
2309     Put(")");
2310     Walk(std::get<OmpClauseList>(x.t));
2311     Put("\n");
2312     EndOpenMP();
2313   }
Unparse(const OmpCriticalDirective & x)2314   void Unparse(const OmpCriticalDirective &x) {
2315     BeginOpenMP();
2316     Word("!$OMP CRITICAL");
2317     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2318     Walk(std::get<OmpClauseList>(x.t));
2319     Put("\n");
2320     EndOpenMP();
2321   }
Unparse(const OmpEndCriticalDirective & x)2322   void Unparse(const OmpEndCriticalDirective &x) {
2323     BeginOpenMP();
2324     Word("!$OMP END CRITICAL");
2325     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2326     Put("\n");
2327     EndOpenMP();
2328   }
Unparse(const OpenMPCriticalConstruct & x)2329   void Unparse(const OpenMPCriticalConstruct &x) {
2330     Walk(std::get<OmpCriticalDirective>(x.t));
2331     Walk(std::get<Block>(x.t), "");
2332     Walk(std::get<OmpEndCriticalDirective>(x.t));
2333   }
Unparse(const OmpDeclareTargetWithList & x)2334   void Unparse(const OmpDeclareTargetWithList &x) {
2335     Put("("), Walk(x.v), Put(")");
2336   }
Unparse(const OmpReductionInitializerClause & x)2337   void Unparse(const OmpReductionInitializerClause &x) {
2338     Word(" INITIALIZER(OMP_PRIV = ");
2339     Walk(x.v);
2340     Put(")");
2341   }
Unparse(const OmpReductionCombiner::FunctionCombiner & x)2342   void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
2343     const auto &pd = std::get<ProcedureDesignator>(x.v.t);
2344     const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
2345     Walk(pd);
2346     if (args.empty()) {
2347       if (std::holds_alternative<ProcComponentRef>(pd.u)) {
2348         Put("()");
2349       }
2350     } else {
2351       Walk("(", args, ", ", ")");
2352     }
2353   }
Unparse(const OpenMPDeclareReductionConstruct & x)2354   void Unparse(const OpenMPDeclareReductionConstruct &x) {
2355     Put("(");
2356     Walk(std::get<OmpReductionOperator>(x.t)), Put(" : ");
2357     Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
2358     Walk(std::get<OmpReductionCombiner>(x.t));
2359     Put(")");
2360     Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
2361   }
Pre(const OpenMPDeclarativeConstruct & x)2362   bool Pre(const OpenMPDeclarativeConstruct &x) {
2363     BeginOpenMP();
2364     Word("!$OMP ");
2365     return common::visit(
2366         common::visitors{
2367             [&](const OpenMPDeclarativeAllocate &z) {
2368               Word("ALLOCATE (");
2369               Walk(std::get<OmpObjectList>(z.t));
2370               Put(")");
2371               Walk(std::get<OmpClauseList>(z.t));
2372               Put("\n");
2373               EndOpenMP();
2374               return false;
2375             },
2376             [&](const OpenMPDeclareReductionConstruct &) {
2377               Word("DECLARE REDUCTION ");
2378               return true;
2379             },
2380             [&](const OpenMPDeclareSimdConstruct &y) {
2381               Word("DECLARE SIMD ");
2382               Walk("(", std::get<std::optional<Name>>(y.t), ")");
2383               Walk(std::get<OmpClauseList>(y.t));
2384               Put("\n");
2385               EndOpenMP();
2386               return false;
2387             },
2388             [&](const OpenMPDeclareTargetConstruct &) {
2389               Word("DECLARE TARGET ");
2390               return true;
2391             },
2392             [&](const OpenMPThreadprivate &) {
2393               Word("THREADPRIVATE (");
2394               return true;
2395             },
2396         },
2397         x.u);
2398   }
Post(const OpenMPDeclarativeConstruct &)2399   void Post(const OpenMPDeclarativeConstruct &) {
2400     Put("\n");
2401     EndOpenMP();
2402   }
Post(const OpenMPThreadprivate &)2403   void Post(const OpenMPThreadprivate &) {
2404     Put(")\n");
2405     EndOpenMP();
2406   }
Unparse(const OmpSectionsDirective & x)2407   void Unparse(const OmpSectionsDirective &x) {
2408     switch (x.v) {
2409     case llvm::omp::Directive::OMPD_sections:
2410       Word("SECTIONS ");
2411       break;
2412     case llvm::omp::Directive::OMPD_parallel_sections:
2413       Word("PARALLEL SECTIONS ");
2414       break;
2415     default:
2416       break;
2417     }
2418   }
Unparse(const OmpSectionBlocks & x)2419   void Unparse(const OmpSectionBlocks &x) {
2420     for (const auto &y : x.v) {
2421       BeginOpenMP();
2422       Word("!$OMP SECTION");
2423       Put("\n");
2424       EndOpenMP();
2425       // y.u is an OpenMPSectionConstruct
2426       // (y.u).v is Block
2427       Walk(std::get<OpenMPSectionConstruct>(y.u).v, "");
2428     }
2429   }
Unparse(const OpenMPSectionsConstruct & x)2430   void Unparse(const OpenMPSectionsConstruct &x) {
2431     BeginOpenMP();
2432     Word("!$OMP ");
2433     Walk(std::get<OmpBeginSectionsDirective>(x.t));
2434     Put("\n");
2435     EndOpenMP();
2436     Walk(std::get<OmpSectionBlocks>(x.t));
2437     BeginOpenMP();
2438     Word("!$OMP END ");
2439     Walk(std::get<OmpEndSectionsDirective>(x.t));
2440     Put("\n");
2441     EndOpenMP();
2442   }
Unparse(const OpenMPCancellationPointConstruct & x)2443   void Unparse(const OpenMPCancellationPointConstruct &x) {
2444     BeginOpenMP();
2445     Word("!$OMP CANCELLATION POINT ");
2446     Walk(std::get<OmpCancelType>(x.t));
2447     Put("\n");
2448     EndOpenMP();
2449   }
Unparse(const OpenMPCancelConstruct & x)2450   void Unparse(const OpenMPCancelConstruct &x) {
2451     BeginOpenMP();
2452     Word("!$OMP CANCEL ");
2453     Walk(std::get<OmpCancelType>(x.t));
2454     Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
2455     Put("\n");
2456     EndOpenMP();
2457   }
Unparse(const OmpMemoryOrderClause & x)2458   void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
Unparse(const OmpAtomicClause & x)2459   void Unparse(const OmpAtomicClause &x) {
2460     common::visit(common::visitors{
2461                       [&](const OmpMemoryOrderClause &y) { Walk(y); },
2462                       [&](const OmpClause &z) { Walk(z); },
2463                   },
2464         x.u);
2465   }
Unparse(const OpenMPFlushConstruct & x)2466   void Unparse(const OpenMPFlushConstruct &x) {
2467     BeginOpenMP();
2468     Word("!$OMP FLUSH ");
2469     Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t));
2470     Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2471     Put("\n");
2472     EndOpenMP();
2473   }
Unparse(const OmpEndLoopDirective & x)2474   void Unparse(const OmpEndLoopDirective &x) {
2475     BeginOpenMP();
2476     Word("!$OMP END ");
2477     Walk(std::get<OmpLoopDirective>(x.t));
2478     Walk(std::get<OmpClauseList>(x.t));
2479     Put("\n");
2480     EndOpenMP();
2481   }
Unparse(const OmpClauseList & x)2482   void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
Unparse(const OpenMPSimpleStandaloneConstruct & x)2483   void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
2484     BeginOpenMP();
2485     Word("!$OMP ");
2486     Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
2487     Walk(std::get<OmpClauseList>(x.t));
2488     Put("\n");
2489     EndOpenMP();
2490   }
Unparse(const OpenMPBlockConstruct & x)2491   void Unparse(const OpenMPBlockConstruct &x) {
2492     BeginOpenMP();
2493     Word("!$OMP ");
2494     Walk(std::get<OmpBeginBlockDirective>(x.t));
2495     Put("\n");
2496     EndOpenMP();
2497     Walk(std::get<Block>(x.t), "");
2498     BeginOpenMP();
2499     Word("!$OMP END ");
2500     Walk(std::get<OmpEndBlockDirective>(x.t));
2501     Put("\n");
2502     EndOpenMP();
2503   }
Unparse(const OpenMPLoopConstruct & x)2504   void Unparse(const OpenMPLoopConstruct &x) {
2505     BeginOpenMP();
2506     Word("!$OMP ");
2507     Walk(std::get<OmpBeginLoopDirective>(x.t));
2508     Put("\n");
2509     EndOpenMP();
2510     Walk(std::get<std::optional<DoConstruct>>(x.t));
2511     Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t));
2512   }
Unparse(const BasedPointer & x)2513   void Unparse(const BasedPointer &x) {
2514     Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
2515     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
2516   }
Unparse(const BasedPointerStmt & x)2517   void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }
Post(const StructureField & x)2518   void Post(const StructureField &x) {
2519     if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {
2520       for (const auto &item :
2521           std::get<std::list<ComponentOrFill>>(def->statement.t)) {
2522         if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) {
2523           structureComponents_.insert(std::get<Name>(comp->t).source);
2524         }
2525       }
2526     }
2527   }
Unparse(const StructureStmt & x)2528   void Unparse(const StructureStmt &x) {
2529     Word("STRUCTURE ");
2530     // The name, if present, includes the /slashes/
2531     Walk(std::get<std::optional<Name>>(x.t));
2532     Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
2533     Indent();
2534   }
Post(const Union::UnionStmt &)2535   void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
Post(const Union::EndUnionStmt &)2536   void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
Post(const Map::MapStmt &)2537   void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
Post(const Map::EndMapStmt &)2538   void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
Post(const StructureDef::EndStructureStmt &)2539   void Post(const StructureDef::EndStructureStmt &) {
2540     Outdent(), Word("END STRUCTURE");
2541   }
Unparse(const OldParameterStmt & x)2542   void Unparse(const OldParameterStmt &x) {
2543     Word("PARAMETER "), Walk(x.v, ", ");
2544   }
Unparse(const ArithmeticIfStmt & x)2545   void Unparse(const ArithmeticIfStmt &x) {
2546     Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
2547     Walk(std::get<1>(x.t)), Put(", ");
2548     Walk(std::get<2>(x.t)), Put(", ");
2549     Walk(std::get<3>(x.t));
2550   }
Unparse(const AssignStmt & x)2551   void Unparse(const AssignStmt &x) {
2552     Word("ASSIGN "), Walk(std::get<Label>(x.t));
2553     Word(" TO "), Walk(std::get<Name>(x.t));
2554   }
Unparse(const AssignedGotoStmt & x)2555   void Unparse(const AssignedGotoStmt &x) {
2556     Word("GO TO "), Walk(std::get<Name>(x.t));
2557     Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
2558   }
Unparse(const PauseStmt & x)2559   void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }
2560 
2561 #define WALK_NESTED_ENUM(CLASS, ENUM) \
2562   void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
WALK_NESTED_ENUM(AccessSpec,Kind)2563   WALK_NESTED_ENUM(AccessSpec, Kind) // R807
2564   WALK_NESTED_ENUM(common, TypeParamAttr) // R734
2565   WALK_NESTED_ENUM(IntentSpec, Intent) // R826
2566   WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
2567   WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
2568   WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
2569   WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
2570   WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
2571   WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
2572   WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
2573   WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
2574   WALK_NESTED_ENUM(OmpProcBindClause, Type) // OMP PROC_BIND
2575   WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
2576   WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
2577   WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
2578   WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
2579   WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
2580   WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
2581   WALK_NESTED_ENUM(OmpMapType, Type) // OMP map-type
2582   WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type
2583   WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
2584   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
2585 #undef WALK_NESTED_ENUM
2586 
2587   void Done() const { CHECK(indent_ == 0); }
2588 
2589 private:
2590   void Put(char);
2591   void Put(const char *);
2592   void Put(const std::string &);
2593   void PutNormalized(const std::string &);
2594   void PutKeywordLetter(char);
2595   void Word(const char *);
2596   void Word(const std::string &);
Indent()2597   void Indent() { indent_ += indentationAmount_; }
Outdent()2598   void Outdent() {
2599     CHECK(indent_ >= indentationAmount_);
2600     indent_ -= indentationAmount_;
2601   }
BeginOpenMP()2602   void BeginOpenMP() { openmpDirective_ = true; }
EndOpenMP()2603   void EndOpenMP() { openmpDirective_ = false; }
BeginOpenACC()2604   void BeginOpenACC() { openaccDirective_ = true; }
EndOpenACC()2605   void EndOpenACC() { openaccDirective_ = false; }
2606 
2607   // Call back to the traversal framework.
Walk(const T & x)2608   template <typename T> void Walk(const T &x) {
2609     Fortran::parser::Walk(x, *this);
2610   }
2611 
2612   // Traverse a std::optional<> value.  Emit a prefix and/or a suffix string
2613   // only when it contains a value.
2614   template <typename A>
Walk(const char * prefix,const std::optional<A> & x,const char * suffix="")2615   void Walk(
2616       const char *prefix, const std::optional<A> &x, const char *suffix = "") {
2617     if (x) {
2618       Word(prefix), Walk(*x), Word(suffix);
2619     }
2620   }
2621   template <typename A>
Walk(const std::optional<A> & x,const char * suffix="")2622   void Walk(const std::optional<A> &x, const char *suffix = "") {
2623     return Walk("", x, suffix);
2624   }
2625 
2626   // Traverse a std::list<>.  Separate the elements with an optional string.
2627   // Emit a prefix and/or a suffix string only when the list is not empty.
2628   template <typename A>
Walk(const char * prefix,const std::list<A> & list,const char * comma=", ",const char * suffix="")2629   void Walk(const char *prefix, const std::list<A> &list,
2630       const char *comma = ", ", const char *suffix = "") {
2631     if (!list.empty()) {
2632       const char *str{prefix};
2633       for (const auto &x : list) {
2634         Word(str), Walk(x);
2635         str = comma;
2636       }
2637       Word(suffix);
2638     }
2639   }
2640   template <typename A>
Walk(const std::list<A> & list,const char * comma=", ",const char * suffix="")2641   void Walk(const std::list<A> &list, const char *comma = ", ",
2642       const char *suffix = "") {
2643     return Walk("", list, comma, suffix);
2644   }
2645 
2646   // Traverse a std::tuple<>, with an optional separator.
2647   template <std::size_t J = 0, typename T>
WalkTupleElements(const T & tuple,const char * separator)2648   void WalkTupleElements(const T &tuple, const char *separator) {
2649     if (J > 0 && J < std::tuple_size_v<T>) {
2650       Word(separator); // this usage dodges "unused parameter" warning
2651     }
2652     if constexpr (J < std::tuple_size_v<T>) {
2653       Walk(std::get<J>(tuple));
2654       WalkTupleElements<J + 1>(tuple, separator);
2655     }
2656   }
2657   template <typename... A>
Walk(const std::tuple<A...> & tuple,const char * separator="")2658   void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
2659     WalkTupleElements(tuple, separator);
2660   }
2661 
EndSubprogram(const char * kind,const std::optional<Name> & name)2662   void EndSubprogram(const char *kind, const std::optional<Name> &name) {
2663     Outdent(), Word("END "), Word(kind), Walk(" ", name);
2664     structureComponents_.clear();
2665   }
2666 
2667   llvm::raw_ostream &out_;
2668   int indent_{0};
2669   const int indentationAmount_{1};
2670   int column_{1};
2671   const int maxColumns_{80};
2672   std::set<CharBlock> structureComponents_;
2673   Encoding encoding_{Encoding::UTF_8};
2674   bool capitalizeKeywords_{true};
2675   bool openaccDirective_{false};
2676   bool openmpDirective_{false};
2677   bool backslashEscapes_{false};
2678   preStatementType *preStatement_{nullptr};
2679   AnalyzedObjectsAsFortran *asFortran_{nullptr};
2680 };
2681 
Put(char ch)2682 void UnparseVisitor::Put(char ch) {
2683   int sav = indent_;
2684   if (openmpDirective_ || openaccDirective_) {
2685     indent_ = 0;
2686   }
2687   if (column_ <= 1) {
2688     if (ch == '\n') {
2689       return;
2690     }
2691     for (int j{0}; j < indent_; ++j) {
2692       out_ << ' ';
2693     }
2694     column_ = indent_ + 2;
2695   } else if (ch == '\n') {
2696     column_ = 1;
2697   } else if (++column_ >= maxColumns_) {
2698     out_ << "&\n";
2699     for (int j{0}; j < indent_; ++j) {
2700       out_ << ' ';
2701     }
2702     if (openmpDirective_) {
2703       out_ << "!$OMP&";
2704       column_ = 8;
2705     } else if (openaccDirective_) {
2706       out_ << "!$ACC&";
2707       column_ = 8;
2708     } else {
2709       out_ << '&';
2710       column_ = indent_ + 3;
2711     }
2712   }
2713   out_ << ch;
2714   if (openmpDirective_ || openaccDirective_) {
2715     indent_ = sav;
2716   }
2717 }
2718 
Put(const char * str)2719 void UnparseVisitor::Put(const char *str) {
2720   for (; *str != '\0'; ++str) {
2721     Put(*str);
2722   }
2723 }
2724 
Put(const std::string & str)2725 void UnparseVisitor::Put(const std::string &str) {
2726   for (char ch : str) {
2727     Put(ch);
2728   }
2729 }
2730 
PutNormalized(const std::string & str)2731 void UnparseVisitor::PutNormalized(const std::string &str) {
2732   auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};
2733   std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};
2734   Put(QuoteCharacterLiteral(encoded, backslashEscapes_));
2735 }
2736 
PutKeywordLetter(char ch)2737 void UnparseVisitor::PutKeywordLetter(char ch) {
2738   if (capitalizeKeywords_) {
2739     Put(ToUpperCaseLetter(ch));
2740   } else {
2741     Put(ToLowerCaseLetter(ch));
2742   }
2743 }
2744 
Word(const char * str)2745 void UnparseVisitor::Word(const char *str) {
2746   for (; *str != '\0'; ++str) {
2747     PutKeywordLetter(*str);
2748   }
2749 }
2750 
Word(const std::string & str)2751 void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
2752 
2753 template <typename A>
Unparse(llvm::raw_ostream & out,const A & root,Encoding encoding,bool capitalizeKeywords,bool backslashEscapes,preStatementType * preStatement,AnalyzedObjectsAsFortran * asFortran)2754 void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
2755     bool capitalizeKeywords, bool backslashEscapes,
2756     preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
2757   UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
2758       preStatement, asFortran};
2759   Walk(root, visitor);
2760   visitor.Done();
2761 }
2762 
2763 template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding,
2764     bool, bool, preStatementType *, AnalyzedObjectsAsFortran *);
2765 template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool,
2766     bool, preStatementType *, AnalyzedObjectsAsFortran *);
2767 } // namespace Fortran::parser
2768