1 //===-- lib/Parser/unparse.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // Generates Fortran from the content of a parse tree, using the
10 // traversal templates in parse-tree-visitor.h.
11 
12 #include "flang/Parser/unparse.h"
13 #include "flang/Common/Fortran.h"
14 #include "flang/Common/idioms.h"
15 #include "flang/Common/indirection.h"
16 #include "flang/Parser/characters.h"
17 #include "flang/Parser/parse-tree-visitor.h"
18 #include "flang/Parser/parse-tree.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include <algorithm>
21 #include <cinttypes>
22 #include <cstddef>
23 #include <set>
24 
25 namespace Fortran::parser {
26 
27 class UnparseVisitor {
28 public:
UnparseVisitor(llvm::raw_ostream & out,int indentationAmount,Encoding encoding,bool capitalize,bool backslashEscapes,preStatementType * preStatement,AnalyzedObjectsAsFortran * asFortran)29   UnparseVisitor(llvm::raw_ostream &out, int indentationAmount,
30       Encoding encoding, bool capitalize, bool backslashEscapes,
31       preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran)
32       : out_{out}, indentationAmount_{indentationAmount}, encoding_{encoding},
33         capitalizeKeywords_{capitalize}, backslashEscapes_{backslashEscapes},
34         preStatement_{preStatement}, asFortran_{asFortran} {}
35 
36   // In nearly all cases, this code avoids defining Boolean-valued Pre()
37   // callbacks for the parse tree walking framework in favor of two void
38   // functions, Before() and Unparse(), which imply true and false return
39   // values for Pre() respectively.
Before(const T &)40   template <typename T> void Before(const T &) {}
41   template <typename T> double Unparse(const T &); // not void, never used
42 
Pre(const T & x)43   template <typename T> bool Pre(const T &x) {
44     if constexpr (std::is_void_v<decltype(Unparse(x))>) {
45       // There is a local definition of Unparse() for this type.  It
46       // overrides the parse tree walker's default Walk() over the descendents.
47       Before(x);
48       Unparse(x);
49       Post(x);
50       return false; // Walk() does not visit descendents
51     } else {
52       Before(x);
53       return true; // there's no Unparse() defined here, Walk() the descendents
54     }
55   }
Post(const T &)56   template <typename T> void Post(const T &) {}
57 
58   // Emit simple types as-is.
Unparse(const std::string & x)59   void Unparse(const std::string &x) { Put(x); }
Unparse(int x)60   void Unparse(int x) { Put(std::to_string(x)); }
Unparse(unsigned int x)61   void Unparse(unsigned int x) { Put(std::to_string(x)); }
Unparse(long x)62   void Unparse(long x) { Put(std::to_string(x)); }
Unparse(unsigned long x)63   void Unparse(unsigned long x) { Put(std::to_string(x)); }
Unparse(long long x)64   void Unparse(long long x) { Put(std::to_string(x)); }
Unparse(unsigned long long x)65   void Unparse(unsigned long long x) { Put(std::to_string(x)); }
Unparse(char x)66   void Unparse(char x) { Put(x); }
67 
68   // Statement labels and ends of lines
Before(const Statement<T> & x)69   template <typename T> void Before(const Statement<T> &x) {
70     if (preStatement_) {
71       (*preStatement_)(x.source, out_, indent_);
72     }
73     Walk(x.label, " ");
74   }
Post(const Statement<T> &)75   template <typename T> void Post(const Statement<T> &) { Put('\n'); }
76 
77   // The special-case formatting functions for these productions are
78   // ordered to correspond roughly to their order of appearance in
79   // the Fortran 2018 standard (and parse-tree.h).
80 
Unparse(const Program & x)81   void Unparse(const Program &x) { // R501
82     Walk("", x.v, "\n"); // put blank lines between ProgramUnits
83   }
84 
Unparse(const Name & x)85   void Unparse(const Name &x) { // R603
86     Put(x.ToString());
87   }
Unparse(const DefinedOperator::IntrinsicOperator & x)88   void Unparse(const DefinedOperator::IntrinsicOperator &x) { // R608
89     switch (x) {
90     case DefinedOperator::IntrinsicOperator::Power:
91       Put("**");
92       break;
93     case DefinedOperator::IntrinsicOperator::Multiply:
94       Put('*');
95       break;
96     case DefinedOperator::IntrinsicOperator::Divide:
97       Put('/');
98       break;
99     case DefinedOperator::IntrinsicOperator::Add:
100       Put('+');
101       break;
102     case DefinedOperator::IntrinsicOperator::Subtract:
103       Put('-');
104       break;
105     case DefinedOperator::IntrinsicOperator::Concat:
106       Put("//");
107       break;
108     case DefinedOperator::IntrinsicOperator::LT:
109       Put('<');
110       break;
111     case DefinedOperator::IntrinsicOperator::LE:
112       Put("<=");
113       break;
114     case DefinedOperator::IntrinsicOperator::EQ:
115       Put("==");
116       break;
117     case DefinedOperator::IntrinsicOperator::NE:
118       Put("/=");
119       break;
120     case DefinedOperator::IntrinsicOperator::GE:
121       Put(">=");
122       break;
123     case DefinedOperator::IntrinsicOperator::GT:
124       Put('>');
125       break;
126     default:
127       Put('.'), Word(DefinedOperator::EnumToString(x)), Put('.');
128     }
129   }
Post(const Star &)130   void Post(const Star &) { Put('*'); } // R701 &c.
Post(const TypeParamValue::Deferred &)131   void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701
Unparse(const DeclarationTypeSpec::Type & x)132   void Unparse(const DeclarationTypeSpec::Type &x) { // R703
133     Word("TYPE("), Walk(x.derived), Put(')');
134   }
Unparse(const DeclarationTypeSpec::Class & x)135   void Unparse(const DeclarationTypeSpec::Class &x) {
136     Word("CLASS("), Walk(x.derived), Put(')');
137   }
Post(const DeclarationTypeSpec::ClassStar &)138   void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); }
Post(const DeclarationTypeSpec::TypeStar &)139   void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); }
Unparse(const DeclarationTypeSpec::Record & x)140   void Unparse(const DeclarationTypeSpec::Record &x) {
141     Word("RECORD/"), Walk(x.v), Put('/');
142   }
Before(const IntrinsicTypeSpec::Real &)143   void Before(const IntrinsicTypeSpec::Real &) { // R704
144     Word("REAL");
145   }
Before(const IntrinsicTypeSpec::Complex &)146   void Before(const IntrinsicTypeSpec::Complex &) { Word("COMPLEX"); }
Post(const IntrinsicTypeSpec::DoublePrecision &)147   void Post(const IntrinsicTypeSpec::DoublePrecision &) {
148     Word("DOUBLE PRECISION");
149   }
Before(const IntrinsicTypeSpec::Character &)150   void Before(const IntrinsicTypeSpec::Character &) { Word("CHARACTER"); }
Before(const IntrinsicTypeSpec::Logical &)151   void Before(const IntrinsicTypeSpec::Logical &) { Word("LOGICAL"); }
Post(const IntrinsicTypeSpec::DoubleComplex &)152   void Post(const IntrinsicTypeSpec::DoubleComplex &) {
153     Word("DOUBLE COMPLEX");
154   }
Before(const IntegerTypeSpec &)155   void Before(const IntegerTypeSpec &) { // R705
156     Word("INTEGER");
157   }
Unparse(const KindSelector & x)158   void Unparse(const KindSelector &x) { // R706
159     std::visit(
160         common::visitors{
161             [&](const ScalarIntConstantExpr &y) {
162               Put('('), Word("KIND="), Walk(y), Put(')');
163             },
164             [&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); },
165         },
166         x.u);
167   }
Unparse(const SignedIntLiteralConstant & x)168   void Unparse(const SignedIntLiteralConstant &x) { // R707
169     Put(std::get<CharBlock>(x.t).ToString());
170     Walk("_", std::get<std::optional<KindParam>>(x.t));
171   }
Unparse(const IntLiteralConstant & x)172   void Unparse(const IntLiteralConstant &x) { // R708
173     Put(std::get<CharBlock>(x.t).ToString());
174     Walk("_", std::get<std::optional<KindParam>>(x.t));
175   }
Unparse(const Sign & x)176   void Unparse(const Sign &x) { // R712
177     Put(x == Sign::Negative ? '-' : '+');
178   }
Unparse(const RealLiteralConstant & x)179   void Unparse(const RealLiteralConstant &x) { // R714, R715
180     Put(x.real.source.ToString()), Walk("_", x.kind);
181   }
Unparse(const ComplexLiteralConstant & x)182   void Unparse(const ComplexLiteralConstant &x) { // R718 - R720
183     Put('('), Walk(x.t, ","), Put(')');
184   }
Unparse(const CharSelector::LengthAndKind & x)185   void Unparse(const CharSelector::LengthAndKind &x) { // R721
186     Put('('), Word("KIND="), Walk(x.kind);
187     Walk(", LEN=", x.length), Put(')');
188   }
Unparse(const LengthSelector & x)189   void Unparse(const LengthSelector &x) { // R722
190     std::visit(common::visitors{
191                    [&](const TypeParamValue &y) {
192                      Put('('), Word("LEN="), Walk(y), Put(')');
193                    },
194                    [&](const CharLength &y) { Put('*'), Walk(y); },
195                },
196         x.u);
197   }
Unparse(const CharLength & x)198   void Unparse(const CharLength &x) { // R723
199     std::visit(
200         common::visitors{
201             [&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); },
202             [&](const std::int64_t &y) { Walk(y); },
203         },
204         x.u);
205   }
Unparse(const CharLiteralConstant & x)206   void Unparse(const CharLiteralConstant &x) { // R724
207     const auto &str{std::get<std::string>(x.t)};
208     if (const auto &k{std::get<std::optional<KindParam>>(x.t)}) {
209       Walk(*k), Put('_');
210     }
211     PutNormalized(str);
212   }
Unparse(const HollerithLiteralConstant & x)213   void Unparse(const HollerithLiteralConstant &x) {
214     auto ucs{DecodeString<std::u32string, Encoding::UTF_8>(x.v, false)};
215     Unparse(ucs.size());
216     Put('H');
217     for (char32_t ch : ucs) {
218       EncodedCharacter encoded{EncodeCharacter(encoding_, ch)};
219       for (int j{0}; j < encoded.bytes; ++j) {
220         Put(encoded.buffer[j]);
221       }
222     }
223   }
Unparse(const LogicalLiteralConstant & x)224   void Unparse(const LogicalLiteralConstant &x) { // R725
225     Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE.");
226     Walk("_", std::get<std::optional<KindParam>>(x.t));
227   }
Unparse(const DerivedTypeStmt & x)228   void Unparse(const DerivedTypeStmt &x) { // R727
229     Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", ");
230     Put(" :: "), Walk(std::get<Name>(x.t));
231     Walk("(", std::get<std::list<Name>>(x.t), ", ", ")");
232     Indent();
233   }
Unparse(const Abstract &)234   void Unparse(const Abstract &) { // R728, &c.
235     Word("ABSTRACT");
236   }
Post(const TypeAttrSpec::BindC &)237   void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); }
Unparse(const TypeAttrSpec::Extends & x)238   void Unparse(const TypeAttrSpec::Extends &x) {
239     Word("EXTENDS("), Walk(x.v), Put(')');
240   }
Unparse(const EndTypeStmt & x)241   void Unparse(const EndTypeStmt &x) { // R730
242     Outdent(), Word("END TYPE"), Walk(" ", x.v);
243   }
Unparse(const SequenceStmt &)244   void Unparse(const SequenceStmt &) { // R731
245     Word("SEQUENCE");
246   }
Unparse(const TypeParamDefStmt & x)247   void Unparse(const TypeParamDefStmt &x) { // R732
248     Walk(std::get<IntegerTypeSpec>(x.t));
249     Put(", "), Walk(std::get<common::TypeParamAttr>(x.t));
250     Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", ");
251   }
Unparse(const TypeParamDecl & x)252   void Unparse(const TypeParamDecl &x) { // R733
253     Walk(std::get<Name>(x.t));
254     Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
255   }
Unparse(const DataComponentDefStmt & x)256   void Unparse(const DataComponentDefStmt &x) { // R737
257     const auto &dts{std::get<DeclarationTypeSpec>(x.t)};
258     const auto &attrs{std::get<std::list<ComponentAttrSpec>>(x.t)};
259     const auto &decls{std::get<std::list<ComponentDecl>>(x.t)};
260     Walk(dts), Walk(", ", attrs, ", ");
261     if (!attrs.empty() ||
262         (!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) &&
263             std::none_of(
264                 decls.begin(), decls.end(), [](const ComponentDecl &d) {
265                   const auto &init{
266                       std::get<std::optional<Initialization>>(d.t)};
267                   return init &&
268                       std::holds_alternative<
269                           std::list<common::Indirection<DataStmtValue>>>(
270                           init->u);
271                 }))) {
272       Put(" ::");
273     }
274     Put(' '), Walk(decls, ", ");
275   }
Unparse(const Allocatable &)276   void Unparse(const Allocatable &) { // R738
277     Word("ALLOCATABLE");
278   }
Unparse(const Pointer &)279   void Unparse(const Pointer &) { Word("POINTER"); }
Unparse(const Contiguous &)280   void Unparse(const Contiguous &) { Word("CONTIGUOUS"); }
Before(const ComponentAttrSpec & x)281   void Before(const ComponentAttrSpec &x) {
282     std::visit(common::visitors{
283                    [&](const CoarraySpec &) { Word("CODIMENSION["); },
284                    [&](const ComponentArraySpec &) { Word("DIMENSION("); },
285                    [](const auto &) {},
286                },
287         x.u);
288   }
Post(const ComponentAttrSpec & x)289   void Post(const ComponentAttrSpec &x) {
290     std::visit(common::visitors{
291                    [&](const CoarraySpec &) { Put(']'); },
292                    [&](const ComponentArraySpec &) { Put(')'); },
293                    [](const auto &) {},
294                },
295         x.u);
296   }
Unparse(const ComponentDecl & x)297   void Unparse(const ComponentDecl &x) { // R739
298     Walk(std::get<ObjectName>(x.t));
299     Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")");
300     Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
301     Walk("*", std::get<std::optional<CharLength>>(x.t));
302     Walk(std::get<std::optional<Initialization>>(x.t));
303   }
Unparse(const ComponentArraySpec & x)304   void Unparse(const ComponentArraySpec &x) { // R740
305     std::visit(common::visitors{
306                    [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
307                    [&](const DeferredShapeSpecList &y) { Walk(y); },
308                },
309         x.u);
310   }
Unparse(const ProcComponentDefStmt & x)311   void Unparse(const ProcComponentDefStmt &x) { // R741
312     Word("PROCEDURE(");
313     Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')');
314     Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", ");
315     Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
316   }
Unparse(const NoPass &)317   void Unparse(const NoPass &) { // R742
318     Word("NOPASS");
319   }
Unparse(const Pass & x)320   void Unparse(const Pass &x) { Word("PASS"), Walk("(", x.v, ")"); }
Unparse(const Initialization & x)321   void Unparse(const Initialization &x) { // R743 & R805
322     std::visit(common::visitors{
323                    [&](const ConstantExpr &y) { Put(" = "), Walk(y); },
324                    [&](const NullInit &y) { Put(" => "), Walk(y); },
325                    [&](const InitialDataTarget &y) { Put(" => "), Walk(y); },
326                    [&](const std::list<common::Indirection<DataStmtValue>> &y) {
327                      Walk("/", y, ", ", "/");
328                    },
329                },
330         x.u);
331   }
Unparse(const PrivateStmt &)332   void Unparse(const PrivateStmt &) { // R745
333     Word("PRIVATE");
334   }
Unparse(const TypeBoundProcedureStmt::WithoutInterface & x)335   void Unparse(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749
336     Word("PROCEDURE"), Walk(", ", x.attributes, ", ");
337     Put(" :: "), Walk(x.declarations, ", ");
338   }
Unparse(const TypeBoundProcedureStmt::WithInterface & x)339   void Unparse(const TypeBoundProcedureStmt::WithInterface &x) {
340     Word("PROCEDURE("), Walk(x.interfaceName), Put("), ");
341     Walk(x.attributes);
342     Put(" :: "), Walk(x.bindingNames, ", ");
343   }
Unparse(const TypeBoundProcDecl & x)344   void Unparse(const TypeBoundProcDecl &x) { // R750
345     Walk(std::get<Name>(x.t));
346     Walk(" => ", std::get<std::optional<Name>>(x.t));
347   }
Unparse(const TypeBoundGenericStmt & x)348   void Unparse(const TypeBoundGenericStmt &x) { // R751
349     Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
350     Put(" :: "), Walk(std::get<common::Indirection<GenericSpec>>(x.t));
351     Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", ");
352   }
Post(const BindAttr::Deferred &)353   void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752
Post(const BindAttr::Non_Overridable &)354   void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); }
Unparse(const FinalProcedureStmt & x)355   void Unparse(const FinalProcedureStmt &x) { // R753
356     Word("FINAL :: "), Walk(x.v, ", ");
357   }
Unparse(const DerivedTypeSpec & x)358   void Unparse(const DerivedTypeSpec &x) { // R754
359     Walk(std::get<Name>(x.t));
360     Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")");
361   }
Unparse(const TypeParamSpec & x)362   void Unparse(const TypeParamSpec &x) { // R755
363     Walk(std::get<std::optional<Keyword>>(x.t), "=");
364     Walk(std::get<TypeParamValue>(x.t));
365   }
Unparse(const StructureConstructor & x)366   void Unparse(const StructureConstructor &x) { // R756
367     Walk(std::get<DerivedTypeSpec>(x.t));
368     Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')');
369   }
Unparse(const ComponentSpec & x)370   void Unparse(const ComponentSpec &x) { // R757
371     Walk(std::get<std::optional<Keyword>>(x.t), "=");
372     Walk(std::get<ComponentDataSource>(x.t));
373   }
Unparse(const EnumDefStmt &)374   void Unparse(const EnumDefStmt &) { // R760
375     Word("ENUM, BIND(C)"), Indent();
376   }
Unparse(const EnumeratorDefStmt & x)377   void Unparse(const EnumeratorDefStmt &x) { // R761
378     Word("ENUMERATOR :: "), Walk(x.v, ", ");
379   }
Unparse(const Enumerator & x)380   void Unparse(const Enumerator &x) { // R762
381     Walk(std::get<NamedConstant>(x.t));
382     Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
383   }
Post(const EndEnumStmt &)384   void Post(const EndEnumStmt &) { // R763
385     Outdent(), Word("END ENUM");
386   }
Unparse(const BOZLiteralConstant & x)387   void Unparse(const BOZLiteralConstant &x) { // R764 - R767
388     Put(x.v);
389   }
Unparse(const AcValue::Triplet & x)390   void Unparse(const AcValue::Triplet &x) { // R773
391     Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
392     Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
393   }
Unparse(const ArrayConstructor & x)394   void Unparse(const ArrayConstructor &x) { // R769
395     Put('['), Walk(x.v), Put(']');
396   }
Unparse(const AcSpec & x)397   void Unparse(const AcSpec &x) { // R770
398     Walk(x.type, "::"), Walk(x.values, ", ");
399   }
Unparse(const LoopBounds<A,B> & x)400   template <typename A, typename B> void Unparse(const LoopBounds<A, B> &x) {
401     Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);
402     Walk(",", x.step);
403   }
Unparse(const AcImpliedDo & x)404   void Unparse(const AcImpliedDo &x) { // R774
405     Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", ");
406     Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')');
407   }
Unparse(const AcImpliedDoControl & x)408   void Unparse(const AcImpliedDoControl &x) { // R775
409     Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
410     Walk(std::get<AcImpliedDoControl::Bounds>(x.t));
411   }
412 
Unparse(const TypeDeclarationStmt & x)413   void Unparse(const TypeDeclarationStmt &x) { // R801
414     const auto &dts{std::get<DeclarationTypeSpec>(x.t)};
415     const auto &attrs{std::get<std::list<AttrSpec>>(x.t)};
416     const auto &decls{std::get<std::list<EntityDecl>>(x.t)};
417     Walk(dts), Walk(", ", attrs, ", ");
418 
419     static const auto isInitializerOldStyle{[](const Initialization &i) {
420       return std::holds_alternative<
421           std::list<common::Indirection<DataStmtValue>>>(i.u);
422     }};
423     static const auto hasAssignmentInitializer{[](const EntityDecl &d) {
424       // Does a declaration have a new-style =x initializer?
425       const auto &init{std::get<std::optional<Initialization>>(d.t)};
426       return init && !isInitializerOldStyle(*init);
427     }};
428     static const auto hasSlashDelimitedInitializer{[](const EntityDecl &d) {
429       // Does a declaration have an old-style /x/ initializer?
430       const auto &init{std::get<std::optional<Initialization>>(d.t)};
431       return init && isInitializerOldStyle(*init);
432     }};
433     const auto useDoubledColons{[&]() {
434       bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)};
435       if (!attrs.empty()) {
436         // Attributes after the type require :: before the entities.
437         CHECK(!isRecord);
438         return true;
439       }
440       if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) {
441         // Always use :: with new style standard initializers (=x),
442         // since the standard requires them to appear (even in free form,
443         // where mandatory spaces already disambiguate INTEGER J=666).
444         CHECK(!isRecord);
445         return true;
446       }
447       if (isRecord) {
448         // Never put :: in a legacy extension RECORD// statement.
449         return false;
450       }
451       // The :: is optional for this declaration.  Avoid usage that can
452       // crash the pgf90 compiler.
453       if (std::any_of(
454               decls.begin(), decls.end(), hasSlashDelimitedInitializer)) {
455         // Don't use :: when a declaration uses legacy DATA-statement-like
456         // /x/ initialization.
457         return false;
458       }
459       // Don't use :: with intrinsic types.  Otherwise, use it.
460       return !std::holds_alternative<IntrinsicTypeSpec>(dts.u);
461     }};
462 
463     if (useDoubledColons()) {
464       Put(" ::");
465     }
466     Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", ");
467   }
Before(const AttrSpec & x)468   void Before(const AttrSpec &x) { // R802
469     std::visit(common::visitors{
470                    [&](const CoarraySpec &) { Word("CODIMENSION["); },
471                    [&](const ArraySpec &) { Word("DIMENSION("); },
472                    [](const auto &) {},
473                },
474         x.u);
475   }
Post(const AttrSpec & x)476   void Post(const AttrSpec &x) {
477     std::visit(common::visitors{
478                    [&](const CoarraySpec &) { Put(']'); },
479                    [&](const ArraySpec &) { Put(')'); },
480                    [](const auto &) {},
481                },
482         x.u);
483   }
Unparse(const EntityDecl & x)484   void Unparse(const EntityDecl &x) { // R803
485     Walk(std::get<ObjectName>(x.t));
486     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
487     Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
488     Walk("*", std::get<std::optional<CharLength>>(x.t));
489     Walk(std::get<std::optional<Initialization>>(x.t));
490   }
Unparse(const NullInit &)491   void Unparse(const NullInit &) { // R806
492     Word("NULL()");
493   }
Unparse(const LanguageBindingSpec & x)494   void Unparse(const LanguageBindingSpec &x) { // R808 & R1528
495     Word("BIND(C"), Walk(", NAME=", x.v), Put(')');
496   }
Unparse(const CoarraySpec & x)497   void Unparse(const CoarraySpec &x) { // R809
498     std::visit(common::visitors{
499                    [&](const DeferredCoshapeSpecList &y) { Walk(y); },
500                    [&](const ExplicitCoshapeSpec &y) { Walk(y); },
501                },
502         x.u);
503   }
Unparse(const DeferredCoshapeSpecList & x)504   void Unparse(const DeferredCoshapeSpecList &x) { // R810
505     for (auto j{x.v}; j > 0; --j) {
506       Put(':');
507       if (j > 1) {
508         Put(',');
509       }
510     }
511   }
Unparse(const ExplicitCoshapeSpec & x)512   void Unparse(const ExplicitCoshapeSpec &x) { // R811
513     Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
514     Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*');
515   }
Unparse(const ExplicitShapeSpec & x)516   void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818
517     Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":");
518     Walk(std::get<SpecificationExpr>(x.t));
519   }
Unparse(const ArraySpec & x)520   void Unparse(const ArraySpec &x) { // R815
521     std::visit(common::visitors{
522                    [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
523                    [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },
524                    [&](const DeferredShapeSpecList &y) { Walk(y); },
525                    [&](const AssumedSizeSpec &y) { Walk(y); },
526                    [&](const ImpliedShapeSpec &y) { Walk(y); },
527                    [&](const AssumedRankSpec &y) { Walk(y); },
528                },
529         x.u);
530   }
Post(const AssumedShapeSpec &)531   void Post(const AssumedShapeSpec &) { Put(':'); } // R819
Unparse(const DeferredShapeSpecList & x)532   void Unparse(const DeferredShapeSpecList &x) { // R820
533     for (auto j{x.v}; j > 0; --j) {
534       Put(':');
535       if (j > 1) {
536         Put(',');
537       }
538     }
539   }
Unparse(const AssumedImpliedSpec & x)540   void Unparse(const AssumedImpliedSpec &x) { // R821
541     Walk(x.v, ":");
542     Put('*');
543   }
Unparse(const AssumedSizeSpec & x)544   void Unparse(const AssumedSizeSpec &x) { // R822
545     Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
546     Walk(std::get<AssumedImpliedSpec>(x.t));
547   }
Unparse(const ImpliedShapeSpec & x)548   void Unparse(const ImpliedShapeSpec &x) { // R823
549     Walk(x.v, ",");
550   }
Post(const AssumedRankSpec &)551   void Post(const AssumedRankSpec &) { Put(".."); } // R825
Post(const Asynchronous &)552   void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); }
Post(const External &)553   void Post(const External &) { Word("EXTERNAL"); }
Post(const Intrinsic &)554   void Post(const Intrinsic &) { Word("INTRINSIC"); }
Post(const Optional &)555   void Post(const Optional &) { Word("OPTIONAL"); }
Post(const Parameter &)556   void Post(const Parameter &) { Word("PARAMETER"); }
Post(const Protected &)557   void Post(const Protected &) { Word("PROTECTED"); }
Post(const Save &)558   void Post(const Save &) { Word("SAVE"); }
Post(const Target &)559   void Post(const Target &) { Word("TARGET"); }
Post(const Value &)560   void Post(const Value &) { Word("VALUE"); }
Post(const Volatile &)561   void Post(const Volatile &) { Word("VOLATILE"); }
Unparse(const IntentSpec & x)562   void Unparse(const IntentSpec &x) { // R826
563     Word("INTENT("), Walk(x.v), Put(")");
564   }
Unparse(const AccessStmt & x)565   void Unparse(const AccessStmt &x) { // R827
566     Walk(std::get<AccessSpec>(x.t));
567     Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", ");
568   }
Unparse(const AllocatableStmt & x)569   void Unparse(const AllocatableStmt &x) { // R829
570     Word("ALLOCATABLE :: "), Walk(x.v, ", ");
571   }
Unparse(const ObjectDecl & x)572   void Unparse(const ObjectDecl &x) { // R830 & R860
573     Walk(std::get<ObjectName>(x.t));
574     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
575     Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
576   }
Unparse(const AsynchronousStmt & x)577   void Unparse(const AsynchronousStmt &x) { // R831
578     Word("ASYNCHRONOUS :: "), Walk(x.v, ", ");
579   }
Unparse(const BindStmt & x)580   void Unparse(const BindStmt &x) { // R832
581     Walk(x.t, " :: ");
582   }
Unparse(const BindEntity & x)583   void Unparse(const BindEntity &x) { // R833
584     bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common};
585     const char *slash{isCommon ? "/" : ""};
586     Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
587   }
Unparse(const CodimensionStmt & x)588   void Unparse(const CodimensionStmt &x) { // R834
589     Word("CODIMENSION :: "), Walk(x.v, ", ");
590   }
Unparse(const CodimensionDecl & x)591   void Unparse(const CodimensionDecl &x) { // R835
592     Walk(std::get<Name>(x.t));
593     Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']');
594   }
Unparse(const ContiguousStmt & x)595   void Unparse(const ContiguousStmt &x) { // R836
596     Word("CONTIGUOUS :: "), Walk(x.v, ", ");
597   }
Unparse(const DataStmt & x)598   void Unparse(const DataStmt &x) { // R837
599     Word("DATA "), Walk(x.v, ", ");
600   }
Unparse(const DataStmtSet & x)601   void Unparse(const DataStmtSet &x) { // R838
602     Walk(std::get<std::list<DataStmtObject>>(x.t), ", ");
603     Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/');
604   }
Unparse(const DataImpliedDo & x)605   void Unparse(const DataImpliedDo &x) { // R840, R842
606     Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');
607     Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
608     Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')');
609   }
Unparse(const DataStmtValue & x)610   void Unparse(const DataStmtValue &x) { // R843
611     Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");
612     Walk(std::get<DataStmtConstant>(x.t));
613   }
Unparse(const DimensionStmt & x)614   void Unparse(const DimensionStmt &x) { // R848
615     Word("DIMENSION :: "), Walk(x.v, ", ");
616   }
Unparse(const DimensionStmt::Declaration & x)617   void Unparse(const DimensionStmt::Declaration &x) {
618     Walk(std::get<Name>(x.t));
619     Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')');
620   }
Unparse(const IntentStmt & x)621   void Unparse(const IntentStmt &x) { // R849
622     Walk(x.t, " :: ");
623   }
Unparse(const OptionalStmt & x)624   void Unparse(const OptionalStmt &x) { // R850
625     Word("OPTIONAL :: "), Walk(x.v, ", ");
626   }
Unparse(const ParameterStmt & x)627   void Unparse(const ParameterStmt &x) { // R851
628     Word("PARAMETER("), Walk(x.v, ", "), Put(')');
629   }
Unparse(const NamedConstantDef & x)630   void Unparse(const NamedConstantDef &x) { // R852
631     Walk(x.t, "=");
632   }
Unparse(const PointerStmt & x)633   void Unparse(const PointerStmt &x) { // R853
634     Word("POINTER :: "), Walk(x.v, ", ");
635   }
Unparse(const PointerDecl & x)636   void Unparse(const PointerDecl &x) { // R854
637     Walk(std::get<Name>(x.t));
638     Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")");
639   }
Unparse(const ProtectedStmt & x)640   void Unparse(const ProtectedStmt &x) { // R855
641     Word("PROTECTED :: "), Walk(x.v, ", ");
642   }
Unparse(const SaveStmt & x)643   void Unparse(const SaveStmt &x) { // R856
644     Word("SAVE"), Walk(" :: ", x.v, ", ");
645   }
Unparse(const SavedEntity & x)646   void Unparse(const SavedEntity &x) { // R857, R858
647     bool isCommon{
648         std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common};
649     const char *slash{isCommon ? "/" : ""};
650     Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
651   }
Unparse(const TargetStmt & x)652   void Unparse(const TargetStmt &x) { // R859
653     Word("TARGET :: "), Walk(x.v, ", ");
654   }
Unparse(const ValueStmt & x)655   void Unparse(const ValueStmt &x) { // R861
656     Word("VALUE :: "), Walk(x.v, ", ");
657   }
Unparse(const VolatileStmt & x)658   void Unparse(const VolatileStmt &x) { // R862
659     Word("VOLATILE :: "), Walk(x.v, ", ");
660   }
Unparse(const ImplicitStmt & x)661   void Unparse(const ImplicitStmt &x) { // R863
662     Word("IMPLICIT ");
663     std::visit(common::visitors{
664                    [&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); },
665                    [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) {
666                      Word("NONE"), Walk(" (", y, ", ", ")");
667                    },
668                },
669         x.u);
670   }
Unparse(const ImplicitSpec & x)671   void Unparse(const ImplicitSpec &x) { // R864
672     Walk(std::get<DeclarationTypeSpec>(x.t));
673     Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')');
674   }
Unparse(const LetterSpec & x)675   void Unparse(const LetterSpec &x) { // R865
676     Put(*std::get<const char *>(x.t));
677     auto second{std::get<std::optional<const char *>>(x.t)};
678     if (second) {
679       Put('-'), Put(**second);
680     }
681   }
Unparse(const ImportStmt & x)682   void Unparse(const ImportStmt &x) { // R867
683     Word("IMPORT");
684     switch (x.kind) {
685     case common::ImportKind::Default:
686       Walk(" :: ", x.names, ", ");
687       break;
688     case common::ImportKind::Only:
689       Put(", "), Word("ONLY: ");
690       Walk(x.names, ", ");
691       break;
692     case common::ImportKind::None:
693       Word(", NONE");
694       break;
695     case common::ImportKind::All:
696       Word(", ALL");
697       break;
698     }
699   }
Unparse(const NamelistStmt & x)700   void Unparse(const NamelistStmt &x) { // R868
701     Word("NAMELIST"), Walk(x.v, ", ");
702   }
Unparse(const NamelistStmt::Group & x)703   void Unparse(const NamelistStmt::Group &x) {
704     Put('/'), Walk(std::get<Name>(x.t)), Put('/');
705     Walk(std::get<std::list<Name>>(x.t), ", ");
706   }
Unparse(const EquivalenceStmt & x)707   void Unparse(const EquivalenceStmt &x) { // R870, R871
708     Word("EQUIVALENCE");
709     const char *separator{" "};
710     for (const std::list<EquivalenceObject> &y : x.v) {
711       Put(separator), Put('('), Walk(y), Put(')');
712       separator = ", ";
713     }
714   }
Unparse(const CommonStmt & x)715   void Unparse(const CommonStmt &x) { // R873
716     Word("COMMON ");
717     Walk(x.blocks);
718   }
Unparse(const CommonBlockObject & x)719   void Unparse(const CommonBlockObject &x) { // R874
720     Walk(std::get<Name>(x.t));
721     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
722   }
Unparse(const CommonStmt::Block & x)723   void Unparse(const CommonStmt::Block &x) {
724     Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/");
725     Walk(std::get<std::list<CommonBlockObject>>(x.t));
726   }
727 
Unparse(const Substring & x)728   void Unparse(const Substring &x) { // R908, R909
729     Walk(std::get<DataRef>(x.t));
730     Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
731   }
Unparse(const CharLiteralConstantSubstring & x)732   void Unparse(const CharLiteralConstantSubstring &x) {
733     Walk(std::get<CharLiteralConstant>(x.t));
734     Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
735   }
Unparse(const SubstringRange & x)736   void Unparse(const SubstringRange &x) { // R910
737     Walk(x.t, ":");
738   }
Unparse(const PartRef & x)739   void Unparse(const PartRef &x) { // R912
740     Walk(x.name);
741     Walk("(", x.subscripts, ",", ")");
742     Walk(x.imageSelector);
743   }
Unparse(const StructureComponent & x)744   void Unparse(const StructureComponent &x) { // R913
745     Walk(x.base);
746     if (structureComponents_.find(x.component.source) !=
747         structureComponents_.end()) {
748       Put('.');
749     } else {
750       Put('%');
751     }
752     Walk(x.component);
753   }
Unparse(const ArrayElement & x)754   void Unparse(const ArrayElement &x) { // R917
755     Walk(x.base);
756     Put('('), Walk(x.subscripts, ","), Put(')');
757   }
Unparse(const SubscriptTriplet & x)758   void Unparse(const SubscriptTriplet &x) { // R921
759     Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
760     Walk(":", std::get<2>(x.t));
761   }
Unparse(const ImageSelector & x)762   void Unparse(const ImageSelector &x) { // R924
763     Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ",");
764     Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']');
765   }
Before(const ImageSelectorSpec::Stat &)766   void Before(const ImageSelectorSpec::Stat &) { // R926
767     Word("STAT=");
768   }
Before(const ImageSelectorSpec::Team_Number &)769   void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); }
Before(const ImageSelectorSpec & x)770   void Before(const ImageSelectorSpec &x) {
771     if (std::holds_alternative<TeamValue>(x.u)) {
772       Word("TEAM=");
773     }
774   }
Unparse(const AllocateStmt & x)775   void Unparse(const AllocateStmt &x) { // R927
776     Word("ALLOCATE(");
777     Walk(std::get<std::optional<TypeSpec>>(x.t), "::");
778     Walk(std::get<std::list<Allocation>>(x.t), ", ");
779     Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')');
780   }
Before(const AllocOpt & x)781   void Before(const AllocOpt &x) { // R928, R931
782     std::visit(common::visitors{
783                    [&](const AllocOpt::Mold &) { Word("MOLD="); },
784                    [&](const AllocOpt::Source &) { Word("SOURCE="); },
785                    [](const StatOrErrmsg &) {},
786                },
787         x.u);
788   }
Unparse(const Allocation & x)789   void Unparse(const Allocation &x) { // R932
790     Walk(std::get<AllocateObject>(x.t));
791     Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")");
792     Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]");
793   }
Unparse(const AllocateShapeSpec & x)794   void Unparse(const AllocateShapeSpec &x) { // R934 & R938
795     Walk(std::get<std::optional<BoundExpr>>(x.t), ":");
796     Walk(std::get<BoundExpr>(x.t));
797   }
Unparse(const AllocateCoarraySpec & x)798   void Unparse(const AllocateCoarraySpec &x) { // R937
799     Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ",");
800     Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*');
801   }
Unparse(const NullifyStmt & x)802   void Unparse(const NullifyStmt &x) { // R939
803     Word("NULLIFY("), Walk(x.v, ", "), Put(')');
804   }
Unparse(const DeallocateStmt & x)805   void Unparse(const DeallocateStmt &x) { // R941
806     Word("DEALLOCATE(");
807     Walk(std::get<std::list<AllocateObject>>(x.t), ", ");
808     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
809   }
Before(const StatOrErrmsg & x)810   void Before(const StatOrErrmsg &x) { // R942 & R1165
811     std::visit(common::visitors{
812                    [&](const StatVariable &) { Word("STAT="); },
813                    [&](const MsgVariable &) { Word("ERRMSG="); },
814                },
815         x.u);
816   }
817 
818   // R1001 - R1022
Pre(const Expr & x)819   bool Pre(const Expr &x) {
820     if (asFortran_ && x.typedExpr) {
821       // Format the expression representation from semantics
822       asFortran_->expr(out_, *x.typedExpr);
823       return false;
824     } else {
825       return true;
826     }
827   }
Unparse(const Expr::Parentheses & x)828   void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); }
Before(const Expr::UnaryPlus &)829   void Before(const Expr::UnaryPlus &) { Put("+"); }
Before(const Expr::Negate &)830   void Before(const Expr::Negate &) { Put("-"); }
Before(const Expr::NOT &)831   void Before(const Expr::NOT &) { Word(".NOT."); }
Unparse(const Expr::PercentLoc & x)832   void Unparse(const Expr::PercentLoc &x) {
833     Word("%LOC("), Walk(x.v), Put(')');
834   }
Unparse(const Expr::Power & x)835   void Unparse(const Expr::Power &x) { Walk(x.t, "**"); }
Unparse(const Expr::Multiply & x)836   void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); }
Unparse(const Expr::Divide & x)837   void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); }
Unparse(const Expr::Add & x)838   void Unparse(const Expr::Add &x) { Walk(x.t, "+"); }
Unparse(const Expr::Subtract & x)839   void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); }
Unparse(const Expr::Concat & x)840   void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); }
Unparse(const Expr::LT & x)841   void Unparse(const Expr::LT &x) { Walk(x.t, "<"); }
Unparse(const Expr::LE & x)842   void Unparse(const Expr::LE &x) { Walk(x.t, "<="); }
Unparse(const Expr::EQ & x)843   void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); }
Unparse(const Expr::NE & x)844   void Unparse(const Expr::NE &x) { Walk(x.t, "/="); }
Unparse(const Expr::GE & x)845   void Unparse(const Expr::GE &x) { Walk(x.t, ">="); }
Unparse(const Expr::GT & x)846   void Unparse(const Expr::GT &x) { Walk(x.t, ">"); }
Unparse(const Expr::AND & x)847   void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); }
Unparse(const Expr::OR & x)848   void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); }
Unparse(const Expr::EQV & x)849   void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); }
Unparse(const Expr::NEQV & x)850   void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); }
Unparse(const Expr::ComplexConstructor & x)851   void Unparse(const Expr::ComplexConstructor &x) {
852     Put('('), Walk(x.t, ","), Put(')');
853   }
Unparse(const Expr::DefinedBinary & x)854   void Unparse(const Expr::DefinedBinary &x) {
855     Walk(std::get<1>(x.t)); // left
856     Walk(std::get<DefinedOpName>(x.t));
857     Walk(std::get<2>(x.t)); // right
858   }
Unparse(const DefinedOpName & x)859   void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415
860     Walk(x.v);
861   }
Unparse(const AssignmentStmt & x)862   void Unparse(const AssignmentStmt &x) { // R1032
863     if (asFortran_ && x.typedAssignment.get()) {
864       Put(' ');
865       asFortran_->assignment(out_, *x.typedAssignment);
866       Put('\n');
867     } else {
868       Walk(x.t, " = ");
869     }
870   }
Unparse(const PointerAssignmentStmt & x)871   void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038
872     if (asFortran_ && x.typedAssignment.get()) {
873       Put(' ');
874       asFortran_->assignment(out_, *x.typedAssignment);
875       Put('\n');
876     } else {
877       Walk(std::get<DataRef>(x.t));
878       std::visit(
879           common::visitors{
880               [&](const std::list<BoundsRemapping> &y) {
881                 Put('('), Walk(y), Put(')');
882               },
883               [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); },
884           },
885           std::get<PointerAssignmentStmt::Bounds>(x.t).u);
886       Put(" => "), Walk(std::get<Expr>(x.t));
887     }
888   }
Post(const BoundsSpec &)889   void Post(const BoundsSpec &) { // R1035
890     Put(':');
891   }
Unparse(const BoundsRemapping & x)892   void Unparse(const BoundsRemapping &x) { // R1036
893     Walk(x.t, ":");
894   }
Unparse(const WhereStmt & x)895   void Unparse(const WhereStmt &x) { // R1041, R1045, R1046
896     Word("WHERE ("), Walk(x.t, ") ");
897   }
Unparse(const WhereConstructStmt & x)898   void Unparse(const WhereConstructStmt &x) { // R1043
899     Walk(std::get<std::optional<Name>>(x.t), ": ");
900     Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
901     Indent();
902   }
Unparse(const MaskedElsewhereStmt & x)903   void Unparse(const MaskedElsewhereStmt &x) { // R1047
904     Outdent();
905     Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
906     Walk(" ", std::get<std::optional<Name>>(x.t));
907     Indent();
908   }
Unparse(const ElsewhereStmt & x)909   void Unparse(const ElsewhereStmt &x) { // R1048
910     Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent();
911   }
Unparse(const EndWhereStmt & x)912   void Unparse(const EndWhereStmt &x) { // R1049
913     Outdent(), Word("END WHERE"), Walk(" ", x.v);
914   }
Unparse(const ForallConstructStmt & x)915   void Unparse(const ForallConstructStmt &x) { // R1051
916     Walk(std::get<std::optional<Name>>(x.t), ": ");
917     Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t));
918     Indent();
919   }
Unparse(const EndForallStmt & x)920   void Unparse(const EndForallStmt &x) { // R1054
921     Outdent(), Word("END FORALL"), Walk(" ", x.v);
922   }
Before(const ForallStmt &)923   void Before(const ForallStmt &) { // R1055
924     Word("FORALL");
925   }
926 
Unparse(const AssociateStmt & x)927   void Unparse(const AssociateStmt &x) { // R1103
928     Walk(std::get<std::optional<Name>>(x.t), ": ");
929     Word("ASSOCIATE (");
930     Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent();
931   }
Unparse(const Association & x)932   void Unparse(const Association &x) { // R1104
933     Walk(x.t, " => ");
934   }
Unparse(const EndAssociateStmt & x)935   void Unparse(const EndAssociateStmt &x) { // R1106
936     Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v);
937   }
Unparse(const BlockStmt & x)938   void Unparse(const BlockStmt &x) { // R1108
939     Walk(x.v, ": "), Word("BLOCK"), Indent();
940   }
Unparse(const EndBlockStmt & x)941   void Unparse(const EndBlockStmt &x) { // R1110
942     Outdent(), Word("END BLOCK"), Walk(" ", x.v);
943   }
Unparse(const ChangeTeamStmt & x)944   void Unparse(const ChangeTeamStmt &x) { // R1112
945     Walk(std::get<std::optional<Name>>(x.t), ": ");
946     Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t));
947     Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", ");
948     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
949     Indent();
950   }
Unparse(const CoarrayAssociation & x)951   void Unparse(const CoarrayAssociation &x) { // R1113
952     Walk(x.t, " => ");
953   }
Unparse(const EndChangeTeamStmt & x)954   void Unparse(const EndChangeTeamStmt &x) { // R1114
955     Outdent(), Word("END TEAM (");
956     Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
957     Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t));
958   }
Unparse(const CriticalStmt & x)959   void Unparse(const CriticalStmt &x) { // R1117
960     Walk(std::get<std::optional<Name>>(x.t), ": ");
961     Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
962     Put(')'), Indent();
963   }
Unparse(const EndCriticalStmt & x)964   void Unparse(const EndCriticalStmt &x) { // R1118
965     Outdent(), Word("END CRITICAL"), Walk(" ", x.v);
966   }
Unparse(const DoConstruct & x)967   void Unparse(const DoConstruct &x) { // R1119, R1120
968     Walk(std::get<Statement<NonLabelDoStmt>>(x.t));
969     Indent(), Walk(std::get<Block>(x.t), ""), Outdent();
970     Walk(std::get<Statement<EndDoStmt>>(x.t));
971   }
Unparse(const LabelDoStmt & x)972   void Unparse(const LabelDoStmt &x) { // R1121
973     Walk(std::get<std::optional<Name>>(x.t), ": ");
974     Word("DO "), Walk(std::get<Label>(x.t));
975     Walk(" ", std::get<std::optional<LoopControl>>(x.t));
976   }
Unparse(const NonLabelDoStmt & x)977   void Unparse(const NonLabelDoStmt &x) { // R1122
978     Walk(std::get<std::optional<Name>>(x.t), ": ");
979     Word("DO "), Walk(std::get<std::optional<LoopControl>>(x.t));
980   }
Unparse(const LoopControl & x)981   void Unparse(const LoopControl &x) { // R1123
982     std::visit(common::visitors{
983                    [&](const ScalarLogicalExpr &y) {
984                      Word("WHILE ("), Walk(y), Put(')');
985                    },
986                    [&](const auto &y) { Walk(y); },
987                },
988         x.u);
989   }
Unparse(const ConcurrentHeader & x)990   void Unparse(const ConcurrentHeader &x) { // R1125
991     Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
992     Walk(std::get<std::list<ConcurrentControl>>(x.t), ", ");
993     Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')');
994   }
Unparse(const ConcurrentControl & x)995   void Unparse(const ConcurrentControl &x) { // R1126 - R1128
996     Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t));
997     Put(':'), Walk(std::get<2>(x.t));
998     Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
999   }
Before(const LoopControl::Concurrent &)1000   void Before(const LoopControl::Concurrent &) { // R1129
1001     Word("CONCURRENT");
1002   }
Unparse(const LocalitySpec::Local & x)1003   void Unparse(const LocalitySpec::Local &x) {
1004     Word("LOCAL("), Walk(x.v, ", "), Put(')');
1005   }
Unparse(const LocalitySpec::LocalInit & x)1006   void Unparse(const LocalitySpec::LocalInit &x) {
1007     Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')');
1008   }
Unparse(const LocalitySpec::Shared & x)1009   void Unparse(const LocalitySpec::Shared &x) {
1010     Word("SHARED("), Walk(x.v, ", "), Put(')');
1011   }
Post(const LocalitySpec::DefaultNone &)1012   void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); }
Unparse(const EndDoStmt & x)1013   void Unparse(const EndDoStmt &x) { // R1132
1014     Word("END DO"), Walk(" ", x.v);
1015   }
Unparse(const CycleStmt & x)1016   void Unparse(const CycleStmt &x) { // R1133
1017     Word("CYCLE"), Walk(" ", x.v);
1018   }
Unparse(const IfThenStmt & x)1019   void Unparse(const IfThenStmt &x) { // R1135
1020     Walk(std::get<std::optional<Name>>(x.t), ": ");
1021     Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t));
1022     Put(") "), Word("THEN"), Indent();
1023   }
Unparse(const ElseIfStmt & x)1024   void Unparse(const ElseIfStmt &x) { // R1136
1025     Outdent(), Word("ELSE IF (");
1026     Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN");
1027     Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1028   }
Unparse(const ElseStmt & x)1029   void Unparse(const ElseStmt &x) { // R1137
1030     Outdent(), Word("ELSE"), Walk(" ", x.v), Indent();
1031   }
Unparse(const EndIfStmt & x)1032   void Unparse(const EndIfStmt &x) { // R1138
1033     Outdent(), Word("END IF"), Walk(" ", x.v);
1034   }
Unparse(const IfStmt & x)1035   void Unparse(const IfStmt &x) { // R1139
1036     Word("IF ("), Walk(x.t, ") ");
1037   }
Unparse(const SelectCaseStmt & x)1038   void Unparse(const SelectCaseStmt &x) { // R1141, R1144
1039     Walk(std::get<std::optional<Name>>(x.t), ": ");
1040     Word("SELECT CASE (");
1041     Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent();
1042   }
Unparse(const CaseStmt & x)1043   void Unparse(const CaseStmt &x) { // R1142
1044     Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t));
1045     Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1046   }
Unparse(const EndSelectStmt & x)1047   void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R1155
1048     Outdent(), Word("END SELECT"), Walk(" ", x.v);
1049   }
Unparse(const CaseSelector & x)1050   void Unparse(const CaseSelector &x) { // R1145
1051     std::visit(common::visitors{
1052                    [&](const std::list<CaseValueRange> &y) {
1053                      Put('('), Walk(y), Put(')');
1054                    },
1055                    [&](const Default &) { Word("DEFAULT"); },
1056                },
1057         x.u);
1058   }
Unparse(const CaseValueRange::Range & x)1059   void Unparse(const CaseValueRange::Range &x) { // R1146
1060     Walk(x.lower), Put(':'), Walk(x.upper);
1061   }
Unparse(const SelectRankStmt & x)1062   void Unparse(const SelectRankStmt &x) { // R1149
1063     Walk(std::get<0>(x.t), ": ");
1064     Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => ");
1065     Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1066   }
Unparse(const SelectRankCaseStmt & x)1067   void Unparse(const SelectRankCaseStmt &x) { // R1150
1068     Outdent(), Word("RANK ");
1069     std::visit(common::visitors{
1070                    [&](const ScalarIntConstantExpr &y) {
1071                      Put('('), Walk(y), Put(')');
1072                    },
1073                    [&](const Star &) { Put("(*)"); },
1074                    [&](const Default &) { Word("DEFAULT"); },
1075                },
1076         std::get<SelectRankCaseStmt::Rank>(x.t).u);
1077     Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1078   }
Unparse(const SelectTypeStmt & x)1079   void Unparse(const SelectTypeStmt &x) { // R1153
1080     Walk(std::get<0>(x.t), ": ");
1081     Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => ");
1082     Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1083   }
Unparse(const TypeGuardStmt & x)1084   void Unparse(const TypeGuardStmt &x) { // R1154
1085     Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t));
1086     Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1087   }
Unparse(const TypeGuardStmt::Guard & x)1088   void Unparse(const TypeGuardStmt::Guard &x) {
1089     std::visit(
1090         common::visitors{
1091             [&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); },
1092             [&](const DerivedTypeSpec &y) {
1093               Word("CLASS IS ("), Walk(y), Put(')');
1094             },
1095             [&](const Default &) { Word("CLASS DEFAULT"); },
1096         },
1097         x.u);
1098   }
Unparse(const ExitStmt & x)1099   void Unparse(const ExitStmt &x) { // R1156
1100     Word("EXIT"), Walk(" ", x.v);
1101   }
Before(const GotoStmt &)1102   void Before(const GotoStmt &) { // R1157
1103     Word("GO TO ");
1104   }
Unparse(const ComputedGotoStmt & x)1105   void Unparse(const ComputedGotoStmt &x) { // R1158
1106     Word("GO TO ("), Walk(x.t, "), ");
1107   }
Unparse(const ContinueStmt &)1108   void Unparse(const ContinueStmt &) { // R1159
1109     Word("CONTINUE");
1110   }
Unparse(const StopStmt & x)1111   void Unparse(const StopStmt &x) { // R1160, R1161
1112     if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) {
1113       Word("ERROR ");
1114     }
1115     Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t));
1116     Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t));
1117   }
Unparse(const FailImageStmt &)1118   void Unparse(const FailImageStmt &) { // R1163
1119     Word("FAIL IMAGE");
1120   }
Unparse(const SyncAllStmt & x)1121   void Unparse(const SyncAllStmt &x) { // R1164
1122     Word("SYNC ALL ("), Walk(x.v, ", "), Put(')');
1123   }
Unparse(const SyncImagesStmt & x)1124   void Unparse(const SyncImagesStmt &x) { // R1166
1125     Word("SYNC IMAGES (");
1126     Walk(std::get<SyncImagesStmt::ImageSet>(x.t));
1127     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1128   }
Unparse(const SyncMemoryStmt & x)1129   void Unparse(const SyncMemoryStmt &x) { // R1168
1130     Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')');
1131   }
Unparse(const SyncTeamStmt & x)1132   void Unparse(const SyncTeamStmt &x) { // R1169
1133     Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t));
1134     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1135   }
Unparse(const EventPostStmt & x)1136   void Unparse(const EventPostStmt &x) { // R1170
1137     Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t));
1138     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1139   }
Before(const EventWaitStmt::EventWaitSpec & x)1140   void Before(const EventWaitStmt::EventWaitSpec &x) { // R1173, R1174
1141     std::visit(common::visitors{
1142                    [&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); },
1143                    [](const StatOrErrmsg &) {},
1144                },
1145         x.u);
1146   }
Unparse(const EventWaitStmt & x)1147   void Unparse(const EventWaitStmt &x) { // R1170
1148     Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t));
1149     Walk(", ", std::get<std::list<EventWaitStmt::EventWaitSpec>>(x.t), ", ");
1150     Put(')');
1151   }
Unparse(const FormTeamStmt & x)1152   void Unparse(const FormTeamStmt &x) { // R1175, R1177
1153     Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));
1154     Put(','), Walk(std::get<TeamVariable>(x.t));
1155     Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");
1156     Put(')');
1157   }
Before(const FormTeamStmt::FormTeamSpec & x)1158   void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1178
1159     std::visit(common::visitors{
1160                    [&](const ScalarIntExpr &) { Word("NEW_INDEX="); },
1161                    [](const StatOrErrmsg &) {},
1162                },
1163         x.u);
1164   }
Unparse(const LockStmt & x)1165   void Unparse(const LockStmt &x) { // R1179
1166     Word("LOCK ("), Walk(std::get<LockVariable>(x.t));
1167     Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");
1168     Put(')');
1169   }
Before(const LockStmt::LockStat & x)1170   void Before(const LockStmt::LockStat &x) { // R1180
1171     std::visit(
1172         common::visitors{
1173             [&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },
1174             [](const StatOrErrmsg &) {},
1175         },
1176         x.u);
1177   }
Unparse(const UnlockStmt & x)1178   void Unparse(const UnlockStmt &x) { // R1181
1179     Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));
1180     Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");
1181     Put(')');
1182   }
1183 
Unparse(const OpenStmt & x)1184   void Unparse(const OpenStmt &x) { // R1204
1185     Word("OPEN ("), Walk(x.v, ", "), Put(')');
1186   }
Pre(const ConnectSpec & x)1187   bool Pre(const ConnectSpec &x) { // R1205
1188     return std::visit(common::visitors{
1189                           [&](const FileUnitNumber &) {
1190                             Word("UNIT=");
1191                             return true;
1192                           },
1193                           [&](const FileNameExpr &) {
1194                             Word("FILE=");
1195                             return true;
1196                           },
1197                           [&](const ConnectSpec::CharExpr &y) {
1198                             Walk(y.t, "=");
1199                             return false;
1200                           },
1201                           [&](const MsgVariable &) {
1202                             Word("IOMSG=");
1203                             return true;
1204                           },
1205                           [&](const StatVariable &) {
1206                             Word("IOSTAT=");
1207                             return true;
1208                           },
1209                           [&](const ConnectSpec::Recl &) {
1210                             Word("RECL=");
1211                             return true;
1212                           },
1213                           [&](const ConnectSpec::Newunit &) {
1214                             Word("NEWUNIT=");
1215                             return true;
1216                           },
1217                           [&](const ErrLabel &) {
1218                             Word("ERR=");
1219                             return true;
1220                           },
1221                           [&](const StatusExpr &) {
1222                             Word("STATUS=");
1223                             return true;
1224                           },
1225                       },
1226         x.u);
1227   }
Unparse(const CloseStmt & x)1228   void Unparse(const CloseStmt &x) { // R1208
1229     Word("CLOSE ("), Walk(x.v, ", "), Put(')');
1230   }
Before(const CloseStmt::CloseSpec & x)1231   void Before(const CloseStmt::CloseSpec &x) { // R1209
1232     std::visit(common::visitors{
1233                    [&](const FileUnitNumber &) { Word("UNIT="); },
1234                    [&](const StatVariable &) { Word("IOSTAT="); },
1235                    [&](const MsgVariable &) { Word("IOMSG="); },
1236                    [&](const ErrLabel &) { Word("ERR="); },
1237                    [&](const StatusExpr &) { Word("STATUS="); },
1238                },
1239         x.u);
1240   }
Unparse(const ReadStmt & x)1241   void Unparse(const ReadStmt &x) { // R1210
1242     Word("READ ");
1243     if (x.iounit) {
1244       Put('('), Walk(x.iounit);
1245       if (x.format) {
1246         Put(", "), Walk(x.format);
1247       }
1248       Walk(", ", x.controls, ", ");
1249       Put(')');
1250     } else if (x.format) {
1251       Walk(x.format);
1252       if (!x.items.empty()) {
1253         Put(", ");
1254       }
1255     } else {
1256       Put('('), Walk(x.controls, ", "), Put(')');
1257     }
1258     Walk(" ", x.items, ", ");
1259   }
Unparse(const WriteStmt & x)1260   void Unparse(const WriteStmt &x) { // R1211
1261     Word("WRITE (");
1262     if (x.iounit) {
1263       Walk(x.iounit);
1264       if (x.format) {
1265         Put(", "), Walk(x.format);
1266       }
1267       Walk(", ", x.controls, ", ");
1268     } else {
1269       Walk(x.controls, ", ");
1270     }
1271     Put(')'), Walk(" ", x.items, ", ");
1272   }
Unparse(const PrintStmt & x)1273   void Unparse(const PrintStmt &x) { // R1212
1274     Word("PRINT "), Walk(std::get<Format>(x.t));
1275     Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");
1276   }
Pre(const IoControlSpec & x)1277   bool Pre(const IoControlSpec &x) { // R1213
1278     return std::visit(common::visitors{
1279                           [&](const IoUnit &) {
1280                             Word("UNIT=");
1281                             return true;
1282                           },
1283                           [&](const Format &) {
1284                             Word("FMT=");
1285                             return true;
1286                           },
1287                           [&](const Name &) {
1288                             Word("NML=");
1289                             return true;
1290                           },
1291                           [&](const IoControlSpec::CharExpr &y) {
1292                             Walk(y.t, "=");
1293                             return false;
1294                           },
1295                           [&](const IoControlSpec::Asynchronous &) {
1296                             Word("ASYNCHRONOUS=");
1297                             return true;
1298                           },
1299                           [&](const EndLabel &) {
1300                             Word("END=");
1301                             return true;
1302                           },
1303                           [&](const EorLabel &) {
1304                             Word("EOR=");
1305                             return true;
1306                           },
1307                           [&](const ErrLabel &) {
1308                             Word("ERR=");
1309                             return true;
1310                           },
1311                           [&](const IdVariable &) {
1312                             Word("ID=");
1313                             return true;
1314                           },
1315                           [&](const MsgVariable &) {
1316                             Word("IOMSG=");
1317                             return true;
1318                           },
1319                           [&](const StatVariable &) {
1320                             Word("IOSTAT=");
1321                             return true;
1322                           },
1323                           [&](const IoControlSpec::Pos &) {
1324                             Word("POS=");
1325                             return true;
1326                           },
1327                           [&](const IoControlSpec::Rec &) {
1328                             Word("REC=");
1329                             return true;
1330                           },
1331                           [&](const IoControlSpec::Size &) {
1332                             Word("SIZE=");
1333                             return true;
1334                           },
1335                       },
1336         x.u);
1337   }
Unparse(const InputImpliedDo & x)1338   void Unparse(const InputImpliedDo &x) { // R1218
1339     Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");
1340     Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1341   }
Unparse(const OutputImpliedDo & x)1342   void Unparse(const OutputImpliedDo &x) { // R1219
1343     Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");
1344     Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1345   }
Unparse(const WaitStmt & x)1346   void Unparse(const WaitStmt &x) { // R1222
1347     Word("WAIT ("), Walk(x.v, ", "), Put(')');
1348   }
Before(const WaitSpec & x)1349   void Before(const WaitSpec &x) { // R1223
1350     std::visit(common::visitors{
1351                    [&](const FileUnitNumber &) { Word("UNIT="); },
1352                    [&](const EndLabel &) { Word("END="); },
1353                    [&](const EorLabel &) { Word("EOR="); },
1354                    [&](const ErrLabel &) { Word("ERR="); },
1355                    [&](const IdExpr &) { Word("ID="); },
1356                    [&](const MsgVariable &) { Word("IOMSG="); },
1357                    [&](const StatVariable &) { Word("IOSTAT="); },
1358                },
1359         x.u);
1360   }
Unparse(const BackspaceStmt & x)1361   void Unparse(const BackspaceStmt &x) { // R1224
1362     Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');
1363   }
Unparse(const EndfileStmt & x)1364   void Unparse(const EndfileStmt &x) { // R1225
1365     Word("ENDFILE ("), Walk(x.v, ", "), Put(')');
1366   }
Unparse(const RewindStmt & x)1367   void Unparse(const RewindStmt &x) { // R1226
1368     Word("REWIND ("), Walk(x.v, ", "), Put(')');
1369   }
Before(const PositionOrFlushSpec & x)1370   void Before(const PositionOrFlushSpec &x) { // R1227 & R1229
1371     std::visit(common::visitors{
1372                    [&](const FileUnitNumber &) { Word("UNIT="); },
1373                    [&](const MsgVariable &) { Word("IOMSG="); },
1374                    [&](const StatVariable &) { Word("IOSTAT="); },
1375                    [&](const ErrLabel &) { Word("ERR="); },
1376                },
1377         x.u);
1378   }
Unparse(const FlushStmt & x)1379   void Unparse(const FlushStmt &x) { // R1228
1380     Word("FLUSH ("), Walk(x.v, ", "), Put(')');
1381   }
Unparse(const InquireStmt & x)1382   void Unparse(const InquireStmt &x) { // R1230
1383     Word("INQUIRE (");
1384     std::visit(
1385         common::visitors{
1386             [&](const InquireStmt::Iolength &y) {
1387               Word("IOLENGTH="), Walk(y.t, ") ");
1388             },
1389             [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); },
1390         },
1391         x.u);
1392   }
Pre(const InquireSpec & x)1393   bool Pre(const InquireSpec &x) { // R1231
1394     return std::visit(common::visitors{
1395                           [&](const FileUnitNumber &) {
1396                             Word("UNIT=");
1397                             return true;
1398                           },
1399                           [&](const FileNameExpr &) {
1400                             Word("FILE=");
1401                             return true;
1402                           },
1403                           [&](const InquireSpec::CharVar &y) {
1404                             Walk(y.t, "=");
1405                             return false;
1406                           },
1407                           [&](const InquireSpec::IntVar &y) {
1408                             Walk(y.t, "=");
1409                             return false;
1410                           },
1411                           [&](const InquireSpec::LogVar &y) {
1412                             Walk(y.t, "=");
1413                             return false;
1414                           },
1415                           [&](const IdExpr &) {
1416                             Word("ID=");
1417                             return true;
1418                           },
1419                           [&](const ErrLabel &) {
1420                             Word("ERR=");
1421                             return true;
1422                           },
1423                       },
1424         x.u);
1425   }
1426 
Before(const FormatStmt &)1427   void Before(const FormatStmt &) { // R1301
1428     Word("FORMAT");
1429   }
Unparse(const format::FormatSpecification & x)1430   void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R1305
1431     Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");
1432     Walk("*(", x.unlimitedItems, ",", ")"), Put(')');
1433   }
Unparse(const format::FormatItem & x)1434   void Unparse(const format::FormatItem &x) { // R1304, R1306, R1321
1435     if (x.repeatCount) {
1436       Walk(*x.repeatCount);
1437     }
1438     std::visit(common::visitors{
1439                    [&](const std::string &y) { PutNormalized(y); },
1440                    [&](const std::list<format::FormatItem> &y) {
1441                      Walk("(", y, ",", ")");
1442                    },
1443                    [&](const auto &y) { Walk(y); },
1444                },
1445         x.u);
1446   }
Unparse(const format::IntrinsicTypeDataEditDesc & x)1447   void Unparse(
1448       const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311
1449     switch (x.kind) {
1450 #define FMT(x) \
1451   case format::IntrinsicTypeDataEditDesc::Kind::x: \
1452     Put(#x); \
1453     break
1454       FMT(I);
1455       FMT(B);
1456       FMT(O);
1457       FMT(Z);
1458       FMT(F);
1459       FMT(E);
1460       FMT(EN);
1461       FMT(ES);
1462       FMT(EX);
1463       FMT(G);
1464       FMT(L);
1465       FMT(A);
1466       FMT(D);
1467 #undef FMT
1468     }
1469     Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);
1470   }
Unparse(const format::DerivedTypeDataEditDesc & x)1471   void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312
1472     Word("DT");
1473     if (!x.type.empty()) {
1474       Put('"'), Put(x.type), Put('"');
1475     }
1476     Walk("(", x.parameters, ",", ")");
1477   }
Unparse(const format::ControlEditDesc & x)1478   void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R1320
1479     switch (x.kind) {
1480     case format::ControlEditDesc::Kind::T:
1481       Word("T");
1482       Walk(x.count);
1483       break;
1484     case format::ControlEditDesc::Kind::TL:
1485       Word("TL");
1486       Walk(x.count);
1487       break;
1488     case format::ControlEditDesc::Kind::TR:
1489       Word("TR");
1490       Walk(x.count);
1491       break;
1492     case format::ControlEditDesc::Kind::X:
1493       if (x.count != 1) {
1494         Walk(x.count);
1495       }
1496       Word("X");
1497       break;
1498     case format::ControlEditDesc::Kind::Slash:
1499       if (x.count != 1) {
1500         Walk(x.count);
1501       }
1502       Put('/');
1503       break;
1504     case format::ControlEditDesc::Kind::Colon:
1505       Put(':');
1506       break;
1507     case format::ControlEditDesc::Kind::P:
1508       Walk(x.count);
1509       Word("P");
1510       break;
1511 #define FMT(x) \
1512   case format::ControlEditDesc::Kind::x: \
1513     Put(#x); \
1514     break
1515       FMT(SS);
1516       FMT(SP);
1517       FMT(S);
1518       FMT(BN);
1519       FMT(BZ);
1520       FMT(RU);
1521       FMT(RD);
1522       FMT(RZ);
1523       FMT(RN);
1524       FMT(RC);
1525       FMT(RP);
1526       FMT(DC);
1527       FMT(DP);
1528 #undef FMT
1529     case format::ControlEditDesc::Kind::Dollar:
1530       Put('$');
1531       break;
1532     case format::ControlEditDesc::Kind::Backslash:
1533       Put('\\');
1534       break;
1535     }
1536   }
1537 
Before(const MainProgram & x)1538   void Before(const MainProgram &x) { // R1401
1539     if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {
1540       Indent();
1541     }
1542   }
Before(const ProgramStmt &)1543   void Before(const ProgramStmt &) { // R1402
1544     Word("PROGRAM "), Indent();
1545   }
Unparse(const EndProgramStmt & x)1546   void Unparse(const EndProgramStmt &x) { // R1403
1547     EndSubprogram("PROGRAM", x.v);
1548   }
Before(const ModuleStmt &)1549   void Before(const ModuleStmt &) { // R1405
1550     Word("MODULE "), Indent();
1551   }
Unparse(const EndModuleStmt & x)1552   void Unparse(const EndModuleStmt &x) { // R1406
1553     EndSubprogram("MODULE", x.v);
1554   }
Unparse(const UseStmt & x)1555   void Unparse(const UseStmt &x) { // R1409
1556     Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);
1557     std::visit(common::visitors{
1558                    [&](const std::list<Rename> &y) { Walk(", ", y, ", "); },
1559                    [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); },
1560                },
1561         x.u);
1562   }
Unparse(const Rename & x)1563   void Unparse(const Rename &x) { // R1411
1564     std::visit(common::visitors{
1565                    [&](const Rename::Names &y) { Walk(y.t, " => "); },
1566                    [&](const Rename::Operators &y) {
1567                      Word("OPERATOR("), Walk(y.t, ") => OPERATOR("), Put(")");
1568                    },
1569                },
1570         x.u);
1571   }
Unparse(const SubmoduleStmt & x)1572   void Unparse(const SubmoduleStmt &x) { // R1417
1573     Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent();
1574   }
Unparse(const ParentIdentifier & x)1575   void Unparse(const ParentIdentifier &x) { // R1418
1576     Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));
1577   }
Unparse(const EndSubmoduleStmt & x)1578   void Unparse(const EndSubmoduleStmt &x) { // R1419
1579     EndSubprogram("SUBMODULE", x.v);
1580   }
Unparse(const BlockDataStmt & x)1581   void Unparse(const BlockDataStmt &x) { // R1421
1582     Word("BLOCK DATA"), Walk(" ", x.v), Indent();
1583   }
Unparse(const EndBlockDataStmt & x)1584   void Unparse(const EndBlockDataStmt &x) { // R1422
1585     EndSubprogram("BLOCK DATA", x.v);
1586   }
1587 
Unparse(const InterfaceStmt & x)1588   void Unparse(const InterfaceStmt &x) { // R1503
1589     std::visit(common::visitors{
1590                    [&](const std::optional<GenericSpec> &y) {
1591                      Word("INTERFACE"), Walk(" ", y);
1592                    },
1593                    [&](const Abstract &) { Word("ABSTRACT INTERFACE"); },
1594                },
1595         x.u);
1596     Indent();
1597   }
Unparse(const EndInterfaceStmt & x)1598   void Unparse(const EndInterfaceStmt &x) { // R1504
1599     Outdent(), Word("END INTERFACE"), Walk(" ", x.v);
1600   }
Unparse(const ProcedureStmt & x)1601   void Unparse(const ProcedureStmt &x) { // R1506
1602     if (std::get<ProcedureStmt::Kind>(x.t) ==
1603         ProcedureStmt::Kind::ModuleProcedure) {
1604       Word("MODULE ");
1605     }
1606     Word("PROCEDURE :: ");
1607     Walk(std::get<std::list<Name>>(x.t), ", ");
1608   }
Before(const GenericSpec & x)1609   void Before(const GenericSpec &x) { // R1508, R1509
1610     std::visit(
1611         common::visitors{
1612             [&](const DefinedOperator &) { Word("OPERATOR("); },
1613             [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },
1614             [&](const GenericSpec::ReadFormatted &) {
1615               Word("READ(FORMATTED)");
1616             },
1617             [&](const GenericSpec::ReadUnformatted &) {
1618               Word("READ(UNFORMATTED)");
1619             },
1620             [&](const GenericSpec::WriteFormatted &) {
1621               Word("WRITE(FORMATTED)");
1622             },
1623             [&](const GenericSpec::WriteUnformatted &) {
1624               Word("WRITE(UNFORMATTED)");
1625             },
1626             [](const auto &) {},
1627         },
1628         x.u);
1629   }
Post(const GenericSpec & x)1630   void Post(const GenericSpec &x) {
1631     std::visit(common::visitors{
1632                    [&](const DefinedOperator &) { Put(')'); },
1633                    [](const auto &) {},
1634                },
1635         x.u);
1636   }
Unparse(const GenericStmt & x)1637   void Unparse(const GenericStmt &x) { // R1510
1638     Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
1639     Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");
1640     Walk(std::get<std::list<Name>>(x.t), ", ");
1641   }
Unparse(const ExternalStmt & x)1642   void Unparse(const ExternalStmt &x) { // R1511
1643     Word("EXTERNAL :: "), Walk(x.v, ", ");
1644   }
Unparse(const ProcedureDeclarationStmt & x)1645   void Unparse(const ProcedureDeclarationStmt &x) { // R1512
1646     Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t));
1647     Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");
1648     Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
1649   }
Unparse(const ProcDecl & x)1650   void Unparse(const ProcDecl &x) { // R1515
1651     Walk(std::get<Name>(x.t));
1652     Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));
1653   }
Unparse(const IntrinsicStmt & x)1654   void Unparse(const IntrinsicStmt &x) { // R1519
1655     Word("INTRINSIC :: "), Walk(x.v, ", ");
1656   }
Unparse(const FunctionReference & x)1657   void Unparse(const FunctionReference &x) { // R1520
1658     Walk(std::get<ProcedureDesignator>(x.v.t));
1659     Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
1660   }
Unparse(const CallStmt & x)1661   void Unparse(const CallStmt &x) { // R1521
1662     if (asFortran_ && x.typedCall.get()) {
1663       Put(' ');
1664       asFortran_->call(out_, *x.typedCall);
1665       Put('\n');
1666     } else {
1667       const auto &pd{std::get<ProcedureDesignator>(x.v.t)};
1668       const auto &args{std::get<std::list<ActualArgSpec>>(x.v.t)};
1669       Word("CALL "), Walk(pd);
1670       if (args.empty()) {
1671         if (std::holds_alternative<ProcComponentRef>(pd.u)) {
1672           Put("()"); // pgf90 crashes on CALL to tbp without parentheses
1673         }
1674       } else {
1675         Walk("(", args, ", ", ")");
1676       }
1677     }
1678   }
Unparse(const ActualArgSpec & x)1679   void Unparse(const ActualArgSpec &x) { // R1523
1680     Walk(std::get<std::optional<Keyword>>(x.t), "=");
1681     Walk(std::get<ActualArg>(x.t));
1682   }
Unparse(const ActualArg::PercentRef & x)1683   void Unparse(const ActualArg::PercentRef &x) { // R1524
1684     Word("%REF("), Walk(x.v), Put(')');
1685   }
Unparse(const ActualArg::PercentVal & x)1686   void Unparse(const ActualArg::PercentVal &x) {
1687     Word("%VAL("), Walk(x.v), Put(')');
1688   }
Before(const AltReturnSpec &)1689   void Before(const AltReturnSpec &) { // R1525
1690     Put('*');
1691   }
Post(const PrefixSpec::Elemental)1692   void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527
Post(const PrefixSpec::Impure)1693   void Post(const PrefixSpec::Impure) { Word("IMPURE"); }
Post(const PrefixSpec::Module)1694   void Post(const PrefixSpec::Module) { Word("MODULE"); }
Post(const PrefixSpec::Non_Recursive)1695   void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }
Post(const PrefixSpec::Pure)1696   void Post(const PrefixSpec::Pure) { Word("PURE"); }
Post(const PrefixSpec::Recursive)1697   void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }
Unparse(const FunctionStmt & x)1698   void Unparse(const FunctionStmt &x) { // R1530
1699     Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1700     Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");
1701     Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');
1702     Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
1703   }
Unparse(const Suffix & x)1704   void Unparse(const Suffix &x) { // R1532
1705     if (x.resultName) {
1706       Word("RESULT("), Walk(x.resultName), Put(')');
1707       Walk(" ", x.binding);
1708     } else {
1709       Walk(x.binding);
1710     }
1711   }
Unparse(const EndFunctionStmt & x)1712   void Unparse(const EndFunctionStmt &x) { // R1533
1713     EndSubprogram("FUNCTION", x.v);
1714   }
Unparse(const SubroutineStmt & x)1715   void Unparse(const SubroutineStmt &x) { // R1535
1716     Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1717     Word("SUBROUTINE "), Walk(std::get<Name>(x.t));
1718     const auto &args{std::get<std::list<DummyArg>>(x.t)};
1719     const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)};
1720     if (args.empty()) {
1721       Walk(" () ", bind);
1722     } else {
1723       Walk(" (", args, ", ", ")");
1724       Walk(" ", bind);
1725     }
1726     Indent();
1727   }
Unparse(const EndSubroutineStmt & x)1728   void Unparse(const EndSubroutineStmt &x) { // R1537
1729     EndSubprogram("SUBROUTINE", x.v);
1730   }
Before(const MpSubprogramStmt &)1731   void Before(const MpSubprogramStmt &) { // R1539
1732     Word("MODULE PROCEDURE "), Indent();
1733   }
Unparse(const EndMpSubprogramStmt & x)1734   void Unparse(const EndMpSubprogramStmt &x) { // R1540
1735     EndSubprogram("PROCEDURE", x.v);
1736   }
Unparse(const EntryStmt & x)1737   void Unparse(const EntryStmt &x) { // R1541
1738     Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("(");
1739     Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")");
1740     Walk(" ", std::get<std::optional<Suffix>>(x.t));
1741   }
Unparse(const ReturnStmt & x)1742   void Unparse(const ReturnStmt &x) { // R1542
1743     Word("RETURN"), Walk(" ", x.v);
1744   }
Unparse(const ContainsStmt &)1745   void Unparse(const ContainsStmt &) { // R1543
1746     Outdent();
1747     Word("CONTAINS");
1748     Indent();
1749   }
Unparse(const StmtFunctionStmt & x)1750   void Unparse(const StmtFunctionStmt &x) { // R1544
1751     Walk(std::get<Name>(x.t)), Put('(');
1752     Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");
1753     Walk(std::get<Scalar<Expr>>(x.t));
1754   }
1755 
1756   // Directives, extensions, and deprecated constructs
Unparse(const CompilerDirective & x)1757   void Unparse(const CompilerDirective &x) {
1758     std::visit(
1759         common::visitors{
1760             [&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {
1761               Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty
1762               Walk(" ", tkr, ", ");
1763             },
1764             [&](const std::list<CompilerDirective::NameValue> &names) {
1765               Walk("!DIR$ ", names, " ");
1766             },
1767         },
1768         x.u);
1769     Put('\n');
1770   }
Unparse(const CompilerDirective::IgnoreTKR & x)1771   void Unparse(const CompilerDirective::IgnoreTKR &x) {
1772     const auto &list{std::get<std::list<const char *>>(x.t)};
1773     if (!list.empty()) {
1774       Put("(");
1775       for (const char *tkr : list) {
1776         Put(*tkr);
1777       }
1778       Put(") ");
1779     }
1780     Walk(std::get<Name>(x.t));
1781   }
Unparse(const CompilerDirective::NameValue & x)1782   void Unparse(const CompilerDirective::NameValue &x) {
1783     Walk(std::get<Name>(x.t));
1784     Walk("=", std::get<std::optional<std::uint64_t>>(x.t));
1785   }
1786 
1787   // OpenACC Directives & Clauses
Unparse(const AccAtomicCapture & x)1788   void Unparse(const AccAtomicCapture &x) {
1789     BeginOpenACC();
1790     Word("!$ACC CAPTURE");
1791     Put("\n");
1792     EndOpenACC();
1793     Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
1794     Put("\n");
1795     Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
1796     BeginOpenACC();
1797     Word("!$ACC END ATOMIC\n");
1798     EndOpenACC();
1799   }
Unparse(const AccAtomicRead & x)1800   void Unparse(const AccAtomicRead &x) {
1801     BeginOpenACC();
1802     Word("!$ACC ATOMIC READ");
1803     Put("\n");
1804     EndOpenACC();
1805     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1806     BeginOpenACC();
1807     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1808     EndOpenACC();
1809   }
Unparse(const AccAtomicWrite & x)1810   void Unparse(const AccAtomicWrite &x) {
1811     BeginOpenACC();
1812     Word("!$ACC ATOMIC WRITE");
1813     Put("\n");
1814     EndOpenACC();
1815     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1816     BeginOpenACC();
1817     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1818     EndOpenACC();
1819   }
Unparse(const AccAtomicUpdate & x)1820   void Unparse(const AccAtomicUpdate &x) {
1821     BeginOpenACC();
1822     Word("!$ACC ATOMIC UPDATE");
1823     Put("\n");
1824     EndOpenACC();
1825     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1826     BeginOpenACC();
1827     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1828     EndOpenACC();
1829   }
Unparse(const llvm::acc::Directive & x)1830   void Unparse(const llvm::acc::Directive &x) {
1831     Word(llvm::acc::getOpenACCDirectiveName(x).str());
1832   }
1833 #define GEN_FLANG_CLAUSE_UNPARSE
1834 #include "llvm/Frontend/OpenACC/ACC.cpp.inc"
Unparse(const AccObjectListWithModifier & x)1835   void Unparse(const AccObjectListWithModifier &x) {
1836     Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
1837     Walk(std::get<AccObjectList>(x.t));
1838   }
Unparse(const AccDataModifier::Modifier & x)1839   void Unparse(const AccDataModifier::Modifier &x) {
1840     Word(AccDataModifier::EnumToString(x));
1841   }
Unparse(const AccDefaultClause & x)1842   void Unparse(const AccDefaultClause &x) {
1843     switch (x.v) {
1844     case AccDefaultClause::Arg::None:
1845       Put("NONE");
1846       break;
1847     case AccDefaultClause::Arg::Present:
1848       Put("PRESENT");
1849       break;
1850     }
1851   }
Unparse(const AccClauseList & x)1852   void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
Unparse(const AccGangArgument & x)1853   void Unparse(const AccGangArgument &x) {
1854     Walk("NUM:", std::get<std::optional<ScalarIntExpr>>(x.t));
1855     Walk(", STATIC:", std::get<std::optional<AccSizeExpr>>(x.t));
1856   }
Unparse(const OpenACCBlockConstruct & x)1857   void Unparse(const OpenACCBlockConstruct &x) {
1858     BeginOpenACC();
1859     Word("!$ACC ");
1860     Walk(std::get<AccBeginBlockDirective>(x.t));
1861     Put("\n");
1862     EndOpenACC();
1863     Walk(std::get<Block>(x.t), "");
1864     BeginOpenACC();
1865     Word("!$ACC END ");
1866     Walk(std::get<AccEndBlockDirective>(x.t));
1867     Put("\n");
1868     EndOpenACC();
1869   }
Unparse(const OpenACCLoopConstruct & x)1870   void Unparse(const OpenACCLoopConstruct &x) {
1871     BeginOpenACC();
1872     Word("!$ACC ");
1873     Walk(std::get<AccBeginLoopDirective>(x.t));
1874     Put("\n");
1875     EndOpenACC();
1876     Walk(std::get<std::optional<DoConstruct>>(x.t));
1877   }
Unparse(const AccBeginLoopDirective & x)1878   void Unparse(const AccBeginLoopDirective &x) {
1879     Walk(std::get<AccLoopDirective>(x.t));
1880     Walk(std::get<AccClauseList>(x.t));
1881   }
Unparse(const OpenACCStandaloneConstruct & x)1882   void Unparse(const OpenACCStandaloneConstruct &x) {
1883     BeginOpenACC();
1884     Word("!$ACC ");
1885     Walk(std::get<AccStandaloneDirective>(x.t));
1886     Walk(std::get<AccClauseList>(x.t));
1887     Put("\n");
1888     EndOpenACC();
1889   }
Unparse(const OpenACCStandaloneDeclarativeConstruct & x)1890   void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
1891     BeginOpenACC();
1892     Word("!$ACC ");
1893     Walk(std::get<AccDeclarativeDirective>(x.t));
1894     Walk(std::get<AccClauseList>(x.t));
1895     Put("\n");
1896     EndOpenACC();
1897   }
Unparse(const OpenACCCombinedConstruct & x)1898   void Unparse(const OpenACCCombinedConstruct &x) {
1899     BeginOpenACC();
1900     Word("!$ACC ");
1901     Walk(std::get<AccBeginCombinedDirective>(x.t));
1902     Put("\n");
1903     EndOpenACC();
1904     Walk(std::get<std::optional<DoConstruct>>(x.t));
1905     BeginOpenACC();
1906     Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),
1907         "\n");
1908     EndOpenACC();
1909   }
Unparse(const OpenACCRoutineConstruct & x)1910   void Unparse(const OpenACCRoutineConstruct &x) {
1911     BeginOpenACC();
1912     Word("!$ACC ROUTINE");
1913     Walk("(", std::get<std::optional<Name>>(x.t), ")");
1914     Walk(std::get<AccClauseList>(x.t));
1915     Put("\n");
1916     EndOpenACC();
1917   }
Unparse(const AccObject & x)1918   void Unparse(const AccObject &x) {
1919     std::visit(common::visitors{
1920                    [&](const Designator &y) { Walk(y); },
1921                    [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
1922                },
1923         x.u);
1924   }
Unparse(const AccObjectList & x)1925   void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
Unparse(const AccReductionOperator::Operator & x)1926   void Unparse(const AccReductionOperator::Operator &x) {
1927     Word(AccReductionOperator::EnumToString(x));
1928   }
Unparse(const AccObjectListWithReduction & x)1929   void Unparse(const AccObjectListWithReduction &x) {
1930     Walk(std::get<AccReductionOperator>(x.t));
1931     Put(":");
1932     Walk(std::get<AccObjectList>(x.t));
1933   }
Unparse(const OpenACCCacheConstruct & x)1934   void Unparse(const OpenACCCacheConstruct &x) {
1935     BeginOpenACC();
1936     Word("!$ACC ");
1937     Word("CACHE(");
1938     Walk(std::get<AccObjectListWithModifier>(x.t));
1939     Put(")");
1940     Put("\n");
1941     EndOpenACC();
1942   }
Unparse(const AccWaitArgument & x)1943   void Unparse(const AccWaitArgument &x) {
1944     Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");
1945     Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");
1946   }
Unparse(const OpenACCWaitConstruct & x)1947   void Unparse(const OpenACCWaitConstruct &x) {
1948     BeginOpenACC();
1949     Word("!$ACC ");
1950     Word("WAIT(");
1951     Walk(std::get<std::optional<AccWaitArgument>>(x.t));
1952     Walk(std::get<AccClauseList>(x.t));
1953     Put(")");
1954     Put("\n");
1955     EndOpenACC();
1956   }
1957 
1958   // OpenMP Clauses & Directives
Unparse(const OmpObject & x)1959   void Unparse(const OmpObject &x) {
1960     std::visit(common::visitors{
1961                    [&](const Designator &y) { Walk(y); },
1962                    [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
1963                },
1964         x.u);
1965   }
Unparse(const OmpMapType::Always &)1966   void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
Unparse(const OmpMapClause & x)1967   void Unparse(const OmpMapClause &x) {
1968     Word("MAP(");
1969     Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
1970     Walk(std::get<OmpObjectList>(x.t));
1971     Put(") ");
1972   }
Unparse(const OmpScheduleModifier & x)1973   void Unparse(const OmpScheduleModifier &x) {
1974     Walk(std::get<OmpScheduleModifier::Modifier1>(x.t));
1975     Walk(",", std::get<std::optional<OmpScheduleModifier::Modifier2>>(x.t));
1976   }
Unparse(const OmpScheduleClause & x)1977   void Unparse(const OmpScheduleClause &x) {
1978     Word("SCHEDULE(");
1979     Walk(std::get<std::optional<OmpScheduleModifier>>(x.t), ":");
1980     Walk(std::get<OmpScheduleClause::ScheduleType>(x.t));
1981     Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
1982     Put(")");
1983   }
Unparse(const OmpAlignedClause & x)1984   void Unparse(const OmpAlignedClause &x) {
1985     Word("ALIGNED("), Walk(std::get<std::list<Name>>(x.t), ",");
1986     Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
1987     Put(") ");
1988   }
Unparse(const OmpIfClause & x)1989   void Unparse(const OmpIfClause &x) {
1990     Word("IF("),
1991         Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t),
1992             ":");
1993     Walk(std::get<ScalarLogicalExpr>(x.t));
1994     Put(") ");
1995   }
Unparse(const OmpLinearClause::WithoutModifier & x)1996   void Unparse(const OmpLinearClause::WithoutModifier &x) {
1997     Word("LINEAR("), Walk(x.names, ", ");
1998     Walk(":", x.step);
1999     Put(")");
2000   }
Unparse(const OmpLinearClause::WithModifier & x)2001   void Unparse(const OmpLinearClause::WithModifier &x) {
2002     Word("LINEAR("), Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
2003     Walk(":", x.step);
2004     Put(")");
2005   }
Unparse(const OmpReductionClause & x)2006   void Unparse(const OmpReductionClause &x) {
2007     Word("REDUCTION(");
2008     Walk(std::get<OmpReductionOperator>(x.t));
2009     Put(":");
2010     Walk(std::get<std::list<Designator>>(x.t), ",");
2011     Put(")");
2012   }
Unparse(const OmpAllocateClause & x)2013   void Unparse(const OmpAllocateClause &x) {
2014     Word("ALLOCATE(");
2015     Walk(std::get<std::optional<OmpAllocateClause::Allocator>>(x.t), ":");
2016     Walk(std::get<OmpObjectList>(x.t));
2017     Put(")");
2018   }
Unparse(const OmpDependSinkVecLength & x)2019   void Unparse(const OmpDependSinkVecLength &x) {
2020     Walk(std::get<DefinedOperator>(x.t));
2021     Walk(std::get<ScalarIntConstantExpr>(x.t));
2022   }
Unparse(const OmpDependSinkVec & x)2023   void Unparse(const OmpDependSinkVec &x) {
2024     Walk(std::get<Name>(x.t));
2025     Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
2026   }
Unparse(const OmpDependClause::InOut & x)2027   void Unparse(const OmpDependClause::InOut &x) {
2028     Put("(");
2029     Walk(std::get<OmpDependenceType>(x.t));
2030     Put(":");
2031     Walk(std::get<std::list<Designator>>(x.t), ",");
2032     Put(")");
2033   }
Pre(const OmpDependClause & x)2034   bool Pre(const OmpDependClause &x) {
2035     return std::visit(common::visitors{
2036                           [&](const OmpDependClause::Source &) {
2037                             Word("DEPEND(SOURCE)");
2038                             return false;
2039                           },
2040                           [&](const OmpDependClause::Sink &y) {
2041                             Word("DEPEND(SINK:");
2042                             Walk(y.v);
2043                             Put(")");
2044                             return false;
2045                           },
2046                           [&](const OmpDependClause::InOut &) {
2047                             Word("DEPEND");
2048                             return true;
2049                           },
2050                       },
2051         x.u);
2052   }
Pre(const OmpDefaultClause &)2053   bool Pre(const OmpDefaultClause &) {
2054     Word("DEFAULT(");
2055     return true;
2056   }
Post(const OmpDefaultClause &)2057   void Post(const OmpDefaultClause &) { Put(")"); }
Pre(const OmpProcBindClause &)2058   bool Pre(const OmpProcBindClause &) {
2059     Word("PROC_BIND(");
2060     return true;
2061   }
Post(const OmpProcBindClause &)2062   void Post(const OmpProcBindClause &) { Put(")"); }
Unparse(const OmpDefaultmapClause & x)2063   void Unparse(const OmpDefaultmapClause &x) {
2064     Word("DEFAULTMAP(");
2065     Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
2066     Walk(":",
2067         std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
2068     Word(")");
2069   }
Unparse(const OmpNowait &)2070   void Unparse(const OmpNowait &) { Word("NOWAIT"); }
Unparse(const OmpDistScheduleClause & x)2071   void Unparse(const OmpDistScheduleClause &x) {
2072     Word("DIST_SCHEDULE(STATIC");
2073     Walk(", ", x.v);
2074     Put(")");
2075   }
2076 #define GEN_FLANG_CLAUSE_UNPARSE
2077 #include "llvm/Frontend/OpenMP/OMP.cpp.inc"
Unparse(const OmpLoopDirective & x)2078   void Unparse(const OmpLoopDirective &x) {
2079     switch (x.v) {
2080     case llvm::omp::Directive::OMPD_distribute:
2081       Word("DISTRIBUTE ");
2082       break;
2083     case llvm::omp::Directive::OMPD_distribute_parallel_do:
2084       Word("DISTRIBUTE PARALLEL DO ");
2085       break;
2086     case llvm::omp::Directive::OMPD_distribute_parallel_do_simd:
2087       Word("DISTRIBUTE PARALLEL DO SIMD ");
2088       break;
2089     case llvm::omp::Directive::OMPD_distribute_simd:
2090       Word("DISTRIBUTE SIMD ");
2091       break;
2092     case llvm::omp::Directive::OMPD_do:
2093       Word("DO ");
2094       break;
2095     case llvm::omp::Directive::OMPD_do_simd:
2096       Word("DO SIMD ");
2097       break;
2098     case llvm::omp::Directive::OMPD_parallel_do:
2099       Word("PARALLEL DO ");
2100       break;
2101     case llvm::omp::Directive::OMPD_parallel_do_simd:
2102       Word("PARALLEL DO SIMD ");
2103       break;
2104     case llvm::omp::Directive::OMPD_simd:
2105       Word("SIMD ");
2106       break;
2107     case llvm::omp::Directive::OMPD_target_parallel_do:
2108       Word("TARGET PARALLEL DO ");
2109       break;
2110     case llvm::omp::Directive::OMPD_target_parallel_do_simd:
2111       Word("TARGET PARALLEL DO SIMD ");
2112       break;
2113     case llvm::omp::Directive::OMPD_target_teams_distribute:
2114       Word("TARGET TEAMS DISTRIBUTE ");
2115       break;
2116     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
2117       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO ");
2118       break;
2119     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
2120       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2121       break;
2122     case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
2123       Word("TARGET TEAMS DISTRIBUTE SIMD ");
2124       break;
2125     case llvm::omp::Directive::OMPD_target_simd:
2126       Word("TARGET SIMD ");
2127       break;
2128     case llvm::omp::Directive::OMPD_taskloop:
2129       Word("TASKLOOP ");
2130       break;
2131     case llvm::omp::Directive::OMPD_taskloop_simd:
2132       Word("TASKLOOP SIMD ");
2133       break;
2134     case llvm::omp::Directive::OMPD_teams_distribute:
2135       Word("TEAMS DISTRIBUTE ");
2136       break;
2137     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do:
2138       Word("TEAMS DISTRIBUTE PARALLEL DO ");
2139       break;
2140     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd:
2141       Word("TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2142       break;
2143     case llvm::omp::Directive::OMPD_teams_distribute_simd:
2144       Word("TEAMS DISTRIBUTE SIMD ");
2145       break;
2146     default:
2147       break;
2148     }
2149   }
Unparse(const OmpObjectList & x)2150   void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
Unparse(const OmpSimpleStandaloneDirective & x)2151   void Unparse(const OmpSimpleStandaloneDirective &x) {
2152     switch (x.v) {
2153     case llvm::omp::Directive::OMPD_barrier:
2154       Word("BARRIER ");
2155       break;
2156     case llvm::omp::Directive::OMPD_taskwait:
2157       Word("TASKWAIT ");
2158       break;
2159     case llvm::omp::Directive::OMPD_taskyield:
2160       Word("TASKYIELD ");
2161       break;
2162     case llvm::omp::Directive::OMPD_target_enter_data:
2163       Word("TARGET ENTER DATA ");
2164       break;
2165     case llvm::omp::Directive::OMPD_target_exit_data:
2166       Word("TARGET EXIT DATA ");
2167       break;
2168     case llvm::omp::Directive::OMPD_target_update:
2169       Word("TARGET UPDATE ");
2170       break;
2171     case llvm::omp::Directive::OMPD_ordered:
2172       Word("ORDERED ");
2173       break;
2174     default:
2175       // Nothing to be done
2176       break;
2177     }
2178   }
Unparse(const OmpBlockDirective & x)2179   void Unparse(const OmpBlockDirective &x) {
2180     switch (x.v) {
2181     case llvm::omp::Directive::OMPD_master:
2182       Word("MASTER");
2183       break;
2184     case llvm::omp::Directive::OMPD_ordered:
2185       Word("ORDERED ");
2186       break;
2187     case llvm::omp::Directive::OMPD_parallel_workshare:
2188       Word("PARALLEL WORKSHARE ");
2189       break;
2190     case llvm::omp::Directive::OMPD_parallel:
2191       Word("PARALLEL ");
2192       break;
2193     case llvm::omp::Directive::OMPD_single:
2194       Word("SINGLE ");
2195       break;
2196     case llvm::omp::Directive::OMPD_target_data:
2197       Word("TARGET DATA ");
2198       break;
2199     case llvm::omp::Directive::OMPD_target_parallel:
2200       Word("TARGET PARALLEL ");
2201       break;
2202     case llvm::omp::Directive::OMPD_target_teams:
2203       Word("TARGET TEAMS ");
2204       break;
2205     case llvm::omp::Directive::OMPD_target:
2206       Word("TARGET ");
2207       break;
2208     case llvm::omp::Directive::OMPD_taskgroup:
2209       Word("TASKGROUP ");
2210       break;
2211     case llvm::omp::Directive::OMPD_task:
2212       Word("TASK ");
2213       break;
2214     case llvm::omp::Directive::OMPD_teams:
2215       Word("TEAMS ");
2216       break;
2217     case llvm::omp::Directive::OMPD_workshare:
2218       Word("WORKSHARE ");
2219       break;
2220     default:
2221       // Nothing to be done
2222       break;
2223     }
2224   }
Unparse(const OmpAtomic & x)2225   void Unparse(const OmpAtomic &x) {
2226     BeginOpenMP();
2227     Word("!$OMP ATOMIC");
2228     Walk(std::get<OmpClauseList>(x.t));
2229     Put("\n");
2230     EndOpenMP();
2231     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2232     BeginOpenMP();
2233     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2234     EndOpenMP();
2235   }
Unparse(const OmpAtomicCapture & x)2236   void Unparse(const OmpAtomicCapture &x) {
2237     BeginOpenMP();
2238     Word("!$OMP ATOMIC");
2239     Walk(std::get<0>(x.t));
2240     Word(" CAPTURE");
2241     Walk(std::get<2>(x.t));
2242     Put("\n");
2243     EndOpenMP();
2244     Walk(std::get<OmpAtomicCapture::Stmt1>(x.t));
2245     Put("\n");
2246     Walk(std::get<OmpAtomicCapture::Stmt2>(x.t));
2247     BeginOpenMP();
2248     Word("!$OMP END ATOMIC\n");
2249     EndOpenMP();
2250   }
Unparse(const OmpAtomicRead & x)2251   void Unparse(const OmpAtomicRead &x) {
2252     BeginOpenMP();
2253     Word("!$OMP ATOMIC");
2254     Walk(std::get<0>(x.t));
2255     Word(" READ");
2256     Walk(std::get<2>(x.t));
2257     Put("\n");
2258     EndOpenMP();
2259     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2260     BeginOpenMP();
2261     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2262     EndOpenMP();
2263   }
Unparse(const OmpAtomicUpdate & x)2264   void Unparse(const OmpAtomicUpdate &x) {
2265     BeginOpenMP();
2266     Word("!$OMP ATOMIC");
2267     Walk(std::get<0>(x.t));
2268     Word(" UPDATE");
2269     Walk(std::get<2>(x.t));
2270     Put("\n");
2271     EndOpenMP();
2272     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2273     BeginOpenMP();
2274     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2275     EndOpenMP();
2276   }
Unparse(const OmpAtomicWrite & x)2277   void Unparse(const OmpAtomicWrite &x) {
2278     BeginOpenMP();
2279     Word("!$OMP ATOMIC");
2280     Walk(std::get<0>(x.t));
2281     Word(" WRITE");
2282     Walk(std::get<2>(x.t));
2283     Put("\n");
2284     EndOpenMP();
2285     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2286     BeginOpenMP();
2287     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2288     EndOpenMP();
2289   }
Unparse(const OmpCriticalDirective & x)2290   void Unparse(const OmpCriticalDirective &x) {
2291     BeginOpenMP();
2292     Word("!$OMP CRITICAL");
2293     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2294     Walk(std::get<std::optional<OmpClause>>(x.t));
2295     Put("\n");
2296     EndOpenMP();
2297   }
Unparse(const OmpEndCriticalDirective & x)2298   void Unparse(const OmpEndCriticalDirective &x) {
2299     BeginOpenMP();
2300     Word("!$OMP END CRITICAL");
2301     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2302     Put("\n");
2303     EndOpenMP();
2304   }
Unparse(const OpenMPCriticalConstruct & x)2305   void Unparse(const OpenMPCriticalConstruct &x) {
2306     Walk(std::get<OmpCriticalDirective>(x.t));
2307     Walk(std::get<Block>(x.t), "");
2308     Walk(std::get<OmpEndCriticalDirective>(x.t));
2309   }
Unparse(const OmpDeclareTargetWithList & x)2310   void Unparse(const OmpDeclareTargetWithList &x) {
2311     Put("("), Walk(x.v), Put(")");
2312   }
Unparse(const OmpReductionInitializerClause & x)2313   void Unparse(const OmpReductionInitializerClause &x) {
2314     Word(" INITIALIZER(OMP_PRIV = ");
2315     Walk(x.v);
2316     Put(")");
2317   }
Unparse(const OmpReductionCombiner::FunctionCombiner & x)2318   void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
2319     const auto &pd = std::get<ProcedureDesignator>(x.v.t);
2320     const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
2321     Walk(pd);
2322     if (args.empty()) {
2323       if (std::holds_alternative<ProcComponentRef>(pd.u)) {
2324         Put("()");
2325       }
2326     } else {
2327       Walk("(", args, ", ", ")");
2328     }
2329   }
Unparse(const OpenMPDeclareReductionConstruct & x)2330   void Unparse(const OpenMPDeclareReductionConstruct &x) {
2331     Put("(");
2332     Walk(std::get<OmpReductionOperator>(x.t)), Put(" : ");
2333     Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
2334     Walk(std::get<OmpReductionCombiner>(x.t));
2335     Put(")");
2336     Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
2337   }
Pre(const OpenMPDeclarativeConstruct & x)2338   bool Pre(const OpenMPDeclarativeConstruct &x) {
2339     BeginOpenMP();
2340     Word("!$OMP ");
2341     return std::visit(common::visitors{
2342                           [&](const OpenMPDeclareReductionConstruct &) {
2343                             Word("DECLARE REDUCTION ");
2344                             return true;
2345                           },
2346                           [&](const OpenMPDeclareSimdConstruct &y) {
2347                             Word("DECLARE SIMD ");
2348                             Walk("(", std::get<std::optional<Name>>(y.t), ")");
2349                             Walk(std::get<OmpClauseList>(y.t));
2350                             Put("\n");
2351                             EndOpenMP();
2352                             return false;
2353                           },
2354                           [&](const OpenMPDeclareTargetConstruct &) {
2355                             Word("DECLARE TARGET ");
2356                             return true;
2357                           },
2358                           [&](const OpenMPThreadprivate &) {
2359                             Word("THREADPRIVATE (");
2360                             return true;
2361                           },
2362                       },
2363         x.u);
2364   }
Post(const OpenMPDeclarativeConstruct &)2365   void Post(const OpenMPDeclarativeConstruct &) {
2366     Put("\n");
2367     EndOpenMP();
2368   }
Post(const OpenMPThreadprivate &)2369   void Post(const OpenMPThreadprivate &) {
2370     Put(")\n");
2371     EndOpenMP();
2372   }
Unparse(const OmpSectionsDirective & x)2373   void Unparse(const OmpSectionsDirective &x) {
2374     switch (x.v) {
2375     case llvm::omp::Directive::OMPD_sections:
2376       Word("SECTIONS ");
2377       break;
2378     case llvm::omp::Directive::OMPD_parallel_sections:
2379       Word("PARALLEL SECTIONS ");
2380       break;
2381     default:
2382       break;
2383     }
2384   }
Unparse(const OmpSectionBlocks & x)2385   void Unparse(const OmpSectionBlocks &x) {
2386     for (const auto &y : x.v) {
2387       BeginOpenMP();
2388       Word("!$OMP SECTION");
2389       Put("\n");
2390       EndOpenMP();
2391       Walk(y, ""); // y is Block
2392     }
2393   }
Unparse(const OpenMPSectionsConstruct & x)2394   void Unparse(const OpenMPSectionsConstruct &x) {
2395     BeginOpenMP();
2396     Word("!$OMP ");
2397     Walk(std::get<OmpBeginSectionsDirective>(x.t));
2398     Put("\n");
2399     EndOpenMP();
2400     Walk(std::get<OmpSectionBlocks>(x.t));
2401     BeginOpenMP();
2402     Word("!$OMP END ");
2403     Walk(std::get<OmpEndSectionsDirective>(x.t));
2404     Put("\n");
2405     EndOpenMP();
2406   }
Unparse(const OpenMPCancellationPointConstruct & x)2407   void Unparse(const OpenMPCancellationPointConstruct &x) {
2408     BeginOpenMP();
2409     Word("!$OMP CANCELLATION POINT ");
2410     Walk(std::get<OmpCancelType>(x.t));
2411     Put("\n");
2412     EndOpenMP();
2413   }
Unparse(const OpenMPCancelConstruct & x)2414   void Unparse(const OpenMPCancelConstruct &x) {
2415     BeginOpenMP();
2416     Word("!$OMP CANCEL ");
2417     Walk(std::get<OmpCancelType>(x.t));
2418     Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
2419     Put("\n");
2420     EndOpenMP();
2421   }
Unparse(const OmpMemoryOrderClause & x)2422   void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
Unparse(const OpenMPFlushConstruct & x)2423   void Unparse(const OpenMPFlushConstruct &x) {
2424     BeginOpenMP();
2425     Word("!$OMP FLUSH ");
2426     Walk(std::get<std::optional<OmpMemoryOrderClause>>(x.t));
2427     Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2428     Put("\n");
2429     EndOpenMP();
2430   }
Unparse(const OmpEndLoopDirective & x)2431   void Unparse(const OmpEndLoopDirective &x) {
2432     BeginOpenMP();
2433     Word("!$OMP END ");
2434     Walk(std::get<OmpLoopDirective>(x.t));
2435     Walk(std::get<OmpClauseList>(x.t));
2436     Put("\n");
2437     EndOpenMP();
2438   }
Unparse(const OmpClauseList & x)2439   void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
Unparse(const OpenMPSimpleStandaloneConstruct & x)2440   void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
2441     BeginOpenMP();
2442     Word("!$OMP ");
2443     Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
2444     Walk(std::get<OmpClauseList>(x.t));
2445     Put("\n");
2446     EndOpenMP();
2447   }
Unparse(const OpenMPBlockConstruct & x)2448   void Unparse(const OpenMPBlockConstruct &x) {
2449     BeginOpenMP();
2450     Word("!$OMP ");
2451     Walk(std::get<OmpBeginBlockDirective>(x.t));
2452     Put("\n");
2453     EndOpenMP();
2454     Walk(std::get<Block>(x.t), "");
2455     BeginOpenMP();
2456     Word("!$OMP END ");
2457     Walk(std::get<OmpEndBlockDirective>(x.t));
2458     Put("\n");
2459     EndOpenMP();
2460   }
Unparse(const OpenMPLoopConstruct & x)2461   void Unparse(const OpenMPLoopConstruct &x) {
2462     BeginOpenMP();
2463     Word("!$OMP ");
2464     Walk(std::get<OmpBeginLoopDirective>(x.t));
2465     Put("\n");
2466     EndOpenMP();
2467     Walk(std::get<std::optional<DoConstruct>>(x.t));
2468     Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t));
2469   }
Unparse(const BasedPointer & x)2470   void Unparse(const BasedPointer &x) {
2471     Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
2472     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
2473   }
Unparse(const BasedPointerStmt & x)2474   void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }
Post(const StructureField & x)2475   void Post(const StructureField &x) {
2476     if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {
2477       for (const auto &decl :
2478           std::get<std::list<ComponentDecl>>(def->statement.t)) {
2479         structureComponents_.insert(std::get<Name>(decl.t).source);
2480       }
2481     }
2482   }
Unparse(const StructureStmt & x)2483   void Unparse(const StructureStmt &x) {
2484     Word("STRUCTURE ");
2485     if (std::get<bool>(x.t)) { // slashes around name
2486       Put('/'), Walk(std::get<Name>(x.t)), Put('/');
2487       Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
2488     } else {
2489       CHECK(std::get<std::list<EntityDecl>>(x.t).empty());
2490       Walk(std::get<Name>(x.t));
2491     }
2492     Indent();
2493   }
Post(const Union::UnionStmt &)2494   void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
Post(const Union::EndUnionStmt &)2495   void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
Post(const Map::MapStmt &)2496   void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
Post(const Map::EndMapStmt &)2497   void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
Post(const StructureDef::EndStructureStmt &)2498   void Post(const StructureDef::EndStructureStmt &) {
2499     Outdent(), Word("END STRUCTURE");
2500   }
Unparse(const OldParameterStmt & x)2501   void Unparse(const OldParameterStmt &x) {
2502     Word("PARAMETER "), Walk(x.v, ", ");
2503   }
Unparse(const ArithmeticIfStmt & x)2504   void Unparse(const ArithmeticIfStmt &x) {
2505     Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
2506     Walk(std::get<1>(x.t)), Put(", ");
2507     Walk(std::get<2>(x.t)), Put(", ");
2508     Walk(std::get<3>(x.t));
2509   }
Unparse(const AssignStmt & x)2510   void Unparse(const AssignStmt &x) {
2511     Word("ASSIGN "), Walk(std::get<Label>(x.t));
2512     Word(" TO "), Walk(std::get<Name>(x.t));
2513   }
Unparse(const AssignedGotoStmt & x)2514   void Unparse(const AssignedGotoStmt &x) {
2515     Word("GO TO "), Walk(std::get<Name>(x.t));
2516     Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
2517   }
Unparse(const PauseStmt & x)2518   void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }
2519 
2520 #define WALK_NESTED_ENUM(CLASS, ENUM) \
2521   void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
WALK_NESTED_ENUM(AccessSpec,Kind)2522   WALK_NESTED_ENUM(AccessSpec, Kind) // R807
2523   WALK_NESTED_ENUM(common, TypeParamAttr) // R734
2524   WALK_NESTED_ENUM(IntentSpec, Intent) // R826
2525   WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
2526   WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
2527   WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
2528   WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
2529   WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
2530   WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
2531   WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
2532   WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
2533   WALK_NESTED_ENUM(OmpProcBindClause, Type) // OMP PROC_BIND
2534   WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
2535   WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
2536   WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
2537   WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
2538   WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
2539   WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
2540   WALK_NESTED_ENUM(OmpMapType, Type) // OMP map-type
2541   WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type
2542   WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
2543   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
2544 #undef WALK_NESTED_ENUM
2545 
2546   void Done() const { CHECK(indent_ == 0); }
2547 
2548 private:
2549   void Put(char);
2550   void Put(const char *);
2551   void Put(const std::string &);
2552   void PutNormalized(const std::string &);
2553   void PutKeywordLetter(char);
2554   void Word(const char *);
2555   void Word(const std::string &);
Indent()2556   void Indent() { indent_ += indentationAmount_; }
Outdent()2557   void Outdent() {
2558     CHECK(indent_ >= indentationAmount_);
2559     indent_ -= indentationAmount_;
2560   }
BeginOpenMP()2561   void BeginOpenMP() { openmpDirective_ = true; }
EndOpenMP()2562   void EndOpenMP() { openmpDirective_ = false; }
BeginOpenACC()2563   void BeginOpenACC() { openaccDirective_ = true; }
EndOpenACC()2564   void EndOpenACC() { openaccDirective_ = false; }
2565 
2566   // Call back to the traversal framework.
Walk(const T & x)2567   template <typename T> void Walk(const T &x) {
2568     Fortran::parser::Walk(x, *this);
2569   }
2570 
2571   // Traverse a std::optional<> value.  Emit a prefix and/or a suffix string
2572   // only when it contains a value.
2573   template <typename A>
Walk(const char * prefix,const std::optional<A> & x,const char * suffix="")2574   void Walk(
2575       const char *prefix, const std::optional<A> &x, const char *suffix = "") {
2576     if (x) {
2577       Word(prefix), Walk(*x), Word(suffix);
2578     }
2579   }
2580   template <typename A>
Walk(const std::optional<A> & x,const char * suffix="")2581   void Walk(const std::optional<A> &x, const char *suffix = "") {
2582     return Walk("", x, suffix);
2583   }
2584 
2585   // Traverse a std::list<>.  Separate the elements with an optional string.
2586   // Emit a prefix and/or a suffix string only when the list is not empty.
2587   template <typename A>
Walk(const char * prefix,const std::list<A> & list,const char * comma=", ",const char * suffix="")2588   void Walk(const char *prefix, const std::list<A> &list,
2589       const char *comma = ", ", const char *suffix = "") {
2590     if (!list.empty()) {
2591       const char *str{prefix};
2592       for (const auto &x : list) {
2593         Word(str), Walk(x);
2594         str = comma;
2595       }
2596       Word(suffix);
2597     }
2598   }
2599   template <typename A>
Walk(const std::list<A> & list,const char * comma=", ",const char * suffix="")2600   void Walk(const std::list<A> &list, const char *comma = ", ",
2601       const char *suffix = "") {
2602     return Walk("", list, comma, suffix);
2603   }
2604 
2605   // Traverse a std::tuple<>, with an optional separator.
2606   template <std::size_t J = 0, typename T>
WalkTupleElements(const T & tuple,const char * separator)2607   void WalkTupleElements(const T &tuple, const char *separator) {
2608     if (J > 0 && J < std::tuple_size_v<T>) {
2609       Word(separator); // this usage dodges "unused parameter" warning
2610     }
2611     if constexpr (J < std::tuple_size_v<T>) {
2612       Walk(std::get<J>(tuple));
2613       WalkTupleElements<J + 1>(tuple, separator);
2614     }
2615   }
2616   template <typename... A>
Walk(const std::tuple<A...> & tuple,const char * separator="")2617   void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
2618     WalkTupleElements(tuple, separator);
2619   }
2620 
EndSubprogram(const char * kind,const std::optional<Name> & name)2621   void EndSubprogram(const char *kind, const std::optional<Name> &name) {
2622     Outdent(), Word("END "), Word(kind), Walk(" ", name);
2623     structureComponents_.clear();
2624   }
2625 
2626   llvm::raw_ostream &out_;
2627   int indent_{0};
2628   const int indentationAmount_{1};
2629   int column_{1};
2630   const int maxColumns_{80};
2631   std::set<CharBlock> structureComponents_;
2632   Encoding encoding_{Encoding::UTF_8};
2633   bool capitalizeKeywords_{true};
2634   bool openaccDirective_{false};
2635   bool openmpDirective_{false};
2636   bool backslashEscapes_{false};
2637   preStatementType *preStatement_{nullptr};
2638   AnalyzedObjectsAsFortran *asFortran_{nullptr};
2639 };
2640 
Put(char ch)2641 void UnparseVisitor::Put(char ch) {
2642   int sav = indent_;
2643   if (openmpDirective_ || openaccDirective_) {
2644     indent_ = 0;
2645   }
2646   if (column_ <= 1) {
2647     if (ch == '\n') {
2648       return;
2649     }
2650     for (int j{0}; j < indent_; ++j) {
2651       out_ << ' ';
2652     }
2653     column_ = indent_ + 2;
2654   } else if (ch == '\n') {
2655     column_ = 1;
2656   } else if (++column_ >= maxColumns_) {
2657     out_ << "&\n";
2658     for (int j{0}; j < indent_; ++j) {
2659       out_ << ' ';
2660     }
2661     if (openmpDirective_) {
2662       out_ << "!$OMP&";
2663       column_ = 8;
2664     } else if (openaccDirective_) {
2665       out_ << "!$ACC&";
2666       column_ = 8;
2667     } else {
2668       out_ << '&';
2669       column_ = indent_ + 3;
2670     }
2671   }
2672   out_ << ch;
2673   if (openmpDirective_ || openaccDirective_) {
2674     indent_ = sav;
2675   }
2676 }
2677 
Put(const char * str)2678 void UnparseVisitor::Put(const char *str) {
2679   for (; *str != '\0'; ++str) {
2680     Put(*str);
2681   }
2682 }
2683 
Put(const std::string & str)2684 void UnparseVisitor::Put(const std::string &str) {
2685   for (char ch : str) {
2686     Put(ch);
2687   }
2688 }
2689 
PutNormalized(const std::string & str)2690 void UnparseVisitor::PutNormalized(const std::string &str) {
2691   auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};
2692   std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};
2693   Put(QuoteCharacterLiteral(encoded, backslashEscapes_));
2694 }
2695 
PutKeywordLetter(char ch)2696 void UnparseVisitor::PutKeywordLetter(char ch) {
2697   if (capitalizeKeywords_) {
2698     Put(ToUpperCaseLetter(ch));
2699   } else {
2700     Put(ToLowerCaseLetter(ch));
2701   }
2702 }
2703 
Word(const char * str)2704 void UnparseVisitor::Word(const char *str) {
2705   for (; *str != '\0'; ++str) {
2706     PutKeywordLetter(*str);
2707   }
2708 }
2709 
Word(const std::string & str)2710 void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
2711 
Unparse(llvm::raw_ostream & out,const Program & program,Encoding encoding,bool capitalizeKeywords,bool backslashEscapes,preStatementType * preStatement,AnalyzedObjectsAsFortran * asFortran)2712 void Unparse(llvm::raw_ostream &out, const Program &program, Encoding encoding,
2713     bool capitalizeKeywords, bool backslashEscapes,
2714     preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
2715   UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
2716       preStatement, asFortran};
2717   Walk(program, visitor);
2718   visitor.Done();
2719 }
2720 } // namespace Fortran::parser
2721