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