xref: /llvm-project/flang/include/flang/Parser/tools.h (revision 8f01ecaeb8e537511718c4df123fb92633d9f73d)
1 //===-- include/flang/Parser/tools.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_TOOLS_H_
10 #define FORTRAN_PARSER_TOOLS_H_
11 
12 #include "parse-tree.h"
13 
14 namespace Fortran::parser {
15 
16 // GetLastName() isolates and returns a reference to the rightmost Name
17 // in a variable (i.e., the Name whose symbol's type determines the type
18 // of the variable or expression).
19 const Name &GetLastName(const Name &);
20 const Name &GetLastName(const StructureComponent &);
21 const Name &GetLastName(const DataRef &);
22 const Name &GetLastName(const Substring &);
23 const Name &GetLastName(const Designator &);
24 const Name &GetLastName(const ProcComponentRef &);
25 const Name &GetLastName(const ProcedureDesignator &);
26 const Name &GetLastName(const Call &);
27 const Name &GetLastName(const FunctionReference &);
28 const Name &GetLastName(const Variable &);
29 const Name &GetLastName(const AllocateObject &);
30 
31 // GetFirstName() isolates and returns a reference to the leftmost Name
32 // in a variable or entity declaration.
33 const Name &GetFirstName(const Name &);
34 const Name &GetFirstName(const StructureComponent &);
35 const Name &GetFirstName(const DataRef &);
36 const Name &GetFirstName(const Substring &);
37 const Name &GetFirstName(const Designator &);
38 const Name &GetFirstName(const ProcComponentRef &);
39 const Name &GetFirstName(const ProcedureDesignator &);
40 const Name &GetFirstName(const Call &);
41 const Name &GetFirstName(const FunctionReference &);
42 const Name &GetFirstName(const Variable &);
43 const Name &GetFirstName(const EntityDecl &);
44 
45 // When a parse tree node is an instance of a specific type wrapped in
46 // layers of packaging, return a pointer to that object.
47 // Implemented with mutually recursive template functions that are
48 // wrapped in a struct to avoid prototypes.
49 struct UnwrapperHelper {
50 
UnwrapUnwrapperHelper51   template <typename A, typename B> static const A *Unwrap(B *p) {
52     if (p) {
53       return Unwrap<A>(*p);
54     } else {
55       return nullptr;
56     }
57   }
58 
59   template <typename A, typename B, bool COPY>
UnwrapUnwrapperHelper60   static const A *Unwrap(const common::Indirection<B, COPY> &x) {
61     return Unwrap<A>(x.value());
62   }
63 
64   template <typename A, typename... Bs>
UnwrapUnwrapperHelper65   static const A *Unwrap(const std::variant<Bs...> &x) {
66     return common::visit([](const auto &y) { return Unwrap<A>(y); }, x);
67   }
68 
69   template <typename A, std::size_t J = 0, typename... Bs>
UnwrapUnwrapperHelper70   static const A *Unwrap(const std::tuple<Bs...> &x) {
71     if constexpr (J < sizeof...(Bs)) {
72       if (auto result{Unwrap<A>(std::get<J>(x))}) {
73         return result;
74       }
75       return Unwrap<A, (J + 1)>(x);
76     } else {
77       return nullptr;
78     }
79   }
80 
81   template <typename A, typename B>
UnwrapUnwrapperHelper82   static const A *Unwrap(const std::optional<B> &o) {
83     if (o) {
84       return Unwrap<A>(*o);
85     } else {
86       return nullptr;
87     }
88   }
89 
90   template <typename A, typename B>
UnwrapUnwrapperHelper91   static const A *Unwrap(const UnlabeledStatement<B> &x) {
92     return Unwrap<A>(x.statement);
93   }
94   template <typename A, typename B>
UnwrapUnwrapperHelper95   static const A *Unwrap(const Statement<B> &x) {
96     return Unwrap<A>(x.statement);
97   }
98 
UnwrapUnwrapperHelper99   template <typename A, typename B> static const A *Unwrap(B &x) {
100     if constexpr (std::is_same_v<std::decay_t<A>, std::decay_t<B>>) {
101       return &x;
102     } else if constexpr (ConstraintTrait<B>) {
103       return Unwrap<A>(x.thing);
104     } else if constexpr (WrapperTrait<B>) {
105       return Unwrap<A>(x.v);
106     } else if constexpr (UnionTrait<B>) {
107       return Unwrap<A>(x.u);
108     } else {
109       return nullptr;
110     }
111   }
112 };
113 
Unwrap(const B & x)114 template <typename A, typename B> const A *Unwrap(const B &x) {
115   return UnwrapperHelper::Unwrap<A>(x);
116 }
Unwrap(B & x)117 template <typename A, typename B> A *Unwrap(B &x) {
118   return const_cast<A *>(Unwrap<A, B>(const_cast<const B &>(x)));
119 }
120 
121 // Get the CoindexedNamedObject if the entity is a coindexed object.
122 const CoindexedNamedObject *GetCoindexedNamedObject(const AllocateObject &);
123 const CoindexedNamedObject *GetCoindexedNamedObject(const DataRef &);
124 const CoindexedNamedObject *GetCoindexedNamedObject(const Designator &);
125 const CoindexedNamedObject *GetCoindexedNamedObject(const Variable &);
126 
127 // Detects parse tree nodes with "source" members.
128 template <typename A, typename = int> struct HasSource : std::false_type {};
129 template <typename A>
130 struct HasSource<A, decltype(static_cast<void>(A::source), 0)>
131     : std::true_type {};
132 
133 // Detects parse tree nodes with "typedExpr" members.
134 template <typename A, typename = int> struct HasTypedExpr : std::false_type {};
135 template <typename A>
136 struct HasTypedExpr<A, decltype(static_cast<void>(A::typedExpr), 0)>
137     : std::true_type {};
138 
139 // GetSource()
140 
141 template <bool GET_FIRST> struct GetSourceHelper {
142 
143   using Result = std::optional<CharBlock>;
144 
145   template <typename A> static Result GetSource(A *p) {
146     if (p) {
147       return GetSource(*p);
148     } else {
149       return std::nullopt;
150     }
151   }
152   template <typename A>
153   static Result GetSource(const common::Indirection<A> &x) {
154     return GetSource(x.value());
155   }
156 
157   template <typename A, bool COPY>
158   static Result GetSource(const common::Indirection<A, COPY> &x) {
159     return GetSource(x.value());
160   }
161 
162   template <typename... As>
163   static Result GetSource(const std::variant<As...> &x) {
164     return common::visit([](const auto &y) { return GetSource(y); }, x);
165   }
166 
167   template <std::size_t J = 0, typename... As>
168   static Result GetSource(const std::tuple<As...> &x) {
169     if constexpr (J < sizeof...(As)) {
170       constexpr std::size_t index{GET_FIRST ? J : sizeof...(As) - J - 1};
171       if (auto result{GetSource(std::get<index>(x))}) {
172         return result;
173       }
174       return GetSource<(J + 1)>(x);
175     } else {
176       return {};
177     }
178   }
179 
180   template <typename A> static Result GetSource(const std::optional<A> &o) {
181     if (o) {
182       return GetSource(*o);
183     } else {
184       return {};
185     }
186   }
187 
188   template <typename A> static Result GetSource(const std::list<A> &x) {
189     if constexpr (GET_FIRST) {
190       for (const A &y : x) {
191         if (auto result{GetSource(y)}) {
192           return result;
193         }
194       }
195     } else {
196       for (auto iter{x.rbegin()}; iter != x.rend(); ++iter) {
197         if (auto result{GetSource(*iter)}) {
198           return result;
199         }
200       }
201     }
202     return {};
203   }
204 
205   template <typename A> static Result GetSource(const std::vector<A> &x) {
206     if constexpr (GET_FIRST) {
207       for (const A &y : x) {
208         if (auto result{GetSource(y)}) {
209           return result;
210         }
211       }
212     } else {
213       for (auto iter{x.rbegin()}; iter != x.rend(); ++iter) {
214         if (auto result{GetSource(*iter)}) {
215           return result;
216         }
217       }
218     }
219     return {};
220   }
221 
222   template <typename A> static Result GetSource(A &x) {
223     if constexpr (HasSource<A>::value) {
224       return x.source;
225     } else if constexpr (ConstraintTrait<A>) {
226       return GetSource(x.thing);
227     } else if constexpr (WrapperTrait<A>) {
228       return GetSource(x.v);
229     } else if constexpr (UnionTrait<A>) {
230       return GetSource(x.u);
231     } else if constexpr (TupleTrait<A>) {
232       return GetSource(x.t);
233     } else {
234       return {};
235     }
236   }
237 };
238 
239 template <typename A> std::optional<CharBlock> GetSource(const A &x) {
240   return GetSourceHelper<true>::GetSource(x);
241 }
242 template <typename A> std::optional<CharBlock> GetSource(A &x) {
243   return GetSourceHelper<true>::GetSource(const_cast<const A &>(x));
244 }
245 
246 template <typename A> std::optional<CharBlock> GetLastSource(const A &x) {
247   return GetSourceHelper<false>::GetSource(x);
248 }
249 template <typename A> std::optional<CharBlock> GetLastSource(A &x) {
250   return GetSourceHelper<false>::GetSource(const_cast<const A &>(x));
251 }
252 
253 } // namespace Fortran::parser
254 #endif // FORTRAN_PARSER_TOOLS_H_
255