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
26namespace Fortran::parser {
27
28class UnparseVisitor {
29public:
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(val: x)); }
70 void Unparse(unsigned int x) { Put(std::to_string(val: x)); }
71 void Unparse(long x) { Put(std::to_string(val: x)); }
72 void Unparse(unsigned long x) { Put(std::to_string(val: x)); }
73 void Unparse(long long x) { Put(std::to_string(val: x)); }
74 void Unparse(unsigned long long x) { Put(std::to_string(val: 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"), Walk(", NAME=", x.v), Put(')');
528 }
529 void Unparse(const CoarraySpec &x) { // R809
530 common::visit(common::visitors{
531 [&](const DeferredCoshapeSpecList &y) { Walk(y); },
532 [&](const ExplicitCoshapeSpec &y) { Walk(y); },
533 },
534 x.u);
535 }
536 void Unparse(const DeferredCoshapeSpecList &x) { // R810
537 for (auto j{x.v}; j > 0; --j) {
538 Put(':');
539 if (j > 1) {
540 Put(',');
541 }
542 }
543 }
544 void Unparse(const ExplicitCoshapeSpec &x) { // R811
545 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
546 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*');
547 }
548 void Unparse(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818
549 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":");
550 Walk(std::get<SpecificationExpr>(x.t));
551 }
552 void Unparse(const ArraySpec &x) { // R815
553 common::visit(
554 common::visitors{
555 [&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
556 [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },
557 [&](const DeferredShapeSpecList &y) { Walk(y); },
558 [&](const AssumedSizeSpec &y) { Walk(y); },
559 [&](const ImpliedShapeSpec &y) { Walk(y); },
560 [&](const AssumedRankSpec &y) { Walk(y); },
561 },
562 x.u);
563 }
564 void Post(const AssumedShapeSpec &) { Put(':'); } // R819
565 void Unparse(const DeferredShapeSpecList &x) { // R820
566 for (auto j{x.v}; j > 0; --j) {
567 Put(':');
568 if (j > 1) {
569 Put(',');
570 }
571 }
572 }
573 void Unparse(const AssumedImpliedSpec &x) { // R821
574 Walk(x.v, ":");
575 Put('*');
576 }
577 void Unparse(const AssumedSizeSpec &x) { // R822
578 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
579 Walk(std::get<AssumedImpliedSpec>(x.t));
580 }
581 void Unparse(const ImpliedShapeSpec &x) { // R823
582 Walk(x.v, ",");
583 }
584 void Post(const AssumedRankSpec &) { Put(".."); } // R825
585 void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); }
586 void Post(const External &) { Word("EXTERNAL"); }
587 void Post(const Intrinsic &) { Word("INTRINSIC"); }
588 void Post(const Optional &) { Word("OPTIONAL"); }
589 void Post(const Parameter &) { Word("PARAMETER"); }
590 void Post(const Protected &) { Word("PROTECTED"); }
591 void Post(const Save &) { Word("SAVE"); }
592 void Post(const Target &) { Word("TARGET"); }
593 void Post(const Value &) { Word("VALUE"); }
594 void Post(const Volatile &) { Word("VOLATILE"); }
595 void Unparse(const IntentSpec &x) { // R826
596 Word("INTENT("), Walk(x.v), Put(")");
597 }
598 void Unparse(const AccessStmt &x) { // R827
599 Walk(std::get<AccessSpec>(x.t));
600 Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", ");
601 }
602 void Unparse(const AllocatableStmt &x) { // R829
603 Word("ALLOCATABLE :: "), Walk(x.v, ", ");
604 }
605 void Unparse(const ObjectDecl &x) { // R830 & R860
606 Walk(std::get<ObjectName>(x.t));
607 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
608 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
609 }
610 void Unparse(const AsynchronousStmt &x) { // R831
611 Word("ASYNCHRONOUS :: "), Walk(x.v, ", ");
612 }
613 void Unparse(const BindStmt &x) { // R832
614 Walk(x.t, " :: ");
615 }
616 void Unparse(const BindEntity &x) { // R833
617 bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common};
618 const char *slash{isCommon ? "/" : ""};
619 Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
620 }
621 void Unparse(const CodimensionStmt &x) { // R834
622 Word("CODIMENSION :: "), Walk(x.v, ", ");
623 }
624 void Unparse(const CodimensionDecl &x) { // R835
625 Walk(std::get<Name>(x.t));
626 Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']');
627 }
628 void Unparse(const ContiguousStmt &x) { // R836
629 Word("CONTIGUOUS :: "), Walk(x.v, ", ");
630 }
631 void Unparse(const DataStmt &x) { // R837
632 Word("DATA "), Walk(x.v, ", ");
633 }
634 void Unparse(const DataStmtSet &x) { // R838
635 Walk(std::get<std::list<DataStmtObject>>(x.t), ", ");
636 Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/');
637 }
638 void Unparse(const DataImpliedDo &x) { // R840, R842
639 Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');
640 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
641 Walk(std::get<DataImpliedDo::Bounds>(x.t)), Put(')');
642 }
643 void Unparse(const DataStmtValue &x) { // R843
644 Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");
645 Walk(std::get<DataStmtConstant>(x.t));
646 }
647 void Unparse(const DimensionStmt &x) { // R848
648 Word("DIMENSION :: "), Walk(x.v, ", ");
649 }
650 void Unparse(const DimensionStmt::Declaration &x) {
651 Walk(std::get<Name>(x.t));
652 Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')');
653 }
654 void Unparse(const IntentStmt &x) { // R849
655 Walk(x.t, " :: ");
656 }
657 void Unparse(const OptionalStmt &x) { // R850
658 Word("OPTIONAL :: "), Walk(x.v, ", ");
659 }
660 void Unparse(const ParameterStmt &x) { // R851
661 Word("PARAMETER("), Walk(x.v, ", "), Put(')');
662 }
663 void Unparse(const NamedConstantDef &x) { // R852
664 Walk(x.t, "=");
665 }
666 void Unparse(const PointerStmt &x) { // R853
667 Word("POINTER :: "), Walk(x.v, ", ");
668 }
669 void Unparse(const PointerDecl &x) { // R854
670 Walk(std::get<Name>(x.t));
671 Walk("(", std::get<std::optional<DeferredShapeSpecList>>(x.t), ")");
672 }
673 void Unparse(const ProtectedStmt &x) { // R855
674 Word("PROTECTED :: "), Walk(x.v, ", ");
675 }
676 void Unparse(const SaveStmt &x) { // R856
677 Word("SAVE"), Walk(" :: ", x.v, ", ");
678 }
679 void Unparse(const SavedEntity &x) { // R857, R858
680 bool isCommon{
681 std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common};
682 const char *slash{isCommon ? "/" : ""};
683 Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
684 }
685 void Unparse(const TargetStmt &x) { // R859
686 Word("TARGET :: "), Walk(x.v, ", ");
687 }
688 void Unparse(const ValueStmt &x) { // R861
689 Word("VALUE :: "), Walk(x.v, ", ");
690 }
691 void Unparse(const VolatileStmt &x) { // R862
692 Word("VOLATILE :: "), Walk(x.v, ", ");
693 }
694 void Unparse(const ImplicitStmt &x) { // R863
695 Word("IMPLICIT ");
696 common::visit(
697 common::visitors{
698 [&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); },
699 [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) {
700 Word("NONE"), Walk(" (", y, ", ", ")");
701 },
702 },
703 x.u);
704 }
705 void Unparse(const ImplicitSpec &x) { // R864
706 Walk(std::get<DeclarationTypeSpec>(x.t));
707 Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')');
708 }
709 void Unparse(const LetterSpec &x) { // R865
710 Put(*std::get<const char *>(x.t));
711 auto second{std::get<std::optional<const char *>>(x.t)};
712 if (second) {
713 Put('-'), Put(**second);
714 }
715 }
716 void Unparse(const ImportStmt &x) { // R867
717 Word("IMPORT");
718 switch (x.kind) {
719 case common::ImportKind::Default:
720 Walk(" :: ", x.names, ", ");
721 break;
722 case common::ImportKind::Only:
723 Put(", "), Word("ONLY: ");
724 Walk(x.names, ", ");
725 break;
726 case common::ImportKind::None:
727 Word(", NONE");
728 break;
729 case common::ImportKind::All:
730 Word(", ALL");
731 break;
732 }
733 }
734 void Unparse(const NamelistStmt &x) { // R868
735 Word("NAMELIST"), Walk(x.v, ", ");
736 }
737 void Unparse(const NamelistStmt::Group &x) {
738 Put('/'), Walk(std::get<Name>(x.t)), Put('/');
739 Walk(std::get<std::list<Name>>(x.t), ", ");
740 }
741 void Unparse(const EquivalenceStmt &x) { // R870, R871
742 Word("EQUIVALENCE");
743 const char *separator{" "};
744 for (const std::list<EquivalenceObject> &y : x.v) {
745 Put(separator), Put('('), Walk(y), Put(')');
746 separator = ", ";
747 }
748 }
749 void Unparse(const CommonStmt &x) { // R873
750 Word("COMMON ");
751 Walk(x.blocks);
752 }
753 void Unparse(const CommonBlockObject &x) { // R874
754 Walk(std::get<Name>(x.t));
755 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
756 }
757 void Unparse(const CommonStmt::Block &x) {
758 Word("/"), Walk(std::get<std::optional<Name>>(x.t)), Word("/");
759 Walk(std::get<std::list<CommonBlockObject>>(x.t));
760 }
761
762 void Unparse(const Substring &x) { // R908, R909
763 Walk(std::get<DataRef>(x.t));
764 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
765 }
766 void Unparse(const CharLiteralConstantSubstring &x) {
767 Walk(std::get<CharLiteralConstant>(x.t));
768 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
769 }
770 void Unparse(const SubstringInquiry &x) {
771 Walk(x.v);
772 Put(x.source.end()[-1] == 'n' ? "%LEN" : "%KIND");
773 }
774 void Unparse(const SubstringRange &x) { // R910
775 Walk(x.t, ":");
776 }
777 void Unparse(const PartRef &x) { // R912
778 Walk(x.name);
779 Walk("(", x.subscripts, ",", ")");
780 Walk(x.imageSelector);
781 }
782 void Unparse(const StructureComponent &x) { // R913
783 Walk(x.base);
784 if (structureComponents_.find(x.component.source) !=
785 structureComponents_.end()) {
786 Put('.');
787 } else {
788 Put('%');
789 }
790 Walk(x.component);
791 }
792 void Unparse(const ArrayElement &x) { // R917
793 Walk(x.base);
794 Put('('), Walk(x.subscripts, ","), Put(')');
795 }
796 void Unparse(const SubscriptTriplet &x) { // R921
797 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
798 Walk(":", std::get<2>(x.t));
799 }
800 void Unparse(const ImageSelector &x) { // R924
801 Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ",");
802 Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']');
803 }
804 void Before(const ImageSelectorSpec::Stat &) { // R926
805 Word("STAT=");
806 }
807 void Before(const ImageSelectorSpec::Team_Number &) { Word("TEAM_NUMBER="); }
808 void Before(const ImageSelectorSpec &x) {
809 if (std::holds_alternative<TeamValue>(x.u)) {
810 Word("TEAM=");
811 }
812 }
813 void Unparse(const AllocateStmt &x) { // R927
814 Word("ALLOCATE(");
815 Walk(std::get<std::optional<TypeSpec>>(x.t), "::");
816 Walk(std::get<std::list<Allocation>>(x.t), ", ");
817 Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')');
818 }
819 void Before(const AllocOpt &x) { // R928, R931
820 common::visit(common::visitors{
821 [&](const AllocOpt::Mold &) { Word("MOLD="); },
822 [&](const AllocOpt::Source &) { Word("SOURCE="); },
823 [&](const AllocOpt::Stream &) { Word("STREAM="); },
824 [&](const AllocOpt::Pinned &) { Word("PINNED="); },
825 [](const StatOrErrmsg &) {},
826 },
827 x.u);
828 }
829 void Unparse(const Allocation &x) { // R932
830 Walk(std::get<AllocateObject>(x.t));
831 Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")");
832 Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]");
833 }
834 void Unparse(const AllocateShapeSpec &x) { // R934 & R938
835 Walk(std::get<std::optional<BoundExpr>>(x.t), ":");
836 Walk(std::get<BoundExpr>(x.t));
837 }
838 void Unparse(const AllocateCoarraySpec &x) { // R937
839 Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ",");
840 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*');
841 }
842 void Unparse(const NullifyStmt &x) { // R939
843 Word("NULLIFY("), Walk(x.v, ", "), Put(')');
844 }
845 void Unparse(const DeallocateStmt &x) { // R941
846 Word("DEALLOCATE(");
847 Walk(std::get<std::list<AllocateObject>>(x.t), ", ");
848 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
849 }
850 void Before(const StatOrErrmsg &x) { // R942 & R1165
851 common::visit(common::visitors{
852 [&](const StatVariable &) { Word("STAT="); },
853 [&](const MsgVariable &) { Word("ERRMSG="); },
854 },
855 x.u);
856 }
857
858 // R1001 - R1022
859 void Unparse(const Expr::Parentheses &x) { Put('('), Walk(x.v), Put(')'); }
860 void Before(const Expr::UnaryPlus &) { Put("+"); }
861 void Before(const Expr::Negate &) { Put("-"); }
862 void Before(const Expr::NOT &) { Word(".NOT."); }
863 void Unparse(const Expr::PercentLoc &x) {
864 Word("%LOC("), Walk(x.v), Put(')');
865 }
866 void Unparse(const Expr::Power &x) { Walk(x.t, "**"); }
867 void Unparse(const Expr::Multiply &x) { Walk(x.t, "*"); }
868 void Unparse(const Expr::Divide &x) { Walk(x.t, "/"); }
869 void Unparse(const Expr::Add &x) { Walk(x.t, "+"); }
870 void Unparse(const Expr::Subtract &x) { Walk(x.t, "-"); }
871 void Unparse(const Expr::Concat &x) { Walk(x.t, "//"); }
872 void Unparse(const Expr::LT &x) { Walk(x.t, "<"); }
873 void Unparse(const Expr::LE &x) { Walk(x.t, "<="); }
874 void Unparse(const Expr::EQ &x) { Walk(x.t, "=="); }
875 void Unparse(const Expr::NE &x) { Walk(x.t, "/="); }
876 void Unparse(const Expr::GE &x) { Walk(x.t, ">="); }
877 void Unparse(const Expr::GT &x) { Walk(x.t, ">"); }
878 void Unparse(const Expr::AND &x) { Walk(x.t, ".AND."); }
879 void Unparse(const Expr::OR &x) { Walk(x.t, ".OR."); }
880 void Unparse(const Expr::EQV &x) { Walk(x.t, ".EQV."); }
881 void Unparse(const Expr::NEQV &x) { Walk(x.t, ".NEQV."); }
882 void Unparse(const Expr::ComplexConstructor &x) {
883 Put('('), Walk(x.t, ","), Put(')');
884 }
885 void Unparse(const Expr::DefinedBinary &x) {
886 Walk(std::get<1>(x.t)); // left
887 Walk(std::get<DefinedOpName>(x.t));
888 Walk(std::get<2>(x.t)); // right
889 }
890 void Unparse(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415
891 Walk(x.v);
892 }
893 void Unparse(const AssignmentStmt &x) { // R1032
894 if (asFortran_ && x.typedAssignment.get()) {
895 Put(' ');
896 asFortran_->assignment(out_, *x.typedAssignment);
897 Put('\n');
898 } else {
899 Walk(x.t, " = ");
900 }
901 }
902 void Unparse(const PointerAssignmentStmt &x) { // R1033, R1034, R1038
903 if (asFortran_ && x.typedAssignment.get()) {
904 Put(' ');
905 asFortran_->assignment(out_, *x.typedAssignment);
906 Put('\n');
907 } else {
908 Walk(std::get<DataRef>(x.t));
909 common::visit(
910 common::visitors{
911 [&](const std::list<BoundsRemapping> &y) {
912 Put('('), Walk(y), Put(')');
913 },
914 [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); },
915 },
916 std::get<PointerAssignmentStmt::Bounds>(x.t).u);
917 Put(" => "), Walk(std::get<Expr>(x.t));
918 }
919 }
920 void Post(const BoundsSpec &) { // R1035
921 Put(':');
922 }
923 void Unparse(const BoundsRemapping &x) { // R1036
924 Walk(x.t, ":");
925 }
926 void Unparse(const WhereStmt &x) { // R1041, R1045, R1046
927 Word("WHERE ("), Walk(x.t, ") ");
928 }
929 void Unparse(const WhereConstructStmt &x) { // R1043
930 Walk(std::get<std::optional<Name>>(x.t), ": ");
931 Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
932 Indent();
933 }
934 void Unparse(const MaskedElsewhereStmt &x) { // R1047
935 Outdent();
936 Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
937 Walk(" ", std::get<std::optional<Name>>(x.t));
938 Indent();
939 }
940 void Unparse(const ElsewhereStmt &x) { // R1048
941 Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent();
942 }
943 void Unparse(const EndWhereStmt &x) { // R1049
944 Outdent(), Word("END WHERE"), Walk(" ", x.v);
945 }
946 void Unparse(const ForallConstructStmt &x) { // R1051
947 Walk(std::get<std::optional<Name>>(x.t), ": ");
948 Word("FORALL"), Walk(std::get<common::Indirection<ConcurrentHeader>>(x.t));
949 Indent();
950 }
951 void Unparse(const EndForallStmt &x) { // R1054
952 Outdent(), Word("END FORALL"), Walk(" ", x.v);
953 }
954 void Before(const ForallStmt &) { // R1055
955 Word("FORALL");
956 }
957
958 void Unparse(const AssociateStmt &x) { // R1103
959 Walk(std::get<std::optional<Name>>(x.t), ": ");
960 Word("ASSOCIATE (");
961 Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent();
962 }
963 void Unparse(const Association &x) { // R1104
964 Walk(x.t, " => ");
965 }
966 void Unparse(const EndAssociateStmt &x) { // R1106
967 Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v);
968 }
969 void Unparse(const BlockStmt &x) { // R1108
970 Walk(x.v, ": "), Word("BLOCK"), Indent();
971 }
972 void Unparse(const EndBlockStmt &x) { // R1110
973 Outdent(), Word("END BLOCK"), Walk(" ", x.v);
974 }
975 void Unparse(const ChangeTeamStmt &x) { // R1112
976 Walk(std::get<std::optional<Name>>(x.t), ": ");
977 Word("CHANGE TEAM ("), Walk(std::get<TeamValue>(x.t));
978 Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", ");
979 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
980 Indent();
981 }
982 void Unparse(const CoarrayAssociation &x) { // R1113
983 Walk(x.t, " => ");
984 }
985 void Unparse(const EndChangeTeamStmt &x) { // R1114
986 Outdent(), Word("END TEAM (");
987 Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
988 Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t));
989 }
990 void Unparse(const CriticalStmt &x) { // R1117
991 Walk(std::get<std::optional<Name>>(x.t), ": ");
992 Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
993 Put(')'), Indent();
994 }
995 void Unparse(const EndCriticalStmt &x) { // R1118
996 Outdent(), Word("END CRITICAL"), Walk(" ", x.v);
997 }
998 void Unparse(const DoConstruct &x) { // R1119, R1120
999 Walk(std::get<Statement<NonLabelDoStmt>>(x.t));
1000 Indent(), Walk(std::get<Block>(x.t), ""), Outdent();
1001 Walk(std::get<Statement<EndDoStmt>>(x.t));
1002 }
1003 void Unparse(const LabelDoStmt &x) { // R1121
1004 Word("DO "), Walk(std::get<Label>(x.t));
1005 Walk(" ", std::get<std::optional<LoopControl>>(x.t));
1006 }
1007 void Unparse(const NonLabelDoStmt &x) { // R1122
1008 Walk(std::get<std::optional<Name>>(x.t), ": ");
1009 Word("DO ");
1010 Walk(std::get<std::optional<Label>>(x.t), " ");
1011 Walk(std::get<std::optional<LoopControl>>(x.t));
1012 }
1013 void Unparse(const LoopControl &x) { // R1123
1014 common::visit(common::visitors{
1015 [&](const ScalarLogicalExpr &y) {
1016 Word("WHILE ("), Walk(y), Put(')');
1017 },
1018 [&](const auto &y) { Walk(y); },
1019 },
1020 x.u);
1021 }
1022 void Unparse(const ConcurrentHeader &x) { // R1125
1023 Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
1024 Walk(std::get<std::list<ConcurrentControl>>(x.t), ", ");
1025 Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')');
1026 }
1027 void Unparse(const ConcurrentControl &x) { // R1126 - R1128
1028 Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t));
1029 Put(':'), Walk(std::get<2>(x.t));
1030 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
1031 }
1032 void Before(const LoopControl::Concurrent &) { // R1129
1033 Word("CONCURRENT");
1034 }
1035 void Unparse(const LocalitySpec::Local &x) {
1036 Word("LOCAL("), Walk(x.v, ", "), Put(')');
1037 }
1038 void Unparse(const LocalitySpec::LocalInit &x) {
1039 Word("LOCAL_INIT("), Walk(x.v, ", "), Put(')');
1040 }
1041 void Unparse(const LocalitySpec::Shared &x) {
1042 Word("SHARED("), Walk(x.v, ", "), Put(')');
1043 }
1044 void Post(const LocalitySpec::DefaultNone &) { Word("DEFAULT(NONE)"); }
1045 void Unparse(const EndDoStmt &x) { // R1132
1046 Word("END DO"), Walk(" ", x.v);
1047 }
1048 void Unparse(const CycleStmt &x) { // R1133
1049 Word("CYCLE"), Walk(" ", x.v);
1050 }
1051 void Unparse(const IfThenStmt &x) { // R1135
1052 Walk(std::get<std::optional<Name>>(x.t), ": ");
1053 Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t));
1054 Put(") "), Word("THEN"), Indent();
1055 }
1056 void Unparse(const ElseIfStmt &x) { // R1136
1057 Outdent(), Word("ELSE IF (");
1058 Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN");
1059 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1060 }
1061 void Unparse(const ElseStmt &x) { // R1137
1062 Outdent(), Word("ELSE"), Walk(" ", x.v), Indent();
1063 }
1064 void Unparse(const EndIfStmt &x) { // R1138
1065 Outdent(), Word("END IF"), Walk(" ", x.v);
1066 }
1067 void Unparse(const IfStmt &x) { // R1139
1068 Word("IF ("), Walk(x.t, ") ");
1069 }
1070 void Unparse(const SelectCaseStmt &x) { // R1141, R1144
1071 Walk(std::get<std::optional<Name>>(x.t), ": ");
1072 Word("SELECT CASE (");
1073 Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent();
1074 }
1075 void Unparse(const CaseStmt &x) { // R1142
1076 Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t));
1077 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1078 }
1079 void Unparse(const EndSelectStmt &x) { // R1143 & R1151 & R1155
1080 Outdent(), Word("END SELECT"), Walk(" ", x.v);
1081 }
1082 void Unparse(const CaseSelector &x) { // R1145
1083 common::visit(common::visitors{
1084 [&](const std::list<CaseValueRange> &y) {
1085 Put('('), Walk(y), Put(')');
1086 },
1087 [&](const Default &) { Word("DEFAULT"); },
1088 },
1089 x.u);
1090 }
1091 void Unparse(const CaseValueRange::Range &x) { // R1146
1092 Walk(x.lower), Put(':'), Walk(x.upper);
1093 }
1094 void Unparse(const SelectRankStmt &x) { // R1149
1095 Walk(std::get<0>(x.t), ": ");
1096 Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => ");
1097 Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1098 }
1099 void Unparse(const SelectRankCaseStmt &x) { // R1150
1100 Outdent(), Word("RANK ");
1101 common::visit(common::visitors{
1102 [&](const ScalarIntConstantExpr &y) {
1103 Put('('), Walk(y), Put(')');
1104 },
1105 [&](const Star &) { Put("(*)"); },
1106 [&](const Default &) { Word("DEFAULT"); },
1107 },
1108 std::get<SelectRankCaseStmt::Rank>(x.t).u);
1109 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1110 }
1111 void Unparse(const SelectTypeStmt &x) { // R1153
1112 Walk(std::get<0>(x.t), ": ");
1113 Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => ");
1114 Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1115 }
1116 void Unparse(const TypeGuardStmt &x) { // R1154
1117 Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t));
1118 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1119 }
1120 void Unparse(const TypeGuardStmt::Guard &x) {
1121 common::visit(
1122 common::visitors{
1123 [&](const TypeSpec &y) { Word("TYPE IS ("), Walk(y), Put(')'); },
1124 [&](const DerivedTypeSpec &y) {
1125 Word("CLASS IS ("), Walk(y), Put(')');
1126 },
1127 [&](const Default &) { Word("CLASS DEFAULT"); },
1128 },
1129 x.u);
1130 }
1131 void Unparse(const ExitStmt &x) { // R1156
1132 Word("EXIT"), Walk(" ", x.v);
1133 }
1134 void Before(const GotoStmt &) { // R1157
1135 Word("GO TO ");
1136 }
1137 void Unparse(const ComputedGotoStmt &x) { // R1158
1138 Word("GO TO ("), Walk(x.t, "), ");
1139 }
1140 void Unparse(const ContinueStmt &) { // R1159
1141 Word("CONTINUE");
1142 }
1143 void Unparse(const StopStmt &x) { // R1160, R1161
1144 if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) {
1145 Word("ERROR ");
1146 }
1147 Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t));
1148 Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t));
1149 }
1150 void Unparse(const FailImageStmt &) { // R1163
1151 Word("FAIL IMAGE");
1152 }
1153 void Unparse(const NotifyWaitStmt &x) { // F2023: R1166
1154 Word("NOTIFY WAIT ("), Walk(std::get<Scalar<Variable>>(x.t));
1155 Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", ");
1156 Put(')');
1157 }
1158 void Unparse(const SyncAllStmt &x) { // R1164
1159 Word("SYNC ALL ("), Walk(x.v, ", "), Put(')');
1160 }
1161 void Unparse(const SyncImagesStmt &x) { // R1166
1162 Word("SYNC IMAGES (");
1163 Walk(std::get<SyncImagesStmt::ImageSet>(x.t));
1164 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1165 }
1166 void Unparse(const SyncMemoryStmt &x) { // R1168
1167 Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')');
1168 }
1169 void Unparse(const SyncTeamStmt &x) { // R1169
1170 Word("SYNC TEAM ("), Walk(std::get<TeamValue>(x.t));
1171 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1172 }
1173 void Unparse(const EventPostStmt &x) { // R1170
1174 Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t));
1175 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1176 }
1177 void Before(const EventWaitSpec &x) { // R1173, R1174
1178 common::visit(common::visitors{
1179 [&](const ScalarIntExpr &) { Word("UNTIL_COUNT="); },
1180 [](const StatOrErrmsg &) {},
1181 },
1182 x.u);
1183 }
1184 void Unparse(const EventWaitStmt &x) { // R1170
1185 Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t));
1186 Walk(", ", std::get<std::list<EventWaitSpec>>(x.t), ", ");
1187 Put(')');
1188 }
1189 void Unparse(const FormTeamStmt &x) { // R1175, R1177
1190 Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));
1191 Put(','), Walk(std::get<TeamVariable>(x.t));
1192 Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");
1193 Put(')');
1194 }
1195 void Before(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1178
1196 common::visit(common::visitors{
1197 [&](const ScalarIntExpr &) { Word("NEW_INDEX="); },
1198 [](const StatOrErrmsg &) {},
1199 },
1200 x.u);
1201 }
1202 void Unparse(const LockStmt &x) { // R1179
1203 Word("LOCK ("), Walk(std::get<LockVariable>(x.t));
1204 Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");
1205 Put(')');
1206 }
1207 void Before(const LockStmt::LockStat &x) { // R1180
1208 common::visit(
1209 common::visitors{
1210 [&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },
1211 [](const StatOrErrmsg &) {},
1212 },
1213 x.u);
1214 }
1215 void Unparse(const UnlockStmt &x) { // R1181
1216 Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));
1217 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");
1218 Put(')');
1219 }
1220
1221 void Unparse(const OpenStmt &x) { // R1204
1222 Word("OPEN ("), Walk(x.v, ", "), Put(')');
1223 }
1224 bool Pre(const ConnectSpec &x) { // R1205
1225 return common::visit(common::visitors{
1226 [&](const FileUnitNumber &) {
1227 Word("UNIT=");
1228 return true;
1229 },
1230 [&](const FileNameExpr &) {
1231 Word("FILE=");
1232 return true;
1233 },
1234 [&](const ConnectSpec::CharExpr &y) {
1235 Walk(y.t, "=");
1236 return false;
1237 },
1238 [&](const MsgVariable &) {
1239 Word("IOMSG=");
1240 return true;
1241 },
1242 [&](const StatVariable &) {
1243 Word("IOSTAT=");
1244 return true;
1245 },
1246 [&](const ConnectSpec::Recl &) {
1247 Word("RECL=");
1248 return true;
1249 },
1250 [&](const ConnectSpec::Newunit &) {
1251 Word("NEWUNIT=");
1252 return true;
1253 },
1254 [&](const ErrLabel &) {
1255 Word("ERR=");
1256 return true;
1257 },
1258 [&](const StatusExpr &) {
1259 Word("STATUS=");
1260 return true;
1261 },
1262 },
1263 x.u);
1264 }
1265 void Unparse(const CloseStmt &x) { // R1208
1266 Word("CLOSE ("), Walk(x.v, ", "), Put(')');
1267 }
1268 void Before(const CloseStmt::CloseSpec &x) { // R1209
1269 common::visit(common::visitors{
1270 [&](const FileUnitNumber &) { Word("UNIT="); },
1271 [&](const StatVariable &) { Word("IOSTAT="); },
1272 [&](const MsgVariable &) { Word("IOMSG="); },
1273 [&](const ErrLabel &) { Word("ERR="); },
1274 [&](const StatusExpr &) { Word("STATUS="); },
1275 },
1276 x.u);
1277 }
1278 void Unparse(const ReadStmt &x) { // R1210
1279 Word("READ ");
1280 if (x.iounit) {
1281 Put('('), Walk(x.iounit);
1282 if (x.format) {
1283 Put(", "), Walk(x.format);
1284 }
1285 Walk(", ", x.controls, ", ");
1286 Put(')');
1287 } else if (x.format) {
1288 Walk(x.format);
1289 if (!x.items.empty()) {
1290 Put(", ");
1291 }
1292 } else {
1293 Put('('), Walk(x.controls, ", "), Put(')');
1294 }
1295 Walk(" ", x.items, ", ");
1296 }
1297 void Unparse(const WriteStmt &x) { // R1211
1298 Word("WRITE (");
1299 if (x.iounit) {
1300 Walk(x.iounit);
1301 if (x.format) {
1302 Put(", "), Walk(x.format);
1303 }
1304 Walk(", ", x.controls, ", ");
1305 } else {
1306 Walk(x.controls, ", ");
1307 }
1308 Put(')'), Walk(" ", x.items, ", ");
1309 }
1310 void Unparse(const PrintStmt &x) { // R1212
1311 Word("PRINT "), Walk(std::get<Format>(x.t));
1312 Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");
1313 }
1314 bool Pre(const IoControlSpec &x) { // R1213
1315 return common::visit(common::visitors{
1316 [&](const IoUnit &) {
1317 Word("UNIT=");
1318 return true;
1319 },
1320 [&](const Format &) {
1321 Word("FMT=");
1322 return true;
1323 },
1324 [&](const Name &) {
1325 Word("NML=");
1326 return true;
1327 },
1328 [&](const IoControlSpec::CharExpr &y) {
1329 Walk(y.t, "=");
1330 return false;
1331 },
1332 [&](const IoControlSpec::Asynchronous &) {
1333 Word("ASYNCHRONOUS=");
1334 return true;
1335 },
1336 [&](const EndLabel &) {
1337 Word("END=");
1338 return true;
1339 },
1340 [&](const EorLabel &) {
1341 Word("EOR=");
1342 return true;
1343 },
1344 [&](const ErrLabel &) {
1345 Word("ERR=");
1346 return true;
1347 },
1348 [&](const IdVariable &) {
1349 Word("ID=");
1350 return true;
1351 },
1352 [&](const MsgVariable &) {
1353 Word("IOMSG=");
1354 return true;
1355 },
1356 [&](const StatVariable &) {
1357 Word("IOSTAT=");
1358 return true;
1359 },
1360 [&](const IoControlSpec::Pos &) {
1361 Word("POS=");
1362 return true;
1363 },
1364 [&](const IoControlSpec::Rec &) {
1365 Word("REC=");
1366 return true;
1367 },
1368 [&](const IoControlSpec::Size &) {
1369 Word("SIZE=");
1370 return true;
1371 },
1372 },
1373 x.u);
1374 }
1375 void Unparse(const InputImpliedDo &x) { // R1218
1376 Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");
1377 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1378 }
1379 void Unparse(const OutputImpliedDo &x) { // R1219
1380 Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");
1381 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1382 }
1383 void Unparse(const WaitStmt &x) { // R1222
1384 Word("WAIT ("), Walk(x.v, ", "), Put(')');
1385 }
1386 void Before(const WaitSpec &x) { // R1223
1387 common::visit(common::visitors{
1388 [&](const FileUnitNumber &) { Word("UNIT="); },
1389 [&](const EndLabel &) { Word("END="); },
1390 [&](const EorLabel &) { Word("EOR="); },
1391 [&](const ErrLabel &) { Word("ERR="); },
1392 [&](const IdExpr &) { Word("ID="); },
1393 [&](const MsgVariable &) { Word("IOMSG="); },
1394 [&](const StatVariable &) { Word("IOSTAT="); },
1395 },
1396 x.u);
1397 }
1398 void Unparse(const BackspaceStmt &x) { // R1224
1399 Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');
1400 }
1401 void Unparse(const EndfileStmt &x) { // R1225
1402 Word("ENDFILE ("), Walk(x.v, ", "), Put(')');
1403 }
1404 void Unparse(const RewindStmt &x) { // R1226
1405 Word("REWIND ("), Walk(x.v, ", "), Put(')');
1406 }
1407 void Before(const PositionOrFlushSpec &x) { // R1227 & R1229
1408 common::visit(common::visitors{
1409 [&](const FileUnitNumber &) { Word("UNIT="); },
1410 [&](const MsgVariable &) { Word("IOMSG="); },
1411 [&](const StatVariable &) { Word("IOSTAT="); },
1412 [&](const ErrLabel &) { Word("ERR="); },
1413 },
1414 x.u);
1415 }
1416 void Unparse(const FlushStmt &x) { // R1228
1417 Word("FLUSH ("), Walk(x.v, ", "), Put(')');
1418 }
1419 void Unparse(const InquireStmt &x) { // R1230
1420 Word("INQUIRE (");
1421 common::visit(
1422 common::visitors{
1423 [&](const InquireStmt::Iolength &y) {
1424 Word("IOLENGTH="), Walk(y.t, ") ");
1425 },
1426 [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); },
1427 },
1428 x.u);
1429 }
1430 bool Pre(const InquireSpec &x) { // R1231
1431 return common::visit(common::visitors{
1432 [&](const FileUnitNumber &) {
1433 Word("UNIT=");
1434 return true;
1435 },
1436 [&](const FileNameExpr &) {
1437 Word("FILE=");
1438 return true;
1439 },
1440 [&](const InquireSpec::CharVar &y) {
1441 Walk(y.t, "=");
1442 return false;
1443 },
1444 [&](const InquireSpec::IntVar &y) {
1445 Walk(y.t, "=");
1446 return false;
1447 },
1448 [&](const InquireSpec::LogVar &y) {
1449 Walk(y.t, "=");
1450 return false;
1451 },
1452 [&](const IdExpr &) {
1453 Word("ID=");
1454 return true;
1455 },
1456 [&](const ErrLabel &) {
1457 Word("ERR=");
1458 return true;
1459 },
1460 },
1461 x.u);
1462 }
1463
1464 void Before(const FormatStmt &) { // R1301
1465 Word("FORMAT");
1466 }
1467 void Unparse(const format::FormatSpecification &x) { // R1302, R1303, R1305
1468 Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");
1469 Walk("*(", x.unlimitedItems, ",", ")"), Put(')');
1470 }
1471 void Unparse(const format::FormatItem &x) { // R1304, R1306, R1321
1472 if (x.repeatCount) {
1473 Walk(*x.repeatCount);
1474 }
1475 common::visit(common::visitors{
1476 [&](const std::string &y) { PutNormalized(y); },
1477 [&](const std::list<format::FormatItem> &y) {
1478 Walk("(", y, ",", ")");
1479 },
1480 [&](const auto &y) { Walk(y); },
1481 },
1482 x.u);
1483 }
1484 void Unparse(
1485 const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311
1486 switch (x.kind) {
1487#define FMT(x) \
1488 case format::IntrinsicTypeDataEditDesc::Kind::x: \
1489 Put(#x); \
1490 break
1491 FMT(I);
1492 FMT(B);
1493 FMT(O);
1494 FMT(Z);
1495 FMT(F);
1496 FMT(E);
1497 FMT(EN);
1498 FMT(ES);
1499 FMT(EX);
1500 FMT(G);
1501 FMT(L);
1502 FMT(A);
1503 FMT(D);
1504#undef FMT
1505 }
1506 Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);
1507 }
1508 void Unparse(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312
1509 Word("DT");
1510 if (!x.type.empty()) {
1511 Put('"'), Put(x.type), Put('"');
1512 }
1513 Walk("(", x.parameters, ",", ")");
1514 }
1515 void Unparse(const format::ControlEditDesc &x) { // R1313, R1315-R1320
1516 switch (x.kind) {
1517 case format::ControlEditDesc::Kind::T:
1518 Word("T");
1519 Walk(x.count);
1520 break;
1521 case format::ControlEditDesc::Kind::TL:
1522 Word("TL");
1523 Walk(x.count);
1524 break;
1525 case format::ControlEditDesc::Kind::TR:
1526 Word("TR");
1527 Walk(x.count);
1528 break;
1529 case format::ControlEditDesc::Kind::X:
1530 if (x.count != 1) {
1531 Walk(x.count);
1532 }
1533 Word("X");
1534 break;
1535 case format::ControlEditDesc::Kind::Slash:
1536 if (x.count != 1) {
1537 Walk(x.count);
1538 }
1539 Put('/');
1540 break;
1541 case format::ControlEditDesc::Kind::Colon:
1542 Put(':');
1543 break;
1544 case format::ControlEditDesc::Kind::P:
1545 Walk(x.count);
1546 Word("P");
1547 break;
1548#define FMT(x) \
1549 case format::ControlEditDesc::Kind::x: \
1550 Put(#x); \
1551 break
1552 FMT(SS);
1553 FMT(SP);
1554 FMT(S);
1555 FMT(BN);
1556 FMT(BZ);
1557 FMT(RU);
1558 FMT(RD);
1559 FMT(RZ);
1560 FMT(RN);
1561 FMT(RC);
1562 FMT(RP);
1563 FMT(DC);
1564 FMT(DP);
1565#undef FMT
1566 case format::ControlEditDesc::Kind::Dollar:
1567 Put('$');
1568 break;
1569 case format::ControlEditDesc::Kind::Backslash:
1570 Put('\\');
1571 break;
1572 }
1573 }
1574
1575 void Before(const MainProgram &x) { // R1401
1576 if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {
1577 Indent();
1578 }
1579 }
1580 void Before(const ProgramStmt &) { // R1402
1581 Word("PROGRAM "), Indent();
1582 }
1583 void Unparse(const EndProgramStmt &x) { // R1403
1584 EndSubprogram("PROGRAM", x.v);
1585 }
1586 void Before(const ModuleStmt &) { // R1405
1587 Word("MODULE "), Indent();
1588 }
1589 void Unparse(const EndModuleStmt &x) { // R1406
1590 EndSubprogram("MODULE", x.v);
1591 }
1592 void Unparse(const UseStmt &x) { // R1409
1593 Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);
1594 common::visit(
1595 common::visitors{
1596 [&](const std::list<Rename> &y) { Walk(", ", y, ", "); },
1597 [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); },
1598 },
1599 x.u);
1600 }
1601 void Unparse(const Rename &x) { // R1411
1602 common::visit(common::visitors{
1603 [&](const Rename::Names &y) { Walk(y.t, " => "); },
1604 [&](const Rename::Operators &y) {
1605 Word("OPERATOR("), Walk(y.t, ") => OPERATOR("),
1606 Put(")");
1607 },
1608 },
1609 x.u);
1610 }
1611 void Unparse(const SubmoduleStmt &x) { // R1417
1612 Word("SUBMODULE ("), WalkTupleElements(x.t, ")"), Indent();
1613 }
1614 void Unparse(const ParentIdentifier &x) { // R1418
1615 Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));
1616 }
1617 void Unparse(const EndSubmoduleStmt &x) { // R1419
1618 EndSubprogram("SUBMODULE", x.v);
1619 }
1620 void Unparse(const BlockDataStmt &x) { // R1421
1621 Word("BLOCK DATA"), Walk(" ", x.v), Indent();
1622 }
1623 void Unparse(const EndBlockDataStmt &x) { // R1422
1624 EndSubprogram("BLOCK DATA", x.v);
1625 }
1626
1627 void Unparse(const InterfaceStmt &x) { // R1503
1628 common::visit(common::visitors{
1629 [&](const std::optional<GenericSpec> &y) {
1630 Word("INTERFACE"), Walk(" ", y);
1631 },
1632 [&](const Abstract &) { Word("ABSTRACT INTERFACE"); },
1633 },
1634 x.u);
1635 Indent();
1636 }
1637 void Unparse(const EndInterfaceStmt &x) { // R1504
1638 Outdent(), Word("END INTERFACE"), Walk(" ", x.v);
1639 }
1640 void Unparse(const ProcedureStmt &x) { // R1506
1641 if (std::get<ProcedureStmt::Kind>(x.t) ==
1642 ProcedureStmt::Kind::ModuleProcedure) {
1643 Word("MODULE ");
1644 }
1645 Word("PROCEDURE :: ");
1646 Walk(std::get<std::list<Name>>(x.t), ", ");
1647 }
1648 void Before(const GenericSpec &x) { // R1508, R1509
1649 common::visit(
1650 common::visitors{
1651 [&](const DefinedOperator &) { Word("OPERATOR("); },
1652 [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },
1653 [&](const GenericSpec::ReadFormatted &) {
1654 Word("READ(FORMATTED)");
1655 },
1656 [&](const GenericSpec::ReadUnformatted &) {
1657 Word("READ(UNFORMATTED)");
1658 },
1659 [&](const GenericSpec::WriteFormatted &) {
1660 Word("WRITE(FORMATTED)");
1661 },
1662 [&](const GenericSpec::WriteUnformatted &) {
1663 Word("WRITE(UNFORMATTED)");
1664 },
1665 [](const auto &) {},
1666 },
1667 x.u);
1668 }
1669 void Post(const GenericSpec &x) {
1670 common::visit(common::visitors{
1671 [&](const DefinedOperator &) { Put(')'); },
1672 [](const auto &) {},
1673 },
1674 x.u);
1675 }
1676 void Unparse(const GenericStmt &x) { // R1510
1677 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
1678 Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");
1679 Walk(std::get<std::list<Name>>(x.t), ", ");
1680 }
1681 void Unparse(const ExternalStmt &x) { // R1511
1682 Word("EXTERNAL :: "), Walk(x.v, ", ");
1683 }
1684 void Unparse(const ProcedureDeclarationStmt &x) { // R1512
1685 Word("PROCEDURE("), Walk(std::get<std::optional<ProcInterface>>(x.t));
1686 Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");
1687 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
1688 }
1689 void Unparse(const ProcDecl &x) { // R1515
1690 Walk(std::get<Name>(x.t));
1691 Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));
1692 }
1693 void Unparse(const IntrinsicStmt &x) { // R1519
1694 Word("INTRINSIC :: "), Walk(x.v, ", ");
1695 }
1696 void Unparse(const CallStmt::Chevrons &x) { // CUDA
1697 Walk(std::get<0>(x.t)); // grid
1698 Word(","), Walk(std::get<1>(x.t)); // block
1699 Walk(",", std::get<2>(x.t)); // bytes
1700 Walk(",", std::get<3>(x.t)); // stream
1701 }
1702 void Unparse(const FunctionReference &x) { // R1520
1703 Walk(std::get<ProcedureDesignator>(x.v.t));
1704 Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
1705 }
1706 void Unparse(const CallStmt &x) { // R1521
1707 if (asFortran_ && x.typedCall.get()) {
1708 Put(' ');
1709 asFortran_->call(out_, *x.typedCall);
1710 Put('\n');
1711 } else {
1712 const auto &pd{std::get<ProcedureDesignator>(x.call.t)};
1713 Word("CALL "), Walk(pd);
1714 Walk("<<<", x.chevrons, ">>>");
1715 const auto &args{std::get<std::list<ActualArgSpec>>(x.call.t)};
1716 if (args.empty()) {
1717 if (std::holds_alternative<ProcComponentRef>(pd.u)) {
1718 Put("()"); // pgf90 crashes on CALL to tbp without parentheses
1719 }
1720 } else {
1721 Walk("(", args, ", ", ")");
1722 }
1723 }
1724 }
1725 void Unparse(const ActualArgSpec &x) { // R1523
1726 Walk(std::get<std::optional<Keyword>>(x.t), "=");
1727 Walk(std::get<ActualArg>(x.t));
1728 }
1729 void Unparse(const ActualArg::PercentRef &x) { // R1524
1730 Word("%REF("), Walk(x.v), Put(')');
1731 }
1732 void Unparse(const ActualArg::PercentVal &x) {
1733 Word("%VAL("), Walk(x.v), Put(')');
1734 }
1735 void Before(const AltReturnSpec &) { // R1525
1736 Put('*');
1737 }
1738 void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527
1739 void Post(const PrefixSpec::Impure) { Word("IMPURE"); }
1740 void Post(const PrefixSpec::Module) { Word("MODULE"); }
1741 void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }
1742 void Post(const PrefixSpec::Pure) { Word("PURE"); }
1743 void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }
1744 void Unparse(const PrefixSpec::Attributes &x) {
1745 Word("ATTRIBUTES("), Walk(x.v), Word(")");
1746 }
1747 void Unparse(const PrefixSpec::Launch_Bounds &x) {
1748 Word("LAUNCH_BOUNDS("), Walk(x.v), Word(")");
1749 }
1750 void Unparse(const PrefixSpec::Cluster_Dims &x) {
1751 Word("CLUSTER_DIMS("), Walk(x.v), Word(")");
1752 }
1753 void Unparse(const FunctionStmt &x) { // R1530
1754 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1755 Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");
1756 Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');
1757 Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
1758 }
1759 void Unparse(const Suffix &x) { // R1532
1760 if (x.resultName) {
1761 Word("RESULT("), Walk(x.resultName), Put(')');
1762 Walk(" ", x.binding);
1763 } else {
1764 Walk(x.binding);
1765 }
1766 }
1767 void Unparse(const EndFunctionStmt &x) { // R1533
1768 EndSubprogram("FUNCTION", x.v);
1769 }
1770 void Unparse(const SubroutineStmt &x) { // R1535
1771 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
1772 Word("SUBROUTINE "), Walk(std::get<Name>(x.t));
1773 const auto &args{std::get<std::list<DummyArg>>(x.t)};
1774 const auto &bind{std::get<std::optional<LanguageBindingSpec>>(x.t)};
1775 if (args.empty()) {
1776 Walk(" () ", bind);
1777 } else {
1778 Walk(" (", args, ", ", ")");
1779 Walk(" ", bind);
1780 }
1781 Indent();
1782 }
1783 void Unparse(const EndSubroutineStmt &x) { // R1537
1784 EndSubprogram("SUBROUTINE", x.v);
1785 }
1786 void Before(const MpSubprogramStmt &) { // R1539
1787 Word("MODULE PROCEDURE "), Indent();
1788 }
1789 void Unparse(const EndMpSubprogramStmt &x) { // R1540
1790 EndSubprogram("PROCEDURE", x.v);
1791 }
1792 void Unparse(const EntryStmt &x) { // R1541
1793 Word("ENTRY "), Walk(std::get<Name>(x.t)), Put("(");
1794 Walk(std::get<std::list<DummyArg>>(x.t), ", "), Put(")");
1795 Walk(" ", std::get<std::optional<Suffix>>(x.t));
1796 }
1797 void Unparse(const ReturnStmt &x) { // R1542
1798 Word("RETURN"), Walk(" ", x.v);
1799 }
1800 void Unparse(const ContainsStmt &) { // R1543
1801 Outdent();
1802 Word("CONTAINS");
1803 Indent();
1804 }
1805 void Unparse(const StmtFunctionStmt &x) { // R1544
1806 Walk(std::get<Name>(x.t)), Put('(');
1807 Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");
1808 Walk(std::get<Scalar<Expr>>(x.t));
1809 }
1810
1811 // Directives, extensions, and deprecated constructs
1812 void Unparse(const CompilerDirective &x) {
1813 common::visit(
1814 common::visitors{
1815 [&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {
1816 Word("!DIR$ IGNORE_TKR"); // emitted even if tkr list is empty
1817 Walk(" ", tkr, ", ");
1818 },
1819 [&](const CompilerDirective::LoopCount &lcount) {
1820 Walk("!DIR$ LOOP COUNT (", lcount.v, ", ", ")");
1821 },
1822 [&](const std::list<CompilerDirective::AssumeAligned>
1823 &assumeAligned) {
1824 Word("!DIR$ ASSUME_ALIGNED ");
1825 Walk(" ", assumeAligned, ", ");
1826 },
1827 [&](const std::list<CompilerDirective::NameValue> &names) {
1828 Walk("!DIR$ ", names, " ");
1829 },
1830 [&](const CompilerDirective::Unrecognized &) {
1831 Word("!DIR$ ");
1832 Word(x.source.ToString());
1833 },
1834 },
1835 x.u);
1836 Put('\n');
1837 }
1838 void Unparse(const CompilerDirective::IgnoreTKR &x) {
1839 if (const auto &maybeList{
1840 std::get<std::optional<std::list<const char *>>>(x.t)}) {
1841 Put("(");
1842 for (const char *tkr : *maybeList) {
1843 Put(*tkr);
1844 }
1845 Put(") ");
1846 }
1847 Walk(std::get<Name>(x.t));
1848 }
1849 void Unparse(const CompilerDirective::NameValue &x) {
1850 Walk(std::get<Name>(x.t));
1851 Walk("=", std::get<std::optional<std::uint64_t>>(x.t));
1852 }
1853 void Unparse(const CompilerDirective::AssumeAligned &x) {
1854 Walk(std::get<common::Indirection<Designator>>(x.t));
1855 Put(":");
1856 Walk(std::get<uint64_t>(x.t));
1857 }
1858
1859 // OpenACC Directives & Clauses
1860 void Unparse(const AccAtomicCapture &x) {
1861 BeginOpenACC();
1862 Word("!$ACC CAPTURE");
1863 Put("\n");
1864 EndOpenACC();
1865 Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
1866 Put("\n");
1867 Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
1868 BeginOpenACC();
1869 Word("!$ACC END ATOMIC\n");
1870 EndOpenACC();
1871 }
1872 void Unparse(const AccAtomicRead &x) {
1873 BeginOpenACC();
1874 Word("!$ACC ATOMIC READ");
1875 Put("\n");
1876 EndOpenACC();
1877 Walk(std::get<Statement<AssignmentStmt>>(x.t));
1878 BeginOpenACC();
1879 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1880 EndOpenACC();
1881 }
1882 void Unparse(const AccAtomicWrite &x) {
1883 BeginOpenACC();
1884 Word("!$ACC ATOMIC WRITE");
1885 Put("\n");
1886 EndOpenACC();
1887 Walk(std::get<Statement<AssignmentStmt>>(x.t));
1888 BeginOpenACC();
1889 Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
1890 EndOpenACC();
1891 }
1892 void Unparse(const AccAtomicUpdate &x) {
1893 BeginOpenACC();
1894 Word("!$ACC ATOMIC UPDATE");
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 llvm::acc::Directive &x) {
1903 Word(llvm::acc::getOpenACCDirectiveName(x).str());
1904 }
1905#define GEN_FLANG_CLAUSE_UNPARSE
1906#include "llvm/Frontend/OpenACC/ACC.inc"
1907 void Unparse(const AccObjectListWithModifier &x) {
1908 Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
1909 Walk(std::get<AccObjectList>(x.t));
1910 }
1911 void Unparse(const AccBindClause &x) {
1912 common::visit(common::visitors{
1913 [&](const Name &y) { Walk(y); },
1914 [&](const ScalarDefaultCharExpr &y) { Walk(y); },
1915 },
1916 x.u);
1917 }
1918 void Unparse(const AccDefaultClause &x) {
1919 switch (x.v) {
1920 case llvm::acc::DefaultValue::ACC_Default_none:
1921 Put("NONE");
1922 break;
1923 case llvm::acc::DefaultValue::ACC_Default_present:
1924 Put("PRESENT");
1925 break;
1926 }
1927 }
1928 void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
1929 void Unparse(const AccGangArgList &x) { Walk(x.v, ","); }
1930 void Before(const AccSizeExpr &x) {
1931 if (!x.v)
1932 Put("*");
1933 }
1934 void Before(const AccGangArg &x) {
1935 common::visit(common::visitors{
1936 [&](const AccGangArg::Num &) { Word("NUM:"); },
1937 [&](const AccGangArg::Dim &) { Word("DIM:"); },
1938 [&](const AccGangArg::Static &) { Word("STATIC:"); },
1939 [](const StatOrErrmsg &) {},
1940 },
1941 x.u);
1942 }
1943 void Unparse(const AccCollapseArg &x) {
1944 const auto &force{std::get<bool>(x.t)};
1945 const auto &collapseValue{std::get<parser::ScalarIntConstantExpr>(x.t)};
1946 if (force) {
1947 Put("FORCE:");
1948 }
1949 Walk(collapseValue);
1950 }
1951 void Unparse(const OpenACCBlockConstruct &x) {
1952 BeginOpenACC();
1953 Word("!$ACC ");
1954 Walk(std::get<AccBeginBlockDirective>(x.t));
1955 Put("\n");
1956 EndOpenACC();
1957 Walk(std::get<Block>(x.t), "");
1958 BeginOpenACC();
1959 Word("!$ACC END ");
1960 Walk(std::get<AccEndBlockDirective>(x.t));
1961 Put("\n");
1962 EndOpenACC();
1963 }
1964 void Unparse(const OpenACCLoopConstruct &x) {
1965 BeginOpenACC();
1966 Word("!$ACC ");
1967 Walk(std::get<AccBeginLoopDirective>(x.t));
1968 Put("\n");
1969 EndOpenACC();
1970 Walk(std::get<std::optional<DoConstruct>>(x.t));
1971 }
1972 void Unparse(const AccBeginLoopDirective &x) {
1973 Walk(std::get<AccLoopDirective>(x.t));
1974 Walk(std::get<AccClauseList>(x.t));
1975 }
1976 void Unparse(const OpenACCStandaloneConstruct &x) {
1977 BeginOpenACC();
1978 Word("!$ACC ");
1979 Walk(std::get<AccStandaloneDirective>(x.t));
1980 Walk(std::get<AccClauseList>(x.t));
1981 Put("\n");
1982 EndOpenACC();
1983 }
1984 void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
1985 BeginOpenACC();
1986 Word("!$ACC ");
1987 Walk(std::get<AccDeclarativeDirective>(x.t));
1988 Walk(std::get<AccClauseList>(x.t));
1989 Put("\n");
1990 EndOpenACC();
1991 }
1992 void Unparse(const OpenACCCombinedConstruct &x) {
1993 BeginOpenACC();
1994 Word("!$ACC ");
1995 Walk(std::get<AccBeginCombinedDirective>(x.t));
1996 Put("\n");
1997 EndOpenACC();
1998 Walk(std::get<std::optional<DoConstruct>>(x.t));
1999 BeginOpenACC();
2000 Walk("!$ACC END ", std::get<std::optional<AccEndCombinedDirective>>(x.t),
2001 "\n");
2002 EndOpenACC();
2003 }
2004 void Unparse(const OpenACCRoutineConstruct &x) {
2005 BeginOpenACC();
2006 Word("!$ACC ROUTINE");
2007 Walk("(", std::get<std::optional<Name>>(x.t), ")");
2008 Walk(std::get<AccClauseList>(x.t));
2009 Put("\n");
2010 EndOpenACC();
2011 }
2012 void Unparse(const AccObject &x) {
2013 common::visit(common::visitors{
2014 [&](const Designator &y) { Walk(y); },
2015 [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
2016 },
2017 x.u);
2018 }
2019 void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
2020 void Unparse(const AccObjectListWithReduction &x) {
2021 Walk(std::get<AccReductionOperator>(x.t));
2022 Put(":");
2023 Walk(std::get<AccObjectList>(x.t));
2024 }
2025 void Unparse(const OpenACCCacheConstruct &x) {
2026 BeginOpenACC();
2027 Word("!$ACC ");
2028 Word("CACHE(");
2029 Walk(std::get<AccObjectListWithModifier>(x.t));
2030 Put(")");
2031 Put("\n");
2032 EndOpenACC();
2033 }
2034 void Unparse(const AccWaitArgument &x) {
2035 Walk("DEVNUM:", std::get<std::optional<ScalarIntExpr>>(x.t), ":");
2036 Walk(std::get<std::list<ScalarIntExpr>>(x.t), ",");
2037 }
2038 void Unparse(const OpenACCWaitConstruct &x) {
2039 BeginOpenACC();
2040 Word("!$ACC ");
2041 Word("WAIT(");
2042 Walk(std::get<std::optional<AccWaitArgument>>(x.t));
2043 Walk(std::get<AccClauseList>(x.t));
2044 Put(")");
2045 Put("\n");
2046 EndOpenACC();
2047 }
2048
2049 // OpenMP Clauses & Directives
2050 void Unparse(const OmpObject &x) {
2051 common::visit(common::visitors{
2052 [&](const Designator &y) { Walk(y); },
2053 [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
2054 },
2055 x.u);
2056 }
2057 void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
2058 void Unparse(const OmpMapClause &x) {
2059 Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
2060 Walk(std::get<OmpObjectList>(x.t));
2061 }
2062 void Unparse(const OmpScheduleModifier &x) {
2063 Walk(std::get<OmpScheduleModifier::Modifier1>(x.t));
2064 Walk(",", std::get<std::optional<OmpScheduleModifier::Modifier2>>(x.t));
2065 }
2066 void Unparse(const OmpScheduleClause &x) {
2067 Walk(std::get<std::optional<OmpScheduleModifier>>(x.t), ":");
2068 Walk(std::get<OmpScheduleClause::ScheduleType>(x.t));
2069 Walk(",", std::get<std::optional<ScalarIntExpr>>(x.t));
2070 }
2071 void Unparse(const OmpDeviceClause &x) {
2072 Walk(std::get<std::optional<OmpDeviceClause::DeviceModifier>>(x.t), ":");
2073 Walk(std::get<ScalarIntExpr>(x.t));
2074 }
2075 void Unparse(const OmpAlignedClause &x) {
2076 Walk(std::get<OmpObjectList>(x.t));
2077 Put(",");
2078 Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
2079 }
2080 void Unparse(const OmpIfClause &x) {
2081 Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
2082 Walk(std::get<ScalarLogicalExpr>(x.t));
2083 }
2084 void Unparse(const OmpLinearClause::WithoutModifier &x) {
2085 Walk(x.names, ", ");
2086 Walk(":", x.step);
2087 }
2088 void Unparse(const OmpLinearClause::WithModifier &x) {
2089 Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
2090 Walk(":", x.step);
2091 }
2092 void Unparse(const OmpReductionClause &x) {
2093 Walk(std::get<std::optional<OmpReductionClause::ReductionModifier>>(x.t),
2094 ",");
2095 Walk(std::get<OmpReductionOperator>(x.t));
2096 Put(":");
2097 Walk(std::get<OmpObjectList>(x.t));
2098 }
2099 void Unparse(const OmpInReductionClause &x) {
2100 Walk(std::get<OmpReductionOperator>(x.t));
2101 Put(":");
2102 Walk(std::get<OmpObjectList>(x.t));
2103 }
2104 void Unparse(const OmpAllocateClause &x) {
2105 Walk(
2106 std::get<std::optional<OmpAllocateClause::AllocateModifier>>(x.t), ":");
2107 Walk(std::get<OmpObjectList>(x.t));
2108 }
2109 void Unparse(const OmpAllocateClause::AllocateModifier &x) {
2110 common::visit(
2111 common::visitors{
2112 [&](const OmpAllocateClause::AllocateModifier::Allocator &y) {
2113 Walk(y);
2114 },
2115 [&](const OmpAllocateClause::AllocateModifier::ComplexModifier &y) {
2116 Word("ALLOCATOR(");
2117 Walk(std::get<OmpAllocateClause::AllocateModifier::Allocator>(
2118 y.t));
2119 Put(")");
2120 Put(",");
2121 Walk(std::get<OmpAllocateClause::AllocateModifier::Align>(y.t));
2122 },
2123 [&](const OmpAllocateClause::AllocateModifier::Align &y) {
2124 Walk(y);
2125 },
2126 },
2127 x.u);
2128 }
2129 void Unparse(const OmpAllocateClause::AllocateModifier::Align &x) {
2130 Word("ALIGN(");
2131 Walk(x.v);
2132 Put(")");
2133 }
2134 void Unparse(const OmpOrderClause &x) {
2135 Walk(std::get<std::optional<OmpOrderModifier>>(x.t), ":");
2136 Walk(std::get<OmpOrderClause::Type>(x.t));
2137 }
2138 void Unparse(const OmpDependSinkVecLength &x) {
2139 Walk(std::get<DefinedOperator>(x.t));
2140 Walk(std::get<ScalarIntConstantExpr>(x.t));
2141 }
2142 void Unparse(const OmpDependSinkVec &x) {
2143 Walk(std::get<Name>(x.t));
2144 Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
2145 }
2146 void Unparse(const OmpDependClause::InOut &x) {
2147 Put("(");
2148 Walk(std::get<OmpDependenceType>(x.t));
2149 Put(":");
2150 Walk(std::get<std::list<Designator>>(x.t), ",");
2151 Put(")");
2152 }
2153 bool Pre(const OmpDependClause &x) {
2154 return common::visit(
2155 common::visitors{
2156 [&](const OmpDependClause::Source &) {
2157 Word("SOURCE");
2158 return false;
2159 },
2160 [&](const OmpDependClause::Sink &y) {
2161 Word("SINK:");
2162 Walk(y.v);
2163 Put(")");
2164 return false;
2165 },
2166 [&](const OmpDependClause::InOut &) { return true; },
2167 },
2168 x.u);
2169 }
2170 void Unparse(const OmpDefaultmapClause &x) {
2171 Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
2172 Walk(":",
2173 std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
2174 }
2175#define GEN_FLANG_CLAUSE_UNPARSE
2176#include "llvm/Frontend/OpenMP/OMP.inc"
2177 void Unparse(const OmpLoopDirective &x) {
2178 switch (x.v) {
2179 case llvm::omp::Directive::OMPD_distribute:
2180 Word("DISTRIBUTE ");
2181 break;
2182 case llvm::omp::Directive::OMPD_distribute_parallel_do:
2183 Word("DISTRIBUTE PARALLEL DO ");
2184 break;
2185 case llvm::omp::Directive::OMPD_distribute_parallel_do_simd:
2186 Word("DISTRIBUTE PARALLEL DO SIMD ");
2187 break;
2188 case llvm::omp::Directive::OMPD_distribute_simd:
2189 Word("DISTRIBUTE SIMD ");
2190 break;
2191 case llvm::omp::Directive::OMPD_do:
2192 Word("DO ");
2193 break;
2194 case llvm::omp::Directive::OMPD_do_simd:
2195 Word("DO SIMD ");
2196 break;
2197 case llvm::omp::Directive::OMPD_parallel_do:
2198 Word("PARALLEL DO ");
2199 break;
2200 case llvm::omp::Directive::OMPD_parallel_do_simd:
2201 Word("PARALLEL DO SIMD ");
2202 break;
2203 case llvm::omp::Directive::OMPD_simd:
2204 Word("SIMD ");
2205 break;
2206 case llvm::omp::Directive::OMPD_target_parallel_do:
2207 Word("TARGET PARALLEL DO ");
2208 break;
2209 case llvm::omp::Directive::OMPD_target_parallel_do_simd:
2210 Word("TARGET PARALLEL DO SIMD ");
2211 break;
2212 case llvm::omp::Directive::OMPD_target_teams_distribute:
2213 Word("TARGET TEAMS DISTRIBUTE ");
2214 break;
2215 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
2216 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO ");
2217 break;
2218 case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
2219 Word("TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2220 break;
2221 case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
2222 Word("TARGET TEAMS DISTRIBUTE SIMD ");
2223 break;
2224 case llvm::omp::Directive::OMPD_target_simd:
2225 Word("TARGET SIMD ");
2226 break;
2227 case llvm::omp::Directive::OMPD_taskloop:
2228 Word("TASKLOOP ");
2229 break;
2230 case llvm::omp::Directive::OMPD_taskloop_simd:
2231 Word("TASKLOOP SIMD ");
2232 break;
2233 case llvm::omp::Directive::OMPD_teams_distribute:
2234 Word("TEAMS DISTRIBUTE ");
2235 break;
2236 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do:
2237 Word("TEAMS DISTRIBUTE PARALLEL DO ");
2238 break;
2239 case llvm::omp::Directive::OMPD_teams_distribute_parallel_do_simd:
2240 Word("TEAMS DISTRIBUTE PARALLEL DO SIMD ");
2241 break;
2242 case llvm::omp::Directive::OMPD_teams_distribute_simd:
2243 Word("TEAMS DISTRIBUTE SIMD ");
2244 break;
2245 case llvm::omp::Directive::OMPD_tile:
2246 Word("TILE ");
2247 break;
2248 case llvm::omp::Directive::OMPD_unroll:
2249 Word("UNROLL ");
2250 break;
2251 default:
2252 break;
2253 }
2254 }
2255 void Unparse(const OmpObjectList &x) { Walk(x.v, ","); }
2256 void Unparse(const OmpSimpleStandaloneDirective &x) {
2257 switch (x.v) {
2258 case llvm::omp::Directive::OMPD_barrier:
2259 Word("BARRIER ");
2260 break;
2261 case llvm::omp::Directive::OMPD_taskwait:
2262 Word("TASKWAIT ");
2263 break;
2264 case llvm::omp::Directive::OMPD_taskyield:
2265 Word("TASKYIELD ");
2266 break;
2267 case llvm::omp::Directive::OMPD_target_enter_data:
2268 Word("TARGET ENTER DATA ");
2269 break;
2270 case llvm::omp::Directive::OMPD_target_exit_data:
2271 Word("TARGET EXIT DATA ");
2272 break;
2273 case llvm::omp::Directive::OMPD_target_update:
2274 Word("TARGET UPDATE ");
2275 break;
2276 case llvm::omp::Directive::OMPD_ordered:
2277 Word("ORDERED ");
2278 break;
2279 default:
2280 // Nothing to be done
2281 break;
2282 }
2283 }
2284 void Unparse(const OmpBlockDirective &x) {
2285 switch (x.v) {
2286 case llvm::omp::Directive::OMPD_master:
2287 Word("MASTER");
2288 break;
2289 case llvm::omp::Directive::OMPD_ordered:
2290 Word("ORDERED ");
2291 break;
2292 case llvm::omp::Directive::OMPD_parallel_workshare:
2293 Word("PARALLEL WORKSHARE ");
2294 break;
2295 case llvm::omp::Directive::OMPD_parallel:
2296 Word("PARALLEL ");
2297 break;
2298 case llvm::omp::Directive::OMPD_single:
2299 Word("SINGLE ");
2300 break;
2301 case llvm::omp::Directive::OMPD_target_data:
2302 Word("TARGET DATA ");
2303 break;
2304 case llvm::omp::Directive::OMPD_target_parallel:
2305 Word("TARGET PARALLEL ");
2306 break;
2307 case llvm::omp::Directive::OMPD_target_teams:
2308 Word("TARGET TEAMS ");
2309 break;
2310 case llvm::omp::Directive::OMPD_target:
2311 Word("TARGET ");
2312 break;
2313 case llvm::omp::Directive::OMPD_taskgroup:
2314 Word("TASKGROUP ");
2315 break;
2316 case llvm::omp::Directive::OMPD_task:
2317 Word("TASK ");
2318 break;
2319 case llvm::omp::Directive::OMPD_teams:
2320 Word("TEAMS ");
2321 break;
2322 case llvm::omp::Directive::OMPD_workshare:
2323 Word("WORKSHARE ");
2324 break;
2325 default:
2326 // Nothing to be done
2327 break;
2328 }
2329 }
2330
2331 void Unparse(const OmpAtomicDefaultMemOrderClause &x) {
2332 Word(ToUpperCaseLetters(common::EnumToString(x.v)));
2333 }
2334
2335 void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); }
2336
2337 void Unparse(const OmpAtomic &x) {
2338 BeginOpenMP();
2339 Word("!$OMP ATOMIC");
2340 Walk(std::get<OmpAtomicClauseList>(x.t));
2341 Put("\n");
2342 EndOpenMP();
2343 Walk(std::get<Statement<AssignmentStmt>>(x.t));
2344 BeginOpenMP();
2345 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2346 EndOpenMP();
2347 }
2348 void Unparse(const OmpAtomicCapture &x) {
2349 BeginOpenMP();
2350 Word("!$OMP ATOMIC");
2351 Walk(std::get<0>(x.t));
2352 Word(" CAPTURE");
2353 Walk(std::get<2>(x.t));
2354 Put("\n");
2355 EndOpenMP();
2356 Walk(std::get<OmpAtomicCapture::Stmt1>(x.t));
2357 Put("\n");
2358 Walk(std::get<OmpAtomicCapture::Stmt2>(x.t));
2359 BeginOpenMP();
2360 Word("!$OMP END ATOMIC\n");
2361 EndOpenMP();
2362 }
2363 void Unparse(const OmpAtomicRead &x) {
2364 BeginOpenMP();
2365 Word("!$OMP ATOMIC");
2366 Walk(std::get<0>(x.t));
2367 Word(" READ");
2368 Walk(std::get<2>(x.t));
2369 Put("\n");
2370 EndOpenMP();
2371 Walk(std::get<Statement<AssignmentStmt>>(x.t));
2372 BeginOpenMP();
2373 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2374 EndOpenMP();
2375 }
2376 void Unparse(const OmpAtomicUpdate &x) {
2377 BeginOpenMP();
2378 Word("!$OMP ATOMIC");
2379 Walk(std::get<0>(x.t));
2380 Word(" UPDATE");
2381 Walk(std::get<2>(x.t));
2382 Put("\n");
2383 EndOpenMP();
2384 Walk(std::get<Statement<AssignmentStmt>>(x.t));
2385 BeginOpenMP();
2386 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2387 EndOpenMP();
2388 }
2389 void Unparse(const OmpAtomicWrite &x) {
2390 BeginOpenMP();
2391 Word("!$OMP ATOMIC");
2392 Walk(std::get<0>(x.t));
2393 Word(" WRITE");
2394 Walk(std::get<2>(x.t));
2395 Put("\n");
2396 EndOpenMP();
2397 Walk(std::get<Statement<AssignmentStmt>>(x.t));
2398 BeginOpenMP();
2399 Walk(std::get<std::optional<OmpEndAtomic>>(x.t), "!$OMP END ATOMIC\n");
2400 EndOpenMP();
2401 }
2402 void Unparse(const OpenMPExecutableAllocate &x) {
2403 const auto &fields =
2404 std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
2405 x.t);
2406 if (fields) {
2407 for (const auto &decl : *fields) {
2408 Walk(decl);
2409 }
2410 }
2411 BeginOpenMP();
2412 Word("!$OMP ALLOCATE");
2413 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2414 Walk(std::get<OmpClauseList>(x.t));
2415 Put("\n");
2416 EndOpenMP();
2417 Walk(std::get<Statement<AllocateStmt>>(x.t));
2418 }
2419 void Unparse(const OpenMPDeclarativeAllocate &x) {
2420 BeginOpenMP();
2421 Word("!$OMP ALLOCATE");
2422 Put(" (");
2423 Walk(std::get<OmpObjectList>(x.t));
2424 Put(")");
2425 Walk(std::get<OmpClauseList>(x.t));
2426 Put("\n");
2427 EndOpenMP();
2428 }
2429 void Unparse(const OmpEndAllocators &x) {
2430 BeginOpenMP();
2431 Word("!$OMP END ALLOCATE");
2432 Put("\n");
2433 EndOpenMP();
2434 }
2435 void Unparse(const OpenMPAllocatorsConstruct &x) {
2436 BeginOpenMP();
2437 Word("!$OMP ALLOCATE");
2438 Walk(std::get<OmpClauseList>(x.t));
2439 Put("\n");
2440 EndOpenMP();
2441 Walk(std::get<Statement<AllocateStmt>>(x.t));
2442 if (const auto &end = std::get<std::optional<OmpEndAllocators>>(x.t)) {
2443 Walk(*end);
2444 }
2445 }
2446 void Unparse(const OmpCriticalDirective &x) {
2447 BeginOpenMP();
2448 Word("!$OMP CRITICAL");
2449 Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2450 Walk(std::get<OmpClauseList>(x.t));
2451 Put("\n");
2452 EndOpenMP();
2453 }
2454 void Unparse(const OmpEndCriticalDirective &x) {
2455 BeginOpenMP();
2456 Word("!$OMP END CRITICAL");
2457 Walk(" (", std::get<std::optional<Name>>(x.t), ")");
2458 Put("\n");
2459 EndOpenMP();
2460 }
2461 void Unparse(const OpenMPCriticalConstruct &x) {
2462 Walk(std::get<OmpCriticalDirective>(x.t));
2463 Walk(std::get<Block>(x.t), "");
2464 Walk(std::get<OmpEndCriticalDirective>(x.t));
2465 }
2466 void Unparse(const OmpDeclareTargetWithList &x) {
2467 Put("("), Walk(x.v), Put(")");
2468 }
2469 void Unparse(const OmpReductionInitializerClause &x) {
2470 Word(" INITIALIZER(OMP_PRIV = ");
2471 Walk(x.v);
2472 Put(")");
2473 }
2474 void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
2475 const auto &pd = std::get<ProcedureDesignator>(x.v.t);
2476 const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
2477 Walk(pd);
2478 if (args.empty()) {
2479 if (std::holds_alternative<ProcComponentRef>(pd.u)) {
2480 Put("()");
2481 }
2482 } else {
2483 Walk("(", args, ", ", ")");
2484 }
2485 }
2486 void Unparse(const OpenMPDeclareReductionConstruct &x) {
2487 Put("(");
2488 Walk(std::get<OmpReductionOperator>(x.t)), Put(" : ");
2489 Walk(std::get<std::list<DeclarationTypeSpec>>(x.t), ","), Put(" : ");
2490 Walk(std::get<OmpReductionCombiner>(x.t));
2491 Put(")");
2492 Walk(std::get<std::optional<OmpReductionInitializerClause>>(x.t));
2493 }
2494 bool Pre(const OpenMPDeclarativeConstruct &x) {
2495 BeginOpenMP();
2496 Word("!$OMP ");
2497 return common::visit(
2498 common::visitors{
2499 [&](const OpenMPDeclarativeAllocate &z) {
2500 Word("ALLOCATE (");
2501 Walk(std::get<OmpObjectList>(z.t));
2502 Put(")");
2503 Walk(std::get<OmpClauseList>(z.t));
2504 Put("\n");
2505 EndOpenMP();
2506 return false;
2507 },
2508 [&](const OpenMPDeclareReductionConstruct &) {
2509 Word("DECLARE REDUCTION ");
2510 return true;
2511 },
2512 [&](const OpenMPDeclareSimdConstruct &y) {
2513 Word("DECLARE SIMD ");
2514 Walk("(", std::get<std::optional<Name>>(y.t), ")");
2515 Walk(std::get<OmpClauseList>(y.t));
2516 Put("\n");
2517 EndOpenMP();
2518 return false;
2519 },
2520 [&](const OpenMPDeclareTargetConstruct &) {
2521 Word("DECLARE TARGET ");
2522 return true;
2523 },
2524 [&](const OpenMPRequiresConstruct &y) {
2525 Word("REQUIRES ");
2526 Walk(std::get<OmpClauseList>(y.t));
2527 Put("\n");
2528 EndOpenMP();
2529 return false;
2530 },
2531 [&](const OpenMPThreadprivate &) {
2532 Word("THREADPRIVATE (");
2533 return true;
2534 },
2535 },
2536 x.u);
2537 }
2538 void Post(const OpenMPDeclarativeConstruct &) {
2539 Put("\n");
2540 EndOpenMP();
2541 }
2542 void Post(const OpenMPThreadprivate &) {
2543 Put(")\n");
2544 EndOpenMP();
2545 }
2546 void Unparse(const OmpSectionsDirective &x) {
2547 switch (x.v) {
2548 case llvm::omp::Directive::OMPD_sections:
2549 Word("SECTIONS ");
2550 break;
2551 case llvm::omp::Directive::OMPD_parallel_sections:
2552 Word("PARALLEL SECTIONS ");
2553 break;
2554 default:
2555 break;
2556 }
2557 }
2558 void Unparse(const OmpSectionBlocks &x) {
2559 for (const auto &y : x.v) {
2560 BeginOpenMP();
2561 Word("!$OMP SECTION");
2562 Put("\n");
2563 EndOpenMP();
2564 // y.u is an OpenMPSectionConstruct
2565 // (y.u).v is Block
2566 Walk(std::get<OpenMPSectionConstruct>(y.u).v, "");
2567 }
2568 }
2569 void Unparse(const OpenMPSectionsConstruct &x) {
2570 BeginOpenMP();
2571 Word("!$OMP ");
2572 Walk(std::get<OmpBeginSectionsDirective>(x.t));
2573 Put("\n");
2574 EndOpenMP();
2575 Walk(std::get<OmpSectionBlocks>(x.t));
2576 BeginOpenMP();
2577 Word("!$OMP END ");
2578 Walk(std::get<OmpEndSectionsDirective>(x.t));
2579 Put("\n");
2580 EndOpenMP();
2581 }
2582 void Unparse(const OpenMPCancellationPointConstruct &x) {
2583 BeginOpenMP();
2584 Word("!$OMP CANCELLATION POINT ");
2585 Walk(std::get<OmpCancelType>(x.t));
2586 Put("\n");
2587 EndOpenMP();
2588 }
2589 void Unparse(const OpenMPCancelConstruct &x) {
2590 BeginOpenMP();
2591 Word("!$OMP CANCEL ");
2592 Walk(std::get<OmpCancelType>(x.t));
2593 Walk(std::get<std::optional<OpenMPCancelConstruct::If>>(x.t));
2594 Put("\n");
2595 EndOpenMP();
2596 }
2597 void Unparse(const OmpMemoryOrderClause &x) { Walk(x.v); }
2598 void Unparse(const OmpAtomicClause &x) {
2599 common::visit(common::visitors{
2600 [&](const OmpMemoryOrderClause &y) { Walk(y); },
2601 [&](const OmpClause &z) { Walk(z); },
2602 },
2603 x.u);
2604 }
2605 void Unparse(const OpenMPFlushConstruct &x) {
2606 BeginOpenMP();
2607 Word("!$OMP FLUSH ");
2608 Walk(std::get<std::optional<std::list<OmpMemoryOrderClause>>>(x.t));
2609 Walk(" (", std::get<std::optional<OmpObjectList>>(x.t), ")");
2610 Put("\n");
2611 EndOpenMP();
2612 }
2613 void Unparse(const OmpEndLoopDirective &x) {
2614 BeginOpenMP();
2615 Word("!$OMP END ");
2616 Walk(std::get<OmpLoopDirective>(x.t));
2617 Walk(std::get<OmpClauseList>(x.t));
2618 Put("\n");
2619 EndOpenMP();
2620 }
2621 void Unparse(const OmpClauseList &x) { Walk(" ", x.v, " "); }
2622 void Unparse(const OpenMPSimpleStandaloneConstruct &x) {
2623 BeginOpenMP();
2624 Word("!$OMP ");
2625 Walk(std::get<OmpSimpleStandaloneDirective>(x.t));
2626 Walk(std::get<OmpClauseList>(x.t));
2627 Put("\n");
2628 EndOpenMP();
2629 }
2630 void Unparse(const OpenMPBlockConstruct &x) {
2631 BeginOpenMP();
2632 Word("!$OMP ");
2633 Walk(std::get<OmpBeginBlockDirective>(x.t));
2634 Put("\n");
2635 EndOpenMP();
2636 Walk(std::get<Block>(x.t), "");
2637 BeginOpenMP();
2638 Word("!$OMP END ");
2639 Walk(std::get<OmpEndBlockDirective>(x.t));
2640 Put("\n");
2641 EndOpenMP();
2642 }
2643 void Unparse(const OpenMPLoopConstruct &x) {
2644 BeginOpenMP();
2645 Word("!$OMP ");
2646 Walk(std::get<OmpBeginLoopDirective>(x.t));
2647 Put("\n");
2648 EndOpenMP();
2649 Walk(std::get<std::optional<DoConstruct>>(x.t));
2650 Walk(std::get<std::optional<OmpEndLoopDirective>>(x.t));
2651 }
2652 void Unparse(const BasedPointer &x) {
2653 Put('('), Walk(std::get<0>(x.t)), Put(","), Walk(std::get<1>(x.t));
2654 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
2655 }
2656 void Unparse(const BasedPointerStmt &x) { Walk("POINTER ", x.v, ","); }
2657 void Unparse(const CUDAAttributesStmt &x) {
2658 Word("ATTRIBUTES("), Walk(std::get<common::CUDADataAttr>(x.t));
2659 Word(") "), Walk(std::get<std::list<Name>>(x.t), ", ");
2660 }
2661 void Post(const StructureField &x) {
2662 if (const auto *def{std::get_if<Statement<DataComponentDefStmt>>(&x.u)}) {
2663 for (const auto &item :
2664 std::get<std::list<ComponentOrFill>>(def->statement.t)) {
2665 if (const auto *comp{std::get_if<ComponentDecl>(&item.u)}) {
2666 structureComponents_.insert(std::get<Name>(comp->t).source);
2667 }
2668 }
2669 }
2670 }
2671 void Unparse(const StructureStmt &x) {
2672 Word("STRUCTURE ");
2673 // The name, if present, includes the /slashes/
2674 Walk(std::get<std::optional<Name>>(x.t));
2675 Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
2676 Indent();
2677 }
2678 void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
2679 void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
2680 void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
2681 void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
2682 void Post(const StructureDef::EndStructureStmt &) {
2683 Outdent(), Word("END STRUCTURE");
2684 }
2685 void Unparse(const OldParameterStmt &x) {
2686 Word("PARAMETER "), Walk(x.v, ", ");
2687 }
2688 void Unparse(const ArithmeticIfStmt &x) {
2689 Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
2690 Walk(std::get<1>(x.t)), Put(", ");
2691 Walk(std::get<2>(x.t)), Put(", ");
2692 Walk(std::get<3>(x.t));
2693 }
2694 void Unparse(const AssignStmt &x) {
2695 Word("ASSIGN "), Walk(std::get<Label>(x.t));
2696 Word(" TO "), Walk(std::get<Name>(x.t));
2697 }
2698 void Unparse(const AssignedGotoStmt &x) {
2699 Word("GO TO "), Walk(std::get<Name>(x.t));
2700 Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
2701 }
2702 void Unparse(const PauseStmt &x) { Word("PAUSE"), Walk(" ", x.v); }
2703
2704#define WALK_NESTED_ENUM(CLASS, ENUM) \
2705 void Unparse(const CLASS::ENUM &x) { Word(CLASS::EnumToString(x)); }
2706 WALK_NESTED_ENUM(AccDataModifier, Modifier)
2707 WALK_NESTED_ENUM(AccessSpec, Kind) // R807
2708 WALK_NESTED_ENUM(AccReductionOperator, Operator)
2709 WALK_NESTED_ENUM(common, TypeParamAttr) // R734
2710 WALK_NESTED_ENUM(common, CUDADataAttr) // CUDA
2711 WALK_NESTED_ENUM(common, CUDASubprogramAttrs) // CUDA
2712 WALK_NESTED_ENUM(IntentSpec, Intent) // R826
2713 WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
2714 WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
2715 WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
2716 WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
2717 WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
2718 WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
2719 WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
2720 WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
2721 WALK_NESTED_ENUM(OmpProcBindClause, Type) // OMP PROC_BIND
2722 WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
2723 WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
2724 WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
2725 WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
2726 WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
2727 WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
2728 WALK_NESTED_ENUM(OmpMapType, Type) // OMP map-type
2729 WALK_NESTED_ENUM(OmpScheduleClause, ScheduleType) // OMP schedule-type
2730 WALK_NESTED_ENUM(OmpDeviceClause, DeviceModifier) // OMP device modifier
2731 WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE
2732 WALK_NESTED_ENUM(
2733 OmpReductionClause, ReductionModifier) // OMP reduction-modifier
2734 WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
2735 WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
2736 WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type
2737 WALK_NESTED_ENUM(OmpOrderModifier, Kind) // OMP order-modifier
2738#undef WALK_NESTED_ENUM
2739
2740 void Unparse(const CUFKernelDoConstruct::StarOrExpr &x) {
2741 if (x.v) {
2742 Walk(*x.v);
2743 } else {
2744 Word("*");
2745 }
2746 }
2747 void Unparse(const CUFKernelDoConstruct::Directive &x) {
2748 Word("!$CUF KERNEL DO");
2749 Walk(" (", std::get<std::optional<ScalarIntConstantExpr>>(x.t), ")");
2750 Word(" <<<");
2751 const auto &grid{std::get<1>(x.t)};
2752 if (grid.empty()) {
2753 Word("*");
2754 } else if (grid.size() == 1) {
2755 Walk(grid.front());
2756 } else {
2757 Walk("(", grid, ",", ")");
2758 }
2759 Word(",");
2760 const auto &block{std::get<2>(x.t)};
2761 if (block.empty()) {
2762 Word("*");
2763 } else if (block.size() == 1) {
2764 Walk(block.front());
2765 } else {
2766 Walk("(", block, ",", ")");
2767 }
2768 if (const auto &stream{std::get<3>(x.t)}) {
2769 Word(",STREAM="), Walk(*stream);
2770 }
2771 Word(">>>\n");
2772 }
2773
2774 void Unparse(const CUFKernelDoConstruct &x) {
2775 Walk(std::get<CUFKernelDoConstruct::Directive>(x.t));
2776 Walk(std::get<std::optional<DoConstruct>>(x.t));
2777 }
2778
2779 void Done() const { CHECK(indent_ == 0); }
2780
2781private:
2782 void Put(char);
2783 void Put(const char *);
2784 void Put(const std::string &);
2785 void PutNormalized(const std::string &);
2786 void PutKeywordLetter(char);
2787 void Word(const char *);
2788 void Word(const std::string &);
2789 void Word(const std::string_view &);
2790 void Indent() { indent_ += indentationAmount_; }
2791 void Outdent() {
2792 CHECK(indent_ >= indentationAmount_);
2793 indent_ -= indentationAmount_;
2794 }
2795 void BeginOpenMP() { openmpDirective_ = true; }
2796 void EndOpenMP() { openmpDirective_ = false; }
2797 void BeginOpenACC() { openaccDirective_ = true; }
2798 void EndOpenACC() { openaccDirective_ = false; }
2799
2800 // Call back to the traversal framework.
2801 template <typename T> void Walk(const T &x) {
2802 Fortran::parser::Walk(x, *this);
2803 }
2804
2805 // Traverse a std::optional<> value. Emit a prefix and/or a suffix string
2806 // only when it contains a value.
2807 template <typename A>
2808 void Walk(
2809 const char *prefix, const std::optional<A> &x, const char *suffix = "") {
2810 if (x) {
2811 Word(prefix), Walk(*x), Word(suffix);
2812 }
2813 }
2814 template <typename A>
2815 void Walk(const std::optional<A> &x, const char *suffix = "") {
2816 return Walk("", x, suffix);
2817 }
2818
2819 // Traverse a std::list<>. Separate the elements with an optional string.
2820 // Emit a prefix and/or a suffix string only when the list is not empty.
2821 template <typename A>
2822 void Walk(const char *prefix, const std::list<A> &list,
2823 const char *comma = ", ", const char *suffix = "") {
2824 if (!list.empty()) {
2825 const char *str{prefix};
2826 for (const auto &x : list) {
2827 Word(str), Walk(x);
2828 str = comma;
2829 }
2830 Word(suffix);
2831 }
2832 }
2833 template <typename A>
2834 void Walk(const std::list<A> &list, const char *comma = ", ",
2835 const char *suffix = "") {
2836 return Walk("", list, comma, suffix);
2837 }
2838
2839 // Traverse a std::tuple<>, with an optional separator.
2840 template <std::size_t J = 0, typename T>
2841 void WalkTupleElements(const T &tuple, const char *separator) {
2842 if (J > 0 && J < std::tuple_size_v<T>) {
2843 Word(separator); // this usage dodges "unused parameter" warning
2844 }
2845 if constexpr (J < std::tuple_size_v<T>) {
2846 Walk(std::get<J>(tuple));
2847 WalkTupleElements<J + 1>(tuple, separator);
2848 }
2849 }
2850 template <typename... A>
2851 void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
2852 WalkTupleElements(tuple, separator);
2853 }
2854
2855 void EndSubprogram(const char *kind, const std::optional<Name> &name) {
2856 Outdent(), Word("END "), Word(kind), Walk(" ", name);
2857 structureComponents_.clear();
2858 }
2859
2860 llvm::raw_ostream &out_;
2861 int indent_{0};
2862 const int indentationAmount_{1};
2863 int column_{1};
2864 const int maxColumns_{80};
2865 std::set<CharBlock> structureComponents_;
2866 Encoding encoding_{Encoding::UTF_8};
2867 bool capitalizeKeywords_{true};
2868 bool openaccDirective_{false};
2869 bool openmpDirective_{false};
2870 bool backslashEscapes_{false};
2871 preStatementType *preStatement_{nullptr};
2872 AnalyzedObjectsAsFortran *asFortran_{nullptr};
2873};
2874
2875void UnparseVisitor::Put(char ch) {
2876 int sav = indent_;
2877 if (openmpDirective_ || openaccDirective_) {
2878 indent_ = 0;
2879 }
2880 if (column_ <= 1) {
2881 if (ch == '\n') {
2882 return;
2883 }
2884 for (int j{0}; j < indent_; ++j) {
2885 out_ << ' ';
2886 }
2887 column_ = indent_ + 2;
2888 } else if (ch == '\n') {
2889 column_ = 1;
2890 } else if (++column_ >= maxColumns_) {
2891 out_ << "&\n";
2892 for (int j{0}; j < indent_; ++j) {
2893 out_ << ' ';
2894 }
2895 if (openmpDirective_) {
2896 out_ << "!$OMP&";
2897 column_ = 8;
2898 } else if (openaccDirective_) {
2899 out_ << "!$ACC&";
2900 column_ = 8;
2901 } else {
2902 out_ << '&';
2903 column_ = indent_ + 3;
2904 }
2905 }
2906 out_ << ch;
2907 if (openmpDirective_ || openaccDirective_) {
2908 indent_ = sav;
2909 }
2910}
2911
2912void UnparseVisitor::Put(const char *str) {
2913 for (; *str != '\0'; ++str) {
2914 Put(ch: *str);
2915 }
2916}
2917
2918void UnparseVisitor::Put(const std::string &str) {
2919 for (char ch : str) {
2920 Put(ch);
2921 }
2922}
2923
2924void UnparseVisitor::PutNormalized(const std::string &str) {
2925 auto decoded{DecodeString<std::string, Encoding::LATIN_1>(str, true)};
2926 std::string encoded{EncodeString<Encoding::LATIN_1>(decoded)};
2927 Put(QuoteCharacterLiteral(encoded, backslashEscapes_));
2928}
2929
2930void UnparseVisitor::PutKeywordLetter(char ch) {
2931 if (capitalizeKeywords_) {
2932 Put(ToUpperCaseLetter(ch));
2933 } else {
2934 Put(ToLowerCaseLetter(ch));
2935 }
2936}
2937
2938void UnparseVisitor::Word(const char *str) {
2939 for (; *str != '\0'; ++str) {
2940 PutKeywordLetter(ch: *str);
2941 }
2942}
2943
2944void UnparseVisitor::Word(const std::string &str) { Word(str: str.c_str()); }
2945
2946void UnparseVisitor::Word(const std::string_view &str) {
2947 for (std::size_t j{0}; j < str.length(); ++j) {
2948 PutKeywordLetter(ch: str[j]);
2949 }
2950}
2951
2952template <typename A>
2953void Unparse(llvm::raw_ostream &out, const A &root, Encoding encoding,
2954 bool capitalizeKeywords, bool backslashEscapes,
2955 preStatementType *preStatement, AnalyzedObjectsAsFortran *asFortran) {
2956 UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords, backslashEscapes,
2957 preStatement, asFortran};
2958 Walk(root, visitor);
2959 visitor.Done();
2960}
2961
2962template void Unparse<Program>(llvm::raw_ostream &, const Program &, Encoding,
2963 bool, bool, preStatementType *, AnalyzedObjectsAsFortran *);
2964template void Unparse<Expr>(llvm::raw_ostream &, const Expr &, Encoding, bool,
2965 bool, preStatementType *, AnalyzedObjectsAsFortran *);
2966} // namespace Fortran::parser
2967

source code of flang/lib/Parser/unparse.cpp