//===-- include/flang/Parser/parse-tree-visitor.h ---------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef FORTRAN_PARSER_PARSE_TREE_VISITOR_H_ #define FORTRAN_PARSER_PARSE_TREE_VISITOR_H_ #include "parse-tree.h" #include "flang/Common/visit.h" #include #include #include #include #include #include /// Parse tree visitor /// Call Walk(x, visitor) to visit x and, by default, each node under x. /// If x is non-const, the visitor member functions can modify the tree. /// /// visitor.Pre(x) is called before visiting x and its children are not /// visited if it returns false. /// /// visitor.Post(x) is called after visiting x. namespace Fortran::parser { // Default case for visitation of non-class data members, strings, and // any other non-decomposable values. template std::enable_if_t || std::is_same_v || std::is_same_v> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { visitor.Post(x); } } template std::enable_if_t || std::is_same_v || std::is_same_v> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { mutator.Post(x); } } template void Walk(const format::ControlEditDesc &, V &); template void Walk(format::ControlEditDesc &, M &); template void Walk(const format::DerivedTypeDataEditDesc &, V &); template void Walk(format::DerivedTypeDataEditDesc &, M &); template void Walk(const format::FormatItem &, V &); template void Walk(format::FormatItem &, M &); template void Walk(const format::FormatSpecification &, V &); template void Walk(format::FormatSpecification &, M &); template void Walk(const format::IntrinsicTypeDataEditDesc &, V &); template void Walk(format::IntrinsicTypeDataEditDesc &, M &); // Traversal of needed STL template classes (optional, list, tuple, variant) // For most lists, just traverse the elements; but when a list constitutes // a Block (i.e., std::list), also invoke the // visitor/mutator on the list itself. template void Walk(const std::list &x, V &visitor) { for (const auto &elem : x) { Walk(elem, visitor); } } template void Walk(std::list &x, M &mutator) { for (auto &elem : x) { Walk(elem, mutator); } } template void Walk(const Block &x, V &visitor) { if (visitor.Pre(x)) { for (const auto &elem : x) { Walk(elem, visitor); } visitor.Post(x); } } template void Walk(Block &x, M &mutator) { if (mutator.Pre(x)) { for (auto &elem : x) { Walk(elem, mutator); } mutator.Post(x); } } template void Walk(const std::optional &x, V &visitor) { if (x) { Walk(*x, visitor); } } template void Walk(std::optional &x, M &mutator) { if (x) { Walk(*x, mutator); } } template void ForEachInTuple(const T &tuple, Func func) { func(std::get(tuple)); if constexpr (I + 1 < std::tuple_size_v) { ForEachInTuple(tuple, func); } } template void Walk(const std::tuple &x, V &visitor) { if (sizeof...(A) > 0) { if (visitor.Pre(x)) { ForEachInTuple(x, [&](const auto &y) { Walk(y, visitor); }); visitor.Post(x); } } } template void ForEachInTuple(T &tuple, Func func) { func(std::get(tuple)); if constexpr (I + 1 < std::tuple_size_v) { ForEachInTuple(tuple, func); } } template void Walk(std::tuple &x, M &mutator) { if (sizeof...(A) > 0) { if (mutator.Pre(x)) { ForEachInTuple(x, [&](auto &y) { Walk(y, mutator); }); mutator.Post(x); } } } template void Walk(const std::variant &x, V &visitor) { if (visitor.Pre(x)) { common::visit([&](const auto &y) { Walk(y, visitor); }, x); visitor.Post(x); } } template void Walk(std::variant &x, M &mutator) { if (mutator.Pre(x)) { common::visit([&](auto &y) { Walk(y, mutator); }, x); mutator.Post(x); } } template void Walk(const std::pair &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.first, visitor); Walk(x.second, visitor); } } template void Walk(std::pair &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.first, mutator); Walk(x.second, mutator); } } // Trait-determined traversal of empty, tuple, union, wrapper, // and constraint-checking classes. template std::enable_if_t> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { visitor.Post(x); } } template std::enable_if_t> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { mutator.Post(x); } } template std::enable_if_t> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.t, visitor); visitor.Post(x); } } template std::enable_if_t> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.t, mutator); mutator.Post(x); } } template std::enable_if_t> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.u, visitor); visitor.Post(x); } } template std::enable_if_t> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.u, mutator); mutator.Post(x); } } template std::enable_if_t> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.v, visitor); visitor.Post(x); } } template std::enable_if_t> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.v, mutator); mutator.Post(x); } } template std::enable_if_t> Walk(const A &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.thing, visitor); visitor.Post(x); } } template std::enable_if_t> Walk(A &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.thing, mutator); mutator.Post(x); } } template void Walk(const common::Indirection &x, V &visitor) { Walk(x.value(), visitor); } template void Walk(common::Indirection &x, M &mutator) { Walk(x.value(), mutator); } template void Walk(const Statement &x, V &visitor) { if (visitor.Pre(x)) { // N.B. The label, if any, is not visited. Walk(x.source, visitor); Walk(x.statement, visitor); visitor.Post(x); } } template void Walk(Statement &x, M &mutator) { if (mutator.Pre(x)) { // N.B. The label, if any, is not visited. Walk(x.source, mutator); Walk(x.statement, mutator); mutator.Post(x); } } template void Walk(const UnlabeledStatement &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.statement, visitor); visitor.Post(x); } } template void Walk(UnlabeledStatement &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.statement, mutator); mutator.Post(x); } } template void Walk(const Name &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); visitor.Post(x); } } template void Walk(Name &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); mutator.Post(x); } } template void Walk(const AcSpec &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.type, visitor); Walk(x.values, visitor); visitor.Post(x); } } template void Walk(AcSpec &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.type, mutator); Walk(x.values, mutator); mutator.Post(x); } } template void Walk(const ArrayElement &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.base, visitor); Walk(x.subscripts, visitor); visitor.Post(x); } } template void Walk(ArrayElement &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.base, mutator); Walk(x.subscripts, mutator); mutator.Post(x); } } template void Walk(const CharSelector::LengthAndKind &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.length, visitor); Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(CharSelector::LengthAndKind &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.length, mutator); Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const CaseValueRange::Range &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.lower, visitor); Walk(x.upper, visitor); visitor.Post(x); } } template void Walk(CaseValueRange::Range &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.lower, mutator); Walk(x.upper, mutator); mutator.Post(x); } } template void Walk(const CoindexedNamedObject &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.base, visitor); Walk(x.imageSelector, visitor); visitor.Post(x); } } template void Walk(CoindexedNamedObject &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.base, mutator); Walk(x.imageSelector, mutator); mutator.Post(x); } } template void Walk(const DeclarationTypeSpec::Class &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.derived, visitor); visitor.Post(x); } } template void Walk(DeclarationTypeSpec::Class &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.derived, mutator); mutator.Post(x); } } template void Walk(const DeclarationTypeSpec::Type &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.derived, visitor); visitor.Post(x); } } template void Walk(DeclarationTypeSpec::Type &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.derived, mutator); mutator.Post(x); } } template void Walk(const ImportStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.names, visitor); visitor.Post(x); } } template void Walk(ImportStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.names, mutator); mutator.Post(x); } } template void Walk(const IntrinsicTypeSpec::Character &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.selector, visitor); visitor.Post(x); } } template void Walk(IntrinsicTypeSpec::Character &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.selector, mutator); mutator.Post(x); } } template void Walk(const IntrinsicTypeSpec::Complex &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(IntrinsicTypeSpec::Complex &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const IntrinsicTypeSpec::Logical &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(IntrinsicTypeSpec::Logical &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const IntrinsicTypeSpec::Real &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(IntrinsicTypeSpec::Real &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const LoopBounds &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.name, visitor); Walk(x.lower, visitor); Walk(x.upper, visitor); Walk(x.step, visitor); visitor.Post(x); } } template void Walk(LoopBounds &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.name, mutator); Walk(x.lower, mutator); Walk(x.upper, mutator); Walk(x.step, mutator); mutator.Post(x); } } template void Walk(const CommonStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.blocks, visitor); visitor.Post(x); } } template void Walk(CommonStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.blocks, mutator); mutator.Post(x); } } // Expr traversal uses iteration rather than recursion to avoid // blowing out the stack on very deep expression parse trees. // It replaces implementations that looked like: // template void Walk(const Expr &x, V visitor) { // if (visitor.Pre(x)) { // Pre on the Expr // Walk(x.source, visitor); // // Pre on the operator, walk the operands, Post on operator // Walk(x.u, visitor); // visitor.Post(x); // Post on the Expr // } // } template static void IterativeWalk(A &start, V &visitor) { struct ExprWorkList { ExprWorkList(A &x) : expr(&x) {} bool doPostExpr{false}, doPostOpr{false}; A *expr; }; std::vector stack; stack.emplace_back(start); do { A &expr{*stack.back().expr}; if (stack.back().doPostOpr) { stack.back().doPostOpr = false; common::visit([&visitor](auto &y) { visitor.Post(y); }, expr.u); } else if (stack.back().doPostExpr) { visitor.Post(expr); stack.pop_back(); } else if (!visitor.Pre(expr)) { stack.pop_back(); } else { stack.back().doPostExpr = true; Walk(expr.source, visitor); UNARY *unary{nullptr}; BINARY *binary{nullptr}; common::visit( [&unary, &binary](auto &y) { if constexpr (std::is_convertible_v) { unary = &y; } else if constexpr (std::is_convertible_v) { binary = &y; } }, expr.u); if (!unary && !binary) { Walk(expr.u, visitor); } else if (common::visit( [&visitor](auto &y) { return visitor.Pre(y); }, expr.u)) { stack.back().doPostOpr = true; if (unary) { stack.emplace_back(unary->v.value()); } else { stack.emplace_back(std::get<1>(binary->t).value()); stack.emplace_back(std::get<0>(binary->t).value()); } } } } while (!stack.empty()); } template void Walk(const Expr &x, V &visitor) { IterativeWalk(x, visitor); } template void Walk(Expr &x, M &mutator) { IterativeWalk( x, mutator); } template void Walk(const Designator &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.u, visitor); visitor.Post(x); } } template void Walk(Designator &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.u, mutator); mutator.Post(x); } } template void Walk(const FunctionReference &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.v, visitor); visitor.Post(x); } } template void Walk(FunctionReference &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.v, mutator); mutator.Post(x); } } template void Walk(const CallStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.call, visitor); Walk(x.chevrons, visitor); visitor.Post(x); } } template void Walk(CallStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.call, mutator); Walk(x.chevrons, mutator); mutator.Post(x); } } template void Walk(const PartRef &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.name, visitor); Walk(x.subscripts, visitor); Walk(x.imageSelector, visitor); visitor.Post(x); } } template void Walk(PartRef &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.name, mutator); Walk(x.subscripts, mutator); Walk(x.imageSelector, mutator); mutator.Post(x); } } template void Walk(const ReadStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.iounit, visitor); Walk(x.format, visitor); Walk(x.controls, visitor); Walk(x.items, visitor); visitor.Post(x); } } template void Walk(ReadStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.iounit, mutator); Walk(x.format, mutator); Walk(x.controls, mutator); Walk(x.items, mutator); mutator.Post(x); } } template void Walk(const SignedIntLiteralConstant &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.t, visitor); visitor.Post(x); } } template void Walk(SignedIntLiteralConstant &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.t, mutator); mutator.Post(x); } } template void Walk(const RealLiteralConstant &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.real, visitor); Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(RealLiteralConstant &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.real, mutator); Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const RealLiteralConstant::Real &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); visitor.Post(x); } } template void Walk(RealLiteralConstant::Real &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); mutator.Post(x); } } template void Walk(const StructureComponent &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.base, visitor); Walk(x.component, visitor); visitor.Post(x); } } template void Walk(StructureComponent &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.base, mutator); Walk(x.component, mutator); mutator.Post(x); } } template void Walk(const Suffix &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.binding, visitor); Walk(x.resultName, visitor); visitor.Post(x); } } template void Walk(Suffix &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.binding, mutator); Walk(x.resultName, mutator); mutator.Post(x); } } template void Walk(const TypeBoundProcedureStmt::WithInterface &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.interfaceName, visitor); Walk(x.attributes, visitor); Walk(x.bindingNames, visitor); visitor.Post(x); } } template void Walk(TypeBoundProcedureStmt::WithInterface &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.interfaceName, mutator); Walk(x.attributes, mutator); Walk(x.bindingNames, mutator); mutator.Post(x); } } template void Walk(const TypeBoundProcedureStmt::WithoutInterface &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.attributes, visitor); Walk(x.declarations, visitor); visitor.Post(x); } } template void Walk(TypeBoundProcedureStmt::WithoutInterface &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.attributes, mutator); Walk(x.declarations, mutator); mutator.Post(x); } } template void Walk(const UseStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.nature, visitor); Walk(x.moduleName, visitor); Walk(x.u, visitor); visitor.Post(x); } } template void Walk(UseStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.nature, mutator); Walk(x.moduleName, mutator); Walk(x.u, mutator); mutator.Post(x); } } template void Walk(const WriteStmt &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.iounit, visitor); Walk(x.format, visitor); Walk(x.controls, visitor); Walk(x.items, visitor); visitor.Post(x); } } template void Walk(WriteStmt &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.iounit, mutator); Walk(x.format, mutator); Walk(x.controls, mutator); Walk(x.items, mutator); mutator.Post(x); } } template void Walk(const format::ControlEditDesc &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.kind, visitor); visitor.Post(x); } } template void Walk(format::ControlEditDesc &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.kind, mutator); mutator.Post(x); } } template void Walk(const format::DerivedTypeDataEditDesc &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.type, visitor); Walk(x.parameters, visitor); visitor.Post(x); } } template void Walk(format::DerivedTypeDataEditDesc &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.type, mutator); Walk(x.parameters, mutator); mutator.Post(x); } } template void Walk(const format::FormatItem &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.repeatCount, visitor); Walk(x.u, visitor); visitor.Post(x); } } template void Walk(format::FormatItem &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.repeatCount, mutator); Walk(x.u, mutator); mutator.Post(x); } } template void Walk(const format::FormatSpecification &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.items, visitor); Walk(x.unlimitedItems, visitor); visitor.Post(x); } } template void Walk(format::FormatSpecification &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.items, mutator); Walk(x.unlimitedItems, mutator); mutator.Post(x); } } template void Walk(const format::IntrinsicTypeDataEditDesc &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.kind, visitor); Walk(x.width, visitor); Walk(x.digits, visitor); Walk(x.exponentWidth, visitor); visitor.Post(x); } } template void Walk(format::IntrinsicTypeDataEditDesc &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.kind, mutator); Walk(x.width, mutator); Walk(x.digits, mutator); Walk(x.exponentWidth, mutator); mutator.Post(x); } } template void Walk(const CompilerDirective &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.source, visitor); Walk(x.u, visitor); visitor.Post(x); } } template void Walk(CompilerDirective &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.source, mutator); Walk(x.u, mutator); mutator.Post(x); } } template void Walk(const OmpLinearClause::WithModifier &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.modifier, visitor); Walk(x.names, visitor); Walk(x.step, visitor); visitor.Post(x); } } template void Walk(OmpLinearClause::WithModifier &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.modifier, mutator); Walk(x.names, mutator); Walk(x.step, mutator); mutator.Post(x); } } template void Walk(const OmpLinearClause::WithoutModifier &x, V &visitor) { if (visitor.Pre(x)) { Walk(x.names, visitor); Walk(x.step, visitor); visitor.Post(x); } } template void Walk(OmpLinearClause::WithoutModifier &x, M &mutator) { if (mutator.Pre(x)) { Walk(x.names, mutator); Walk(x.step, mutator); mutator.Post(x); } } } // namespace Fortran::parser #endif // FORTRAN_PARSER_PARSE_TREE_VISITOR_H_