FLANG
parse-tree-visitor.h
1//===-- include/flang/Parser/parse-tree-visitor.h ---------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_PARSER_PARSE_TREE_VISITOR_H_
10#define FORTRAN_PARSER_PARSE_TREE_VISITOR_H_
11
12#include "parse-tree.h"
13#include "tools.h"
14#include "flang/Common/enum-set.h"
15#include "flang/Common/visit.h"
16#include <cstddef>
17#include <optional>
18#include <tuple>
19#include <utility>
20#include <variant>
21#include <vector>
22
31
32namespace Fortran::parser {
33
34template <typename A, typename V> void Walk(const A &x, V &visitor);
35template <typename A, typename M> void Walk(A &x, M &mutator);
36
37namespace detail {
38// A number of the Walk functions below call other Walk functions. Define
39// a dummy class, and put all of them in it to ensure that name lookup for
40// Walk considers all overloads (not just those defined prior to the call
41// to Walk).
43 // Default case for visitation of non-class data members, strings, and
44 // any other non-decomposable values.
45 template <typename A, typename V>
46 static std::enable_if_t<!std::is_class_v<A> || common::IsEnumSet<A> ||
47 std::is_same_v<std::string, A> || std::is_same_v<CharBlock, A>>
48 Walk(const A &x, V &visitor) {
49 if (visitor.Pre(x)) {
50 visitor.Post(x);
51 }
52 }
53 template <typename A, typename M>
54 static std::enable_if_t<!std::is_class_v<A> ||
55 std::is_same_v<std::string, A> || std::is_same_v<CharBlock, A>>
56 Walk(A &x, M &mutator) {
57 if (mutator.Pre(x)) {
58 mutator.Post(x);
59 }
60 }
61
62 template <typename A, typename VM>
63 static void WalkSource(A &x, VM &visitorOrMutator) {
64 if constexpr (HasSource<A>::value) {
65 Walk(x.source, visitorOrMutator);
66 }
67 }
68
69 // Traversal of needed STL template classes (optional, list, tuple, variant)
70 // For most lists, just traverse the elements; but when a list constitutes
71 // a Block (i.e., std::list<ExecutionPartConstruct>), also invoke the
72 // visitor/mutator on the list itself.
73 template <typename T, typename V>
74 static void Walk(const std::list<T> &x, V &visitor) {
75 for (const auto &elem : x) {
76 Walk(elem, visitor);
77 }
78 }
79 template <typename T, typename M>
80 static void Walk(std::list<T> &x, M &mutator) {
81 for (auto &elem : x) {
82 Walk(elem, mutator);
83 }
84 }
85 template <typename V> static void Walk(const Block &x, V &visitor) {
86 if (visitor.Pre(x)) {
87 for (const auto &elem : x) {
88 Walk(elem, visitor);
89 }
90 visitor.Post(x);
91 }
92 }
93 template <typename M> static void Walk(Block &x, M &mutator) {
94 if (mutator.Pre(x)) {
95 for (auto &elem : x) {
96 Walk(elem, mutator);
97 }
98 mutator.Post(x);
99 }
100 }
101 template <typename T, typename V>
102 static void Walk(const std::optional<T> &x, V &visitor) {
103 if (x) {
104 Walk(*x, visitor);
105 }
106 }
107 template <typename T, typename M>
108 static void Walk(std::optional<T> &x, M &mutator) {
109 if (x) {
110 Walk(*x, mutator);
111 }
112 }
113 template <std::size_t I = 0, typename Func, typename T>
114 static void ForEachInTuple(const T &tuple, Func func) {
115 func(std::get<I>(tuple));
116 if constexpr (I + 1 < std::tuple_size_v<T>) {
117 ForEachInTuple<I + 1>(tuple, func);
118 }
119 }
120 template <typename V, typename... A>
121 static void Walk(const std::tuple<A...> &x, V &visitor) {
122 if (sizeof...(A) > 0) {
123 if (visitor.Pre(x)) {
124 ForEachInTuple(x, [&](const auto &y) { Walk(y, visitor); });
125 visitor.Post(x);
126 }
127 }
128 }
129 template <std::size_t I = 0, typename Func, typename T>
130 static void ForEachInTuple(T &tuple, Func func) {
131 func(std::get<I>(tuple));
132 if constexpr (I + 1 < std::tuple_size_v<T>) {
133 ForEachInTuple<I + 1>(tuple, func);
134 }
135 }
136 template <typename M, typename... A>
137 static void Walk(std::tuple<A...> &x, M &mutator) {
138 if (sizeof...(A) > 0) {
139 if (mutator.Pre(x)) {
140 ForEachInTuple(x, [&](auto &y) { Walk(y, mutator); });
141 mutator.Post(x);
142 }
143 }
144 }
145 template <typename V, typename... A>
146 static void Walk(const std::variant<A...> &x, V &visitor) {
147 if (visitor.Pre(x)) {
148 common::visit([&](const auto &y) { Walk(y, visitor); }, x);
149 visitor.Post(x);
150 }
151 }
152 template <typename M, typename... A>
153 static void Walk(std::variant<A...> &x, M &mutator) {
154 if (mutator.Pre(x)) {
155 common::visit([&](auto &y) { Walk(y, mutator); }, x);
156 mutator.Post(x);
157 }
158 }
159 template <typename A, typename B, typename V>
160 static void Walk(const std::pair<A, B> &x, V &visitor) {
161 if (visitor.Pre(x)) {
162 Walk(x.first, visitor);
163 Walk(x.second, visitor);
164 }
165 }
166 template <typename A, typename B, typename M>
167 static void Walk(std::pair<A, B> &x, M &mutator) {
168 if (mutator.Pre(x)) {
169 Walk(x.first, mutator);
170 Walk(x.second, mutator);
171 }
172 }
173
174 // Trait-determined traversal of empty, tuple, union, wrapper,
175 // and constraint-checking classes.
176 template <typename A, typename V>
177 static std::enable_if_t<EmptyTrait<A>> Walk(const A &x, V &visitor) {
178 if (visitor.Pre(x)) {
179 WalkSource(x, visitor);
180 visitor.Post(x);
181 }
182 }
183 template <typename A, typename M>
184 static std::enable_if_t<EmptyTrait<A>> Walk(A &x, M &mutator) {
185 if (mutator.Pre(x)) {
186 WalkSource(x, mutator);
187 mutator.Post(x);
188 }
189 }
190
191 template <typename A, typename V>
192 static std::enable_if_t<TupleTrait<A>> Walk(const A &x, V &visitor) {
193 if (visitor.Pre(x)) {
194 WalkSource(x, visitor);
195 Walk(x.t, visitor);
196 visitor.Post(x);
197 }
198 }
199 template <typename A, typename M>
200 static std::enable_if_t<TupleTrait<A>> Walk(A &x, M &mutator) {
201 if (mutator.Pre(x)) {
202 WalkSource(x, mutator);
203 Walk(x.t, mutator);
204 mutator.Post(x);
205 }
206 }
207
208 template <typename A, typename V>
209 static std::enable_if_t<UnionTrait<A>> Walk(const A &x, V &visitor) {
210 if (visitor.Pre(x)) {
211 WalkSource(x, visitor);
212 Walk(x.u, visitor);
213 visitor.Post(x);
214 }
215 }
216 template <typename A, typename M>
217 static std::enable_if_t<UnionTrait<A>> Walk(A &x, M &mutator) {
218 if (mutator.Pre(x)) {
219 WalkSource(x, mutator);
220 Walk(x.u, mutator);
221 mutator.Post(x);
222 }
223 }
224
225 template <typename A, typename V>
226 static std::enable_if_t<WrapperTrait<A>> Walk(const A &x, V &visitor) {
227 if (visitor.Pre(x)) {
228 WalkSource(x, visitor);
229 Walk(x.v, visitor);
230 visitor.Post(x);
231 }
232 }
233 template <typename A, typename M>
234 static std::enable_if_t<WrapperTrait<A>> Walk(A &x, M &mutator) {
235 if (mutator.Pre(x)) {
236 WalkSource(x, mutator);
237 Walk(x.v, mutator);
238 mutator.Post(x);
239 }
240 }
241
242 template <typename A, typename V>
243 static std::enable_if_t<ConstraintTrait<A>> Walk(const A &x, V &visitor) {
244 if (visitor.Pre(x)) {
245 WalkSource(x, visitor);
246 Walk(x.thing, visitor);
247 visitor.Post(x);
248 }
249 }
250 template <typename A, typename M>
251 static std::enable_if_t<ConstraintTrait<A>> Walk(A &x, M &mutator) {
252 if (mutator.Pre(x)) {
253 WalkSource(x, mutator);
254 Walk(x.thing, mutator);
255 mutator.Post(x);
256 }
257 }
258
259 template <typename T, typename V>
260 static void Walk(const common::Indirection<T> &x, V &visitor) {
261 Walk(x.value(), visitor);
262 }
263 template <typename T, typename M>
264 static void Walk(common::Indirection<T> &x, M &mutator) {
265 Walk(x.value(), mutator);
266 }
267
268 template <typename T, typename V>
269 static void Walk(const Statement<T> &x, V &visitor) {
270 if (visitor.Pre(x)) {
271 // N.B. The label, if any, is not visited.
272 Walk(x.source, visitor);
273 Walk(x.statement, visitor);
274 visitor.Post(x);
275 }
276 }
277 template <typename T, typename M>
278 static void Walk(Statement<T> &x, M &mutator) {
279 if (mutator.Pre(x)) {
280 // N.B. The label, if any, is not visited.
281 Walk(x.source, mutator);
282 Walk(x.statement, mutator);
283 mutator.Post(x);
284 }
285 }
286
287 template <typename T, typename V>
288 static void Walk(const UnlabeledStatement<T> &x, V &visitor) {
289 if (visitor.Pre(x)) {
290 Walk(x.source, visitor);
291 Walk(x.statement, visitor);
292 visitor.Post(x);
293 }
294 }
295 template <typename T, typename M>
296 static void Walk(UnlabeledStatement<T> &x, M &mutator) {
297 if (mutator.Pre(x)) {
298 Walk(x.source, mutator);
299 Walk(x.statement, mutator);
300 mutator.Post(x);
301 }
302 }
303
304 template <typename V> static void Walk(const Name &x, V &visitor) {
305 if (visitor.Pre(x)) {
306 Walk(x.source, visitor);
307 visitor.Post(x);
308 }
309 }
310 template <typename M> static void Walk(Name &x, M &mutator) {
311 if (mutator.Pre(x)) {
312 Walk(x.source, mutator);
313 mutator.Post(x);
314 }
315 }
316
317 // Expr traversal uses iteration rather than recursion to avoid
318 // blowing out the stack on very deep expression parse trees.
319 // It replaces implementations that looked like:
320 // template <typename V> static void Walk(const Expr &x, V visitor) {
321 // if (visitor.Pre(x)) { // Pre on the Expr
322 // Walk(x.source, visitor);
323 // // Pre on the operator, walk the operands, Post on operator
324 // Walk(x.u, visitor);
325 // visitor.Post(x); // Post on the Expr
326 // }
327 // }
328 template <typename A, typename V, typename UNARY, typename BINARY>
329 static void IterativeWalk(A &start, V &visitor) {
330 struct ExprWorkList {
331 ExprWorkList(A &x) : expr(&x) {}
332 bool doPostExpr{false}, doPostOpr{false};
333 A *expr;
334 };
335 std::vector<ExprWorkList> stack;
336 stack.emplace_back(start);
337 do {
338 A &expr{*stack.back().expr};
339 if (stack.back().doPostOpr) {
340 stack.back().doPostOpr = false;
341 common::visit([&visitor](auto &y) { visitor.Post(y); }, expr.u);
342 } else if (stack.back().doPostExpr) {
343 visitor.Post(expr);
344 stack.pop_back();
345 } else if (!visitor.Pre(expr)) {
346 stack.pop_back();
347 } else {
348 stack.back().doPostExpr = true;
349 Walk(expr.source, visitor);
350 UNARY *unary{nullptr};
351 BINARY *binary{nullptr};
352 common::visit(
353 [&unary, &binary](auto &y) {
354 if constexpr (std::is_convertible_v<decltype(&y), UNARY *>) {
355 unary = &y;
356 } else if constexpr (std::is_convertible_v<decltype(&y),
357 BINARY *>) {
358 binary = &y;
359 }
360 },
361 expr.u);
362 if (!unary && !binary) {
363 Walk(expr.u, visitor);
364 } else if (common::visit([&visitor](auto &y) { return visitor.Pre(y); },
365 expr.u)) {
366 stack.back().doPostOpr = true;
367 if (unary) {
368 stack.emplace_back(unary->v.value());
369 } else {
370 stack.emplace_back(std::get<1>(binary->t).value());
371 stack.emplace_back(std::get<0>(binary->t).value());
372 }
373 }
374 }
375 } while (!stack.empty());
376 }
377 template <typename V> static void Walk(const Expr &x, V &visitor) {
378 IterativeWalk<const Expr, V, const Expr::IntrinsicUnary,
379 const Expr::IntrinsicBinary>(x, visitor);
380 }
381 template <typename M> static void Walk(Expr &x, M &mutator) {
382 IterativeWalk<Expr, M, Expr::IntrinsicUnary, Expr::IntrinsicBinary>(
383 x, mutator);
384 }
385
386 template <typename V> static void Walk(const ReadStmt &x, V &visitor) {
387 if (visitor.Pre(x)) {
388 Walk(x.iounit, visitor);
389 Walk(x.format, visitor);
390 Walk(x.controls, visitor);
391 Walk(x.items, visitor);
392 visitor.Post(x);
393 }
394 }
395 template <typename M> static void Walk(ReadStmt &x, M &mutator) {
396 if (mutator.Pre(x)) {
397 Walk(x.iounit, mutator);
398 Walk(x.format, mutator);
399 Walk(x.controls, mutator);
400 Walk(x.items, mutator);
401 mutator.Post(x);
402 }
403 }
404 template <typename V> static void Walk(const UseStmt &x, V &visitor) {
405 if (visitor.Pre(x)) {
406 Walk(x.nature, visitor);
407 Walk(x.moduleName, visitor);
408 Walk(x.u, visitor);
409 visitor.Post(x);
410 }
411 }
412 template <typename M> static void Walk(UseStmt &x, M &mutator) {
413 if (mutator.Pre(x)) {
414 Walk(x.nature, mutator);
415 Walk(x.moduleName, mutator);
416 Walk(x.u, mutator);
417 mutator.Post(x);
418 }
419 }
420 template <typename V> static void Walk(const WriteStmt &x, V &visitor) {
421 if (visitor.Pre(x)) {
422 Walk(x.iounit, visitor);
423 Walk(x.format, visitor);
424 Walk(x.controls, visitor);
425 Walk(x.items, visitor);
426 visitor.Post(x);
427 }
428 }
429 template <typename M> static void Walk(WriteStmt &x, M &mutator) {
430 if (mutator.Pre(x)) {
431 Walk(x.iounit, mutator);
432 Walk(x.format, mutator);
433 Walk(x.controls, mutator);
434 Walk(x.items, mutator);
435 mutator.Post(x);
436 }
437 }
438 template <typename V>
439 static void Walk(const format::ControlEditDesc &x, V &visitor) {
440 if (visitor.Pre(x)) {
441 Walk(x.kind, visitor);
442 visitor.Post(x);
443 }
444 }
445 template <typename M>
446 static void Walk(format::ControlEditDesc &x, M &mutator) {
447 if (mutator.Pre(x)) {
448 Walk(x.kind, mutator);
449 mutator.Post(x);
450 }
451 }
452 template <typename V>
453 static void Walk(const format::DerivedTypeDataEditDesc &x, V &visitor) {
454 if (visitor.Pre(x)) {
455 Walk(x.type, visitor);
456 Walk(x.parameters, visitor);
457 visitor.Post(x);
458 }
459 }
460 template <typename M>
461 static void Walk(format::DerivedTypeDataEditDesc &x, M &mutator) {
462 if (mutator.Pre(x)) {
463 Walk(x.type, mutator);
464 Walk(x.parameters, mutator);
465 mutator.Post(x);
466 }
467 }
468 template <typename V>
469 static void Walk(const format::FormatItem &x, V &visitor) {
470 if (visitor.Pre(x)) {
471 Walk(x.repeatCount, visitor);
472 Walk(x.u, visitor);
473 visitor.Post(x);
474 }
475 }
476 template <typename M> static void Walk(format::FormatItem &x, M &mutator) {
477 if (mutator.Pre(x)) {
478 Walk(x.repeatCount, mutator);
479 Walk(x.u, mutator);
480 mutator.Post(x);
481 }
482 }
483 template <typename V>
484 static void Walk(const format::FormatSpecification &x, V &visitor) {
485 if (visitor.Pre(x)) {
486 Walk(x.items, visitor);
487 Walk(x.unlimitedItems, visitor);
488 visitor.Post(x);
489 }
490 }
491 template <typename M>
492 static void Walk(format::FormatSpecification &x, M &mutator) {
493 if (mutator.Pre(x)) {
494 Walk(x.items, mutator);
495 Walk(x.unlimitedItems, mutator);
496 mutator.Post(x);
497 }
498 }
499 template <typename V>
500 static void Walk(const format::IntrinsicTypeDataEditDesc &x, V &visitor) {
501 if (visitor.Pre(x)) {
502 Walk(x.kind, visitor);
503 Walk(x.width, visitor);
504 Walk(x.digits, visitor);
505 Walk(x.exponentWidth, visitor);
506 visitor.Post(x);
507 }
508 }
509 template <typename M>
510 static void Walk(format::IntrinsicTypeDataEditDesc &x, M &mutator) {
511 if (mutator.Pre(x)) {
512 Walk(x.kind, mutator);
513 Walk(x.width, mutator);
514 Walk(x.digits, mutator);
515 Walk(x.exponentWidth, mutator);
516 mutator.Post(x);
517 }
518 }
519};
520} // namespace detail
521
522template <typename A, typename V> void Walk(const A &x, V &visitor) {
523 detail::ParseTreeVisitorLookupScope::Walk(x, visitor);
524}
525
526template <typename A, typename M> void Walk(A &x, M &mutator) {
527 detail::ParseTreeVisitorLookupScope::Walk(x, mutator);
528}
529
530} // namespace Fortran::parser
531#endif // FORTRAN_PARSER_PARSE_TREE_VISITOR_H_
Definition indirection.h:31
Definition check-expression.h:19
Definition format-specification.h:76
Definition format-specification.h:56
Definition format-specification.h:116
Definition format-specification.h:135
Definition format-specification.h:38
Definition parse-tree.h:1706
Definition parse-tree.h:1682
Definition tools.h:134
Definition parse-tree.h:587
Definition parse-tree.h:2727
Definition parse-tree.h:359
Definition parse-tree.h:354
Definition parse-tree.h:3053
Definition parse-tree.h:2749