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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

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