blob: 595cb8c8b004aa6c644be84f8f96a67ad217730a [file] [log] [blame]
peter klausler79d044e2018-03-01 00:56:101// Generates Fortran from the content of a parse tree, using the
2// traversal templates in parse-tree-visitor.h.
3
Tim Keith2af29bc2018-02-26 22:28:324#include "unparse.h"
peter klausler79d044e2018-03-01 00:56:105#include "characters.h"
Tim Keith2af29bc2018-02-26 22:28:326#include "idioms.h"
7#include "indirection.h"
8#include "parse-tree-visitor.h"
9#include "parse-tree.h"
peter klausler79d044e2018-03-01 00:56:1010#include <algorithm>
peter klausler424ec7b2018-03-20 17:59:0711#include <cinttypes>
12#include <cstddef>
peter klausler4e354d82018-03-30 22:23:3713#include <set>
Tim Keith2af29bc2018-02-26 22:28:3214
15namespace Fortran {
16namespace parser {
17
18class UnparseVisitor {
19public:
peter klauslerb7cf5122018-03-14 22:31:1620 UnparseVisitor(std::ostream &out, int indentationAmount, Encoding encoding,
21 bool capitalize)
22 : out_{out}, indentationAmount_{indentationAmount}, encoding_{encoding},
23 capitalizeKeywords_{capitalize} {}
Tim Keith2af29bc2018-02-26 22:28:3224
peter klausler79d044e2018-03-01 00:56:1025 // Default actions: just traverse the children
Tim Keith2af29bc2018-02-26 22:28:3226 template<typename T> bool Pre(const T &x) { return true; }
Tim Keith2af29bc2018-02-26 22:28:3227 template<typename T> void Post(const T &) {}
28
Tim Keith2af29bc2018-02-26 22:28:3229 // Emit simple types as-is.
30 bool Pre(const std::string &x) {
31 Put(x);
32 return false;
33 }
34 bool Pre(int x) {
35 Put(std::to_string(x));
36 return false;
37 }
38 bool Pre(std::uint64_t x) {
39 Put(std::to_string(x));
40 return false;
41 }
42 bool Pre(std::int64_t x) {
43 Put(std::to_string(x));
44 return false;
45 }
46 bool Pre(char x) {
47 Put(x);
48 return false;
49 }
50
peter klausler79d044e2018-03-01 00:56:1051 // Statement labels and ends of lines
52 template<typename T> bool Pre(const Statement<T> &x) {
53 Walk(x.label, " ");
54 return true;
Tim Keith2af29bc2018-02-26 22:28:3255 }
peter klausler79d044e2018-03-01 00:56:1056 template<typename T> void Post(const Statement<T> &) { Put('\n'); }
57
58 // The special-case formatting functions for these productions are
59 // ordered to correspond roughly to their order of appearance in
60 // the Fortran 2018 standard (and parse-tree.h).
61
62 void Post(const ProgramUnit &x) { // R502, R503
63 out_ << '\n'; // blank line after each ProgramUnit
Tim Keith2af29bc2018-02-26 22:28:3264 }
peter klausler424ec7b2018-03-20 17:59:0765
66 bool Pre(const Name &x) { // R603
peter klausler938d1eb2018-03-23 21:18:5967 Put(x.ToString());
peter klausler424ec7b2018-03-20 17:59:0768 return false;
69 }
peter klausler79d044e2018-03-01 00:56:1070 bool Pre(const DefinedOperator::IntrinsicOperator &x) { // R608
71 switch (x) {
72 case DefinedOperator::IntrinsicOperator::Power: Put("**"); break;
73 case DefinedOperator::IntrinsicOperator::Multiply: Put('*'); break;
74 case DefinedOperator::IntrinsicOperator::Divide: Put('/'); break;
75 case DefinedOperator::IntrinsicOperator::Add: Put('+'); break;
76 case DefinedOperator::IntrinsicOperator::Subtract: Put('-'); break;
77 case DefinedOperator::IntrinsicOperator::Concat: Put("//"); break;
78 case DefinedOperator::IntrinsicOperator::LT: Put('<'); break;
79 case DefinedOperator::IntrinsicOperator::LE: Put("<="); break;
80 case DefinedOperator::IntrinsicOperator::EQ: Put("=="); break;
81 case DefinedOperator::IntrinsicOperator::NE: Put("/="); break;
82 case DefinedOperator::IntrinsicOperator::GE: Put(">="); break;
83 case DefinedOperator::IntrinsicOperator::GT: Put('>'); break;
84 default:
peter klausler62d9cdd2018-03-15 00:02:2185 Put('.');
Tim Keith9f755662018-03-23 21:31:1486 Word(DefinedOperator::EnumToString(x));
peter klausler62d9cdd2018-03-15 00:02:2187 Put('.');
Tim Keith2af29bc2018-02-26 22:28:3288 }
89 return false;
90 }
peter klausler79d044e2018-03-01 00:56:1091 void Post(const Star &) { Put('*'); } // R701 &c.
92 void Post(const TypeParamValue::Deferred &) { Put(':'); } // R701
93 bool Pre(const DeclarationTypeSpec::Type &x) { // R703
peter klauslerb7cf5122018-03-14 22:31:1694 Word("TYPE("), Walk(x.derived), Put(')');
Tim Keith2af29bc2018-02-26 22:28:3295 return false;
96 }
peter klausler79d044e2018-03-01 00:56:1097 bool Pre(const DeclarationTypeSpec::Class &x) {
peter klauslerb7cf5122018-03-14 22:31:1698 Word("CLASS("), Walk(x.derived), Put(')');
Tim Keith2af29bc2018-02-26 22:28:3299 return false;
100 }
peter klauslerb7cf5122018-03-14 22:31:16101 void Post(const DeclarationTypeSpec::ClassStar &) { Word("CLASS(*)"); }
102 void Post(const DeclarationTypeSpec::TypeStar &) { Word("TYPE(*)"); }
peter klausler79d044e2018-03-01 00:56:10103 bool Pre(const DeclarationTypeSpec::Record &x) {
peter klauslerb7cf5122018-03-14 22:31:16104 Word("RECORD/"), Walk(x.v), Put('/');
Tim Keith2af29bc2018-02-26 22:28:32105 return false;
106 }
peter klausler79d044e2018-03-01 00:56:10107 bool Pre(const IntrinsicTypeSpec::Real &x) { // R704
peter klauslerb7cf5122018-03-14 22:31:16108 Word("REAL");
Tim Keith2af29bc2018-02-26 22:28:32109 return true;
110 }
111 bool Pre(const IntrinsicTypeSpec::Complex &x) {
peter klauslerb7cf5122018-03-14 22:31:16112 Word("COMPLEX");
Tim Keith2af29bc2018-02-26 22:28:32113 return true;
114 }
peter klausler79d044e2018-03-01 00:56:10115 void Post(const IntrinsicTypeSpec::DoublePrecision &) {
peter klauslerb7cf5122018-03-14 22:31:16116 Word("DOUBLE PRECISION");
peter klausler79d044e2018-03-01 00:56:10117 }
118 bool Pre(const IntrinsicTypeSpec::Character &x) {
peter klauslerb7cf5122018-03-14 22:31:16119 Word("CHARACTER");
Tim Keith2af29bc2018-02-26 22:28:32120 return true;
121 }
122 bool Pre(const IntrinsicTypeSpec::Logical &x) {
peter klauslerb7cf5122018-03-14 22:31:16123 Word("LOGICAL");
Tim Keith2af29bc2018-02-26 22:28:32124 return true;
125 }
peter klauslerb7cf5122018-03-14 22:31:16126 void Post(const IntrinsicTypeSpec::DoubleComplex &) {
127 Word("DOUBLE COMPLEX");
128 }
Tim Keith2af29bc2018-02-26 22:28:32129 bool Pre(const IntrinsicTypeSpec::NCharacter &x) {
peter klauslerb7cf5122018-03-14 22:31:16130 Word("NCHARACTER");
Tim Keith2af29bc2018-02-26 22:28:32131 return true;
132 }
peter klausler79d044e2018-03-01 00:56:10133 bool Pre(const IntegerTypeSpec &x) { // R705
peter klauslerb7cf5122018-03-14 22:31:16134 Word("INTEGER");
Tim Keith2af29bc2018-02-26 22:28:32135 return true;
136 }
peter klausler79d044e2018-03-01 00:56:10137 bool Pre(const KindSelector &x) { // R706
138 std::visit(
139 visitors{[&](const ScalarIntConstantExpr &y) {
peter klauslerb7cf5122018-03-14 22:31:16140 Put('('), Word("KIND="), Walk(y), Put(')');
peter klausler79d044e2018-03-01 00:56:10141 },
142 [&](const KindSelector::StarSize &y) { Put('*'), Walk(y.v); }},
143 x.u);
144 return false;
145 }
146 bool Pre(const SignedIntLiteralConstant &x) { // R707
147 Walk(std::get<std::int64_t>(x.t));
148 Walk("_", std::get<std::optional<KindParam>>(x.t));
149 return false;
150 }
151 bool Pre(const IntLiteralConstant &x) { // R708
152 Walk(std::get<std::uint64_t>(x.t));
153 Walk("_", std::get<std::optional<KindParam>>(x.t));
154 return false;
155 }
156 bool Pre(const Sign &x) { // R712
157 Put(x == Sign::Negative ? '-' : '+');
158 return false;
159 }
160 bool Pre(const RealLiteralConstant &x) { // R714, R715
peter klausler424ec7b2018-03-20 17:59:07161 Put(x.real.source.ToString()), Walk("_", x.kind);
peter klausler79d044e2018-03-01 00:56:10162 return false;
163 }
164 bool Pre(const ComplexLiteralConstant &x) { // R718 - R720
165 Put('('), Walk(x.t, ","), Put(')');
166 return false;
167 }
168 bool Pre(const CharSelector::LengthAndKind &x) { // R721
peter klauslerb7cf5122018-03-14 22:31:16169 Put('('), Word("KIND="), Walk(x.kind);
170 Walk(", LEN=", x.length), Put(')');
peter klausler79d044e2018-03-01 00:56:10171 return false;
172 }
173 bool Pre(const LengthSelector &x) { // R722
174 std::visit(visitors{[&](const TypeParamValue &y) {
peter klauslerb7cf5122018-03-14 22:31:16175 Put('('), Word("LEN="), Walk(y), Put(')');
peter klausler79d044e2018-03-01 00:56:10176 },
177 [&](const CharLength &y) { Put('*'), Walk(y); }},
178 x.u);
179 return false;
180 }
181 bool Pre(const CharLength &x) { // R723
182 std::visit(
183 visitors{[&](const TypeParamValue &y) { Put('('), Walk(y), Put(')'); },
184 [&](const std::int64_t &y) { Walk(y); }},
185 x.u);
186 return false;
187 }
188 bool Pre(const CharLiteralConstant &x) { // R724
189 if (const auto &k = std::get<std::optional<KindParam>>(x.t)) {
190 if (std::holds_alternative<KindParam::Kanji>(k->u)) {
peter klauslerb7cf5122018-03-14 22:31:16191 Word("NC");
peter klausler79d044e2018-03-01 00:56:10192 } else {
193 Walk(*k), Put('_');
194 }
195 }
196 PutQuoted(std::get<std::string>(x.t));
197 return false;
198 }
199 bool Pre(const HollerithLiteralConstant &x) {
peter klausler424ec7b2018-03-20 17:59:07200 std::optional<std::size_t> chars{CountCharacters(x.v.data(), x.v.size(),
peter klausler79d044e2018-03-01 00:56:10201 encoding_ == Encoding::EUC_JP ? EUC_JPCharacterBytes
202 : UTF8CharacterBytes)};
203 if (chars.has_value()) {
204 Pre(*chars);
205 } else {
206 Pre(x.v.size());
207 }
208 Put('H');
Tim Keith2af29bc2018-02-26 22:28:32209 return true;
210 }
peter klausler79d044e2018-03-01 00:56:10211 bool Pre(const LogicalLiteralConstant &x) { // R725
peter klausler42b72c42018-03-15 17:59:46212 Put(std::get<bool>(x.t) ? ".TRUE." : ".FALSE.");
213 Walk("_", std::get<std::optional<KindParam>>(x.t));
Tim Keith2af29bc2018-02-26 22:28:32214 return false;
215 }
peter klausler79d044e2018-03-01 00:56:10216 bool Pre(const DerivedTypeStmt &x) { // R727
peter klauslerb7cf5122018-03-14 22:31:16217 Word("TYPE"), Walk(", ", std::get<std::list<TypeAttrSpec>>(x.t), ", ");
peter klausler424ec7b2018-03-20 17:59:07218 Put(" :: "), Walk(std::get<Name>(x.t));
peter klausler79d044e2018-03-01 00:56:10219 Walk("(", std::get<std::list<Name>>(x.t), ", ", ")");
Tim Keith2af29bc2018-02-26 22:28:32220 Indent();
221 return false;
222 }
peter klausler79d044e2018-03-01 00:56:10223 bool Pre(const Abstract &x) { // R728, &c.
peter klauslerb7cf5122018-03-14 22:31:16224 Word("ABSTRACT");
Tim Keith2af29bc2018-02-26 22:28:32225 return false;
226 }
peter klauslerd71f3cf2018-03-14 23:31:41227 void Post(const TypeAttrSpec::BindC &) { Word("BIND(C)"); }
Tim Keith2af29bc2018-02-26 22:28:32228 bool Pre(const TypeAttrSpec::Extends &x) {
peter klauslerb7cf5122018-03-14 22:31:16229 Word("EXTENDS("), Walk(x.v), Put(')');
Tim Keith2af29bc2018-02-26 22:28:32230 return false;
231 }
peter klausler46c35382018-03-14 00:11:26232 bool Pre(const EndTypeStmt &x) { // R730
peter klauslerb7cf5122018-03-14 22:31:16233 Outdent(), Word("END TYPE"), Walk(" ", x.v);
peter klausler46c35382018-03-14 00:11:26234 return false;
peter klausler79d044e2018-03-01 00:56:10235 }
236 bool Pre(const SequenceStmt &x) { // R731
peter klauslerb7cf5122018-03-14 22:31:16237 Word("SEQUENCE");
Tim Keith2af29bc2018-02-26 22:28:32238 return false;
239 }
peter klausler79d044e2018-03-01 00:56:10240 bool Pre(const TypeParamDefStmt &x) { // R732
241 Walk(std::get<IntegerTypeSpec>(x.t));
242 Put(", "), Walk(std::get<TypeParamDefStmt::KindOrLen>(x.t));
243 Put(" :: "), Walk(std::get<std::list<TypeParamDecl>>(x.t), ", ");
Tim Keith2af29bc2018-02-26 22:28:32244 return false;
245 }
peter klausler79d044e2018-03-01 00:56:10246 bool Pre(const TypeParamDecl &x) { // R733
peter klausler424ec7b2018-03-20 17:59:07247 Walk(std::get<Name>(x.t));
peter klausler79d044e2018-03-01 00:56:10248 Walk("=", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
Tim Keith2af29bc2018-02-26 22:28:32249 return false;
250 }
peter klausler79d044e2018-03-01 00:56:10251 bool Pre(const DataComponentDefStmt &x) { // R737
252 const auto &dts = std::get<DeclarationTypeSpec>(x.t);
253 const auto &attrs = std::get<std::list<ComponentAttrSpec>>(x.t);
254 const auto &decls = std::get<std::list<ComponentDecl>>(x.t);
255 Walk(dts), Walk(", ", attrs, ", ");
256 if (!attrs.empty() ||
257 (!std::holds_alternative<DeclarationTypeSpec::Record>(dts.u) &&
258 std::none_of(
259 decls.begin(), decls.end(), [](const ComponentDecl &d) {
260 const auto &init =
261 std::get<std::optional<Initialization>>(d.t);
262 return init.has_value() &&
263 std::holds_alternative<
264 std::list<Indirection<DataStmtValue>>>(init->u);
265 }))) {
266 Put(" ::");
267 }
268 Put(' '), Walk(decls, ", ");
Tim Keith2af29bc2018-02-26 22:28:32269 return false;
270 }
peter klausler79d044e2018-03-01 00:56:10271 bool Pre(const Allocatable &x) { // R738
peter klauslerb7cf5122018-03-14 22:31:16272 Word("ALLOCATABLE");
Tim Keith2af29bc2018-02-26 22:28:32273 return false;
274 }
275 bool Pre(const Pointer &x) {
peter klauslerb7cf5122018-03-14 22:31:16276 Word("POINTER");
Tim Keith2af29bc2018-02-26 22:28:32277 return false;
278 }
peter klausler79d044e2018-03-01 00:56:10279 bool Pre(const Contiguous &x) {
peter klauslerb7cf5122018-03-14 22:31:16280 Word("CONTIGUOUS");
peter klausler79d044e2018-03-01 00:56:10281 return false;
282 }
283 bool Pre(const ComponentAttrSpec &x) {
peter klauslerb7cf5122018-03-14 22:31:16284 std::visit(visitors{[&](const CoarraySpec &) { Word("CODIMENSION["); },
285 [&](const ComponentArraySpec &) { Word("DIMENSION("); },
peter klauslerd71f3cf2018-03-14 23:31:41286 [](const auto &) {}},
peter klausler79d044e2018-03-01 00:56:10287 x.u);
Tim Keith2af29bc2018-02-26 22:28:32288 return true;
289 }
peter klausler79d044e2018-03-01 00:56:10290 void Post(const ComponentAttrSpec &x) {
peter klauslerd71f3cf2018-03-14 23:31:41291 std::visit(
292 visitors{[&](const CoarraySpec &) { Put(']'); },
293 [&](const ComponentArraySpec &) { Put(')'); }, [](const auto &) {}},
peter klausler79d044e2018-03-01 00:56:10294 x.u);
295 }
296 bool Pre(const ComponentDecl &x) { // R739
297 Walk(std::get<ObjectName>(x.t));
298 Walk("(", std::get<std::optional<ComponentArraySpec>>(x.t), ")");
299 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
300 Walk("*", std::get<std::optional<CharLength>>(x.t));
301 Walk(std::get<std::optional<Initialization>>(x.t));
302 return false;
303 }
304 bool Pre(const ComponentArraySpec &x) { // R740
305 std::visit(
306 visitors{[&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
307 [&](const DeferredShapeSpecList &y) { Walk(y); }},
308 x.u);
309 return false;
310 }
311 bool Pre(const ProcComponentDefStmt &x) { // R741
peter klauslerb7cf5122018-03-14 22:31:16312 Word("PROCEDURE(");
peter klausler79d044e2018-03-01 00:56:10313 Walk(std::get<std::optional<ProcInterface>>(x.t)), Put(')');
314 Walk(", ", std::get<std::list<ProcComponentAttrSpec>>(x.t), ", ");
315 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
316 return false;
317 }
318 bool Pre(const NoPass &x) { // R742
peter klauslerb7cf5122018-03-14 22:31:16319 Word("NOPASS");
peter klausler79d044e2018-03-01 00:56:10320 return false;
321 }
322 bool Pre(const Pass &x) {
peter klauslerb7cf5122018-03-14 22:31:16323 Word("PASS"), Walk("(", x.v, ")");
peter klausler79d044e2018-03-01 00:56:10324 return false;
325 }
326 bool Pre(const Initialization &x) { // R743 & R805
327 std::visit(visitors{[&](const ConstantExpr &y) { Put(" = "), Walk(y); },
328 [&](const NullInit &y) { Put(" => "), Walk(y); },
329 [&](const InitialDataTarget &y) { Put(" => "), Walk(y); },
330 [&](const std::list<Indirection<DataStmtValue>> &y) {
331 Walk("/", y, ", ", "/");
332 }},
333 x.u);
334 return false;
335 }
336 bool Pre(const PrivateStmt &x) { // R745
peter klauslerb7cf5122018-03-14 22:31:16337 Word("PRIVATE");
peter klausler79d044e2018-03-01 00:56:10338 return false;
339 }
340 bool Pre(const TypeBoundProcedureStmt::WithoutInterface &x) { // R749
peter klauslerb7cf5122018-03-14 22:31:16341 Word("PROCEDURE"), Walk(", ", x.attributes, ", ");
peter klauslerdcd09422018-03-15 23:03:28342 Put(" :: "), Walk(x.declarations, ", ");
peter klausler79d044e2018-03-01 00:56:10343 return false;
344 }
345 bool Pre(const TypeBoundProcedureStmt::WithInterface &x) {
peter klauslerb7cf5122018-03-14 22:31:16346 Word("PROCEDURE("), Walk(x.interfaceName), Put("), ");
peter klausler79d044e2018-03-01 00:56:10347 Walk(x.attributes);
peter klauslerdcd09422018-03-15 23:03:28348 Put(" :: "), Walk(x.bindingNames, ", ");
peter klausler79d044e2018-03-01 00:56:10349 return false;
350 }
351 bool Pre(const TypeBoundProcDecl &x) { // R750
352 Walk(std::get<Name>(x.t));
353 Walk(" => ", std::get<std::optional<Name>>(x.t));
354 return false;
355 }
356 bool Pre(const TypeBoundGenericStmt &x) { // R751
peter klauslerb7cf5122018-03-14 22:31:16357 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
peter klausler79d044e2018-03-01 00:56:10358 Put(" :: "), Walk(std::get<Indirection<GenericSpec>>(x.t));
359 Put(" => "), Walk(std::get<std::list<Name>>(x.t), ", ");
360 return false;
361 }
peter klauslerb7cf5122018-03-14 22:31:16362 void Post(const BindAttr::Deferred &) { Word("DEFERRED"); } // R752
363 void Post(const BindAttr::Non_Overridable &) { Word("NON_OVERRIDABLE"); }
peter klausler62d9cdd2018-03-15 00:02:21364 bool Pre(const FinalProcedureStmt &x) { // R753
365 Word("FINAL :: "), Walk(x.v, ", ");
366 return false;
peter klauslerb7cf5122018-03-14 22:31:16367 }
peter klausler79d044e2018-03-01 00:56:10368 bool Pre(const DerivedTypeSpec &x) { // R754
369 Walk(std::get<Name>(x.t));
370 Walk("(", std::get<std::list<TypeParamSpec>>(x.t), ",", ")");
371 return false;
372 }
373 bool Pre(const TypeParamSpec &x) { // R755
374 Walk(std::get<std::optional<Keyword>>(x.t), "=");
375 Walk(std::get<TypeParamValue>(x.t));
376 return false;
377 }
378 bool Pre(const StructureConstructor &x) { // R756
379 Walk(std::get<DerivedTypeSpec>(x.t));
380 Put('('), Walk(std::get<std::list<ComponentSpec>>(x.t), ", "), Put(')');
381 return false;
382 }
383 bool Pre(const ComponentSpec &x) { // R757
384 Walk(std::get<std::optional<Keyword>>(x.t), "=");
385 Walk(std::get<ComponentDataSource>(x.t));
386 return false;
387 }
388 bool Pre(const EnumDefStmt &) { // R760
peter klausler62d9cdd2018-03-15 00:02:21389 Word("ENUM, BIND(C)"), Indent();
peter klausler79d044e2018-03-01 00:56:10390 return false;
391 }
peter klausler62d9cdd2018-03-15 00:02:21392 bool Pre(const EnumeratorDefStmt &x) { // R761
393 Word("ENUMERATOR :: "), Walk(x.v, ", ");
394 return false;
peter klausler79d044e2018-03-01 00:56:10395 }
396 bool Pre(const Enumerator &x) { // R762
397 Walk(std::get<NamedConstant>(x.t));
398 Walk(" = ", std::get<std::optional<ScalarIntConstantExpr>>(x.t));
399 return false;
400 }
401 void Post(const EndEnumStmt &) { // R763
peter klausler62d9cdd2018-03-15 00:02:21402 Outdent(), Word("END ENUM");
peter klausler79d044e2018-03-01 00:56:10403 }
404 bool Pre(const BOZLiteralConstant &x) { // R764 - R767
405 Put("Z'");
406 out_ << std::hex << x.v << std::dec << '\'';
407 return false;
408 }
409 bool Pre(const AcValue::Triplet &x) { // R773
410 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
411 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
412 return false;
413 }
414 bool Pre(const ArrayConstructor &x) { // R769
415 Put('['), Walk(x.v), Put(']');
416 return false;
417 }
418 bool Pre(const AcSpec &x) { // R770
419 Walk(x.type, "::"), Walk(x.values, ", ");
420 return false;
421 }
422 template<typename A> bool Pre(const LoopBounds<A> &x) {
423 Walk(x.name), Put('='), Walk(x.lower), Put(','), Walk(x.upper);
424 Walk(",", x.step);
425 return false;
426 }
peter klausler46c35382018-03-14 00:11:26427 bool Pre(const AcImpliedDo &x) { // R774
428 Put('('), Walk(std::get<std::list<AcValue>>(x.t), ", ");
429 Put(", "), Walk(std::get<AcImpliedDoControl>(x.t)), Put(')');
430 return false;
431 }
peter klausler79d044e2018-03-01 00:56:10432 bool Pre(const AcImpliedDoControl &x) { // R775
433 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
434 Walk(std::get<LoopBounds<ScalarIntExpr>>(x.t));
Tim Keith2af29bc2018-02-26 22:28:32435 return false;
436 }
437
peter klausler79d044e2018-03-01 00:56:10438 bool Pre(const TypeDeclarationStmt &x) { // R801
439 const auto &dts = std::get<DeclarationTypeSpec>(x.t);
440 const auto &attrs = std::get<std::list<AttrSpec>>(x.t);
441 const auto &decls = std::get<std::list<EntityDecl>>(x.t);
442 Walk(dts), Walk(", ", attrs, ", ");
peter klausler92bcb7ce2018-03-19 23:17:23443
444 static const auto isInitializerOldStyle = [](const Initialization &i) {
445 return std::holds_alternative<std::list<Indirection<DataStmtValue>>>(i.u);
446 };
447 static const auto hasAssignmentInitializer = [](const EntityDecl &d) {
448 // Does a declaration have a new-style =x initializer?
449 const auto &init = std::get<std::optional<Initialization>>(d.t);
450 return init.has_value() && !isInitializerOldStyle(*init);
451 };
452 static const auto hasSlashDelimitedInitializer = [](const EntityDecl &d) {
453 // Does a declaration have an old-style /x/ initializer?
454 const auto &init = std::get<std::optional<Initialization>>(d.t);
455 return init.has_value() && isInitializerOldStyle(*init);
456 };
457 const auto useDoubledColons = [&]() {
458 bool isRecord{std::holds_alternative<DeclarationTypeSpec::Record>(dts.u)};
459 if (!attrs.empty()) {
460 // Attributes after the type require :: before the entities.
461 CHECK(!isRecord);
462 return true;
463 }
464 if (std::any_of(decls.begin(), decls.end(), hasAssignmentInitializer)) {
465 // Always use :: with new style standard initializers (=x),
466 // since the standard requires them to appear (even in free form,
467 // where mandatory spaces already disambiguate INTEGER J=666).
468 CHECK(!isRecord);
469 return true;
470 }
471 if (isRecord) {
472 // Never put :: in a legacy extension RECORD// statement.
473 return false;
474 }
475 // The :: is optional for this declaration. Avoid usage that can
476 // crash the pgf90 compiler.
477 if (std::any_of(
478 decls.begin(), decls.end(), hasSlashDelimitedInitializer)) {
479 // Don't use :: when a declaration uses legacy DATA-statement-like
480 // /x/ initialization.
481 return false;
482 }
483 // Don't use :: with intrinsic types. Otherwise, use it.
484 return !std::holds_alternative<IntrinsicTypeSpec>(dts.u);
485 };
486
487 if (useDoubledColons()) {
488 Put(" ::");
Tim Keith2af29bc2018-02-26 22:28:32489 }
peter klausler79d044e2018-03-01 00:56:10490 Put(' '), Walk(std::get<std::list<EntityDecl>>(x.t), ", ");
491 return false;
492 }
peter klauslerd39a33f2018-03-13 23:59:30493 bool Pre(const AttrSpec &x) { // R802
peter klauslerb7cf5122018-03-14 22:31:16494 std::visit(visitors{[&](const CoarraySpec &y) { Word("CODIMENSION["); },
495 [&](const ArraySpec &y) { Word("DIMENSION("); },
peter klauslerd71f3cf2018-03-14 23:31:41496 [](const auto &) {}},
peter klauslerd39a33f2018-03-13 23:59:30497 x.u);
498 return true;
499 }
500 void Post(const AttrSpec &x) {
501 std::visit(visitors{[&](const CoarraySpec &y) { Put(']'); },
peter klauslerd71f3cf2018-03-14 23:31:41502 [&](const ArraySpec &y) { Put(')'); }, [](const auto &) {}},
peter klauslerd39a33f2018-03-13 23:59:30503 x.u);
504 }
peter klausler79d044e2018-03-01 00:56:10505 bool Pre(const EntityDecl &x) { // R803
506 Walk(std::get<ObjectName>(x.t));
507 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
508 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
509 Walk("*", std::get<std::optional<CharLength>>(x.t));
510 Walk(std::get<std::optional<Initialization>>(x.t));
511 return false;
512 }
513 bool Pre(const NullInit &x) { // R806
peter klauslerb7cf5122018-03-14 22:31:16514 Word("NULL()");
peter klausler79d044e2018-03-01 00:56:10515 return false;
516 }
517 bool Pre(const LanguageBindingSpec &x) { // R808 & R1528
peter klauslerb7cf5122018-03-14 22:31:16518 Word("BIND(C"), Walk(", NAME=", x.v), Put(')');
peter klausler79d044e2018-03-01 00:56:10519 return false;
520 }
521 bool Pre(const CoarraySpec &x) { // R809
522 std::visit(visitors{[&](const DeferredCoshapeSpecList &y) { Walk(y); },
523 [&](const ExplicitCoshapeSpec &y) { Walk(y); }},
524 x.u);
525 return false;
526 }
peter klauslerb7cf5122018-03-14 22:31:16527 bool Pre(const DeferredCoshapeSpecList &x) { // R810
peter klausler79d044e2018-03-01 00:56:10528 for (auto j = x.v; j > 0; --j) {
529 Put(':');
530 if (j > 1) {
531 Put(',');
Tim Keith2af29bc2018-02-26 22:28:32532 }
533 }
peter klausler79d044e2018-03-01 00:56:10534 return false;
Tim Keith2af29bc2018-02-26 22:28:32535 }
peter klausler79d044e2018-03-01 00:56:10536 bool Pre(const ExplicitCoshapeSpec &x) { // R811
537 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
538 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":"), Put('*');
539 return false;
Tim Keith2af29bc2018-02-26 22:28:32540 }
peter klausler79d044e2018-03-01 00:56:10541 bool Pre(const ExplicitShapeSpec &x) { // R812 - R813 & R816 - R818
542 Walk(std::get<std::optional<SpecificationExpr>>(x.t), ":");
543 Walk(std::get<SpecificationExpr>(x.t));
544 return false;
545 }
546 bool Pre(const ArraySpec &x) { // R815
547 std::visit(
548 visitors{[&](const std::list<ExplicitShapeSpec> &y) { Walk(y, ","); },
549 [&](const std::list<AssumedShapeSpec> &y) { Walk(y, ","); },
550 [&](const DeferredShapeSpecList &y) { Walk(y); },
551 [&](const AssumedSizeSpec &y) { Walk(y); },
552 [&](const ImpliedShapeSpec &y) { Walk(y); },
553 [&](const AssumedRankSpec &y) { Walk(y); }},
554 x.u);
555 return false;
556 }
557 void Post(const AssumedShapeSpec &) { Put(':'); } // R819
peter klauslerb7cf5122018-03-14 22:31:16558 bool Pre(const DeferredShapeSpecList &x) { // R820
peter klausler79d044e2018-03-01 00:56:10559 for (auto j = x.v; j > 0; --j) {
560 Put(':');
561 if (j > 1) {
562 Put(',');
563 }
564 }
565 return false;
566 }
567 bool Pre(const AssumedImpliedSpec &x) { // R821
568 Walk(x.v, ":");
569 Put('*');
570 return false;
571 }
572 bool Pre(const AssumedSizeSpec &x) { // R822
573 Walk(std::get<std::list<ExplicitShapeSpec>>(x.t), ",", ",");
574 Walk(std::get<AssumedImpliedSpec>(x.t));
575 return false;
576 }
577 bool Pre(const ImpliedShapeSpec &x) { // R823
578 Walk(x.v, ",");
579 return false;
580 }
581 void Post(const AssumedRankSpec &) { Put(".."); } // R825
peter klauslerb7cf5122018-03-14 22:31:16582 void Post(const Asynchronous &) { Word("ASYNCHRONOUS"); }
583 void Post(const External &) { Word("EXTERNAL"); }
584 void Post(const Intrinsic &) { Word("INTRINSIC"); }
585 void Post(const Optional &) { Word("OPTIONAL"); }
586 void Post(const Parameter &) { Word("PARAMETER"); }
587 void Post(const Protected &) { Word("PROTECTED"); }
588 void Post(const Save &) { Word("SAVE"); }
589 void Post(const Target &) { Word("TARGET"); }
590 void Post(const Value &) { Word("VALUE"); }
591 void Post(const Volatile &) { Word("VOLATILE"); }
peter klausler79d044e2018-03-01 00:56:10592 bool Pre(const IntentSpec &x) { // R826
peter klauslerb7cf5122018-03-14 22:31:16593 Word("INTENT("), Walk(x.v), Put(")");
peter klausler79d044e2018-03-01 00:56:10594 return false;
595 }
596 bool Pre(const AccessStmt &x) { // R827
597 Walk(std::get<AccessSpec>(x.t));
598 Walk(" :: ", std::get<std::list<AccessId>>(x.t), ", ");
599 return false;
600 }
601 bool Pre(const AllocatableStmt &x) { // R829
peter klauslerb7cf5122018-03-14 22:31:16602 Word("ALLOCATABLE :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10603 return false;
604 }
605 bool Pre(const ObjectDecl &x) { // R830 & R860
606 Walk(std::get<ObjectName>(x.t));
607 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
608 Walk("[", std::get<std::optional<CoarraySpec>>(x.t), "]");
609 return false;
610 }
611 bool Pre(const AsynchronousStmt &x) { // R831
peter klauslerb7cf5122018-03-14 22:31:16612 Word("ASYNCHRONOUS :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10613 return false;
614 }
615 bool Pre(const BindStmt &x) { // R832
616 Walk(x.t, " :: ");
617 return false;
618 }
619 bool Pre(const BindEntity &x) { // R833
620 bool isCommon{std::get<BindEntity::Kind>(x.t) == BindEntity::Kind::Common};
621 const char *slash{isCommon ? "/" : ""};
622 Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
623 return false;
624 }
625 bool Pre(const CodimensionStmt &x) { // R834
peter klauslerb7cf5122018-03-14 22:31:16626 Word("CODIMENSION :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10627 return false;
628 }
629 bool Pre(const CodimensionDecl &x) { // R835
630 Walk(std::get<Name>(x.t));
631 Put('['), Walk(std::get<CoarraySpec>(x.t)), Put(']');
632 return false;
633 }
634 bool Pre(const ContiguousStmt &x) { // R836
peter klauslerb7cf5122018-03-14 22:31:16635 Word("CONTIGUOUS :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10636 return false;
637 }
peter klauslerb7cf5122018-03-14 22:31:16638 bool Pre(const DataStmt &x) { // R837
639 Word("DATA "), Walk(x.v, ", ");
640 return false;
peter klausler79d044e2018-03-01 00:56:10641 }
642 bool Pre(const DataStmtSet &x) { // R838
643 Walk(std::get<std::list<DataStmtObject>>(x.t), ", ");
644 Put('/'), Walk(std::get<std::list<DataStmtValue>>(x.t), ", "), Put('/');
645 return false;
646 }
647 bool Pre(const DataImpliedDo &x) { // R840, R842
peter klauslerb7cf5122018-03-14 22:31:16648 Put('('), Walk(std::get<std::list<DataIDoObject>>(x.t), ", "), Put(',');
peter klausler79d044e2018-03-01 00:56:10649 Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
650 Walk(std::get<LoopBounds<ScalarIntConstantExpr>>(x.t)), Put(')');
651 return false;
652 }
653 bool Pre(const DataStmtValue &x) { // R843
654 Walk(std::get<std::optional<DataStmtRepeat>>(x.t), "*");
655 Walk(std::get<DataStmtConstant>(x.t));
656 return false;
657 }
658 bool Pre(const DimensionStmt &x) { // R848
peter klauslerb7cf5122018-03-14 22:31:16659 Word("DIMENSION :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10660 return false;
661 }
662 bool Pre(const DimensionStmt::Declaration &x) {
663 Walk(std::get<Name>(x.t));
664 Put('('), Walk(std::get<ArraySpec>(x.t)), Put(')');
665 return false;
666 }
667 bool Pre(const IntentStmt &x) { // R849
668 Walk(x.t, " :: ");
669 return false;
670 }
671 bool Pre(const OptionalStmt &x) { // R850
peter klauslerb7cf5122018-03-14 22:31:16672 Word("OPTIONAL :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10673 return false;
674 }
675 bool Pre(const ParameterStmt &x) { // R851
peter klauslerb7cf5122018-03-14 22:31:16676 Word("PARAMETER("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:10677 return false;
678 }
679 bool Pre(const NamedConstantDef &x) { // R852
680 Walk(x.t, "=");
681 return false;
682 }
683 bool Pre(const PointerStmt &x) { // R853
peter klauslerdcd09422018-03-15 23:03:28684 Word("POINTER"), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10685 return false;
686 }
687 bool Pre(const ProtectedStmt &x) { // R855
peter klauslerb7cf5122018-03-14 22:31:16688 Word("PROTECTED :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10689 return false;
690 }
691 bool Pre(const SaveStmt &x) { // R856
peter klauslerb7cf5122018-03-14 22:31:16692 Word("SAVE"), Walk(" :: ", x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10693 return false;
694 }
695 bool Pre(const SavedEntity &x) { // R857, R858
696 bool isCommon{
697 std::get<SavedEntity::Kind>(x.t) == SavedEntity::Kind::Common};
698 const char *slash{isCommon ? "/" : ""};
699 Put(slash), Walk(std::get<Name>(x.t)), Put(slash);
700 return false;
701 }
702 bool Pre(const TargetStmt &x) { // R859
peter klauslerb7cf5122018-03-14 22:31:16703 Word("TARGET :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10704 return false;
705 }
706 bool Pre(const ValueStmt &x) { // R861
peter klauslerb7cf5122018-03-14 22:31:16707 Word("VALUE :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10708 return false;
709 }
710 bool Pre(const VolatileStmt &x) { // R862
peter klauslerb7cf5122018-03-14 22:31:16711 Word("VOLATILE :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10712 return false;
713 }
714 bool Pre(const ImplicitStmt &x) { // R863
peter klauslerb7cf5122018-03-14 22:31:16715 Word("IMPLICIT ");
peter klausler79d044e2018-03-01 00:56:10716 std::visit(
717 visitors{[&](const std::list<ImplicitSpec> &y) { Walk(y, ", "); },
718 [&](const std::list<ImplicitStmt::ImplicitNoneNameSpec> &y) {
peter klauslerb7cf5122018-03-14 22:31:16719 Word("NONE"), Walk(" (", y, ", ", ")");
peter klausler79d044e2018-03-01 00:56:10720 }},
721 x.u);
722 return false;
723 }
724 bool Pre(const ImplicitSpec &x) { // R864
725 Walk(std::get<DeclarationTypeSpec>(x.t));
726 Put('('), Walk(std::get<std::list<LetterSpec>>(x.t), ", "), Put(')');
727 return false;
728 }
729 bool Pre(const LetterSpec &x) { // R865
peter klausler424ec7b2018-03-20 17:59:07730 Put(*std::get<const char *>(x.t));
731 auto second = std::get<std::optional<const char *>>(x.t);
732 if (second.has_value()) {
733 Put('-'), Put(**second);
734 }
peter klausler79d044e2018-03-01 00:56:10735 return false;
736 }
737 bool Pre(const ImportStmt &x) { // R867
peter klauslerb7cf5122018-03-14 22:31:16738 Word("IMPORT");
peter klausler79d044e2018-03-01 00:56:10739 switch (x.kind) {
peter klausler2e5300c2018-03-15 23:22:38740 case ImportStmt::Kind::Default: Walk(" :: ", x.names, ", "); break;
peter klausler79d044e2018-03-01 00:56:10741 case ImportStmt::Kind::Only:
peter klauslerb7cf5122018-03-14 22:31:16742 Put(", "), Word("ONLY: ");
peter klauslerdcd09422018-03-15 23:03:28743 Walk(x.names, ", ");
peter klausler79d044e2018-03-01 00:56:10744 break;
peter klauslerb7cf5122018-03-14 22:31:16745 case ImportStmt::Kind::None: Word(", NONE"); break;
746 case ImportStmt::Kind::All: Word(", ALL"); break;
peter klausler79d044e2018-03-01 00:56:10747 default: CRASH_NO_CASE;
748 }
749 return false;
750 }
751 bool Pre(const NamelistStmt &x) { // R868
peter klauslerb7cf5122018-03-14 22:31:16752 Word("NAMELIST"), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:10753 return false;
754 }
755 bool Pre(const NamelistStmt::Group &x) {
peter klausler424ec7b2018-03-20 17:59:07756 Put('/'), Walk(std::get<Name>(x.t)), Put('/');
peter klausler79d044e2018-03-01 00:56:10757 Walk(std::get<std::list<Name>>(x.t), ", ");
758 return false;
759 }
760 bool Pre(const EquivalenceStmt &x) { // R870, R871
peter klauslerb7cf5122018-03-14 22:31:16761 Word("EQUIVALENCE");
peter klausler79d044e2018-03-01 00:56:10762 const char *separator{" "};
763 for (const std::list<EquivalenceObject> &y : x.v) {
764 Put(separator), Put('('), Walk(y), Put(')');
765 separator = ", ";
766 }
767 return false;
768 }
769 bool Pre(const CommonStmt &x) { // R873
peter klauslerb7cf5122018-03-14 22:31:16770 Word("COMMON ");
peter klausler79d044e2018-03-01 00:56:10771 Walk("/", std::get<std::optional<std::optional<Name>>>(x.t), "/");
772 Walk(std::get<std::list<CommonBlockObject>>(x.t), ", ");
773 Walk(", ", std::get<std::list<CommonStmt::Block>>(x.t), ", ");
774 return false;
775 }
776 bool Pre(const CommonBlockObject &x) { // R874
777 Walk(std::get<Name>(x.t));
778 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")");
779 return false;
780 }
781 bool Pre(const CommonStmt::Block &x) {
782 Walk("/", std::get<std::optional<Name>>(x.t), "/");
783 Walk(std::get<std::list<CommonBlockObject>>(x.t));
784 return false;
785 }
Tim Keith2af29bc2018-02-26 22:28:32786
peter klausler79d044e2018-03-01 00:56:10787 bool Pre(const Substring &x) { // R908, R909
788 Walk(std::get<DataReference>(x.t));
789 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
790 return false;
791 }
792 bool Pre(const CharLiteralConstantSubstring &x) {
793 Walk(std::get<CharLiteralConstant>(x.t));
794 Put('('), Walk(std::get<SubstringRange>(x.t)), Put(')');
795 return false;
796 }
797 bool Pre(const SubstringRange &x) { // R910
798 Walk(x.t, ":");
799 return false;
800 }
801 bool Pre(const PartRef &x) { // R912
802 Walk(x.name);
803 Walk("(", x.subscripts, ",", ")");
804 Walk(x.imageSelector);
805 return false;
806 }
807 bool Pre(const StructureComponent &x) { // R913
peter klausler4e354d82018-03-30 22:23:37808 Walk(x.base);
809 if (structureComponents_.find(x.component.source) !=
810 structureComponents_.end()) {
811 Put('.');
812 } else {
813 Put('%');
814 }
815 Walk(x.component);
peter klausler79d044e2018-03-01 00:56:10816 return false;
817 }
818 bool Pre(const ArrayElement &x) { // R917
819 Walk(x.base);
820 Put('('), Walk(x.subscripts, ","), Put(')');
821 return false;
822 }
823 bool Pre(const SubscriptTriplet &x) { // R921
824 Walk(std::get<0>(x.t)), Put(':'), Walk(std::get<1>(x.t));
825 Walk(":", std::get<2>(x.t));
826 return false;
827 }
828 bool Pre(const ImageSelector &x) { // R924
829 Put('['), Walk(std::get<std::list<Cosubscript>>(x.t), ",");
830 Walk(",", std::get<std::list<ImageSelectorSpec>>(x.t), ","), Put(']');
831 return false;
832 }
peter klausler62d9cdd2018-03-15 00:02:21833 bool Pre(const ImageSelectorSpec::Stat &) { // R926
peter klauslerb7cf5122018-03-14 22:31:16834 Word("STAT=");
peter klausler79d044e2018-03-01 00:56:10835 return true;
836 }
837 bool Pre(const ImageSelectorSpec::Team &) {
peter klauslerb7cf5122018-03-14 22:31:16838 Word("TEAM=");
peter klausler79d044e2018-03-01 00:56:10839 return true;
840 }
841 bool Pre(const ImageSelectorSpec::Team_Number &) {
peter klauslerb7cf5122018-03-14 22:31:16842 Word("TEAM_NUMBER=");
peter klausler79d044e2018-03-01 00:56:10843 return true;
844 }
845 bool Pre(const AllocateStmt &x) { // R927
peter klauslerb7cf5122018-03-14 22:31:16846 Word("ALLOCATE(");
847 Walk(std::get<std::optional<TypeSpec>>(x.t), "::");
peter klausler79d044e2018-03-01 00:56:10848 Walk(std::get<std::list<Allocation>>(x.t), ", ");
849 Walk(", ", std::get<std::list<AllocOpt>>(x.t), ", "), Put(')');
850 return false;
851 }
852 bool Pre(const AllocOpt &x) { // R928, R931
peter klauslerb7cf5122018-03-14 22:31:16853 std::visit(visitors{[&](const AllocOpt::Mold &) { Word("MOLD="); },
854 [&](const AllocOpt::Source &) { Word("SOURCE="); },
peter klauslered5a6c92018-03-15 00:07:15855 [](const StatOrErrmsg &) {}},
peter klausler79d044e2018-03-01 00:56:10856 x.u);
857 return true;
858 }
859 bool Pre(const Allocation &x) { // R932
860 Walk(std::get<AllocateObject>(x.t));
861 Walk("(", std::get<std::list<AllocateShapeSpec>>(x.t), ",", ")");
862 Walk("[", std::get<std::optional<AllocateCoarraySpec>>(x.t), "]");
863 return false;
864 }
865 bool Pre(const AllocateShapeSpec &x) { // R934 & R938
866 Walk(std::get<std::optional<BoundExpr>>(x.t), ":");
867 Walk(std::get<BoundExpr>(x.t));
868 return false;
869 }
870 bool Pre(const AllocateCoarraySpec &x) { // R937
871 Walk(std::get<std::list<AllocateCoshapeSpec>>(x.t), ",", ",");
872 Walk(std::get<std::optional<BoundExpr>>(x.t), ":"), Put('*');
873 return false;
874 }
875 bool Pre(const NullifyStmt &x) { // R939
peter klauslerb7cf5122018-03-14 22:31:16876 Word("NULLIFY("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:10877 return false;
878 }
879 bool Pre(const DeallocateStmt &x) { // R941
peter klauslerb7cf5122018-03-14 22:31:16880 Word("DEALLOCATE(");
881 Walk(std::get<std::list<AllocateObject>>(x.t), ", ");
peter klausler79d044e2018-03-01 00:56:10882 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
883 return false;
884 }
885 bool Pre(const StatOrErrmsg &x) { // R942 & R1165
peter klauslerb7cf5122018-03-14 22:31:16886 std::visit(visitors{[&](const StatVariable &) { Word("STAT="); },
887 [&](const MsgVariable &) { Word("ERRMSG="); }},
peter klausler79d044e2018-03-01 00:56:10888 x.u);
889 return true;
890 }
891
892 // R1001 - R1022
893 bool Pre(const Expr::Parentheses &x) {
894 Put('('), Walk(x.v), Put(')');
895 return false;
896 }
897 bool Pre(const Expr::UnaryPlus &x) {
898 Put("+");
899 return true;
900 }
901 bool Pre(const Expr::Negate &x) {
902 Put("-");
903 return true;
904 }
905 bool Pre(const Expr::NOT &x) {
peter klauslerb7cf5122018-03-14 22:31:16906 Word(".NOT.");
peter klausler79d044e2018-03-01 00:56:10907 return true;
908 }
909 bool Pre(const Expr::PercentLoc &x) {
peter klauslerb7cf5122018-03-14 22:31:16910 Word("%LOC("), Walk(x.v), Put(')');
peter klausler79d044e2018-03-01 00:56:10911 return false;
912 }
peter klausler79d044e2018-03-01 00:56:10913 bool Pre(const Expr::Power &x) {
914 Walk(x.t, "**");
915 return false;
916 }
917 bool Pre(const Expr::Multiply &x) {
918 Walk(x.t, "*");
919 return false;
920 }
921 bool Pre(const Expr::Divide &x) {
922 Walk(x.t, "/");
923 return false;
924 }
925 bool Pre(const Expr::Add &x) {
926 Walk(x.t, "+");
927 return false;
928 }
929 bool Pre(const Expr::Subtract &x) {
930 Walk(x.t, "-");
931 return false;
932 }
933 bool Pre(const Expr::Concat &x) {
934 Walk(x.t, "//");
935 return false;
936 }
937 bool Pre(const Expr::LT &x) {
938 Walk(x.t, "<");
939 return false;
940 }
941 bool Pre(const Expr::LE &x) {
942 Walk(x.t, "<=");
943 return false;
944 }
945 bool Pre(const Expr::EQ &x) {
946 Walk(x.t, "==");
947 return false;
948 }
949 bool Pre(const Expr::NE &x) {
950 Walk(x.t, "/=");
951 return false;
952 }
953 bool Pre(const Expr::GE &x) {
954 Walk(x.t, ">=");
955 return false;
956 }
957 bool Pre(const Expr::GT &x) {
958 Walk(x.t, ">");
959 return false;
960 }
961 bool Pre(const Expr::AND &x) {
962 Walk(x.t, ".AND.");
963 return false;
964 }
965 bool Pre(const Expr::OR &x) {
966 Walk(x.t, ".OR.");
967 return false;
968 }
969 bool Pre(const Expr::EQV &x) {
970 Walk(x.t, ".EQV.");
971 return false;
972 }
973 bool Pre(const Expr::NEQV &x) {
974 Walk(x.t, ".NEQV.");
975 return false;
976 }
peter klausler0983fbc2018-03-16 23:13:49977 bool Pre(const Expr::XOR &x) {
978 Walk(x.t, ".XOR.");
979 return false;
980 }
peter klausler79d044e2018-03-01 00:56:10981 bool Pre(const Expr::ComplexConstructor &x) {
982 Put('('), Walk(x.t, ","), Put(')');
983 return false;
984 }
985 bool Pre(const Expr::DefinedBinary &x) {
986 Walk(std::get<1>(x.t)); // left
987 Walk(std::get<DefinedOpName>(x.t));
988 Walk(std::get<2>(x.t)); // right
989 return false;
990 }
991 bool Pre(const DefinedOpName &x) { // R1003, R1023, R1414, & R1415
peter klausler424ec7b2018-03-20 17:59:07992 Put('.'), Walk(x.v), Put('.');
peter klausler79d044e2018-03-01 00:56:10993 return false;
994 }
995 bool Pre(const AssignmentStmt &x) { // R1032
996 Walk(x.t, " = ");
997 return false;
998 }
999 bool Pre(const PointerAssignmentStmt &x) { // R1033, R1034, R1038
1000 Walk(std::get<Variable>(x.t));
1001 std::visit(
1002 visitors{[&](const std::list<BoundsRemapping> &y) {
1003 Put('('), Walk(y), Put(')');
1004 },
1005 [&](const std::list<BoundsSpec> &y) { Walk("(", y, ", ", ")"); }},
1006 std::get<PointerAssignmentStmt::Bounds>(x.t).u);
1007 Put(" => "), Walk(std::get<Expr>(x.t));
1008 return false;
1009 }
1010 void Post(const BoundsSpec &) { // R1035
1011 Put(':');
1012 }
1013 bool Pre(const BoundsRemapping &x) { // R1036
1014 Walk(x.t, ":");
1015 return false;
1016 }
1017 bool Pre(const ProcComponentRef &x) { // R1039
peter klausler4e354d82018-03-30 22:23:371018 Walk(std::get<Scalar<Variable>>(x.t)), Put('%'), Walk(std::get<Name>(x.t));
peter klausler79d044e2018-03-01 00:56:101019 return false;
1020 }
1021 bool Pre(const WhereStmt &x) { // R1041, R1045, R1046
peter klauslerb7cf5122018-03-14 22:31:161022 Word("WHERE ("), Walk(x.t, ") ");
peter klausler79d044e2018-03-01 00:56:101023 return false;
1024 }
1025 bool Pre(const WhereConstructStmt &x) { // R1043
1026 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161027 Word("WHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
peter klausler79d044e2018-03-01 00:56:101028 Indent();
1029 return false;
1030 }
1031 bool Pre(const MaskedElsewhereStmt &x) { // R1047
1032 Outdent();
peter klauslerb7cf5122018-03-14 22:31:161033 Word("ELSEWHERE ("), Walk(std::get<LogicalExpr>(x.t)), Put(')');
peter klausler79d044e2018-03-01 00:56:101034 Walk(" ", std::get<std::optional<Name>>(x.t));
1035 Indent();
1036 return false;
1037 }
1038 bool Pre(const ElsewhereStmt &x) { // R1048
peter klauslerb7cf5122018-03-14 22:31:161039 Outdent(), Word("ELSEWHERE"), Walk(" ", x.v), Indent();
peter klausler79d044e2018-03-01 00:56:101040 return false;
1041 }
1042 bool Pre(const EndWhereStmt &x) { // R1049
peter klauslerb7cf5122018-03-14 22:31:161043 Outdent(), Word("END WHERE"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101044 return false;
1045 }
1046 bool Pre(const ForallConstructStmt &x) { // R1051
1047 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161048 Word("FORALL"), Walk(std::get<Indirection<ConcurrentHeader>>(x.t));
peter klausler79d044e2018-03-01 00:56:101049 Indent();
1050 return false;
1051 }
1052 bool Pre(const EndForallStmt &x) { // R1054
peter klauslerb7cf5122018-03-14 22:31:161053 Outdent(), Word("END FORALL"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101054 return false;
1055 }
1056 bool Pre(const ForallStmt &) { // R1055
peter klauslerb7cf5122018-03-14 22:31:161057 Word("FORALL");
peter klausler79d044e2018-03-01 00:56:101058 return true;
1059 }
1060
1061 bool Pre(const AssociateStmt &x) { // R1103
1062 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161063 Word("ASSOCIATE (");
1064 Walk(std::get<std::list<Association>>(x.t), ", "), Put(')'), Indent();
peter klausler79d044e2018-03-01 00:56:101065 return false;
1066 }
1067 bool Pre(const Association &x) { // R1104
1068 Walk(x.t, " => ");
1069 return false;
1070 }
1071 bool Pre(const EndAssociateStmt &x) { // R1106
peter klauslerb7cf5122018-03-14 22:31:161072 Outdent(), Word("END ASSOCIATE"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101073 return false;
1074 }
1075 bool Pre(const BlockStmt &x) { // R1108
peter klauslerb7cf5122018-03-14 22:31:161076 Walk(x.v, ": "), Word("BLOCK"), Indent();
peter klausler79d044e2018-03-01 00:56:101077 return false;
1078 }
1079 bool Pre(const EndBlockStmt &x) { // R1110
peter klauslerb7cf5122018-03-14 22:31:161080 Outdent(), Word("END BLOCK"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101081 return false;
1082 }
1083 bool Pre(const ChangeTeamStmt &x) { // R1112
1084 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161085 Word("CHANGE TEAM ("), Walk(std::get<TeamVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101086 Walk(", ", std::get<std::list<CoarrayAssociation>>(x.t), ", ");
1087 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1088 Indent();
1089 return false;
1090 }
1091 bool Pre(const CoarrayAssociation &x) { // R1113
1092 Walk(x.t, " => ");
1093 return false;
1094 }
1095 bool Pre(const EndChangeTeamStmt &x) { // R1114
peter klauslerb7cf5122018-03-14 22:31:161096 Outdent(), Word("END TEAM (");
peter klausler79d044e2018-03-01 00:56:101097 Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
1098 Put(')'), Walk(" ", std::get<std::optional<Name>>(x.t));
1099 return false;
1100 }
1101 bool Pre(const CriticalStmt &x) { // R1117
1102 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161103 Word("CRITICAL ("), Walk(std::get<std::list<StatOrErrmsg>>(x.t), ", ");
peter klausler79d044e2018-03-01 00:56:101104 Put(')'), Indent();
1105 return false;
1106 }
1107 bool Pre(const EndCriticalStmt &x) { // R1118
peter klauslerb7cf5122018-03-14 22:31:161108 Outdent(), Word("END CRITICAL"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101109 return false;
1110 }
1111 bool Pre(const DoConstruct &x) { // R1119, R1120
1112 Walk(std::get<Statement<NonLabelDoStmt>>(x.t));
1113 Indent(), Walk(std::get<Block>(x.t), ""), Outdent();
1114 Walk(std::get<Statement<EndDoStmt>>(x.t));
1115 return false;
1116 }
1117 bool Pre(const LabelDoStmt &x) { // R1121
1118 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161119 Word("DO "), Walk(std::get<Label>(x.t));
peter klausler79d044e2018-03-01 00:56:101120 Walk(" ", std::get<std::optional<LoopControl>>(x.t));
1121 return false;
1122 }
1123 bool Pre(const NonLabelDoStmt &x) { // R1122
1124 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161125 Word("DO "), Walk(std::get<std::optional<LoopControl>>(x.t));
peter klausler79d044e2018-03-01 00:56:101126 return false;
1127 }
1128 bool Pre(const LoopControl &x) { // R1123
1129 std::visit(visitors{[&](const ScalarLogicalExpr &y) {
peter klauslerb7cf5122018-03-14 22:31:161130 Word("WHILE ("), Walk(y), Put(')');
peter klausler79d044e2018-03-01 00:56:101131 },
1132 [&](const auto &y) { Walk(y); }},
1133 x.u);
1134 return false;
1135 }
1136 bool Pre(const ConcurrentHeader &x) { // R1125
1137 Put('('), Walk(std::get<std::optional<IntegerTypeSpec>>(x.t), "::");
1138 Walk(std::get<std::list<ConcurrentControl>>(x.t), ", ");
1139 Walk(", ", std::get<std::optional<ScalarLogicalExpr>>(x.t)), Put(')');
1140 return false;
1141 }
1142 bool Pre(const ConcurrentControl &x) { // R1126 - R1128
1143 Walk(std::get<Name>(x.t)), Put('='), Walk(std::get<1>(x.t));
1144 Put(':'), Walk(std::get<2>(x.t));
1145 Walk(":", std::get<std::optional<ScalarIntExpr>>(x.t));
1146 return false;
1147 }
1148 bool Pre(const LoopControl::Concurrent &x) { // R1129
peter klauslerb7cf5122018-03-14 22:31:161149 Word("CONCURRENT");
peter klausler79d044e2018-03-01 00:56:101150 return true;
1151 }
1152 bool Pre(const LocalitySpec::Local &x) {
peter klauslerb7cf5122018-03-14 22:31:161153 Word("LOCAL("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101154 return false;
1155 }
1156 bool Pre(const LocalitySpec::LocalInit &x) {
peter klauslerb7cf5122018-03-14 22:31:161157 Word("LOCAL INIT("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101158 return false;
1159 }
1160 bool Pre(const LocalitySpec::Shared &x) {
peter klauslerb7cf5122018-03-14 22:31:161161 Word("SHARED("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101162 return false;
1163 }
peter klauslerb7cf5122018-03-14 22:31:161164 void Post(const LocalitySpec::DefaultNone &x) { Word("DEFAULT(NONE)"); }
peter klausler79d044e2018-03-01 00:56:101165 bool Pre(const EndDoStmt &x) { // R1132
peter klauslerb7cf5122018-03-14 22:31:161166 Word("END DO"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101167 return false;
1168 }
1169 bool Pre(const CycleStmt &x) { // R1133
peter klauslerb7cf5122018-03-14 22:31:161170 Word("CYCLE"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101171 return false;
1172 }
1173 bool Pre(const IfThenStmt &x) { // R1135
1174 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161175 Word("IF ("), Walk(std::get<ScalarLogicalExpr>(x.t));
1176 Put(") "), Word("THEN"), Indent();
peter klausler79d044e2018-03-01 00:56:101177 return false;
1178 }
1179 bool Pre(const ElseIfStmt &x) { // R1136
peter klauslerb7cf5122018-03-14 22:31:161180 Outdent(), Word("ELSE IF (");
1181 Walk(std::get<ScalarLogicalExpr>(x.t)), Put(") "), Word("THEN");
1182 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
peter klausler79d044e2018-03-01 00:56:101183 return false;
1184 }
1185 bool Pre(const ElseStmt &x) { // R1137
peter klauslerb7cf5122018-03-14 22:31:161186 Outdent(), Word("ELSE"), Walk(" ", x.v), Indent();
peter klausler79d044e2018-03-01 00:56:101187 return false;
1188 }
1189 bool Pre(const EndIfStmt &x) { // R1138
peter klauslerb7cf5122018-03-14 22:31:161190 Outdent(), Word("END IF"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101191 return false;
1192 }
1193 bool Pre(const IfStmt &x) { // R1139
peter klauslerb7cf5122018-03-14 22:31:161194 Word("IF ("), Walk(x.t, ") ");
peter klausler79d044e2018-03-01 00:56:101195 return false;
1196 }
1197 bool Pre(const SelectCaseStmt &x) { // R1141, R1144
1198 Walk(std::get<std::optional<Name>>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161199 Word("SELECT CASE (");
1200 Walk(std::get<Scalar<Expr>>(x.t)), Put(')'), Indent();
peter klausler79d044e2018-03-01 00:56:101201 return false;
1202 }
1203 bool Pre(const CaseStmt &x) { // R1142
peter klauslerb7cf5122018-03-14 22:31:161204 Outdent(), Word("CASE "), Walk(std::get<CaseSelector>(x.t));
peter klausler79d044e2018-03-01 00:56:101205 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1206 return false;
1207 }
1208 bool Pre(const EndSelectStmt &x) { // R1143 & R1151 & R1155
peter klauslerb7cf5122018-03-14 22:31:161209 Outdent(), Word("END SELECT"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101210 return false;
1211 }
1212 bool Pre(const CaseSelector &x) { // R1145
1213 std::visit(visitors{[&](const std::list<CaseValueRange> &y) {
1214 Put('('), Walk(y), Put(')');
1215 },
peter klauslerb7cf5122018-03-14 22:31:161216 [&](const Default &) { Word("DEFAULT"); }},
peter klausler79d044e2018-03-01 00:56:101217 x.u);
1218 return false;
1219 }
1220 bool Pre(const CaseValueRange::Range &x) { // R1146
1221 Walk(x.lower), Put(':'), Walk(x.upper);
1222 return false;
1223 }
1224 bool Pre(const SelectRankStmt &x) { // R1149
1225 Walk(std::get<0>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161226 Word("SELECT RANK ("), Walk(std::get<1>(x.t), " => ");
peter klausler79d044e2018-03-01 00:56:101227 Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1228 return false;
1229 }
1230 bool Pre(const SelectRankCaseStmt &x) { // R1150
peter klauslerb7cf5122018-03-14 22:31:161231 Outdent(), Word("RANK ");
peter klausler79d044e2018-03-01 00:56:101232 std::visit(visitors{[&](const ScalarIntConstantExpr &y) {
1233 Put('('), Walk(y), Put(')');
1234 },
1235 [&](const Star &) { Put("(*)"); },
peter klauslerb7cf5122018-03-14 22:31:161236 [&](const Default &) { Word("DEFAULT"); }},
peter klausler79d044e2018-03-01 00:56:101237 std::get<SelectRankCaseStmt::Rank>(x.t).u);
1238 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1239 return false;
1240 }
1241 bool Pre(const SelectTypeStmt &x) { // R1153
1242 Walk(std::get<0>(x.t), ": ");
peter klauslerb7cf5122018-03-14 22:31:161243 Word("SELECT TYPE ("), Walk(std::get<1>(x.t), " => ");
peter klausler79d044e2018-03-01 00:56:101244 Walk(std::get<Selector>(x.t)), Put(')'), Indent();
1245 return false;
1246 }
1247 bool Pre(const TypeGuardStmt &x) { // R1154
1248 Outdent(), Walk(std::get<TypeGuardStmt::Guard>(x.t));
1249 Walk(" ", std::get<std::optional<Name>>(x.t)), Indent();
1250 return false;
1251 }
1252 bool Pre(const TypeGuardStmt::Guard &x) {
1253 std::visit(visitors{[&](const TypeSpec &y) {
peter klauslerb7cf5122018-03-14 22:31:161254 Word("TYPE IS ("), Walk(y), Put(')');
peter klausler79d044e2018-03-01 00:56:101255 },
1256 [&](const DerivedTypeSpec &y) {
peter klauslerb7cf5122018-03-14 22:31:161257 Word("CLASS IS ("), Walk(y), Put(')');
peter klausler79d044e2018-03-01 00:56:101258 },
peter klauslerb7cf5122018-03-14 22:31:161259 [&](const Default &) { Word("CLASS DEFAULT"); }},
peter klausler79d044e2018-03-01 00:56:101260 x.u);
1261 return false;
1262 }
1263 bool Pre(const ExitStmt &x) { // R1156
peter klauslerb7cf5122018-03-14 22:31:161264 Word("EXIT"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101265 return false;
1266 }
1267 bool Pre(const GotoStmt &x) { // R1157
peter klauslerb7cf5122018-03-14 22:31:161268 Word("GO TO ");
peter klausler79d044e2018-03-01 00:56:101269 return true;
1270 }
1271 bool Pre(const ComputedGotoStmt &x) { // R1158
peter klauslerb7cf5122018-03-14 22:31:161272 Word("GO TO ("), Walk(x.t, "), ");
peter klausler79d044e2018-03-01 00:56:101273 return false;
1274 }
1275 bool Pre(const ContinueStmt &x) { // R1159
peter klauslerb7cf5122018-03-14 22:31:161276 Word("CONTINUE");
peter klausler79d044e2018-03-01 00:56:101277 return false;
1278 }
1279 bool Pre(const StopStmt &x) { // R1160, R1161
1280 if (std::get<StopStmt::Kind>(x.t) == StopStmt::Kind::ErrorStop) {
peter klauslerb7cf5122018-03-14 22:31:161281 Word("ERROR ");
peter klausler79d044e2018-03-01 00:56:101282 }
peter klauslerb7cf5122018-03-14 22:31:161283 Word("STOP"), Walk(" ", std::get<std::optional<StopCode>>(x.t));
peter klausler79d044e2018-03-01 00:56:101284 Walk(", QUIET=", std::get<std::optional<ScalarLogicalExpr>>(x.t));
1285 return false;
1286 }
1287 bool Pre(const FailImageStmt &x) { // R1163
peter klauslerb7cf5122018-03-14 22:31:161288 Word("FAIL IMAGE");
peter klausler79d044e2018-03-01 00:56:101289 return false;
1290 }
1291 bool Pre(const SyncAllStmt &x) { // R1164
peter klauslerb7cf5122018-03-14 22:31:161292 Word("SYNC ALL ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101293 return false;
1294 }
1295 bool Pre(const SyncImagesStmt &x) { // R1166
peter klauslerb7cf5122018-03-14 22:31:161296 Word("SYNC IMAGES (");
1297 Walk(std::get<SyncImagesStmt::ImageSet>(x.t));
peter klausler79d044e2018-03-01 00:56:101298 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1299 return false;
1300 }
1301 bool Pre(const SyncMemoryStmt &x) { // R1168
peter klauslerb7cf5122018-03-14 22:31:161302 Word("SYNC MEMORY ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101303 return false;
1304 }
1305 bool Pre(const SyncTeamStmt &x) { // R1169
peter klauslerb7cf5122018-03-14 22:31:161306 Word("SYNC TEAM ("), Walk(std::get<TeamVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101307 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1308 return false;
1309 }
1310 bool Pre(const EventPostStmt &x) { // R1170
peter klauslerb7cf5122018-03-14 22:31:161311 Word("EVENT POST ("), Walk(std::get<EventVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101312 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", "), Put(')');
1313 return false;
1314 }
1315 bool Pre(const EventWaitStmt::EventWaitSpec &x) { // R1173, R1174
peter klausler62d9cdd2018-03-15 00:02:211316 std::visit(visitors{[&](const ScalarIntExpr &x) { Word("UNTIL_COUNT="); },
peter klauslered5a6c92018-03-15 00:07:151317 [](const StatOrErrmsg &) {}},
peter klausler79d044e2018-03-01 00:56:101318 x.u);
1319 return true;
1320 }
1321 bool Pre(const EventWaitStmt &x) { // R1170
peter klauslerb7cf5122018-03-14 22:31:161322 Word("EVENT WAIT ("), Walk(std::get<EventVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101323 Walk(", ", std::get<std::list<EventWaitStmt::EventWaitSpec>>(x.t), ", ");
1324 Put(')');
1325 return false;
1326 }
1327 bool Pre(const FormTeamStmt &x) { // R1175
peter klauslerb7cf5122018-03-14 22:31:161328 Word("FORM TEAM ("), Walk(std::get<ScalarIntExpr>(x.t));
peter klausler79d044e2018-03-01 00:56:101329 Put(','), Walk(std::get<TeamVariable>(x.t));
1330 Walk(", ", std::get<std::list<FormTeamStmt::FormTeamSpec>>(x.t), ", ");
1331 Put(')');
1332 return false;
1333 }
1334 bool Pre(const FormTeamStmt::FormTeamSpec &x) { // R1176, R1177
peter klausler62d9cdd2018-03-15 00:02:211335 std::visit(visitors{[&](const ScalarIntExpr &x) { Word("NEW_INDEX="); },
peter klauslered5a6c92018-03-15 00:07:151336 [](const StatOrErrmsg &) {}},
peter klausler79d044e2018-03-01 00:56:101337 x.u);
1338 return true;
1339 }
1340 bool Pre(const LockStmt &x) { // R1178
peter klauslerb7cf5122018-03-14 22:31:161341 Word("LOCK ("), Walk(std::get<LockVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101342 Walk(", ", std::get<std::list<LockStmt::LockStat>>(x.t), ", ");
1343 Put(')');
1344 return false;
1345 }
1346 bool Pre(const LockStmt::LockStat &x) { // R1179
peter klausler62d9cdd2018-03-15 00:02:211347 std::visit(
1348 visitors{[&](const ScalarLogicalVariable &) { Word("ACQUIRED_LOCK="); },
peter klauslered5a6c92018-03-15 00:07:151349 [](const StatOrErrmsg &y) {}},
peter klausler79d044e2018-03-01 00:56:101350 x.u);
1351 return true;
1352 }
1353 bool Pre(const UnlockStmt &x) { // R1180
peter klauslerb7cf5122018-03-14 22:31:161354 Word("UNLOCK ("), Walk(std::get<LockVariable>(x.t));
peter klausler79d044e2018-03-01 00:56:101355 Walk(", ", std::get<std::list<StatOrErrmsg>>(x.t), ", ");
1356 Put(')');
1357 return false;
1358 }
1359
1360 bool Pre(const OpenStmt &x) { // R1204
peter klauslerb7cf5122018-03-14 22:31:161361 Word("OPEN ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101362 return false;
1363 }
1364 bool Pre(const ConnectSpec &x) { // R1205
1365 return std::visit(visitors{[&](const FileUnitNumber &) {
peter klauslerb7cf5122018-03-14 22:31:161366 Word("UNIT=");
peter klausler79d044e2018-03-01 00:56:101367 return true;
1368 },
1369 [&](const FileNameExpr &) {
peter klauslerb7cf5122018-03-14 22:31:161370 Word("FILE=");
peter klausler79d044e2018-03-01 00:56:101371 return true;
1372 },
1373 [&](const ConnectSpec::CharExpr &y) {
1374 Walk(y.t, "=");
1375 return false;
1376 },
1377 [&](const MsgVariable &) {
peter klauslerb7cf5122018-03-14 22:31:161378 Word("IOMSG=");
peter klausler79d044e2018-03-01 00:56:101379 return true;
1380 },
1381 [&](const StatVariable &) {
peter klauslerb7cf5122018-03-14 22:31:161382 Word("IOSTAT=");
peter klausler79d044e2018-03-01 00:56:101383 return true;
1384 },
1385 [&](const ConnectSpec::Recl &) {
peter klauslerb7cf5122018-03-14 22:31:161386 Word("RECL=");
peter klausler79d044e2018-03-01 00:56:101387 return true;
1388 },
1389 [&](const ConnectSpec::Newunit &) {
peter klauslerb7cf5122018-03-14 22:31:161390 Word("NEWUNIT=");
peter klausler79d044e2018-03-01 00:56:101391 return true;
1392 },
1393 [&](const ErrLabel &) {
peter klauslerb7cf5122018-03-14 22:31:161394 Word("ERR=");
peter klausler79d044e2018-03-01 00:56:101395 return true;
1396 },
1397 [&](const StatusExpr &) {
peter klauslerb7cf5122018-03-14 22:31:161398 Word("STATUS=");
peter klausler79d044e2018-03-01 00:56:101399 return true;
1400 }},
1401 x.u);
1402 }
1403 bool Pre(const CloseStmt &x) { // R1208
peter klauslerb7cf5122018-03-14 22:31:161404 Word("CLOSE ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101405 return false;
1406 }
1407 bool Pre(const CloseStmt::CloseSpec &x) { // R1209
peter klauslerb7cf5122018-03-14 22:31:161408 std::visit(visitors{[&](const FileUnitNumber &) { Word("UNIT="); },
1409 [&](const StatVariable &) { Word("IOSTAT="); },
1410 [&](const MsgVariable &) { Word("IOMSG="); },
1411 [&](const ErrLabel &) { Word("ERR="); },
1412 [&](const StatusExpr &) { Word("STATUS="); }},
peter klausler79d044e2018-03-01 00:56:101413 x.u);
1414 return true;
1415 }
1416 bool Pre(const ReadStmt &x) { // R1210
peter klauslerb7cf5122018-03-14 22:31:161417 Word("READ ");
peter klausler79d044e2018-03-01 00:56:101418 if (x.iounit) {
1419 Put('('), Walk(x.iounit);
1420 if (x.format) {
1421 Put(", "), Walk(x.format);
1422 }
peter klauslerdcd09422018-03-15 23:03:281423 Walk(", ", x.controls, ", ");
peter klausler79d044e2018-03-01 00:56:101424 Put(')');
1425 } else if (x.format) {
1426 Walk(x.format);
1427 if (!x.items.empty()) {
1428 Put(", ");
1429 }
1430 } else {
peter klauslerdcd09422018-03-15 23:03:281431 Put('('), Walk(x.controls, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101432 }
1433 Walk(" ", x.items, ", ");
1434 return false;
1435 }
1436 bool Pre(const WriteStmt &x) { // R1211
peter klauslerb7cf5122018-03-14 22:31:161437 Word("WRITE (");
peter klausler79d044e2018-03-01 00:56:101438 if (x.iounit) {
1439 Walk(x.iounit);
1440 if (x.format) {
1441 Put(", "), Walk(x.format);
1442 }
peter klauslerdcd09422018-03-15 23:03:281443 Walk(", ", x.controls, ", ");
peter klausler79d044e2018-03-01 00:56:101444 } else {
peter klauslerdcd09422018-03-15 23:03:281445 Walk(x.controls, ", ");
peter klausler79d044e2018-03-01 00:56:101446 }
1447 Put(')'), Walk(" ", x.items, ", ");
1448 return false;
1449 }
1450 bool Pre(const PrintStmt &x) { // R1212
peter klauslerb7cf5122018-03-14 22:31:161451 Word("PRINT "), Walk(std::get<Format>(x.t));
peter klausler79d044e2018-03-01 00:56:101452 Walk(", ", std::get<std::list<OutputItem>>(x.t), ", ");
1453 return false;
1454 }
1455 bool Pre(const IoControlSpec &x) { // R1213
1456 return std::visit(visitors{[&](const IoUnit &) {
peter klauslerb7cf5122018-03-14 22:31:161457 Word("UNIT=");
peter klausler79d044e2018-03-01 00:56:101458 return true;
1459 },
1460 [&](const Format &) {
peter klauslerb7cf5122018-03-14 22:31:161461 Word("FMT=");
peter klausler79d044e2018-03-01 00:56:101462 return true;
1463 },
1464 [&](const Name &) {
peter klauslerb7cf5122018-03-14 22:31:161465 Word("NML=");
peter klausler79d044e2018-03-01 00:56:101466 return true;
1467 },
1468 [&](const IoControlSpec::CharExpr &y) {
1469 Walk(y.t, "=");
1470 return false;
1471 },
1472 [&](const IoControlSpec::Asynchronous &) {
peter klauslerb7cf5122018-03-14 22:31:161473 Word("ASYNCHRONOUS=");
peter klausler79d044e2018-03-01 00:56:101474 return true;
1475 },
1476 [&](const EndLabel &) {
peter klauslerb7cf5122018-03-14 22:31:161477 Word("END=");
peter klausler79d044e2018-03-01 00:56:101478 return true;
1479 },
1480 [&](const EorLabel &) {
peter klauslerb7cf5122018-03-14 22:31:161481 Word("EOR=");
peter klausler79d044e2018-03-01 00:56:101482 return true;
1483 },
1484 [&](const ErrLabel &) {
peter klauslerb7cf5122018-03-14 22:31:161485 Word("ERR=");
peter klausler79d044e2018-03-01 00:56:101486 return true;
1487 },
1488 [&](const IdVariable &) {
peter klauslerb7cf5122018-03-14 22:31:161489 Word("ID=");
peter klausler79d044e2018-03-01 00:56:101490 return true;
1491 },
1492 [&](const MsgVariable &) {
peter klauslerb7cf5122018-03-14 22:31:161493 Word("IOMSG=");
peter klausler79d044e2018-03-01 00:56:101494 return true;
1495 },
1496 [&](const StatVariable &) {
peter klauslerb7cf5122018-03-14 22:31:161497 Word("IOSTAT=");
peter klausler79d044e2018-03-01 00:56:101498 return true;
1499 },
1500 [&](const IoControlSpec::Pos &) {
peter klauslerb7cf5122018-03-14 22:31:161501 Word("POS=");
peter klausler79d044e2018-03-01 00:56:101502 return true;
1503 },
1504 [&](const IoControlSpec::Rec &) {
peter klauslerb7cf5122018-03-14 22:31:161505 Word("REC=");
peter klausler79d044e2018-03-01 00:56:101506 return true;
1507 },
1508 [&](const IoControlSpec::Size &) {
peter klauslerb7cf5122018-03-14 22:31:161509 Word("SIZE=");
peter klausler79d044e2018-03-01 00:56:101510 return true;
1511 }},
1512 x.u);
1513 }
1514 bool Pre(const InputImpliedDo &x) { // R1218
1515 Put('('), Walk(std::get<std::list<InputItem>>(x.t), ", "), Put(", ");
1516 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1517 return false;
1518 }
1519 bool Pre(const OutputImpliedDo &x) { // R1219
1520 Put('('), Walk(std::get<std::list<OutputItem>>(x.t), ", "), Put(", ");
1521 Walk(std::get<IoImpliedDoControl>(x.t)), Put(')');
1522 return false;
1523 }
1524 bool Pre(const WaitStmt &x) { // R1222
peter klauslerb7cf5122018-03-14 22:31:161525 Word("WAIT ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101526 return false;
1527 }
1528 bool Pre(const WaitSpec &x) { // R1223
peter klauslerb7cf5122018-03-14 22:31:161529 std::visit(visitors{[&](const FileUnitNumber &) { Word("UNIT="); },
1530 [&](const EndLabel &) { Word("END="); },
1531 [&](const EorLabel &) { Word("EOR="); },
1532 [&](const ErrLabel &) { Word("ERR="); },
1533 [&](const IdExpr &) { Word("ID="); },
1534 [&](const MsgVariable &) { Word("IOMSG="); },
1535 [&](const StatVariable &) { Word("IOSTAT="); }},
peter klausler79d044e2018-03-01 00:56:101536 x.u);
1537 return true;
1538 }
1539 bool Pre(const BackspaceStmt &x) { // R1224
peter klauslerb7cf5122018-03-14 22:31:161540 Word("BACKSPACE ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101541 return false;
1542 }
1543 bool Pre(const EndfileStmt &x) { // R1225
peter klauslerb7cf5122018-03-14 22:31:161544 Word("ENDFILE ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101545 return false;
1546 }
1547 bool Pre(const RewindStmt &x) { // R1226
peter klauslerb7cf5122018-03-14 22:31:161548 Word("REWIND ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101549 return false;
1550 }
peter klauslerad4adc22018-03-16 00:09:271551 bool Pre(const PositionOrFlushSpec &x) { // R1227 & R1229
1552 std::visit(visitors{[&](const FileUnitNumber &) { Word("UNIT="); },
1553 [&](const MsgVariable &) { Word("IOMSG="); },
1554 [&](const StatVariable &) { Word("IOSTAT="); },
1555 [&](const ErrLabel &) { Word("ERR="); }},
1556 x.u);
1557 return true;
1558 }
peter klausler79d044e2018-03-01 00:56:101559 bool Pre(const FlushStmt &x) { // R1228
peter klauslerb7cf5122018-03-14 22:31:161560 Word("FLUSH ("), Walk(x.v, ", "), Put(')');
peter klausler79d044e2018-03-01 00:56:101561 return false;
1562 }
1563 bool Pre(const InquireStmt &x) { // R1230
peter klauslerb7cf5122018-03-14 22:31:161564 Word("INQUIRE (");
peter klausler79d044e2018-03-01 00:56:101565 std::visit(
1566 visitors{[&](const InquireStmt::Iolength &y) {
peter klauslerb7cf5122018-03-14 22:31:161567 Word("IOLENGTH="), Walk(y.t, ") ");
peter klausler79d044e2018-03-01 00:56:101568 },
1569 [&](const std::list<InquireSpec> &y) { Walk(y, ", "), Put(')'); }},
1570 x.u);
1571 return false;
1572 }
1573 bool Pre(const InquireSpec &x) { // R1231
1574 return std::visit(visitors{[&](const FileUnitNumber &) {
peter klauslerb7cf5122018-03-14 22:31:161575 Word("UNIT=");
peter klausler79d044e2018-03-01 00:56:101576 return true;
1577 },
1578 [&](const FileNameExpr &) {
peter klauslerb7cf5122018-03-14 22:31:161579 Word("FILE=");
peter klausler79d044e2018-03-01 00:56:101580 return true;
1581 },
1582 [&](const InquireSpec::CharVar &y) {
1583 Walk(y.t, "=");
1584 return false;
1585 },
1586 [&](const InquireSpec::IntVar &y) {
1587 Walk(y.t, "=");
1588 return false;
1589 },
1590 [&](const InquireSpec::LogVar &y) {
1591 Walk(y.t, "=");
1592 return false;
1593 },
1594 [&](const IdExpr &) {
peter klauslerb7cf5122018-03-14 22:31:161595 Word("ID=");
peter klausler79d044e2018-03-01 00:56:101596 return true;
1597 },
1598 [&](const ErrLabel &) {
peter klauslerb7cf5122018-03-14 22:31:161599 Word("ERR=");
peter klausler79d044e2018-03-01 00:56:101600 return true;
1601 }},
1602 x.u);
1603 }
1604
1605 bool Pre(const FormatStmt &) { // R1301
peter klauslerb7cf5122018-03-14 22:31:161606 Word("FORMAT");
peter klausler79d044e2018-03-01 00:56:101607 return true;
1608 }
1609 bool Pre(const format::FormatSpecification &x) { // R1302, R1303, R1305
1610 Put('('), Walk("", x.items, ",", x.unlimitedItems.empty() ? "" : ",");
1611 Walk("*(", x.unlimitedItems, ",", ")"), Put(')');
1612 return false;
1613 }
1614 bool Pre(const format::FormatItem &x) { // R1304, R1306, R1321
1615 if (x.repeatCount.has_value()) {
1616 Walk(*x.repeatCount);
1617 }
1618 std::visit(visitors{[&](const std::string &y) { PutQuoted(y); },
1619 [&](const std::list<format::FormatItem> &y) {
1620 Walk("(", y, ",", ")");
1621 },
1622 [&](const auto &y) { Walk(y); }},
1623 x.u);
1624 return false;
1625 }
1626 bool Pre(const format::IntrinsicTypeDataEditDesc &x) { // R1307(1/2) - R1311
1627 switch (x.kind) {
1628#define FMT(x) \
1629 case format::IntrinsicTypeDataEditDesc::Kind::x: Put(#x); break
1630 FMT(I);
1631 FMT(B);
1632 FMT(O);
1633 FMT(Z);
1634 FMT(F);
1635 FMT(E);
1636 FMT(EN);
1637 FMT(ES);
1638 FMT(EX);
1639 FMT(G);
1640 FMT(L);
1641 FMT(A);
1642 FMT(D);
1643#undef FMT
1644 default: CRASH_NO_CASE;
1645 }
1646 Walk(x.width), Walk(".", x.digits), Walk("E", x.exponentWidth);
1647 return false;
1648 }
1649 bool Pre(const format::DerivedTypeDataEditDesc &x) { // R1307(2/2), R1312
peter klauslerb7cf5122018-03-14 22:31:161650 Word("DT");
peter klausler79d044e2018-03-01 00:56:101651 if (!x.type.empty()) {
1652 Put('"'), Put(x.type), Put('"');
1653 }
1654 Walk("(", x.parameters, ",", ")");
1655 return false;
1656 }
1657 bool Pre(const format::ControlEditDesc &x) { // R1313, R1315-R1320
1658 switch (x.kind) {
1659 case format::ControlEditDesc::Kind::T:
peter klauslerb7cf5122018-03-14 22:31:161660 Word("T");
peter klausler79d044e2018-03-01 00:56:101661 Walk(x.count);
1662 break;
1663 case format::ControlEditDesc::Kind::TL:
peter klauslerb7cf5122018-03-14 22:31:161664 Word("TL");
peter klausler79d044e2018-03-01 00:56:101665 Walk(x.count);
1666 break;
1667 case format::ControlEditDesc::Kind::TR:
peter klauslerb7cf5122018-03-14 22:31:161668 Word("TR");
peter klausler79d044e2018-03-01 00:56:101669 Walk(x.count);
1670 break;
1671 case format::ControlEditDesc::Kind::X:
1672 if (x.count != 1) {
1673 Walk(x.count);
1674 }
peter klauslerb7cf5122018-03-14 22:31:161675 Word("X");
peter klausler79d044e2018-03-01 00:56:101676 break;
1677 case format::ControlEditDesc::Kind::Slash:
1678 if (x.count != 1) {
1679 Walk(x.count);
1680 }
1681 Put('/');
1682 break;
1683 case format::ControlEditDesc::Kind::Colon: Put(':'); break;
1684 case format::ControlEditDesc::Kind::P:
1685 Walk(x.count);
peter klauslerb7cf5122018-03-14 22:31:161686 Word("P");
peter klausler79d044e2018-03-01 00:56:101687 break;
1688#define FMT(x) \
1689 case format::ControlEditDesc::Kind::x: Put(#x); break
1690 FMT(SS);
1691 FMT(SP);
1692 FMT(S);
1693 FMT(BN);
1694 FMT(BZ);
1695 FMT(RU);
1696 FMT(RD);
1697 FMT(RZ);
1698 FMT(RN);
1699 FMT(RC);
1700 FMT(RP);
1701 FMT(DC);
1702 FMT(DP);
1703#undef FMT
1704 default: CRASH_NO_CASE;
1705 }
1706 return false;
1707 }
1708
1709 bool Pre(const MainProgram &x) { // R1401
1710 if (!std::get<std::optional<Statement<ProgramStmt>>>(x.t)) {
1711 Indent();
1712 }
1713 return true;
1714 }
1715 bool Pre(const ProgramStmt &x) { // R1402
peter klauslerb7cf5122018-03-14 22:31:161716 Word("PROGRAM "), Indent();
peter klausler79d044e2018-03-01 00:56:101717 return true;
1718 }
1719 bool Pre(const EndProgramStmt &x) { // R1403
peter klausler41d9cfd2018-04-03 17:29:041720 EndSubprogram("PROGRAM", x.v);
peter klausler47dbbda2018-03-13 23:47:481721 return false;
peter klausler79d044e2018-03-01 00:56:101722 }
1723 bool Pre(const ModuleStmt &) { // R1405
peter klauslerb7cf5122018-03-14 22:31:161724 Word("MODULE "), Indent();
peter klausler79d044e2018-03-01 00:56:101725 return true;
1726 }
peter klausler47dbbda2018-03-13 23:47:481727 bool Pre(const EndModuleStmt &x) { // R1406
peter klausler41d9cfd2018-04-03 17:29:041728 EndSubprogram("MODULE", x.v);
peter klausler47dbbda2018-03-13 23:47:481729 return false;
peter klausler79d044e2018-03-01 00:56:101730 }
1731 bool Pre(const UseStmt &x) { // R1409
peter klauslerb7cf5122018-03-14 22:31:161732 Word("USE"), Walk(", ", x.nature), Put(" :: "), Walk(x.moduleName);
peter klausler79d044e2018-03-01 00:56:101733 std::visit(
1734 visitors{[&](const std::list<Rename> &y) { Walk(", ", y, ", "); },
1735 [&](const std::list<Only> &y) { Walk(", ONLY: ", y, ", "); }},
1736 x.u);
1737 return false;
1738 }
1739 bool Pre(const Rename &x) { // R1411
1740 std::visit(visitors{[&](const Rename::Names &y) { Walk(y.t, " => "); },
1741 [&](const Rename::Operators &y) {
peter klauslerd71f3cf2018-03-14 23:31:411742 Word("OPERATOR(."), Walk(y.t, ".) => OPERATOR(."),
1743 Put(".)");
peter klausler79d044e2018-03-01 00:56:101744 }},
1745 x.u);
1746 return false;
1747 }
1748 bool Pre(const SubmoduleStmt &x) { // R1417
peter klauslerb7cf5122018-03-14 22:31:161749 Word("SUBMODULE "), Indent();
peter klausler79d044e2018-03-01 00:56:101750 return true;
1751 }
1752 bool Pre(const ParentIdentifier &x) { // R1418
1753 Walk(std::get<Name>(x.t)), Walk(":", std::get<std::optional<Name>>(x.t));
1754 return false;
1755 }
peter klausler47dbbda2018-03-13 23:47:481756 bool Pre(const EndSubmoduleStmt &x) { // R1419
peter klausler41d9cfd2018-04-03 17:29:041757 EndSubprogram("SUBMODULE", x.v);
peter klausler47dbbda2018-03-13 23:47:481758 return false;
peter klausler79d044e2018-03-01 00:56:101759 }
1760 bool Pre(const BlockDataStmt &x) { // R1421
peter klauslerb7cf5122018-03-14 22:31:161761 Word("BLOCK DATA"), Walk(" ", x.v), Indent();
peter klausler79d044e2018-03-01 00:56:101762 return false;
1763 }
1764 bool Pre(const EndBlockDataStmt &x) { // R1422
peter klausler41d9cfd2018-04-03 17:29:041765 EndSubprogram("BLOCK DATA", x.v);
peter klausler79d044e2018-03-01 00:56:101766 return false;
1767 }
1768
1769 bool Pre(const InterfaceStmt &x) { // R1503
1770 std::visit(visitors{[&](const std::optional<GenericSpec> &y) {
peter klauslerb7cf5122018-03-14 22:31:161771 Word("INTERFACE"), Walk(" ", y);
peter klausler79d044e2018-03-01 00:56:101772 },
peter klauslerb7cf5122018-03-14 22:31:161773 [&](const Abstract &) { Word("ABSTRACT INTERFACE"); }},
peter klausler79d044e2018-03-01 00:56:101774 x.u);
1775 Indent();
1776 return false;
1777 }
1778 bool Pre(const EndInterfaceStmt &x) { // R1504
peter klauslerb7cf5122018-03-14 22:31:161779 Outdent(), Word("END INTERFACE"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101780 return false;
1781 }
1782 bool Pre(const ProcedureStmt &x) { // R1506
1783 if (std::get<ProcedureStmt::Kind>(x.t) ==
1784 ProcedureStmt::Kind::ModuleProcedure) {
peter klauslerb7cf5122018-03-14 22:31:161785 Word("MODULE ");
peter klausler79d044e2018-03-01 00:56:101786 }
peter klauslerb7cf5122018-03-14 22:31:161787 Word("PROCEDURE :: ");
peter klausler79d044e2018-03-01 00:56:101788 Walk(std::get<std::list<Name>>(x.t), ", ");
1789 return false;
1790 }
1791 bool Pre(const GenericSpec &x) { // R1508, R1509
peter klauslerd71f3cf2018-03-14 23:31:411792 std::visit(
1793 visitors{[&](const DefinedOperator &x) { Word("OPERATOR("); },
1794 [&](const GenericSpec::Assignment &) { Word("ASSIGNMENT(=)"); },
1795 [&](const GenericSpec::ReadFormatted &) {
1796 Word("READ(FORMATTED)");
1797 },
1798 [&](const GenericSpec::ReadUnformatted &) {
1799 Word("READ(UNFORMATTED)");
1800 },
1801 [&](const GenericSpec::WriteFormatted &) {
1802 Word("WRITE(FORMATTED)");
1803 },
1804 [&](const GenericSpec::WriteUnformatted &) {
1805 Word("WRITE(UNFORMATTED)");
1806 },
1807 [](const auto &) {}},
peter klausler79d044e2018-03-01 00:56:101808 x.u);
1809 return true;
1810 }
peter klauslerd71f3cf2018-03-14 23:31:411811 void Post(const GenericSpec &x) {
1812 std::visit(visitors{[&](const DefinedOperator &x) { Put(')'); },
1813 [](const auto &) {}},
1814 x.u);
1815 }
peter klausler79d044e2018-03-01 00:56:101816 bool Pre(const GenericStmt &x) { // R1510
peter klauslerb7cf5122018-03-14 22:31:161817 Word("GENERIC"), Walk(", ", std::get<std::optional<AccessSpec>>(x.t));
peter klausler79d044e2018-03-01 00:56:101818 Put(" :: "), Walk(std::get<GenericSpec>(x.t)), Put(" => ");
1819 Walk(std::get<std::list<Name>>(x.t), ", ");
1820 return false;
1821 }
1822 bool Pre(const ExternalStmt &x) { // R1511
peter klauslerb7cf5122018-03-14 22:31:161823 Word("EXTERNAL :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:101824 return false;
1825 }
1826 bool Pre(const ProcedureDeclarationStmt &x) { // R1512
peter klauslerb7cf5122018-03-14 22:31:161827 Word("PROCEDURE ("), Walk(std::get<std::optional<ProcInterface>>(x.t));
peter klausler79d044e2018-03-01 00:56:101828 Put(')'), Walk(", ", std::get<std::list<ProcAttrSpec>>(x.t), ", ");
1829 Put(" :: "), Walk(std::get<std::list<ProcDecl>>(x.t), ", ");
1830 return false;
1831 }
1832 bool Pre(const ProcDecl &x) { // R1515
1833 Walk(std::get<Name>(x.t));
1834 Walk(" => ", std::get<std::optional<ProcPointerInit>>(x.t));
1835 return false;
1836 }
1837 bool Pre(const IntrinsicStmt &x) { // R1519
peter klauslerb7cf5122018-03-14 22:31:161838 Word("INTRINSIC :: "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:101839 return false;
1840 }
1841 bool Pre(const FunctionReference &x) { // R1520
1842 Walk(std::get<ProcedureDesignator>(x.v.t));
1843 Put('('), Walk(std::get<std::list<ActualArgSpec>>(x.v.t), ", "), Put(')');
1844 return false;
1845 }
1846 bool Pre(const CallStmt &x) { // R1521
peter klauslerad4adc22018-03-16 00:09:271847 const auto &pd = std::get<ProcedureDesignator>(x.v.t);
1848 const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
1849 Word("CALL "), Walk(pd);
1850 if (args.empty()) {
1851 if (std::holds_alternative<ProcComponentRef>(pd.u)) {
1852 Put("()"); // pgf90 crashes on CALL to tbp without parentheses
1853 }
1854 } else {
1855 Walk("(", args, ", ", ")");
1856 }
peter klausler79d044e2018-03-01 00:56:101857 return false;
1858 }
1859 bool Pre(const ActualArgSpec &x) { // R1523
1860 Walk(std::get<std::optional<Keyword>>(x.t), "=");
1861 Walk(std::get<ActualArg>(x.t));
1862 return false;
1863 }
1864 bool Pre(const ActualArg::PercentRef &x) { // R1524
peter klauslerb7cf5122018-03-14 22:31:161865 Word("%REF("), Walk(x.v), Put(')');
peter klausler79d044e2018-03-01 00:56:101866 return false;
1867 }
1868 bool Pre(const ActualArg::PercentVal &x) {
peter klauslerb7cf5122018-03-14 22:31:161869 Word("%VAL("), Walk(x.v), Put(')');
peter klausler79d044e2018-03-01 00:56:101870 return false;
1871 }
1872 bool Pre(const AltReturnSpec &) { // R1525
peter klauslerb7cf5122018-03-14 22:31:161873 Put('*');
peter klausler79d044e2018-03-01 00:56:101874 return true;
1875 }
peter klauslerd71f3cf2018-03-14 23:31:411876 void Post(const PrefixSpec::Elemental) { Word("ELEMENTAL"); } // R1527
1877 void Post(const PrefixSpec::Impure) { Word("IMPURE"); }
1878 void Post(const PrefixSpec::Module) { Word("MODULE"); }
1879 void Post(const PrefixSpec::Non_Recursive) { Word("NON_RECURSIVE"); }
1880 void Post(const PrefixSpec::Pure) { Word("PURE"); }
1881 void Post(const PrefixSpec::Recursive) { Word("RECURSIVE"); }
peter klausler79d044e2018-03-01 00:56:101882 bool Pre(const FunctionStmt &x) { // R1530
1883 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
peter klausler62d9cdd2018-03-15 00:02:211884 Word("FUNCTION "), Walk(std::get<Name>(x.t)), Put("(");
peter klausler79d044e2018-03-01 00:56:101885 Walk(std::get<std::list<Name>>(x.t), ", "), Put(')');
1886 Walk(" ", std::get<std::optional<Suffix>>(x.t)), Indent();
1887 return false;
1888 }
1889 bool Pre(const Suffix &x) { // R1532
1890 if (x.resultName) {
peter klauslerb7cf5122018-03-14 22:31:161891 Word("RESULT("), Walk(x.resultName), Put(')');
peter klausler79d044e2018-03-01 00:56:101892 Walk(" ", x.binding);
1893 } else {
1894 Walk(x.binding);
1895 }
1896 return false;
1897 }
1898 bool Pre(const EndFunctionStmt &x) { // R1533
peter klausler41d9cfd2018-04-03 17:29:041899 EndSubprogram("FUNCTION", x.v);
peter klausler79d044e2018-03-01 00:56:101900 return false;
1901 }
1902 bool Pre(const SubroutineStmt &x) { // R1535
1903 Walk("", std::get<std::list<PrefixSpec>>(x.t), " ", " ");
peter klauslerb7cf5122018-03-14 22:31:161904 Word("SUBROUTINE "), Walk(std::get<Name>(x.t));
peter klauslerd71f3cf2018-03-14 23:31:411905 const auto &args = std::get<std::list<DummyArg>>(x.t);
1906 const auto &bind = std::get<std::optional<LanguageBindingSpec>>(x.t);
1907 if (args.empty()) {
1908 Walk(" () ", bind);
1909 } else {
1910 Walk(" (", args, ", ", ")");
1911 Walk(" ", bind);
1912 }
peter klausler79d044e2018-03-01 00:56:101913 Indent();
1914 return false;
1915 }
1916 bool Pre(const EndSubroutineStmt &x) { // R1537
peter klausler41d9cfd2018-04-03 17:29:041917 EndSubprogram("SUBROUTINE", x.v);
peter klausler79d044e2018-03-01 00:56:101918 return false;
1919 }
1920 bool Pre(const MpSubprogramStmt &) { // R1539
peter klauslerb7cf5122018-03-14 22:31:161921 Word("MODULE PROCEDURE "), Indent();
peter klausler79d044e2018-03-01 00:56:101922 return true;
1923 }
1924 bool Pre(const EndMpSubprogramStmt &x) { // R1540
peter klausler41d9cfd2018-04-03 17:29:041925 EndSubprogram("PROCEDURE", x.v);
peter klausler79d044e2018-03-01 00:56:101926 return false;
1927 }
1928 bool Pre(const EntryStmt &x) { // R1541
peter klauslerb7cf5122018-03-14 22:31:161929 Word("ENTRY "), Walk(std::get<Name>(x.t));
peter klausler62d9cdd2018-03-15 00:02:211930 Walk("(", std::get<std::list<DummyArg>>(x.t), ", ", ")");
peter klausler79d044e2018-03-01 00:56:101931 Walk(" ", std::get<std::optional<Suffix>>(x.t));
1932 return false;
1933 }
1934 bool Pre(const ReturnStmt &x) { // R1542
peter klauslerb7cf5122018-03-14 22:31:161935 Word("RETURN"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:101936 return false;
1937 }
1938 bool Pre(const ContainsStmt &x) { // R1543
1939 Outdent();
peter klauslerb7cf5122018-03-14 22:31:161940 Word("CONTAINS");
peter klausler79d044e2018-03-01 00:56:101941 Indent();
1942 return false;
1943 }
1944 bool Pre(const StmtFunctionStmt &x) { // R1544
1945 Walk(std::get<Name>(x.t)), Put('(');
1946 Walk(std::get<std::list<Name>>(x.t), ", "), Put(") = ");
1947 Walk(std::get<Scalar<Expr>>(x.t));
1948 return false;
1949 }
1950
peter klausler75b29332018-03-23 22:14:521951 // Directives, extensions, and deprecated constructs
1952 bool Pre(const CompilerDirective &x) {
1953 std::visit(
1954 visitors{[&](const std::list<CompilerDirective::IgnoreTKR> &tkr) {
1955 Word("!DIR$ IGNORE_TKR");
1956 Walk(" ", tkr, ", ");
1957 },
1958 [&](const CompilerDirective::IVDEP &) { Word("!DIR$ IVDEP\n"); }},
1959 x.u);
1960 Put('\n');
1961 return false;
1962 }
1963 bool Pre(const CompilerDirective::IgnoreTKR &x) {
1964 const auto &list = std::get<std::list<const char *>>(x.t);
1965 if (!list.empty()) {
1966 Put("(");
1967 for (const char *tkr : list) {
1968 Put(*tkr);
1969 }
1970 Put(") ");
1971 }
1972 Walk(std::get<Name>(x.t));
1973 return false;
1974 }
peter klausler79d044e2018-03-01 00:56:101975 bool Pre(const BasedPointerStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:161976 Word("POINTER ("), Walk(std::get<0>(x.t)), Put(", ");
1977 Walk(std::get<1>(x.t));
peter klausler79d044e2018-03-01 00:56:101978 Walk("(", std::get<std::optional<ArraySpec>>(x.t), ")"), Put(')');
1979 return false;
1980 }
peter klausler4e354d82018-03-30 22:23:371981 void Post(const StructureField &x) {
1982 if (const auto *def = std::get_if<Statement<DataComponentDefStmt>>(&x.u)) {
1983 for (const auto &decl :
1984 std::get<std::list<ComponentDecl>>(def->statement.t)) {
1985 structureComponents_.insert(std::get<Name>(decl.t).source);
1986 }
1987 }
1988 }
peter klausler79d044e2018-03-01 00:56:101989 bool Pre(const StructureStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:161990 Word("STRUCTURE ");
peter klausler79d044e2018-03-01 00:56:101991 if (std::get<bool>(x.t)) { // slashes around name
1992 Put('/'), Walk(std::get<Name>(x.t)), Put('/');
1993 Walk(" ", std::get<std::list<EntityDecl>>(x.t), ", ");
1994 } else {
1995 CHECK(std::get<std::list<EntityDecl>>(x.t).empty());
1996 Walk(std::get<Name>(x.t));
1997 }
1998 Indent();
peter klausler79d044e2018-03-01 00:56:101999 return false;
2000 }
peter klauslerb7cf5122018-03-14 22:31:162001 void Post(const Union::UnionStmt &) { Word("UNION"), Indent(); }
2002 void Post(const Union::EndUnionStmt &) { Outdent(), Word("END UNION"); }
2003 void Post(const Map::MapStmt &) { Word("MAP"), Indent(); }
2004 void Post(const Map::EndMapStmt &) { Outdent(), Word("END MAP"); }
peter klausler79d044e2018-03-01 00:56:102005 void Post(const StructureDef::EndStructureStmt &) {
peter klauslerb7cf5122018-03-14 22:31:162006 Outdent(), Word("END STRUCTURE");
peter klausler79d044e2018-03-01 00:56:102007 }
2008 bool Pre(const OldParameterStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:162009 Word("PARAMETER "), Walk(x.v, ", ");
peter klausler79d044e2018-03-01 00:56:102010 return false;
2011 }
2012 bool Pre(const ArithmeticIfStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:162013 Word("IF ("), Walk(std::get<Expr>(x.t)), Put(") ");
peter klausler79d044e2018-03-01 00:56:102014 Walk(std::get<1>(x.t)), Put(", ");
2015 Walk(std::get<2>(x.t)), Put(", ");
2016 Walk(std::get<3>(x.t));
2017 return false;
2018 }
2019 bool Pre(const AssignStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:162020 Word("ASSIGN "), Walk(std::get<Label>(x.t));
2021 Word(" TO "), Walk(std::get<Name>(x.t));
peter klausler79d044e2018-03-01 00:56:102022 return false;
2023 }
2024 bool Pre(const AssignedGotoStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:162025 Word("GO TO "), Walk(std::get<Name>(x.t));
peter klausler79d044e2018-03-01 00:56:102026 Walk(", (", std::get<std::list<Label>>(x.t), ", ", ")");
2027 return false;
2028 }
2029 bool Pre(const PauseStmt &x) {
peter klauslerb7cf5122018-03-14 22:31:162030 Word("PAUSE"), Walk(" ", x.v);
peter klausler79d044e2018-03-01 00:56:102031 return false;
2032 }
2033
Tim Keith9f755662018-03-23 21:31:142034#define WALK_NESTED_ENUM(CLASS, ENUM) \
2035 bool Pre(const CLASS::ENUM &x) { \
2036 Word(CLASS::EnumToString(x)); \
peter klausler79d044e2018-03-01 00:56:102037 return false; \
2038 }
Tim Keith9f755662018-03-23 21:31:142039 WALK_NESTED_ENUM(AccessSpec, Kind) // R807
2040 WALK_NESTED_ENUM(TypeParamDefStmt, KindOrLen) // R734
2041 WALK_NESTED_ENUM(IntentSpec, Intent) // R826
2042 WALK_NESTED_ENUM(ImplicitStmt, ImplicitNoneNameSpec) // R866
2043 WALK_NESTED_ENUM(ConnectSpec::CharExpr, Kind) // R1205
2044 WALK_NESTED_ENUM(IoControlSpec::CharExpr, Kind)
2045 WALK_NESTED_ENUM(InquireSpec::CharVar, Kind)
2046 WALK_NESTED_ENUM(InquireSpec::IntVar, Kind)
2047 WALK_NESTED_ENUM(InquireSpec::LogVar, Kind)
2048 WALK_NESTED_ENUM(ProcedureStmt, Kind) // R1506
2049 WALK_NESTED_ENUM(UseStmt, ModuleNature) // R1410
peter klausler79d044e2018-03-01 00:56:102050#undef WALK_NESTED_ENUM
2051
2052 void Done() const { CHECK(indent_ == 0); }
2053
2054private:
2055 void Put(char);
2056 void Put(const char *);
2057 void Put(const std::string &);
peter klauslerb7cf5122018-03-14 22:31:162058 void PutKeywordLetter(char);
peter klausler79d044e2018-03-01 00:56:102059 void PutQuoted(const std::string &);
peter klauslerb7cf5122018-03-14 22:31:162060 void Word(const char *);
Tim Keith9f755662018-03-23 21:31:142061 void Word(const std::string &);
peter klausler79d044e2018-03-01 00:56:102062 void Indent() { indent_ += indentationAmount_; }
2063 void Outdent() {
2064 CHECK(indent_ >= indentationAmount_);
2065 indent_ -= indentationAmount_;
2066 }
2067
2068 // Call back to the traversal framework.
Tim Keith2af29bc2018-02-26 22:28:322069 template<typename T> void Walk(const T &x) {
2070 Fortran::parser::Walk(x, *this);
2071 }
2072
peter klausler79d044e2018-03-01 00:56:102073 // Traverse a std::optional<> value. Emit a prefix and/or a suffix string
2074 // only when it contains a value.
2075 template<typename A>
2076 void Walk(
2077 const char *prefix, const std::optional<A> &x, const char *suffix = "") {
2078 if (x.has_value()) {
peter klauslerb7cf5122018-03-14 22:31:162079 Word(prefix), Walk(*x), Word(suffix);
Tim Keith2af29bc2018-02-26 22:28:322080 }
2081 }
peter klausler79d044e2018-03-01 00:56:102082 template<typename A>
2083 void Walk(const std::optional<A> &x, const char *suffix = "") {
2084 return Walk("", x, suffix);
2085 }
2086
2087 // Traverse a std::list<>. Separate the elements with an optional string.
2088 // Emit a prefix and/or a suffix string only when the list is not empty.
2089 template<typename A>
2090 void Walk(const char *prefix, const std::list<A> &list,
2091 const char *comma = ", ", const char *suffix = "") {
2092 if (!list.empty()) {
2093 const char *str{prefix};
2094 for (const auto &x : list) {
peter klauslerb7cf5122018-03-14 22:31:162095 Word(str), Walk(x);
peter klausler79d044e2018-03-01 00:56:102096 str = comma;
2097 }
peter klauslerb7cf5122018-03-14 22:31:162098 Word(suffix);
peter klausler79d044e2018-03-01 00:56:102099 }
2100 }
2101 template<typename A>
2102 void Walk(const std::list<A> &list, const char *comma = ", ",
2103 const char *suffix = "") {
2104 return Walk("", list, comma, suffix);
2105 }
2106
2107 // Traverse a std::tuple<>, with an optional separator.
peter klausler424ec7b2018-03-20 17:59:072108 template<std::size_t J = 0, typename T>
peter klausler79d044e2018-03-01 00:56:102109 void WalkTupleElements(const T &tuple, const char *separator) {
2110 if constexpr (J < std::tuple_size_v<T>) {
2111 if (J > 0) {
peter klauslerb7cf5122018-03-14 22:31:162112 Word(separator);
peter klausler79d044e2018-03-01 00:56:102113 }
2114 Walk(std::get<J>(tuple));
2115 WalkTupleElements<J + 1>(tuple, separator);
2116 }
2117 }
2118 template<typename... A>
2119 void Walk(const std::tuple<A...> &tuple, const char *separator = "") {
2120 WalkTupleElements(tuple, separator);
2121 }
2122
peter klausler41d9cfd2018-04-03 17:29:042123 void EndSubprogram(const char *kind, const std::optional<Name> &name) {
2124 Outdent(), Word("END "), Word(kind), Walk(" ", name);
2125 structureComponents_.clear();
2126 }
peter klausler4e354d82018-03-30 22:23:372127
peter klausler79d044e2018-03-01 00:56:102128 std::ostream &out_;
2129 int indent_{0};
2130 const int indentationAmount_{1};
2131 int column_{1};
2132 const int maxColumns_{80};
peter klausler4e354d82018-03-30 22:23:372133 std::set<CharBlock> structureComponents_;
peter klausler79d044e2018-03-01 00:56:102134 Encoding encoding_{Encoding::UTF8};
peter klauslerb7cf5122018-03-14 22:31:162135 bool capitalizeKeywords_{true};
Tim Keith2af29bc2018-02-26 22:28:322136};
2137
peter klausler79d044e2018-03-01 00:56:102138void UnparseVisitor::Put(char ch) {
2139 if (column_ <= 1) {
2140 if (ch == '\n') {
2141 return;
2142 }
2143 for (int j{0}; j < indent_; ++j) {
2144 out_ << ' ';
2145 }
2146 column_ = indent_ + 2;
2147 } else if (ch == '\n') {
2148 column_ = 1;
2149 } else if (++column_ >= maxColumns_) {
2150 out_ << "&\n";
2151 for (int j{0}; j < indent_; ++j) {
2152 out_ << ' ';
2153 }
2154 out_ << '&';
2155 column_ = indent_ + 3;
2156 }
2157 out_ << ch;
Tim Keith2af29bc2018-02-26 22:28:322158}
2159
peter klausler79d044e2018-03-01 00:56:102160void UnparseVisitor::Put(const char *str) {
2161 for (; *str != '\0'; ++str) {
2162 Put(*str);
2163 }
2164}
2165
2166void UnparseVisitor::Put(const std::string &str) {
2167 for (char ch : str) {
2168 Put(ch);
2169 }
2170}
2171
peter klauslerb7cf5122018-03-14 22:31:162172void UnparseVisitor::PutKeywordLetter(char ch) {
2173 if (capitalizeKeywords_) {
peter klausler79d044e2018-03-01 00:56:102174 Put(ToUpperCaseLetter(ch));
peter klauslerb7cf5122018-03-14 22:31:162175 } else {
2176 Put(ToLowerCaseLetter(ch));
peter klausler79d044e2018-03-01 00:56:102177 }
2178}
2179
2180void UnparseVisitor::PutQuoted(const std::string &str) {
2181 Put('"');
2182 const auto emit = [&](char ch) { Put(ch); };
2183 for (char ch : str) {
2184 EmitQuotedChar(ch, emit, emit);
2185 }
2186 Put('"');
2187}
2188
peter klauslerb7cf5122018-03-14 22:31:162189void UnparseVisitor::Word(const char *str) {
2190 for (; *str != '\0'; ++str) {
2191 PutKeywordLetter(*str);
2192 }
2193}
2194
peter klausler75b29332018-03-23 22:14:522195void UnparseVisitor::Word(const std::string &str) { Word(str.c_str()); }
Tim Keith9f755662018-03-23 21:31:142196
peter klauslerb7cf5122018-03-14 22:31:162197void Unparse(std::ostream &out, const Program &program, Encoding encoding,
2198 bool capitalizeKeywords) {
2199 UnparseVisitor visitor{out, 1, encoding, capitalizeKeywords};
peter klausler79d044e2018-03-01 00:56:102200 Walk(program, visitor);
2201 visitor.Done();
2202}
Tim Keith2af29bc2018-02-26 22:28:322203} // namespace parser
2204} // namespace Fortran