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