xref: /llvm-project/flang/include/flang/Parser/parse-tree-visitor.h (revision 03cbe42627c7a7940b47cc1a2cda0120bc9c6d5e)
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 "flang/Common/visit.h"
14 #include <cstddef>
15 #include <optional>
16 #include <tuple>
17 #include <utility>
18 #include <variant>
19 #include <vector>
20 
21 /// Parse tree visitor
22 /// Call Walk(x, visitor) to visit x and, by default, each node under x.
23 /// If x is non-const, the visitor member functions can modify the tree.
24 ///
25 /// visitor.Pre(x) is called before visiting x and its children are not
26 /// visited if it returns false.
27 ///
28 /// visitor.Post(x) is called after visiting x.
29 
30 namespace Fortran::parser {
31 
32 template <typename A, typename V> void Walk(const A &x, V &visitor);
33 template <typename A, typename M> void Walk(A &x, M &mutator);
34 
35 namespace detail {
36 // A number of the Walk functions below call other Walk functions. Define
37 // a dummy class, and put all of them in it to ensure that name lookup for
38 // Walk considers all overloads (not just those defined prior to the call
39 // to Walk).
40 struct ParseTreeVisitorLookupScope {
41   // Default case for visitation of non-class data members, strings, and
42   // any other non-decomposable values.
43   template <typename A, typename V>
44   static std::enable_if_t<!std::is_class_v<A> ||
45       std::is_same_v<std::string, A> || std::is_same_v<CharBlock, A>>
46   Walk(const A &x, V &visitor) {
47     if (visitor.Pre(x)) {
48       visitor.Post(x);
49     }
50   }
51   template <typename A, typename M>
52   static std::enable_if_t<!std::is_class_v<A> ||
53       std::is_same_v<std::string, A> || std::is_same_v<CharBlock, A>>
54   Walk(A &x, M &mutator) {
55     if (mutator.Pre(x)) {
56       mutator.Post(x);
57     }
58   }
59 
60   // Traversal of needed STL template classes (optional, list, tuple, variant)
61   // For most lists, just traverse the elements; but when a list constitutes
62   // a Block (i.e., std::list<ExecutionPartConstruct>), also invoke the
63   // visitor/mutator on the list itself.
64   template <typename T, typename V>
65   static void Walk(const std::list<T> &x, V &visitor) {
66     for (const auto &elem : x) {
67       Walk(elem, visitor);
68     }
69   }
70   template <typename T, typename M>
71   static void Walk(std::list<T> &x, M &mutator) {
72     for (auto &elem : x) {
73       Walk(elem, mutator);
74     }
75   }
76   template <typename V> static void Walk(const Block &x, V &visitor) {
77     if (visitor.Pre(x)) {
78       for (const auto &elem : x) {
79         Walk(elem, visitor);
80       }
81       visitor.Post(x);
82     }
83   }
84   template <typename M> static void Walk(Block &x, M &mutator) {
85     if (mutator.Pre(x)) {
86       for (auto &elem : x) {
87         Walk(elem, mutator);
88       }
89       mutator.Post(x);
90     }
91   }
92   template <typename T, typename V>
93   static void Walk(const std::optional<T> &x, V &visitor) {
94     if (x) {
95       Walk(*x, visitor);
96     }
97   }
98   template <typename T, typename M>
99   static void Walk(std::optional<T> &x, M &mutator) {
100     if (x) {
101       Walk(*x, mutator);
102     }
103   }
104   template <std::size_t I = 0, typename Func, typename T>
105   static void ForEachInTuple(const T &tuple, Func func) {
106     func(std::get<I>(tuple));
107     if constexpr (I + 1 < std::tuple_size_v<T>) {
108       ForEachInTuple<I + 1>(tuple, func);
109     }
110   }
111   template <typename V, typename... A>
112   static void Walk(const std::tuple<A...> &x, V &visitor) {
113     if (sizeof...(A) > 0) {
114       if (visitor.Pre(x)) {
115         ForEachInTuple(x, [&](const auto &y) { Walk(y, visitor); });
116         visitor.Post(x);
117       }
118     }
119   }
120   template <std::size_t I = 0, typename Func, typename T>
121   static void ForEachInTuple(T &tuple, Func func) {
122     func(std::get<I>(tuple));
123     if constexpr (I + 1 < std::tuple_size_v<T>) {
124       ForEachInTuple<I + 1>(tuple, func);
125     }
126   }
127   template <typename M, typename... A>
128   static void Walk(std::tuple<A...> &x, M &mutator) {
129     if (sizeof...(A) > 0) {
130       if (mutator.Pre(x)) {
131         ForEachInTuple(x, [&](auto &y) { Walk(y, mutator); });
132         mutator.Post(x);
133       }
134     }
135   }
136   template <typename V, typename... A>
137   static void Walk(const std::variant<A...> &x, V &visitor) {
138     if (visitor.Pre(x)) {
139       common::visit([&](const auto &y) { Walk(y, visitor); }, x);
140       visitor.Post(x);
141     }
142   }
143   template <typename M, typename... A>
144   static void Walk(std::variant<A...> &x, M &mutator) {
145     if (mutator.Pre(x)) {
146       common::visit([&](auto &y) { Walk(y, mutator); }, x);
147       mutator.Post(x);
148     }
149   }
150   template <typename A, typename B, typename V>
151   static void Walk(const std::pair<A, B> &x, V &visitor) {
152     if (visitor.Pre(x)) {
153       Walk(x.first, visitor);
154       Walk(x.second, visitor);
155     }
156   }
157   template <typename A, typename B, typename M>
158   static void Walk(std::pair<A, B> &x, M &mutator) {
159     if (mutator.Pre(x)) {
160       Walk(x.first, mutator);
161       Walk(x.second, mutator);
162     }
163   }
164 
165   // Trait-determined traversal of empty, tuple, union, wrapper,
166   // and constraint-checking classes.
167   template <typename A, typename V>
168   static std::enable_if_t<EmptyTrait<A>> Walk(const A &x, V &visitor) {
169     if (visitor.Pre(x)) {
170       visitor.Post(x);
171     }
172   }
173   template <typename A, typename M>
174   static std::enable_if_t<EmptyTrait<A>> Walk(A &x, M &mutator) {
175     if (mutator.Pre(x)) {
176       mutator.Post(x);
177     }
178   }
179 
180   template <typename A, typename V>
181   static std::enable_if_t<TupleTrait<A>> Walk(const A &x, V &visitor) {
182     if (visitor.Pre(x)) {
183       Walk(x.t, visitor);
184       visitor.Post(x);
185     }
186   }
187   template <typename A, typename M>
188   static std::enable_if_t<TupleTrait<A>> Walk(A &x, M &mutator) {
189     if (mutator.Pre(x)) {
190       Walk(x.t, mutator);
191       mutator.Post(x);
192     }
193   }
194 
195   template <typename A, typename V>
196   static std::enable_if_t<UnionTrait<A>> Walk(const A &x, V &visitor) {
197     if (visitor.Pre(x)) {
198       Walk(x.u, visitor);
199       visitor.Post(x);
200     }
201   }
202   template <typename A, typename M>
203   static std::enable_if_t<UnionTrait<A>> Walk(A &x, M &mutator) {
204     if (mutator.Pre(x)) {
205       Walk(x.u, mutator);
206       mutator.Post(x);
207     }
208   }
209 
210   template <typename A, typename V>
211   static std::enable_if_t<WrapperTrait<A>> Walk(const A &x, V &visitor) {
212     if (visitor.Pre(x)) {
213       Walk(x.v, visitor);
214       visitor.Post(x);
215     }
216   }
217   template <typename A, typename M>
218   static std::enable_if_t<WrapperTrait<A>> Walk(A &x, M &mutator) {
219     if (mutator.Pre(x)) {
220       Walk(x.v, mutator);
221       mutator.Post(x);
222     }
223   }
224 
225   template <typename A, typename V>
226   static std::enable_if_t<ConstraintTrait<A>> Walk(const A &x, V &visitor) {
227     if (visitor.Pre(x)) {
228       Walk(x.thing, visitor);
229       visitor.Post(x);
230     }
231   }
232   template <typename A, typename M>
233   static std::enable_if_t<ConstraintTrait<A>> Walk(A &x, M &mutator) {
234     if (mutator.Pre(x)) {
235       Walk(x.thing, mutator);
236       mutator.Post(x);
237     }
238   }
239 
240   template <typename T, typename V>
241   static void Walk(const common::Indirection<T> &x, V &visitor) {
242     Walk(x.value(), visitor);
243   }
244   template <typename T, typename M>
245   static void Walk(common::Indirection<T> &x, M &mutator) {
246     Walk(x.value(), mutator);
247   }
248 
249   template <typename T, typename V>
250   static void Walk(const Statement<T> &x, V &visitor) {
251     if (visitor.Pre(x)) {
252       // N.B. The label, if any, is not visited.
253       Walk(x.source, visitor);
254       Walk(x.statement, visitor);
255       visitor.Post(x);
256     }
257   }
258   template <typename T, typename M>
259   static void Walk(Statement<T> &x, M &mutator) {
260     if (mutator.Pre(x)) {
261       // N.B. The label, if any, is not visited.
262       Walk(x.source, mutator);
263       Walk(x.statement, mutator);
264       mutator.Post(x);
265     }
266   }
267 
268   template <typename T, typename V>
269   static void Walk(const UnlabeledStatement<T> &x, V &visitor) {
270     if (visitor.Pre(x)) {
271       Walk(x.source, visitor);
272       Walk(x.statement, visitor);
273       visitor.Post(x);
274     }
275   }
276   template <typename T, typename M>
277   static void Walk(UnlabeledStatement<T> &x, M &mutator) {
278     if (mutator.Pre(x)) {
279       Walk(x.source, mutator);
280       Walk(x.statement, mutator);
281       mutator.Post(x);
282     }
283   }
284 
285   template <typename V> static void Walk(const Name &x, V &visitor) {
286     if (visitor.Pre(x)) {
287       Walk(x.source, visitor);
288       visitor.Post(x);
289     }
290   }
291   template <typename M> static void Walk(Name &x, M &mutator) {
292     if (mutator.Pre(x)) {
293       Walk(x.source, mutator);
294       mutator.Post(x);
295     }
296   }
297 
298   template <typename V> static void Walk(const AcSpec &x, V &visitor) {
299     if (visitor.Pre(x)) {
300       Walk(x.type, visitor);
301       Walk(x.values, visitor);
302       visitor.Post(x);
303     }
304   }
305   template <typename M> static void Walk(AcSpec &x, M &mutator) {
306     if (mutator.Pre(x)) {
307       Walk(x.type, mutator);
308       Walk(x.values, mutator);
309       mutator.Post(x);
310     }
311   }
312   template <typename V> static void Walk(const ArrayElement &x, V &visitor) {
313     if (visitor.Pre(x)) {
314       Walk(x.base, visitor);
315       Walk(x.subscripts, visitor);
316       visitor.Post(x);
317     }
318   }
319   template <typename M> static void Walk(ArrayElement &x, M &mutator) {
320     if (mutator.Pre(x)) {
321       Walk(x.base, mutator);
322       Walk(x.subscripts, mutator);
323       mutator.Post(x);
324     }
325   }
326   template <typename V>
327   static void Walk(const CharSelector::LengthAndKind &x, V &visitor) {
328     if (visitor.Pre(x)) {
329       Walk(x.length, visitor);
330       Walk(x.kind, visitor);
331       visitor.Post(x);
332     }
333   }
334   template <typename M>
335   static void Walk(CharSelector::LengthAndKind &x, M &mutator) {
336     if (mutator.Pre(x)) {
337       Walk(x.length, mutator);
338       Walk(x.kind, mutator);
339       mutator.Post(x);
340     }
341   }
342   template <typename V>
343   static void Walk(const CaseValueRange::Range &x, V &visitor) {
344     if (visitor.Pre(x)) {
345       Walk(x.lower, visitor);
346       Walk(x.upper, visitor);
347       visitor.Post(x);
348     }
349   }
350   template <typename M> static void Walk(CaseValueRange::Range &x, M &mutator) {
351     if (mutator.Pre(x)) {
352       Walk(x.lower, mutator);
353       Walk(x.upper, mutator);
354       mutator.Post(x);
355     }
356   }
357   template <typename V>
358   static void Walk(const CoindexedNamedObject &x, V &visitor) {
359     if (visitor.Pre(x)) {
360       Walk(x.base, visitor);
361       Walk(x.imageSelector, visitor);
362       visitor.Post(x);
363     }
364   }
365   template <typename M> static void Walk(CoindexedNamedObject &x, M &mutator) {
366     if (mutator.Pre(x)) {
367       Walk(x.base, mutator);
368       Walk(x.imageSelector, mutator);
369       mutator.Post(x);
370     }
371   }
372   template <typename V>
373   static void Walk(const DeclarationTypeSpec::Class &x, V &visitor) {
374     if (visitor.Pre(x)) {
375       Walk(x.derived, visitor);
376       visitor.Post(x);
377     }
378   }
379   template <typename M>
380   static void Walk(DeclarationTypeSpec::Class &x, M &mutator) {
381     if (mutator.Pre(x)) {
382       Walk(x.derived, mutator);
383       mutator.Post(x);
384     }
385   }
386   template <typename V>
387   static void Walk(const DeclarationTypeSpec::Type &x, V &visitor) {
388     if (visitor.Pre(x)) {
389       Walk(x.derived, visitor);
390       visitor.Post(x);
391     }
392   }
393   template <typename M>
394   static void Walk(DeclarationTypeSpec::Type &x, M &mutator) {
395     if (mutator.Pre(x)) {
396       Walk(x.derived, mutator);
397       mutator.Post(x);
398     }
399   }
400   template <typename V> static void Walk(const ImportStmt &x, V &visitor) {
401     if (visitor.Pre(x)) {
402       Walk(x.names, visitor);
403       visitor.Post(x);
404     }
405   }
406   template <typename M> static void Walk(ImportStmt &x, M &mutator) {
407     if (mutator.Pre(x)) {
408       Walk(x.names, mutator);
409       mutator.Post(x);
410     }
411   }
412   template <typename V>
413   static void Walk(const IntrinsicTypeSpec::Character &x, V &visitor) {
414     if (visitor.Pre(x)) {
415       Walk(x.selector, visitor);
416       visitor.Post(x);
417     }
418   }
419   template <typename M>
420   static void Walk(IntrinsicTypeSpec::Character &x, M &mutator) {
421     if (mutator.Pre(x)) {
422       Walk(x.selector, mutator);
423       mutator.Post(x);
424     }
425   }
426   template <typename V>
427   static void Walk(const IntrinsicTypeSpec::Complex &x, V &visitor) {
428     if (visitor.Pre(x)) {
429       Walk(x.kind, visitor);
430       visitor.Post(x);
431     }
432   }
433   template <typename M>
434   static void Walk(IntrinsicTypeSpec::Complex &x, M &mutator) {
435     if (mutator.Pre(x)) {
436       Walk(x.kind, mutator);
437       mutator.Post(x);
438     }
439   }
440   template <typename V>
441   static void Walk(const IntrinsicTypeSpec::Logical &x, V &visitor) {
442     if (visitor.Pre(x)) {
443       Walk(x.kind, visitor);
444       visitor.Post(x);
445     }
446   }
447   template <typename M>
448   static void Walk(IntrinsicTypeSpec::Logical &x, M &mutator) {
449     if (mutator.Pre(x)) {
450       Walk(x.kind, mutator);
451       mutator.Post(x);
452     }
453   }
454   template <typename V>
455   static void Walk(const IntrinsicTypeSpec::Real &x, V &visitor) {
456     if (visitor.Pre(x)) {
457       Walk(x.kind, visitor);
458       visitor.Post(x);
459     }
460   }
461   template <typename M>
462   static void Walk(IntrinsicTypeSpec::Real &x, M &mutator) {
463     if (mutator.Pre(x)) {
464       Walk(x.kind, mutator);
465       mutator.Post(x);
466     }
467   }
468   template <typename A, typename B, typename V>
469   static void Walk(const LoopBounds<A, B> &x, V &visitor) {
470     if (visitor.Pre(x)) {
471       Walk(x.name, visitor);
472       Walk(x.lower, visitor);
473       Walk(x.upper, visitor);
474       Walk(x.step, visitor);
475       visitor.Post(x);
476     }
477   }
478   template <typename A, typename B, typename M>
479   static void Walk(LoopBounds<A, B> &x, M &mutator) {
480     if (mutator.Pre(x)) {
481       Walk(x.name, mutator);
482       Walk(x.lower, mutator);
483       Walk(x.upper, mutator);
484       Walk(x.step, mutator);
485       mutator.Post(x);
486     }
487   }
488   template <typename V> static void Walk(const CommonStmt &x, V &visitor) {
489     if (visitor.Pre(x)) {
490       Walk(x.blocks, visitor);
491       visitor.Post(x);
492     }
493   }
494   template <typename M> static void Walk(CommonStmt &x, M &mutator) {
495     if (mutator.Pre(x)) {
496       Walk(x.blocks, mutator);
497       mutator.Post(x);
498     }
499   }
500 
501   // Expr traversal uses iteration rather than recursion to avoid
502   // blowing out the stack on very deep expression parse trees.
503   // It replaces implementations that looked like:
504   //   template <typename V> static void Walk(const Expr &x, V visitor) {
505   //     if (visitor.Pre(x)) {      // Pre on the Expr
506   //       Walk(x.source, visitor);
507   //       // Pre on the operator, walk the operands, Post on operator
508   //       Walk(x.u, visitor);
509   //       visitor.Post(x);         // Post on the Expr
510   //     }
511   //   }
512   template <typename A, typename V, typename UNARY, typename BINARY>
513   static void IterativeWalk(A &start, V &visitor) {
514     struct ExprWorkList {
515       ExprWorkList(A &x) : expr(&x) {}
516       bool doPostExpr{false}, doPostOpr{false};
517       A *expr;
518     };
519     std::vector<ExprWorkList> stack;
520     stack.emplace_back(start);
521     do {
522       A &expr{*stack.back().expr};
523       if (stack.back().doPostOpr) {
524         stack.back().doPostOpr = false;
525         common::visit([&visitor](auto &y) { visitor.Post(y); }, expr.u);
526       } else if (stack.back().doPostExpr) {
527         visitor.Post(expr);
528         stack.pop_back();
529       } else if (!visitor.Pre(expr)) {
530         stack.pop_back();
531       } else {
532         stack.back().doPostExpr = true;
533         Walk(expr.source, visitor);
534         UNARY *unary{nullptr};
535         BINARY *binary{nullptr};
536         common::visit(
537             [&unary, &binary](auto &y) {
538               if constexpr (std::is_convertible_v<decltype(&y), UNARY *>) {
539                 unary = &y;
540               } else if constexpr (std::is_convertible_v<decltype(&y),
541                                        BINARY *>) {
542                 binary = &y;
543               }
544             },
545             expr.u);
546         if (!unary && !binary) {
547           Walk(expr.u, visitor);
548         } else if (common::visit([&visitor](auto &y) { return visitor.Pre(y); },
549                        expr.u)) {
550           stack.back().doPostOpr = true;
551           if (unary) {
552             stack.emplace_back(unary->v.value());
553           } else {
554             stack.emplace_back(std::get<1>(binary->t).value());
555             stack.emplace_back(std::get<0>(binary->t).value());
556           }
557         }
558       }
559     } while (!stack.empty());
560   }
561   template <typename V> static void Walk(const Expr &x, V &visitor) {
562     IterativeWalk<const Expr, V, const Expr::IntrinsicUnary,
563         const Expr::IntrinsicBinary>(x, visitor);
564   }
565   template <typename M> static void Walk(Expr &x, M &mutator) {
566     IterativeWalk<Expr, M, Expr::IntrinsicUnary, Expr::IntrinsicBinary>(
567         x, mutator);
568   }
569 
570   template <typename V> static void Walk(const Designator &x, V &visitor) {
571     if (visitor.Pre(x)) {
572       Walk(x.source, visitor);
573       Walk(x.u, visitor);
574       visitor.Post(x);
575     }
576   }
577   template <typename M> static void Walk(Designator &x, M &mutator) {
578     if (mutator.Pre(x)) {
579       Walk(x.source, mutator);
580       Walk(x.u, mutator);
581       mutator.Post(x);
582     }
583   }
584   template <typename V>
585   static void Walk(const FunctionReference &x, V &visitor) {
586     if (visitor.Pre(x)) {
587       Walk(x.source, visitor);
588       Walk(x.v, visitor);
589       visitor.Post(x);
590     }
591   }
592   template <typename M> static void Walk(FunctionReference &x, M &mutator) {
593     if (mutator.Pre(x)) {
594       Walk(x.source, mutator);
595       Walk(x.v, mutator);
596       mutator.Post(x);
597     }
598   }
599   template <typename V> static void Walk(const CallStmt &x, V &visitor) {
600     if (visitor.Pre(x)) {
601       Walk(x.source, visitor);
602       Walk(x.call, visitor);
603       Walk(x.chevrons, visitor);
604       visitor.Post(x);
605     }
606   }
607   template <typename M> static void Walk(CallStmt &x, M &mutator) {
608     if (mutator.Pre(x)) {
609       Walk(x.source, mutator);
610       Walk(x.call, mutator);
611       Walk(x.chevrons, mutator);
612       mutator.Post(x);
613     }
614   }
615   template <typename V> static void Walk(const PartRef &x, V &visitor) {
616     if (visitor.Pre(x)) {
617       Walk(x.name, visitor);
618       Walk(x.subscripts, visitor);
619       Walk(x.imageSelector, visitor);
620       visitor.Post(x);
621     }
622   }
623   template <typename M> static void Walk(PartRef &x, M &mutator) {
624     if (mutator.Pre(x)) {
625       Walk(x.name, mutator);
626       Walk(x.subscripts, mutator);
627       Walk(x.imageSelector, mutator);
628       mutator.Post(x);
629     }
630   }
631   template <typename V> static void Walk(const ReadStmt &x, V &visitor) {
632     if (visitor.Pre(x)) {
633       Walk(x.iounit, visitor);
634       Walk(x.format, visitor);
635       Walk(x.controls, visitor);
636       Walk(x.items, visitor);
637       visitor.Post(x);
638     }
639   }
640   template <typename M> static void Walk(ReadStmt &x, M &mutator) {
641     if (mutator.Pre(x)) {
642       Walk(x.iounit, mutator);
643       Walk(x.format, mutator);
644       Walk(x.controls, mutator);
645       Walk(x.items, mutator);
646       mutator.Post(x);
647     }
648   }
649   template <typename V>
650   static void Walk(const SignedIntLiteralConstant &x, V &visitor) {
651     if (visitor.Pre(x)) {
652       Walk(x.source, visitor);
653       Walk(x.t, visitor);
654       visitor.Post(x);
655     }
656   }
657   template <typename M>
658   static void Walk(SignedIntLiteralConstant &x, M &mutator) {
659     if (mutator.Pre(x)) {
660       Walk(x.source, mutator);
661       Walk(x.t, mutator);
662       mutator.Post(x);
663     }
664   }
665   template <typename V>
666   static void Walk(const RealLiteralConstant &x, V &visitor) {
667     if (visitor.Pre(x)) {
668       Walk(x.real, visitor);
669       Walk(x.kind, visitor);
670       visitor.Post(x);
671     }
672   }
673   template <typename M> static void Walk(RealLiteralConstant &x, M &mutator) {
674     if (mutator.Pre(x)) {
675       Walk(x.real, mutator);
676       Walk(x.kind, mutator);
677       mutator.Post(x);
678     }
679   }
680   template <typename V>
681   static void Walk(const RealLiteralConstant::Real &x, V &visitor) {
682     if (visitor.Pre(x)) {
683       Walk(x.source, visitor);
684       visitor.Post(x);
685     }
686   }
687   template <typename M>
688   static void Walk(RealLiteralConstant::Real &x, M &mutator) {
689     if (mutator.Pre(x)) {
690       Walk(x.source, mutator);
691       mutator.Post(x);
692     }
693   }
694   template <typename V>
695   static void Walk(const StructureComponent &x, V &visitor) {
696     if (visitor.Pre(x)) {
697       Walk(x.base, visitor);
698       Walk(x.component, visitor);
699       visitor.Post(x);
700     }
701   }
702   template <typename M> static void Walk(StructureComponent &x, M &mutator) {
703     if (mutator.Pre(x)) {
704       Walk(x.base, mutator);
705       Walk(x.component, mutator);
706       mutator.Post(x);
707     }
708   }
709   template <typename V> static void Walk(const Suffix &x, V &visitor) {
710     if (visitor.Pre(x)) {
711       Walk(x.binding, visitor);
712       Walk(x.resultName, visitor);
713       visitor.Post(x);
714     }
715   }
716   template <typename M> static void Walk(Suffix &x, M &mutator) {
717     if (mutator.Pre(x)) {
718       Walk(x.binding, mutator);
719       Walk(x.resultName, mutator);
720       mutator.Post(x);
721     }
722   }
723   template <typename V>
724   static void Walk(const TypeBoundProcedureStmt::WithInterface &x, V &visitor) {
725     if (visitor.Pre(x)) {
726       Walk(x.interfaceName, visitor);
727       Walk(x.attributes, visitor);
728       Walk(x.bindingNames, visitor);
729       visitor.Post(x);
730     }
731   }
732   template <typename M>
733   static void Walk(TypeBoundProcedureStmt::WithInterface &x, M &mutator) {
734     if (mutator.Pre(x)) {
735       Walk(x.interfaceName, mutator);
736       Walk(x.attributes, mutator);
737       Walk(x.bindingNames, mutator);
738       mutator.Post(x);
739     }
740   }
741   template <typename V>
742   static void Walk(
743       const TypeBoundProcedureStmt::WithoutInterface &x, V &visitor) {
744     if (visitor.Pre(x)) {
745       Walk(x.attributes, visitor);
746       Walk(x.declarations, visitor);
747       visitor.Post(x);
748     }
749   }
750   template <typename M>
751   static void Walk(TypeBoundProcedureStmt::WithoutInterface &x, M &mutator) {
752     if (mutator.Pre(x)) {
753       Walk(x.attributes, mutator);
754       Walk(x.declarations, mutator);
755       mutator.Post(x);
756     }
757   }
758   template <typename V> static void Walk(const UseStmt &x, V &visitor) {
759     if (visitor.Pre(x)) {
760       Walk(x.nature, visitor);
761       Walk(x.moduleName, visitor);
762       Walk(x.u, visitor);
763       visitor.Post(x);
764     }
765   }
766   template <typename M> static void Walk(UseStmt &x, M &mutator) {
767     if (mutator.Pre(x)) {
768       Walk(x.nature, mutator);
769       Walk(x.moduleName, mutator);
770       Walk(x.u, mutator);
771       mutator.Post(x);
772     }
773   }
774   template <typename V> static void Walk(const WriteStmt &x, V &visitor) {
775     if (visitor.Pre(x)) {
776       Walk(x.iounit, visitor);
777       Walk(x.format, visitor);
778       Walk(x.controls, visitor);
779       Walk(x.items, visitor);
780       visitor.Post(x);
781     }
782   }
783   template <typename M> static void Walk(WriteStmt &x, M &mutator) {
784     if (mutator.Pre(x)) {
785       Walk(x.iounit, mutator);
786       Walk(x.format, mutator);
787       Walk(x.controls, mutator);
788       Walk(x.items, mutator);
789       mutator.Post(x);
790     }
791   }
792   template <typename V>
793   static void Walk(const format::ControlEditDesc &x, V &visitor) {
794     if (visitor.Pre(x)) {
795       Walk(x.kind, visitor);
796       visitor.Post(x);
797     }
798   }
799   template <typename M>
800   static void Walk(format::ControlEditDesc &x, M &mutator) {
801     if (mutator.Pre(x)) {
802       Walk(x.kind, mutator);
803       mutator.Post(x);
804     }
805   }
806   template <typename V>
807   static void Walk(const format::DerivedTypeDataEditDesc &x, V &visitor) {
808     if (visitor.Pre(x)) {
809       Walk(x.type, visitor);
810       Walk(x.parameters, visitor);
811       visitor.Post(x);
812     }
813   }
814   template <typename M>
815   static void Walk(format::DerivedTypeDataEditDesc &x, M &mutator) {
816     if (mutator.Pre(x)) {
817       Walk(x.type, mutator);
818       Walk(x.parameters, mutator);
819       mutator.Post(x);
820     }
821   }
822   template <typename V>
823   static void Walk(const format::FormatItem &x, V &visitor) {
824     if (visitor.Pre(x)) {
825       Walk(x.repeatCount, visitor);
826       Walk(x.u, visitor);
827       visitor.Post(x);
828     }
829   }
830   template <typename M> static void Walk(format::FormatItem &x, M &mutator) {
831     if (mutator.Pre(x)) {
832       Walk(x.repeatCount, mutator);
833       Walk(x.u, mutator);
834       mutator.Post(x);
835     }
836   }
837   template <typename V>
838   static void Walk(const format::FormatSpecification &x, V &visitor) {
839     if (visitor.Pre(x)) {
840       Walk(x.items, visitor);
841       Walk(x.unlimitedItems, visitor);
842       visitor.Post(x);
843     }
844   }
845   template <typename M>
846   static void Walk(format::FormatSpecification &x, M &mutator) {
847     if (mutator.Pre(x)) {
848       Walk(x.items, mutator);
849       Walk(x.unlimitedItems, mutator);
850       mutator.Post(x);
851     }
852   }
853   template <typename V>
854   static void Walk(const format::IntrinsicTypeDataEditDesc &x, V &visitor) {
855     if (visitor.Pre(x)) {
856       Walk(x.kind, visitor);
857       Walk(x.width, visitor);
858       Walk(x.digits, visitor);
859       Walk(x.exponentWidth, visitor);
860       visitor.Post(x);
861     }
862   }
863   template <typename M>
864   static void Walk(format::IntrinsicTypeDataEditDesc &x, M &mutator) {
865     if (mutator.Pre(x)) {
866       Walk(x.kind, mutator);
867       Walk(x.width, mutator);
868       Walk(x.digits, mutator);
869       Walk(x.exponentWidth, mutator);
870       mutator.Post(x);
871     }
872   }
873   template <typename V>
874   static void Walk(const CompilerDirective &x, V &visitor) {
875     if (visitor.Pre(x)) {
876       Walk(x.source, visitor);
877       Walk(x.u, visitor);
878       visitor.Post(x);
879     }
880   }
881   template <typename M> static void Walk(CompilerDirective &x, M &mutator) {
882     if (mutator.Pre(x)) {
883       Walk(x.source, mutator);
884       Walk(x.u, mutator);
885       mutator.Post(x);
886     }
887   }
888   template <typename V>
889   static void Walk(const CompilerDirective::Unrecognized &x, V &visitor) {
890     if (visitor.Pre(x)) {
891       visitor.Post(x);
892     }
893   }
894   template <typename M>
895   static void Walk(CompilerDirective::Unrecognized &x, M &mutator) {
896     if (mutator.Pre(x)) {
897       mutator.Post(x);
898     }
899   }
900 };
901 } // namespace detail
902 
903 template <typename A, typename V> void Walk(const A &x, V &visitor) {
904   detail::ParseTreeVisitorLookupScope::Walk(x, visitor);
905 }
906 
907 template <typename A, typename M> void Walk(A &x, M &mutator) {
908   detail::ParseTreeVisitorLookupScope::Walk(x, mutator);
909 }
910 
911 } // namespace Fortran::parser
912 #endif // FORTRAN_PARSER_PARSE_TREE_VISITOR_H_
913