xref: /llvm-project/flang/lib/Parser/unparse.cpp (revision bde79c0e27fd0fb1e31c9b8b34ae71716c51a8e8)
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::Unrecognized &) {
1851               Word("!DIR$ ");
1852               Word(x.source.ToString());
1853             },
1854         },
1855         x.u);
1856     Put('\n');
1857   }
1858   void Unparse(const CompilerDirective::IgnoreTKR &x) {
1859     if (const auto &maybeList{
1860             std::get<std::optional<std::list<const char *>>>(x.t)}) {
1861       Put("(");
1862       for (const char *tkr : *maybeList) {
1863         Put(*tkr);
1864       }
1865       Put(") ");
1866     }
1867     Walk(std::get<Name>(x.t));
1868   }
1869   void Unparse(const CompilerDirective::NameValue &x) {
1870     Walk(std::get<Name>(x.t));
1871     Walk("=", std::get<std::optional<std::uint64_t>>(x.t));
1872   }
1873   void Unparse(const CompilerDirective::AssumeAligned &x) {
1874     Walk(std::get<common::Indirection<Designator>>(x.t));
1875     Put(":");
1876     Walk(std::get<uint64_t>(x.t));
1877   }
1878 
1879   // OpenACC Directives & Clauses
1880   void Unparse(const AccAtomicCapture &x) {
1881     BeginOpenACC();
1882     Word("!$ACC CAPTURE");
1883     Put("\n");
1884     EndOpenACC();
1885     Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
1886     Put("\n");
1887     Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
1888     BeginOpenACC();
1889     Word("!$ACC END ATOMIC\n");
1890     EndOpenACC();
1891   }
1892   void Unparse(const AccAtomicRead &x) {
1893     BeginOpenACC();
1894     Word("!$ACC ATOMIC READ");
1895     Put("\n");
1896     EndOpenACC();
1897     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1898     BeginOpenACC();
1899     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1900     EndOpenACC();
1901   }
1902   void Unparse(const AccAtomicWrite &x) {
1903     BeginOpenACC();
1904     Word("!$ACC ATOMIC WRITE");
1905     Put("\n");
1906     EndOpenACC();
1907     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1908     BeginOpenACC();
1909     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1910     EndOpenACC();
1911   }
1912   void Unparse(const AccAtomicUpdate &x) {
1913     BeginOpenACC();
1914     Word("!$ACC ATOMIC UPDATE");
1915     Put("\n");
1916     EndOpenACC();
1917     Walk(std::get<Statement<AssignmentStmt>>(x.t));
1918     BeginOpenACC();
1919     Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1920     EndOpenACC();
1921   }
1922   void Unparse(const llvm::acc::Directive &x) {
1923     Word(llvm::acc::getOpenACCDirectiveName(x).str());
1924   }
1925 #define GEN_FLANG_CLAUSE_UNPARSE
1926 #include "llvm/Frontend/OpenACC/ACC.inc"
1927   void Unparse(const AccObjectListWithModifier &x) {
1928     Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
1929     Walk(std::get<AccObjectList>(x.t));
1930   }
1931   void Unparse(const AccBindClause &x) {
1932     common::visit(common::visitors{
1933                       [&](const Name &y) { Walk(y); },
1934                       [&](const ScalarDefaultCharExpr &y) { Walk(y); },
1935                   },
1936         x.u);
1937   }
1938   void Unparse(const AccDefaultClause &x) {
1939     switch (x.v) {
1940     case llvm::acc::DefaultValue::ACC_Default_none:
1941       Put("NONE");
1942       break;
1943     case llvm::acc::DefaultValue::ACC_Default_present:
1944       Put("PRESENT");
1945       break;
1946     }
1947   }
1948   void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
1949   void Unparse(const AccGangArgList &x) { Walk(x.v, ","); }
1950   void Before(const AccSizeExpr &x) {
1951     if (!x.v)
1952       Put("*");
1953   }
1954   void Before(const AccGangArg &x) {
1955     common::visit(common::visitors{
1956                       [&](const AccGangArg::Num &) { Word("NUM:"); },
1957                       [&](const AccGangArg::Dim &) { Word("DIM:"); },
1958                       [&](const AccGangArg::Static &) { Word("STATIC:"); },
1959                       [](const StatOrErrmsg &) {},
1960                   },
1961         x.u);
1962   }
1963   void Unparse(const AccCollapseArg &x) {
1964     const auto &force{std::get<bool>(x.t)};
1965     const auto &collapseValue{std::get<parser::ScalarIntConstantExpr>(x.t)};
1966     if (force) {
1967       Put("FORCE:");
1968     }
1969     Walk(collapseValue);
1970   }
1971   void Unparse(const OpenACCBlockConstruct &x) {
1972     BeginOpenACC();
1973     Word("!$ACC ");
1974     Walk(std::get<AccBeginBlockDirective>(x.t));
1975     Put("\n");
1976     EndOpenACC();
1977     Walk(std::get<Block>(x.t), "");
1978     BeginOpenACC();
1979     Word("!$ACC END ");
1980     Walk(std::get<AccEndBlockDirective>(x.t));
1981     Put("\n");
1982     EndOpenACC();
1983   }
1984   void Unparse(const OpenACCLoopConstruct &x) {
1985     BeginOpenACC();
1986     Word("!$ACC ");
1987     Walk(std::get<AccBeginLoopDirective>(x.t));
1988     Put("\n");
1989     EndOpenACC();
1990     Walk(std::get<std::optional<DoConstruct>>(x.t));
1991   }
1992   void Unparse(const AccBeginLoopDirective &x) {
1993     Walk(std::get<AccLoopDirective>(x.t));
1994     Walk(std::get<AccClauseList>(x.t));
1995   }
1996   void Unparse(const OpenACCStandaloneConstruct &x) {
1997     BeginOpenACC();
1998     Word("!$ACC ");
1999     Walk(std::get<AccStandaloneDirective>(x.t));
2000     Walk(std::get<AccClauseList>(x.t));
2001     Put("\n");
2002     EndOpenACC();
2003   }
2004   void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
2005     BeginOpenACC();
2006     Word("!$ACC ");
2007     Walk(std::get<AccDeclarativeDirective>(x.t));
2008     Walk(std::get<AccClauseList>(x.t));
2009     Put("\n");
2010     EndOpenACC();
2011   }
2012   void Unparse(const OpenACCCombinedConstruct &x) {
2013     BeginOpenACC();
2014     Word("!$ACC ");
2015     Walk(std::get<AccBeginCombinedDirective>(x.t));
2016     Put("\n");
2017     EndOpenACC();
2018     Walk(std::get<std::optional<DoConstruct>>(x.t));
2019     BeginOpenACC();
2020     Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),
2021         "\n");
2022     EndOpenACC();
2023   }
2024   void Unparse(const OpenACCRoutineConstruct &x) {
2025     BeginOpenACC();
2026     Word("!$ACC ROUTINE");
2027     Walk("(", std::get<std::optional<Name>>(x.t), ")");
2028     Walk(std::get<AccClauseList>(x.t));
2029     Put("\n");
2030     EndOpenACC();
2031   }
2032   void Unparse(const AccObject &x) {
2033     common::visit(common::visitors{
2034                       [&](const Designator &y) { Walk(y); },
2035                       [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
2036                   },
2037         x.u);
2038   }
2039   void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
2040   void Unparse(const AccObjectListWithReduction &x) {
2041     Walk(std::get<ReductionOperator>(x.t));
2042     Put(":");
2043     Walk(std::get<AccObjectList>(x.t));
2044   }
2045   void Unparse(const OpenACCCacheConstruct &x) {
2046     BeginOpenACC();
2047     Word("!$ACC ");
2048     Word("CACHE(");
2049     Walk(std::get<AccObjectListWithModifier>(x.t));
2050     Put(")");
2051     Put("\n");
2052     EndOpenACC();
2053   }
2054   void Unparse(const AccWaitArgument &x) {
2055     Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");
2056     Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");
2057   }
2058   void Unparse(const OpenACCWaitConstruct &x) {
2059     BeginOpenACC();
2060     Word("!$ACC ");
2061     Word("WAIT(");
2062     Walk(std::get<std::optional<AccWaitArgument>>(x.t));
2063     Walk(std::get<AccClauseList>(x.t));
2064     Put(")");
2065     Put("\n");
2066     EndOpenACC();
2067   }
2068 
2069   // OpenMP Clauses & Directives
2070   void Unparse(const OmpObject &x) {
2071     common::visit(common::visitors{
2072                       [&](const Designator &y) { Walk(y); },
2073                       [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
2074                   },
2075         x.u);
2076   }
2077   void Unparse(const OmpIteratorSpecifier &x) {
2078     Walk(std::get<TypeDeclarationStmt>(x.t));
2079     Put(" = ");
2080     Walk(std::get<SubscriptTriplet>(x.t));
2081   }
2082   void Unparse(const OmpIterator &x) {
2083     Word("ITERATOR(");
2084     Walk(x.v);
2085     Put(")");
2086   }
2087   void Unparse(const OmpMapper &x) {
2088     Word("MAPPER(");
2089     Walk(x.v);
2090     Put(")");
2091   }
2092   void Unparse(const OmpLastprivateClause &x) {
2093     Walk(
2094         std::get<std::optional<OmpLastprivateClause::LastprivateModifier>>(x.t),
2095         ":");
2096     Walk(std::get<OmpObjectList>(x.t));
2097   }
2098   void Unparse(const OmpMapClause &x) {
2099     using Modifier = OmpMapClause::Modifier;
2100     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2101     Walk(std::get<OmpObjectList>(x.t));
2102   }
2103   void Unparse(const OmpScheduleClause &x) {
2104     using Modifier = OmpScheduleClause::Modifier;
2105     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":");
2106     Walk(std::get<OmpScheduleClause::Kind>(x.t));
2107     Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
2108   }
2109   void Unparse(const OmpDeviceClause &x) {
2110     using Modifier = OmpDeviceClause::Modifier;
2111     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2112     Walk(std::get<ScalarIntExpr>(x.t));
2113   }
2114   void Unparse(const OmpAffinityClause &x) {
2115     using Modifier = OmpAffinityClause::Modifier;
2116     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2117     Walk(std::get<OmpObjectList>(x.t));
2118   }
2119   void Unparse(const OmpAlignedClause &x) {
2120     using Modifier = OmpAlignedClause::Modifier;
2121     Walk(std::get<OmpObjectList>(x.t));
2122     Walk(": ", std::get<std::optional<std::list<Modifier>>>(x.t));
2123   }
2124   void Unparse(const OmpFromClause &x) {
2125     using Modifier = OmpFromClause::Modifier;
2126     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2127     Walk(std::get<OmpObjectList>(x.t));
2128   }
2129   void Unparse(const OmpIfClause &x) {
2130     Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
2131     Walk(std::get<ScalarLogicalExpr>(x.t));
2132   }
2133   void Unparse(const OmpLinearClause::WithoutModifier &x) {
2134     Walk(x.names, ", ");
2135     Walk(":", x.step);
2136   }
2137   void Unparse(const OmpLinearClause::WithModifier &x) {
2138     Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
2139     Walk(":", x.step);
2140   }
2141   void Unparse(const OmpReductionClause &x) {
2142     using Modifier = OmpReductionClause::Modifier;
2143     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":");
2144     Walk(std::get<OmpObjectList>(x.t));
2145   }
2146   void Unparse(const OmpDetachClause &x) { Walk(x.v); }
2147   void Unparse(const OmpInReductionClause &x) {
2148     Walk(std::get<OmpReductionIdentifier>(x.t));
2149     Put(":");
2150     Walk(std::get<OmpObjectList>(x.t));
2151   }
2152   void Unparse(const OmpAllocateClause &x) {
2153     using Modifier = OmpAllocateClause::Modifier;
2154     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2155     Walk(std::get<OmpObjectList>(x.t));
2156   }
2157   void Unparse(const OmpAlignModifier &x) {
2158     Word("ALIGN(");
2159     Walk(x.v);
2160     Put(")");
2161   }
2162   void Unparse(const OmpAllocatorSimpleModifier &x) { Walk(x.v); }
2163   void Unparse(const OmpAllocatorComplexModifier &x) {
2164     Word("ALLOCATOR(");
2165     Walk(x.v);
2166     Put(")");
2167   }
2168   void Unparse(const OmpOrderClause &x) {
2169     using Modifier = OmpOrderClause::Modifier;
2170     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ":");
2171     Walk(std::get<OmpOrderClause::Ordering>(x.t));
2172   }
2173   void Unparse(const OmpGrainsizeClause &x) {
2174     using Modifier = OmpGrainsizeClause::Modifier;
2175     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2176     Walk(std::get<ScalarIntExpr>(x.t));
2177   }
2178   void Unparse(const OmpNumTasksClause &x) {
2179     using Modifier = OmpNumTasksClause::Modifier;
2180     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2181     Walk(std::get<ScalarIntExpr>(x.t));
2182   }
2183   void Unparse(const OmpDoacross::Sink &x) {
2184     Word("SINK: ");
2185     Walk(x.v.v);
2186   }
2187   void Unparse(const OmpDoacross::Source &) { Word("SOURCE"); }
2188   void Unparse(const OmpDependClause::TaskDep &x) {
2189     using Modifier = OmpDependClause::TaskDep::Modifier;
2190     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2191     Walk(std::get<OmpObjectList>(x.t));
2192   }
2193   void Unparse(const OmpDefaultmapClause &x) {
2194     using Modifier = OmpDefaultmapClause::Modifier;
2195     Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
2196     Walk(":", std::get<std::optional<std::list<Modifier>>>(x.t));
2197   }
2198   void Unparse(const OmpToClause &x) {
2199     using Modifier = OmpToClause::Modifier;
2200     Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
2201     Walk(std::get<OmpObjectList>(x.t));
2202   }
2203 #define GEN_FLANG_CLAUSE_UNPARSE
2204 #include "llvm/Frontend/OpenMP/OMP.inc"
2205   void Unparse(const OmpLoopDirective &x) {
2206     switch (x.v) {
2207     case llvm::omp::Directive::OMPD_distribute:
2208       Word("DISTRIBUTE ");
2209       break;
2210     case llvm::omp::Directive::OMPD_distribute_parallel_do:
2211       Word("DISTRIBUTE PARALLEL DO ");
2212       break;
2213     case llvm::omp::Directive::OMPD_distribute_parallel_do_simd:
2214       Word("DISTRIBUTE PARALLEL DO SIMD ");
2215       break;
2216     case llvm::omp::Directive::OMPD_distribute_simd:
2217       Word("DISTRIBUTE SIMD ");
2218       break;
2219     case llvm::omp::Directive::OMPD_do:
2220       Word("DO ");
2221       break;
2222     case llvm::omp::Directive::OMPD_do_simd:
2223       Word("DO SIMD ");
2224       break;
2225     case llvm::omp::Directive::OMPD_loop:
2226       Word("LOOP ");
2227       break;
2228     case llvm::omp::Directive::OMPD_masked_taskloop_simd:
2229       Word("MASKED TASKLOOP SIMD");
2230       break;
2231     case llvm::omp::Directive::OMPD_masked_taskloop:
2232       Word("MASKED TASKLOOP");
2233       break;
2234     case llvm::omp::Directive::OMPD_master_taskloop_simd:
2235       Word("MASTER TASKLOOP SIMD");
2236       break;
2237     case llvm::omp::Directive::OMPD_master_taskloop:
2238       Word("MASTER TASKLOOP");
2239       break;
2240     case llvm::omp::Directive::OMPD_parallel_do:
2241       Word("PARALLEL DO ");
2242       break;
2243     case llvm::omp::Directive::OMPD_parallel_do_simd:
2244       Word("PARALLEL DO SIMD ");
2245       break;
2246     case llvm::omp::Directive::OMPD_parallel_masked_taskloop_simd:
2247       Word("PARALLEL MASKED TASKLOOP SIMD");
2248       break;
2249     case llvm::omp::Directive::OMPD_parallel_masked_taskloop:
2250       Word("PARALLEL MASKED TASKLOOP");
2251       break;
2252     case llvm::omp::Directive::OMPD_parallel_master_taskloop_simd:
2253       Word("PARALLEL MASTER TASKLOOP SIMD");
2254       break;
2255     case llvm::omp::Directive::OMPD_parallel_master_taskloop:
2256       Word("PARALLEL MASTER TASKLOOP");
2257       break;
2258     case llvm::omp::Directive::OMPD_simd:
2259       Word("SIMD ");
2260       break;
2261     case llvm::omp::Directive::OMPD_target_loop:
2262       Word("TARGET LOOP ");
2263       break;
2264     case llvm::omp::Directive::OMPD_target_parallel_do:
2265       Word("TARGET PARALLEL DO ");
2266       break;
2267     case llvm::omp::Directive::OMPD_target_parallel_do_simd:
2268       Word("TARGET PARALLEL DO SIMD ");
2269       break;
2270     case llvm::omp::Directive::OMPD_target_parallel_loop:
2271       Word("TARGET PARALLEL LOOP ");
2272       break;
2273     case llvm::omp::Directive::OMPD_target_teams_distribute:
2274       Word("TARGET TEAMS DISTRIBUTE ");
2275       break;
2276     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
2277       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO ");
2278       break;
2279     case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
2280       Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2281       break;
2282     case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
2283       Word("TARGET TEAMS DISTRIBUTE SIMD ");
2284       break;
2285     case llvm::omp::Directive::OMPD_target_teams_loop:
2286       Word("TARGET TEAMS LOOP ");
2287       break;
2288     case llvm::omp::Directive::OMPD_target_simd:
2289       Word("TARGET SIMD ");
2290       break;
2291     case llvm::omp::Directive::OMPD_taskloop:
2292       Word("TASKLOOP ");
2293       break;
2294     case llvm::omp::Directive::OMPD_taskloop_simd:
2295       Word("TASKLOOP SIMD ");
2296       break;
2297     case llvm::omp::Directive::OMPD_teams_distribute:
2298       Word("TEAMS DISTRIBUTE ");
2299       break;
2300     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do:
2301       Word("TEAMS DISTRIBUTE PARALLEL DO ");
2302       break;
2303     case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd:
2304       Word("TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2305       break;
2306     case llvm::omp::Directive::OMPD_teams_distribute_simd:
2307       Word("TEAMS DISTRIBUTE SIMD ");
2308       break;
2309     case llvm::omp::Directive::OMPD_tile:
2310       Word("TILE ");
2311       break;
2312     case llvm::omp::Directive::OMPD_unroll:
2313       Word("UNROLL ");
2314       break;
2315     default:
2316       break;
2317     }
2318   }
2319   void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
2320   void Unparse(const OmpSimpleStandaloneDirective &x) {
2321     switch (x.v) {
2322     case llvm::omp::Directive::OMPD_barrier:
2323       Word("BARRIER ");
2324       break;
2325     case llvm::omp::Directive::OMPD_scan:
2326       Word("SCAN ");
2327       break;
2328     case llvm::omp::Directive::OMPD_taskwait:
2329       Word("TASKWAIT ");
2330       break;
2331     case llvm::omp::Directive::OMPD_taskyield:
2332       Word("TASKYIELD ");
2333       break;
2334     case llvm::omp::Directive::OMPD_target_enter_data:
2335       Word("TARGET ENTER DATA ");
2336       break;
2337     case llvm::omp::Directive::OMPD_target_exit_data:
2338       Word("TARGET EXIT DATA ");
2339       break;
2340     case llvm::omp::Directive::OMPD_target_update:
2341       Word("TARGET UPDATE ");
2342       break;
2343     case llvm::omp::Directive::OMPD_ordered:
2344       Word("ORDERED ");
2345       break;
2346     default:
2347       // Nothing to be done
2348       break;
2349     }
2350   }
2351   void Unparse(const OmpBlockDirective &x) {
2352     switch (x.v) {
2353     case llvm::omp::Directive::OMPD_masked:
2354       Word("MASKED");
2355       break;
2356     case llvm::omp::Directive::OMPD_master:
2357       Word("MASTER");
2358       break;
2359     case llvm::omp::Directive::OMPD_ordered:
2360       Word("ORDERED ");
2361       break;
2362     case llvm::omp::Directive::OMPD_parallel_masked:
2363       Word("PARALLEL MASKED");
2364       break;
2365     case llvm::omp::Directive::OMPD_parallel_master:
2366       Word("PARALLEL MASTER");
2367       break;
2368     case llvm::omp::Directive::OMPD_parallel_workshare:
2369       Word("PARALLEL WORKSHARE ");
2370       break;
2371     case llvm::omp::Directive::OMPD_parallel:
2372       Word("PARALLEL ");
2373       break;
2374     case llvm::omp::Directive::OMPD_scope:
2375       Word("SCOPE ");
2376       break;
2377     case llvm::omp::Directive::OMPD_single:
2378       Word("SINGLE ");
2379       break;
2380     case llvm::omp::Directive::OMPD_target_data:
2381       Word("TARGET DATA ");
2382       break;
2383     case llvm::omp::Directive::OMPD_target_parallel:
2384       Word("TARGET PARALLEL ");
2385       break;
2386     case llvm::omp::Directive::OMPD_target_teams:
2387       Word("TARGET TEAMS ");
2388       break;
2389     case llvm::omp::Directive::OMPD_target:
2390       Word("TARGET ");
2391       break;
2392     case llvm::omp::Directive::OMPD_taskgroup:
2393       Word("TASKGROUP ");
2394       break;
2395     case llvm::omp::Directive::OMPD_task:
2396       Word("TASK ");
2397       break;
2398     case llvm::omp::Directive::OMPD_teams:
2399       Word("TEAMS ");
2400       break;
2401     case llvm::omp::Directive::OMPD_workshare:
2402       Word("WORKSHARE ");
2403       break;
2404     default:
2405       // Nothing to be done
2406       break;
2407     }
2408   }
2409 
2410   void Unparse(const OmpAtomicDefaultMemOrderClause &x) {
2411     Word(ToUpperCaseLetters(common::EnumToString(x.v)));
2412   }
2413 
2414   void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }
2415 
2416   void Unparse(const OmpAtomic &x) {
2417     BeginOpenMP();
2418     Word("!$OMP ATOMIC");
2419     Walk(std::get<OmpAtomicClauseList>(x.t));
2420     Put("\n");
2421     EndOpenMP();
2422     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2423     BeginOpenMP();
2424     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2425     EndOpenMP();
2426   }
2427   void Unparse(const OmpAtomicCapture &x) {
2428     BeginOpenMP();
2429     Word("!$OMP ATOMIC");
2430     Walk(std::get<0>(x.t));
2431     Word(" CAPTURE");
2432     Walk(std::get<2>(x.t));
2433     Put("\n");
2434     EndOpenMP();
2435     Walk(std::get<OmpAtomicCapture::Stmt1>(x.t));
2436     Put("\n");
2437     Walk(std::get<OmpAtomicCapture::Stmt2>(x.t));
2438     BeginOpenMP();
2439     Word("!$OMP END ATOMIC\n");
2440     EndOpenMP();
2441   }
2442   void Unparse(const OmpAtomicCompare &x) {
2443     BeginOpenMP();
2444     Word("!$OMP ATOMIC");
2445     Walk(std::get<0>(x.t));
2446     Word(" COMPARE");
2447     Walk(std::get<2>(x.t));
2448     Put("\n");
2449     EndOpenMP();
2450     Walk(std::get<OmpAtomicCompareIfStmt>(x.t));
2451   }
2452   void Unparse(const OmpAtomicRead &x) {
2453     BeginOpenMP();
2454     Word("!$OMP ATOMIC");
2455     Walk(std::get<0>(x.t));
2456     Word(" READ");
2457     Walk(std::get<2>(x.t));
2458     Put("\n");
2459     EndOpenMP();
2460     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2461     BeginOpenMP();
2462     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2463     EndOpenMP();
2464   }
2465   void Unparse(const OmpAtomicUpdate &x) {
2466     BeginOpenMP();
2467     Word("!$OMP ATOMIC");
2468     Walk(std::get<0>(x.t));
2469     Word(" UPDATE");
2470     Walk(std::get<2>(x.t));
2471     Put("\n");
2472     EndOpenMP();
2473     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2474     BeginOpenMP();
2475     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2476     EndOpenMP();
2477   }
2478   void Unparse(const OmpAtomicWrite &x) {
2479     BeginOpenMP();
2480     Word("!$OMP ATOMIC");
2481     Walk(std::get<0>(x.t));
2482     Word(" WRITE");
2483     Walk(std::get<2>(x.t));
2484     Put("\n");
2485     EndOpenMP();
2486     Walk(std::get<Statement<AssignmentStmt>>(x.t));
2487     BeginOpenMP();
2488     Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2489     EndOpenMP();
2490   }
2491   void Unparse(const OpenMPExecutableAllocate &x) {
2492     const auto &fields =
2493         std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
2494             x.t);
2495     if (fields) {
2496       for (const auto &decl : *fields) {
2497         Walk(decl);
2498       }
2499     }
2500     BeginOpenMP();
2501     Word("!$OMP ALLOCATE");
2502     Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2503     Walk(std::get<OmpClauseList>(x.t));
2504     Put("\n");
2505     EndOpenMP();
2506     Walk(std::get<Statement<AllocateStmt>>(x.t));
2507   }
2508   void Unparse(const OpenMPDeclarativeAllocate &x) {
2509     BeginOpenMP();
2510     Word("!$OMP ALLOCATE");
2511     Put(" (");
2512     Walk(std::get<OmpObjectList>(x.t));
2513     Put(")");
2514     Walk(std::get<OmpClauseList>(x.t));
2515     Put("\n");
2516     EndOpenMP();
2517   }
2518   void Unparse(const OmpEndAllocators &x) {
2519     BeginOpenMP();
2520     Word("!$OMP END ALLOCATE");
2521     Put("\n");
2522     EndOpenMP();
2523   }
2524   void Unparse(const OpenMPAllocatorsConstruct &x) {
2525     BeginOpenMP();
2526     Word("!$OMP ALLOCATE");
2527     Walk(std::get<OmpClauseList>(x.t));
2528     Put("\n");
2529     EndOpenMP();
2530     Walk(std::get<Statement<AllocateStmt>>(x.t));
2531     if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) {
2532       Walk(*end);
2533     }
2534   }
2535   void Unparse(const OmpCriticalDirective &x) {
2536     BeginOpenMP();
2537     Word("!$OMP CRITICAL");
2538     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2539     Walk(std::get<OmpClauseList>(x.t));
2540     Put("\n");
2541     EndOpenMP();
2542   }
2543   void Unparse(const OmpEndCriticalDirective &x) {
2544     BeginOpenMP();
2545     Word("!$OMP END CRITICAL");
2546     Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2547     Put("\n");
2548     EndOpenMP();
2549   }
2550   void Unparse(const OpenMPCriticalConstruct &x) {
2551     Walk(std::get<OmpCriticalDirective>(x.t));
2552     Walk(std::get<Block>(x.t), "");
2553     Walk(std::get<OmpEndCriticalDirective>(x.t));
2554   }
2555   void Unparse(const OmpDeclareTargetWithList &x) {
2556     Put("("), Walk(x.v), Put(")");
2557   }
2558   void Unparse(const OmpReductionInitializerClause &x) {
2559     Word(" INITIALIZER(OMP_PRIV = ");
2560     Walk(x.v);
2561     Put(")");
2562   }
2563   void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
2564     const auto &pd = std::get<ProcedureDesignator>(x.v.t);
2565     const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
2566     Walk(pd);
2567     if (args.empty()) {
2568       if (std::holds_alternative<ProcComponentRef>(pd.u)) {
2569         Put("()");
2570       }
2571     } else {
2572       Walk("(", args, ", ", ")");
2573     }
2574   }
2575   void Unparse(const OpenMPDeclareReductionConstruct &x) {
2576     Put("(");
2577     Walk(std::get<OmpReductionIdentifier>(x.t)), Put(" : ");
2578     Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
2579     Walk(std::get<OmpReductionCombiner>(x.t));
2580     Put(")");
2581     Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
2582   }
2583   bool Pre(const OpenMPDeclarativeConstruct &x) {
2584     BeginOpenMP();
2585     Word("!$OMP ");
2586     return common::visit(
2587         common::visitors{
2588             [&](const OpenMPDeclarativeAllocate &z) {
2589               Word("ALLOCATE (");
2590               Walk(std::get<OmpObjectList>(z.t));
2591               Put(")");
2592               Walk(std::get<OmpClauseList>(z.t));
2593               Put("\n");
2594               EndOpenMP();
2595               return false;
2596             },
2597             [&](const OpenMPDeclareMapperConstruct &z) {
2598               Word("DECLARE MAPPER (");
2599               const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)};
2600               if (auto mapname{std::get<std::optional<Name>>(spec.t)}) {
2601                 Walk(mapname);
2602                 Put(":");
2603               }
2604               Walk(std::get<TypeSpec>(spec.t));
2605               Put("::");
2606               Walk(std::get<Name>(spec.t));
2607               Put(")");
2608 
2609               Walk(std::get<OmpClauseList>(z.t));
2610               Put("\n");
2611               return false;
2612             },
2613             [&](const OpenMPDeclareReductionConstruct &) {
2614               Word("DECLARE REDUCTION ");
2615               return true;
2616             },
2617             [&](const OpenMPDeclareSimdConstruct &y) {
2618               Word("DECLARE SIMD ");
2619               Walk("(", std::get<std::optional<Name>>(y.t), ")");
2620               Walk(std::get<OmpClauseList>(y.t));
2621               Put("\n");
2622               EndOpenMP();
2623               return false;
2624             },
2625             [&](const OpenMPDeclareTargetConstruct &) {
2626               Word("DECLARE TARGET ");
2627               return true;
2628             },
2629             [&](const OpenMPRequiresConstruct &y) {
2630               Word("REQUIRES ");
2631               Walk(std::get<OmpClauseList>(y.t));
2632               Put("\n");
2633               EndOpenMP();
2634               return false;
2635             },
2636             [&](const OpenMPThreadprivate &) {
2637               Word("THREADPRIVATE (");
2638               return true;
2639             },
2640         },
2641         x.u);
2642   }
2643   void Post(const OpenMPDeclarativeConstruct &) {
2644     Put("\n");
2645     EndOpenMP();
2646   }
2647   void Post(const OpenMPThreadprivate &) {
2648     Put(")\n");
2649     EndOpenMP();
2650   }
2651   void Unparse(const OmpSectionsDirective &x) {
2652     switch (x.v) {
2653     case llvm::omp::Directive::OMPD_sections:
2654       Word("SECTIONS ");
2655       break;
2656     case llvm::omp::Directive::OMPD_parallel_sections:
2657       Word("PARALLEL SECTIONS ");
2658       break;
2659     default:
2660       break;
2661     }
2662   }
2663   void Unparse(const OmpSectionBlocks &x) {
2664     for (const auto &y : x.v) {
2665       BeginOpenMP();
2666       Word("!$OMP SECTION");
2667       Put("\n");
2668       EndOpenMP();
2669       // y.u is an OpenMPSectionConstruct
2670       // (y.u).v is Block
2671       Walk(std::get<OpenMPSectionConstruct>(y.u).v, "");
2672     }
2673   }
2674   void Unparse(const OpenMPSectionsConstruct &x) {
2675     BeginOpenMP();
2676     Word("!$OMP ");
2677     Walk(std::get<OmpBeginSectionsDirective>(x.t));
2678     Put("\n");
2679     EndOpenMP();
2680     Walk(std::get<OmpSectionBlocks>(x.t));
2681     BeginOpenMP();
2682     Word("!$OMP END ");
2683     Walk(std::get<OmpEndSectionsDirective>(x.t));
2684     Put("\n");
2685     EndOpenMP();
2686   }
2687   void Unparse(const OpenMPCancellationPointConstruct &x) {
2688     BeginOpenMP();
2689     Word("!$OMP CANCELLATION POINT ");
2690     Walk(std::get<OmpCancelType>(x.t));
2691     Put("\n");
2692     EndOpenMP();
2693   }
2694   void Unparse(const OpenMPCancelConstruct &x) {
2695     BeginOpenMP();
2696     Word("!$OMP CANCEL ");
2697     Walk(std::get<OmpCancelType>(x.t));
2698     Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
2699     Put("\n");
2700     EndOpenMP();
2701   }
2702   void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
2703   void Unparse(const OmpAtomicClause &x) {
2704     common::visit(common::visitors{
2705                       [&](const OmpMemoryOrderClause &y) { Walk(y); },
2706                       [&](const OmpClause &z) { Walk(z); },
2707                   },
2708         x.u);
2709   }
2710   void Unparse(const OpenMPDepobjConstruct &x) {
2711     BeginOpenMP();
2712     Word("!$OMP DEPOBJ");
2713     Put("(");
2714     Walk(std::get<OmpObject>(x.t));
2715     Put(") ");
2716     Walk(std::get<OmpClause>(x.t));
2717     Put("\n");
2718     EndOpenMP();
2719   }
2720   void Unparse(const OpenMPFlushConstruct &x) {
2721     BeginOpenMP();
2722     Word("!$OMP FLUSH ");
2723     Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t));
2724     Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2725     Put("\n");
2726     EndOpenMP();
2727   }
2728   void Unparse(const OmpEndLoopDirective &x) {
2729     BeginOpenMP();
2730     Word("!$OMP END ");
2731     Walk(std::get<OmpLoopDirective>(x.t));
2732     Walk(std::get<OmpClauseList>(x.t));
2733     Put("\n");
2734     EndOpenMP();
2735   }
2736   void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
2737   void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
2738     BeginOpenMP();
2739     Word("!$OMP ");
2740     Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
2741     Walk(std::get<OmpClauseList>(x.t));
2742     Put("\n");
2743     EndOpenMP();
2744   }
2745   void Unparse(const OpenMPBlockConstruct &x) {
2746     BeginOpenMP();
2747     Word("!$OMP ");
2748     Walk(std::get<OmpBeginBlockDirective>(x.t));
2749     Put("\n");
2750     EndOpenMP();
2751     Walk(std::get<Block>(x.t), "");
2752     BeginOpenMP();
2753     Word("!$OMP END ");
2754     Walk(std::get<OmpEndBlockDirective>(x.t));
2755     Put("\n");
2756     EndOpenMP();
2757   }
2758   void Unparse(const OpenMPLoopConstruct &x) {
2759     BeginOpenMP();
2760     Word("!$OMP ");
2761     Walk(std::get<OmpBeginLoopDirective>(x.t));
2762     Put("\n");
2763     EndOpenMP();
2764     Walk(std::get<std::optional<DoConstruct>>(x.t));
2765     Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t));
2766   }
2767   void Unparse(const BasedPointer &x) {
2768     Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
2769     Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
2770   }
2771   void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }
2772   void Unparse(const CUDAAttributesStmt &x) {
2773     Word("ATTRIBUTES("), Walk(std::get<common::CUDADataAttr>(x.t));
2774     Word(") "), Walk(std::get<std::list<Name>>(x.t), ", ");
2775   }
2776   void Post(const StructureField &x) {
2777     if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {
2778       for (const auto &item :
2779           std::get<std::list<ComponentOrFill>>(def->statement.t)) {
2780         if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) {
2781           structureComponents_.insert(std::get<Name>(comp->t).source);
2782         }
2783       }
2784     }
2785   }
2786   void Unparse(const StructureStmt &x) {
2787     Word("STRUCTURE ");
2788     // The name, if present, includes the /slashes/
2789     Walk(std::get<std::optional<Name>>(x.t));
2790     Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
2791     Indent();
2792   }
2793   void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
2794   void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
2795   void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
2796   void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
2797   void Post(const StructureDef::EndStructureStmt &) {
2798     Outdent(), Word("END STRUCTURE");
2799   }
2800   void Unparse(const OldParameterStmt &x) {
2801     Word("PARAMETER "), Walk(x.v, ", ");
2802   }
2803   void Unparse(const ArithmeticIfStmt &x) {
2804     Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
2805     Walk(std::get<1>(x.t)), Put(", ");
2806     Walk(std::get<2>(x.t)), Put(", ");
2807     Walk(std::get<3>(x.t));
2808   }
2809   void Unparse(const AssignStmt &x) {
2810     Word("ASSIGN "), Walk(std::get<Label>(x.t));
2811     Word(" TO "), Walk(std::get<Name>(x.t));
2812   }
2813   void Unparse(const AssignedGotoStmt &x) {
2814     Word("GO TO "), Walk(std::get<Name>(x.t));
2815     Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
2816   }
2817   void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }
2818 
2819 #define WALK_NESTED_ENUM(CLASS, ENUM) \
2820   void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
2821   WALK_NESTED_ENUM(AccDataModifier, Modifier)
2822   WALK_NESTED_ENUM(AccessSpec, Kind) // R807
2823   WALK_NESTED_ENUM(common, TypeParamAttr) // R734
2824   WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA
2825   WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA
2826   WALK_NESTED_ENUM(IntentSpec, Intent) // R826
2827   WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
2828   WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
2829   WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
2830   WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
2831   WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
2832   WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
2833   WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
2834   WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
2835   WALK_NESTED_ENUM(OmpBindClause, Binding) // OMP bind
2836   WALK_NESTED_ENUM(OmpProcBindClause, AffinityPolicy) // OMP proc_bind
2837   WALK_NESTED_ENUM(OmpDefaultClause, DataSharingAttribute) // OMP default
2838   WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP defaultmap
2839   WALK_NESTED_ENUM(OmpVariableCategory, Value) // OMP variable-category
2840   WALK_NESTED_ENUM(
2841       OmpLastprivateClause, LastprivateModifier) // OMP lastprivate-modifier
2842   WALK_NESTED_ENUM(OmpChunkModifier, Value) // OMP chunk-modifier
2843   WALK_NESTED_ENUM(OmpLinearModifier, Value) // OMP linear-modifier
2844   WALK_NESTED_ENUM(OmpOrderingModifier, Value) // OMP ordering-modifier
2845   WALK_NESTED_ENUM(OmpTaskDependenceType, Value) // OMP task-dependence-type
2846   WALK_NESTED_ENUM(OmpScheduleClause, Kind) // OMP schedule-kind
2847   WALK_NESTED_ENUM(OmpDeviceModifier, Value) // OMP device modifier
2848   WALK_NESTED_ENUM(
2849       OmpDeviceTypeClause, DeviceTypeDescription) // OMP device_type
2850   WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier
2851   WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation
2852   WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
2853   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
2854   WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering
2855   WALK_NESTED_ENUM(OmpOrderModifier, Value) // OMP order-modifier
2856   WALK_NESTED_ENUM(OmpPrescriptiveness, Value) // OMP prescriptiveness
2857   WALK_NESTED_ENUM(OmpMapType, Value) // OMP map-type
2858   WALK_NESTED_ENUM(OmpMapTypeModifier, Value) // OMP map-type-modifier
2859 #undef WALK_NESTED_ENUM
2860   void Unparse(const ReductionOperator::Operator x) {
2861     switch (x) {
2862     case ReductionOperator::Operator::Plus:
2863       Word("+");
2864       break;
2865     case ReductionOperator::Operator::Multiply:
2866       Word("*");
2867       break;
2868     case ReductionOperator::Operator::And:
2869       Word(".AND.");
2870       break;
2871     case ReductionOperator::Operator::Or:
2872       Word(".OR.");
2873       break;
2874     case ReductionOperator::Operator::Eqv:
2875       Word(".EQV.");
2876       break;
2877     case ReductionOperator::Operator::Neqv:
2878       Word(".NEQV.");
2879       break;
2880     default:
2881       Word(ReductionOperator::EnumToString(x));
2882       break;
2883     }
2884   }
2885 
2886   void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) {
2887     if (x.v) {
2888       Walk(*x.v);
2889     } else {
2890       Word("*");
2891     }
2892   }
2893   void Unparse(const CUFKernelDoConstruct::LaunchConfiguration &x) {
2894     Word(" <<<");
2895     const auto &grid{std::get<0>(x.t)};
2896     if (grid.empty()) {
2897       Word("*");
2898     } else if (grid.size() == 1) {
2899       Walk(grid.front());
2900     } else {
2901       Walk("(", grid, ",", ")");
2902     }
2903     Word(",");
2904     const auto &block{std::get<1>(x.t)};
2905     if (block.empty()) {
2906       Word("*");
2907     } else if (block.size() == 1) {
2908       Walk(block.front());
2909     } else {
2910       Walk("(", block, ",", ")");
2911     }
2912     if (const auto &stream{std::get<2>(x.t)}) {
2913       Word(",STREAM="), Walk(*stream);
2914     }
2915     Word(">>>");
2916   }
2917   void Unparse(const CUFKernelDoConstruct::Directive &x) {
2918     Word("!$CUF KERNEL DO");
2919     Walk(" (", std::get<std::optional<ScalarIntConstantExpr>>(x.t), ")");
2920     Walk(std::get<std::optional<CUFKernelDoConstruct::LaunchConfiguration>>(
2921         x.t));
2922     Walk(" ", std::get<std::list<CUFReduction>>(x.t), " ");
2923     Word("\n");
2924   }
2925   void Unparse(const CUFKernelDoConstruct &x) {
2926     Walk(std::get<CUFKernelDoConstruct::Directive>(x.t));
2927     Walk(std::get<std::optional<DoConstruct>>(x.t));
2928   }
2929   void Unparse(const CUFReduction &x) {
2930     Word("REDUCE(");
2931     Walk(std::get<CUFReduction::Operator>(x.t));
2932     Walk(":", std::get<std::list<Scalar<Variable>>>(x.t), ",", ")");
2933   }
2934 
2935   void Done() const { CHECK(indent_ == 0); }
2936 
2937 private:
2938   void Put(char);
2939   void Put(const char *);
2940   void Put(const std::string &);
2941   void PutNormalized(const std::string &);
2942   void PutKeywordLetter(char);
2943   void Word(const char *);
2944   void Word(const std::string &);
2945   void Word(const std::string_view &);
2946   void Indent() { indent_ += indentationAmount_; }
2947   void Outdent() {
2948     CHECK(indent_ >= indentationAmount_);
2949     indent_ -= indentationAmount_;
2950   }
2951   void BeginOpenMP() { openmpDirective_ = true; }
2952   void EndOpenMP() { openmpDirective_ = false; }
2953   void BeginOpenACC() { openaccDirective_ = true; }
2954   void EndOpenACC() { openaccDirective_ = false; }
2955 
2956   // Call back to the traversal framework.
2957   template <typename T> void Walk(const T &x) {
2958     Fortran::parser::Walk(x, *this);
2959   }
2960 
2961   // Traverse a std::optional<> value.  Emit a prefix and/or a suffix string
2962   // only when it contains a value.
2963   template <typename A>
2964   void Walk(
2965       const char *prefix, const std::optional<A> &x, const char *suffix = "") {
2966     if (x) {
2967       Word(prefix), Walk(*x), Word(suffix);
2968     }
2969   }
2970   template <typename A>
2971   void Walk(const std::optional<A> &x, const char *suffix = "") {
2972     return Walk("", x, suffix);
2973   }
2974 
2975   // Traverse a std::list<>.  Separate the elements with an optional string.
2976   // Emit a prefix and/or a suffix string only when the list is not empty.
2977   template <typename A>
2978   void Walk(const char *prefix, const std::list<A> &list,
2979       const char *comma = ", ", const char *suffix = "") {
2980     if (!list.empty()) {
2981       const char *str{prefix};
2982       for (const auto &x : list) {
2983         Word(str), Walk(x);
2984         str = comma;
2985       }
2986       Word(suffix);
2987     }
2988   }
2989   template <typename A>
2990   void Walk(const std::list<A> &list, const char *comma = ", ",
2991       const char *suffix = "") {
2992     return Walk("", list, comma, suffix);
2993   }
2994 
2995   // Traverse a std::tuple<>, with an optional separator.
2996   template <std::size_t J = 0, typename T>
2997   void WalkTupleElements(const T &tuple, const char *separator) {
2998     if (J > 0 && J < std::tuple_size_v<T>) {
2999       Word(separator); // this usage dodges "unused parameter" warning
3000     }
3001     if constexpr (J < std::tuple_size_v<T>) {
3002       Walk(std::get<J>(tuple));
3003       WalkTupleElements<J + 1>(tuple, separator);
3004     }
3005   }
3006   template <typename... A>
3007   void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
3008     WalkTupleElements(tuple, separator);
3009   }
3010 
3011   void EndSubprogram(const char *kind, const std::optional<Name> &name) {
3012     Outdent(), Word("END "), Word(kind), Walk(" ", name);
3013     structureComponents_.clear();
3014   }
3015 
3016   llvm::raw_ostream &out_;
3017   int indent_{0};
3018   const int indentationAmount_{1};
3019   int column_{1};
3020   const int maxColumns_{80};
3021   std::set<CharBlock> structureComponents_;
3022   Encoding encoding_{Encoding::UTF_8};
3023   bool capitalizeKeywords_{true};
3024   bool openaccDirective_{false};
3025   bool openmpDirective_{false};
3026   bool backslashEscapes_{false};
3027   preStatementType *preStatement_{nullptr};
3028   AnalyzedObjectsAsFortran *asFortran_{nullptr};
3029 };
3030 
3031 void UnparseVisitor::Put(char ch) {
3032   int sav = indent_;
3033   if (openmpDirective_ || openaccDirective_) {
3034     indent_ = 0;
3035   }
3036   if (column_ <= 1) {
3037     if (ch == '\n') {
3038       return;
3039     }
3040     for (int j{0}; j < indent_; ++j) {
3041       out_ << ' ';
3042     }
3043     column_ = indent_ + 2;
3044   } else if (ch == '\n') {
3045     column_ = 1;
3046   } else if (++column_ >= maxColumns_) {
3047     out_ << "&\n";
3048     for (int j{0}; j < indent_; ++j) {
3049       out_ << ' ';
3050     }
3051     if (openmpDirective_) {
3052       out_ << "!$OMP&";
3053       column_ = 8;
3054     } else if (openaccDirective_) {
3055       out_ << "!$ACC&";
3056       column_ = 8;
3057     } else {
3058       out_ << '&';
3059       column_ = indent_ + 3;
3060     }
3061   }
3062   out_ << ch;
3063   if (openmpDirective_ || openaccDirective_) {
3064     indent_ = sav;
3065   }
3066 }
3067 
3068 void UnparseVisitor::Put(const char *str) {
3069   for (; *str != '\0'; ++str) {
3070     Put(*str);
3071   }
3072 }
3073 
3074 void UnparseVisitor::Put(const std::string &str) {
3075   for (char ch : str) {
3076     Put(ch);
3077   }
3078 }
3079 
3080 void UnparseVisitor::PutNormalized(const std::string &str) {
3081   auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};
3082   std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};
3083   Put(QuoteCharacterLiteral(encoded, backslashEscapes_));
3084 }
3085 
3086 void UnparseVisitor::PutKeywordLetter(char ch) {
3087   if (capitalizeKeywords_) {
3088     Put(ToUpperCaseLetter(ch));
3089   } else {
3090     Put(ToLowerCaseLetter(ch));
3091   }
3092 }
3093 
3094 void UnparseVisitor::Word(const char *str) {
3095   for (; *str != '\0'; ++str) {
3096     PutKeywordLetter(*str);
3097   }
3098 }
3099 
3100 void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
3101 
3102 void UnparseVisitor::Word(const std::string_view &str) {
3103   for (std::size_t j{0}; j < str.length(); ++j) {
3104     PutKeywordLetter(str[j]);
3105   }
3106 }
3107 
3108 template <typename A>
3109 void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
3110     bool capitalizeKeywords, bool backslashEscapes,
3111     preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
3112   UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
3113       preStatement, asFortran};
3114   Walk(root, visitor);
3115   visitor.Done();
3116 }
3117 
3118 template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding,
3119     bool, bool, preStatementType *, AnalyzedObjectsAsFortran *);
3120 template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool,
3121     bool, preStatementType *, AnalyzedObjectsAsFortran *);
3122 } // namespace Fortran::parser
3123