| //===-- lib/Parser/basic-parsers.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_BASIC_PARSERS_H_ | 
 | #define FORTRAN_PARSER_BASIC_PARSERS_H_ | 
 |  | 
 | // Let a "parser" be an instance of any class that supports this | 
 | // type definition and member (or static) function: | 
 | // | 
 | //   using resultType = ...; | 
 | //   std::optional<resultType> Parse(ParseState &) const; | 
 | // | 
 | // which either returns a value to signify a successful recognition or else | 
 | // returns {} to signify failure.  On failure, the state cannot be assumed | 
 | // to still be valid, in general -- see below for exceptions. | 
 | // | 
 | // This header defines the fundamental parser class templates and helper | 
 | // template functions.  See parser-combinators.txt for documentation. | 
 |  | 
 | #include "flang/Common/Fortran-features.h" | 
 | #include "flang/Common/idioms.h" | 
 | #include "flang/Common/indirection.h" | 
 | #include "flang/Parser/char-block.h" | 
 | #include "flang/Parser/message.h" | 
 | #include "flang/Parser/parse-state.h" | 
 | #include "flang/Parser/provenance.h" | 
 | #include "flang/Parser/user-state.h" | 
 | #include <cstring> | 
 | #include <functional> | 
 | #include <list> | 
 | #include <memory> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <tuple> | 
 | #include <type_traits> | 
 | #include <utility> | 
 |  | 
 | namespace Fortran::parser { | 
 |  | 
 | // fail<A>("..."_err_en_US) returns a parser that never succeeds.  It reports an | 
 | // error message at the current position.  The result type is unused, | 
 | // but might have to be specified at the point of call to satisfy | 
 | // the type checker.  The state remains valid. | 
 | template <typename A> class FailParser { | 
 | public: | 
 |   using resultType = A; | 
 |   constexpr FailParser(const FailParser &) = default; | 
 |   constexpr explicit FailParser(MessageFixedText t) : text_{t} {} | 
 |   std::optional<A> Parse(ParseState &state) const { | 
 |     state.Say(text_); | 
 |     return std::nullopt; | 
 |   } | 
 |  | 
 | private: | 
 |   const MessageFixedText text_; | 
 | }; | 
 |  | 
 | template <typename A = Success> inline constexpr auto fail(MessageFixedText t) { | 
 |   return FailParser<A>{t}; | 
 | } | 
 |  | 
 | // pure(x) returns a parser that always succeeds, does not advance the | 
 | // parse, and returns a captured value x whose type must be copy-constructible. | 
 | // | 
 | // pure<A>() is essentially pure(A{}); it returns a default-constructed A{}, | 
 | // and works even when A is not copy-constructible. | 
 | template <typename A> class PureParser { | 
 | public: | 
 |   using resultType = A; | 
 |   constexpr PureParser(const PureParser &) = default; | 
 |   constexpr explicit PureParser(A &&x) : value_(std::move(x)) {} | 
 |   std::optional<A> Parse(ParseState &) const { return value_; } | 
 |  | 
 | private: | 
 |   const A value_; | 
 | }; | 
 |  | 
 | template <typename A> inline constexpr auto pure(A x) { | 
 |   return PureParser<A>(std::move(x)); | 
 | } | 
 |  | 
 | template <typename A> class PureDefaultParser { | 
 | public: | 
 |   using resultType = A; | 
 |   constexpr PureDefaultParser(const PureDefaultParser &) = default; | 
 |   constexpr PureDefaultParser() {} | 
 |   std::optional<A> Parse(ParseState &) const { return std::make_optional<A>(); } | 
 | }; | 
 |  | 
 | template <typename A> inline constexpr auto pure() { | 
 |   return PureDefaultParser<A>(); | 
 | } | 
 |  | 
 | // If a is a parser, attempt(a) is the same parser, but on failure | 
 | // the ParseState is guaranteed to have been restored to its initial value. | 
 | template <typename A> class BacktrackingParser { | 
 | public: | 
 |   using resultType = typename A::resultType; | 
 |   constexpr BacktrackingParser(const BacktrackingParser &) = default; | 
 |   constexpr BacktrackingParser(const A &parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     Messages messages{std::move(state.messages())}; | 
 |     ParseState backtrack{state}; | 
 |     std::optional<resultType> result{parser_.Parse(state)}; | 
 |     if (result) { | 
 |       state.messages().Restore(std::move(messages)); | 
 |     } else { | 
 |       state = std::move(backtrack); | 
 |       state.messages() = std::move(messages); | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const A parser_; | 
 | }; | 
 |  | 
 | template <typename A> inline constexpr auto attempt(const A &parser) { | 
 |   return BacktrackingParser<A>{parser}; | 
 | } | 
 |  | 
 | // For any parser x, the parser returned by !x is one that succeeds when | 
 | // x fails, returning a useless (but present) result.  !x fails when x succeeds. | 
 | template <typename PA> class NegatedParser { | 
 | public: | 
 |   using resultType = Success; | 
 |   constexpr NegatedParser(const NegatedParser &) = default; | 
 |   constexpr NegatedParser(PA p) : parser_{p} {} | 
 |   std::optional<Success> Parse(ParseState &state) const { | 
 |     ParseState forked{state}; | 
 |     forked.set_deferMessages(true); | 
 |     if (parser_.Parse(forked)) { | 
 |       return std::nullopt; | 
 |     } | 
 |     return Success{}; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA, typename = typename PA::resultType> | 
 | constexpr auto operator!(PA p) { | 
 |   return NegatedParser<PA>(p); | 
 | } | 
 |  | 
 | // For any parser x, the parser returned by lookAhead(x) is one that succeeds | 
 | // or fails if x does, but the state is not modified. | 
 | template <typename PA> class LookAheadParser { | 
 | public: | 
 |   using resultType = Success; | 
 |   constexpr LookAheadParser(const LookAheadParser &) = default; | 
 |   constexpr LookAheadParser(PA p) : parser_{p} {} | 
 |   std::optional<Success> Parse(ParseState &state) const { | 
 |     ParseState forked{state}; | 
 |     forked.set_deferMessages(true); | 
 |     if (parser_.Parse(forked)) { | 
 |       return Success{}; | 
 |     } | 
 |     return std::nullopt; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto lookAhead(PA p) { | 
 |   return LookAheadParser<PA>{p}; | 
 | } | 
 |  | 
 | // If a is a parser, inContext("..."_en_US, a) runs it in a nested message | 
 | // context. | 
 | template <typename PA> class MessageContextParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr MessageContextParser(const MessageContextParser &) = default; | 
 |   constexpr MessageContextParser(MessageFixedText t, PA p) | 
 |       : text_{t}, parser_{p} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     state.PushContext(text_); | 
 |     std::optional<resultType> result{parser_.Parse(state)}; | 
 |     state.PopContext(); | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const MessageFixedText text_; | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> | 
 | inline constexpr auto inContext(MessageFixedText context, PA parser) { | 
 |   return MessageContextParser{context, parser}; | 
 | } | 
 |  | 
 | // If a is a parser, withMessage("..."_en_US, a) runs it unchanged if it | 
 | // succeeds, and overrides its messages with a specific one if it fails and | 
 | // has matched no tokens. | 
 | template <typename PA> class WithMessageParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr WithMessageParser(const WithMessageParser &) = default; | 
 |   constexpr WithMessageParser(MessageFixedText t, PA p) | 
 |       : text_{t}, parser_{p} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     Messages messages{std::move(state.messages())}; | 
 |     ParseState backtrack{state}; | 
 |     state.set_anyTokenMatched(false); | 
 |     std::optional<resultType> result{parser_.Parse(state)}; | 
 |     bool emitMessage{false}; | 
 |     if (result) { | 
 |       messages.Annex(std::move(state.messages())); | 
 |       if (backtrack.anyTokenMatched()) { | 
 |         state.set_anyTokenMatched(); | 
 |       } | 
 |     } else if (state.anyTokenMatched()) { | 
 |       emitMessage = state.messages().empty(); | 
 |       messages.Annex(std::move(state.messages())); | 
 |       backtrack.set_anyTokenMatched(); | 
 |       if (state.anyDeferredMessages()) { | 
 |         backtrack.set_anyDeferredMessages(true); | 
 |       } | 
 |       state = std::move(backtrack); | 
 |     } else { | 
 |       emitMessage = true; | 
 |     } | 
 |     state.messages() = std::move(messages); | 
 |     if (emitMessage) { | 
 |       state.Say(text_); | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const MessageFixedText text_; | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> | 
 | inline constexpr auto withMessage(MessageFixedText msg, PA parser) { | 
 |   return WithMessageParser{msg, parser}; | 
 | } | 
 |  | 
 | // If a and b are parsers, then a >> b returns a parser that succeeds when | 
 | // b succeeds after a does so, but fails when either a or b does.  The | 
 | // result is taken from b.  Similarly, a / b also succeeds if both a and b | 
 | // do so, but the result is that returned by a. | 
 | template <typename PA, typename PB> class SequenceParser { | 
 | public: | 
 |   using resultType = typename PB::resultType; | 
 |   constexpr SequenceParser(const SequenceParser &) = default; | 
 |   constexpr SequenceParser(PA pa, PB pb) : pa_{pa}, pb2_{pb} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if (pa_.Parse(state)) { | 
 |       return pb2_.Parse(state); | 
 |     } else { | 
 |       return std::nullopt; | 
 |     } | 
 |   } | 
 |  | 
 | private: | 
 |   const PA pa_; | 
 |   const PB pb2_; | 
 | }; | 
 |  | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto operator>>(PA pa, PB pb) { | 
 |   return SequenceParser<PA, PB>{pa, pb}; | 
 | } | 
 |  | 
 | template <typename PA, typename PB> class FollowParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr FollowParser(const FollowParser &) = default; | 
 |   constexpr FollowParser(PA pa, PB pb) : pa_{pa}, pb_{pb} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if (std::optional<resultType> ax{pa_.Parse(state)}) { | 
 |       if (pb_.Parse(state)) { | 
 |         return ax; | 
 |       } | 
 |     } | 
 |     return std::nullopt; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA pa_; | 
 |   const PB pb_; | 
 | }; | 
 |  | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto operator/(PA pa, PB pb) { | 
 |   return FollowParser<PA, PB>{pa, pb}; | 
 | } | 
 |  | 
 | template <typename PA, typename... Ps> class AlternativesParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr AlternativesParser(PA pa, Ps... ps) : ps_{pa, ps...} {} | 
 |   constexpr AlternativesParser(const AlternativesParser &) = default; | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     Messages messages{std::move(state.messages())}; | 
 |     ParseState backtrack{state}; | 
 |     std::optional<resultType> result{std::get<0>(ps_).Parse(state)}; | 
 |     if constexpr (sizeof...(Ps) > 0) { | 
 |       if (!result) { | 
 |         ParseRest<1>(result, state, backtrack); | 
 |       } | 
 |     } | 
 |     state.messages().Restore(std::move(messages)); | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   template <int J> | 
 |   void ParseRest(std::optional<resultType> &result, ParseState &state, | 
 |       ParseState &backtrack) const { | 
 |     ParseState prevState{std::move(state)}; | 
 |     state = backtrack; | 
 |     result = std::get<J>(ps_).Parse(state); | 
 |     if (!result) { | 
 |       state.CombineFailedParses(std::move(prevState)); | 
 |       if constexpr (J < sizeof...(Ps)) { | 
 |         ParseRest<J + 1>(result, state, backtrack); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   const std::tuple<PA, Ps...> ps_; | 
 | }; | 
 |  | 
 | template <typename... Ps> inline constexpr auto first(Ps... ps) { | 
 |   return AlternativesParser<Ps...>{ps...}; | 
 | } | 
 |  | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto operator||(PA pa, PB pb) { | 
 |   return AlternativesParser<PA, PB>{pa, pb}; | 
 | } | 
 |  | 
 | // If a and b are parsers, then recovery(a,b) returns a parser that succeeds if | 
 | // a does so, or if a fails and b succeeds.  If a succeeds, b is not attempted. | 
 | // All messages from the first parse are retained. | 
 | // The two parsers must return values of the same type. | 
 | template <typename PA, typename PB> class RecoveryParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   static_assert(std::is_same_v<resultType, typename PB::resultType>); | 
 |   constexpr RecoveryParser(const RecoveryParser &) = default; | 
 |   constexpr RecoveryParser(PA pa, PB pb) : pa_{pa}, pb3_{pb} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     bool originallyDeferred{state.deferMessages()}; | 
 |     ParseState backtrack{state}; | 
 |     if (!originallyDeferred && state.messages().empty() && | 
 |         !state.anyErrorRecovery()) { | 
 |       // Fast path.  There are no messages or recovered errors in the incoming | 
 |       // state.  Attempt to parse with messages deferred, expecting that the | 
 |       // parse will succeed silently. | 
 |       state.set_deferMessages(true); | 
 |       if (std::optional<resultType> ax{pa_.Parse(state)}) { | 
 |         if (!state.anyDeferredMessages() && !state.anyErrorRecovery()) { | 
 |           state.set_deferMessages(false); | 
 |           return ax; | 
 |         } | 
 |       } | 
 |       state = backtrack; | 
 |     } | 
 |     Messages messages{std::move(state.messages())}; | 
 |     if (std::optional<resultType> ax{pa_.Parse(state)}) { | 
 |       state.messages().Restore(std::move(messages)); | 
 |       return ax; | 
 |     } | 
 |     messages.Annex(std::move(state.messages())); | 
 |     bool hadDeferredMessages{state.anyDeferredMessages()}; | 
 |     bool anyTokenMatched{state.anyTokenMatched()}; | 
 |     state = std::move(backtrack); | 
 |     state.set_deferMessages(true); | 
 |     std::optional<resultType> bx{pb3_.Parse(state)}; | 
 |     state.messages() = std::move(messages); | 
 |     state.set_deferMessages(originallyDeferred); | 
 |     if (anyTokenMatched) { | 
 |       state.set_anyTokenMatched(); | 
 |     } | 
 |     if (hadDeferredMessages) { | 
 |       state.set_anyDeferredMessages(); | 
 |     } | 
 |     if (bx) { | 
 |       // Error recovery situations must also produce messages. | 
 |       CHECK(state.anyDeferredMessages() || state.messages().AnyFatalError()); | 
 |       state.set_anyErrorRecovery(); | 
 |     } | 
 |     return bx; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA pa_; | 
 |   const PB pb3_; | 
 | }; | 
 |  | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto recovery(PA pa, PB pb) { | 
 |   return RecoveryParser<PA, PB>{pa, pb}; | 
 | } | 
 |  | 
 | // If x is a parser, then many(x) returns a parser that always succeeds | 
 | // and whose value is a list, possibly empty, of the values returned from | 
 | // repeated application of x until it fails or does not advance the parse. | 
 | template <typename PA> class ManyParser { | 
 |   using paType = typename PA::resultType; | 
 |  | 
 | public: | 
 |   using resultType = std::list<paType>; | 
 |   constexpr ManyParser(const ManyParser &) = default; | 
 |   constexpr ManyParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     resultType result; | 
 |     auto at{state.GetLocation()}; | 
 |     while (std::optional<paType> x{parser_.Parse(state)}) { | 
 |       result.emplace_back(std::move(*x)); | 
 |       if (state.GetLocation() <= at) { | 
 |         break; // no forward progress, don't loop | 
 |       } | 
 |       at = state.GetLocation(); | 
 |     } | 
 |     return {std::move(result)}; | 
 |   } | 
 |  | 
 | private: | 
 |   const BacktrackingParser<PA> parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto many(PA parser) { | 
 |   return ManyParser<PA>{parser}; | 
 | } | 
 |  | 
 | // If x is a parser, then some(x) returns a parser that succeeds if x does | 
 | // and whose value is a nonempty list of the values returned from repeated | 
 | // application of x until it fails or does not advance the parse.  In other | 
 | // words, some(x) is a variant of many(x) that has to succeed at least once. | 
 | template <typename PA> class SomeParser { | 
 |   using paType = typename PA::resultType; | 
 |  | 
 | public: | 
 |   using resultType = std::list<paType>; | 
 |   constexpr SomeParser(const SomeParser &) = default; | 
 |   constexpr SomeParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     auto start{state.GetLocation()}; | 
 |     if (std::optional<paType> first{parser_.Parse(state)}) { | 
 |       resultType result; | 
 |       result.emplace_back(std::move(*first)); | 
 |       if (state.GetLocation() > start) { | 
 |         result.splice(result.end(), many(parser_).Parse(state).value()); | 
 |       } | 
 |       return {std::move(result)}; | 
 |     } | 
 |     return std::nullopt; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto some(PA parser) { | 
 |   return SomeParser<PA>{parser}; | 
 | } | 
 |  | 
 | // If x is a parser, skipMany(x) is equivalent to many(x) but with no result. | 
 | template <typename PA> class SkipManyParser { | 
 | public: | 
 |   using resultType = Success; | 
 |   constexpr SkipManyParser(const SkipManyParser &) = default; | 
 |   constexpr SkipManyParser(PA parser) : parser_{parser} {} | 
 |   std::optional<Success> Parse(ParseState &state) const { | 
 |     for (auto at{state.GetLocation()}; | 
 |          parser_.Parse(state) && state.GetLocation() > at; | 
 |          at = state.GetLocation()) { | 
 |     } | 
 |     return Success{}; | 
 |   } | 
 |  | 
 | private: | 
 |   const BacktrackingParser<PA> parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto skipMany(PA parser) { | 
 |   return SkipManyParser<PA>{parser}; | 
 | } | 
 |  | 
 | // If x is a parser, skipManyFast(x) is equivalent to skipMany(x). | 
 | // The parser x must always advance on success and never invalidate the | 
 | // state on failure. | 
 | template <typename PA> class SkipManyFastParser { | 
 | public: | 
 |   using resultType = Success; | 
 |   constexpr SkipManyFastParser(const SkipManyFastParser &) = default; | 
 |   constexpr SkipManyFastParser(PA parser) : parser_{parser} {} | 
 |   std::optional<Success> Parse(ParseState &state) const { | 
 |     while (parser_.Parse(state)) { | 
 |     } | 
 |     return Success{}; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto skipManyFast(PA parser) { | 
 |   return SkipManyFastParser<PA>{parser}; | 
 | } | 
 |  | 
 | // If x is a parser returning some type A, then maybe(x) returns a | 
 | // parser that returns std::optional<A>, always succeeding. | 
 | template <typename PA> class MaybeParser { | 
 |   using paType = typename PA::resultType; | 
 |  | 
 | public: | 
 |   using resultType = std::optional<paType>; | 
 |   constexpr MaybeParser(const MaybeParser &) = default; | 
 |   constexpr MaybeParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if (resultType result{parser_.Parse(state)}) { | 
 |       // permit optional<optional<...>> | 
 |       return {std::move(result)}; | 
 |     } | 
 |     return resultType{}; | 
 |   } | 
 |  | 
 | private: | 
 |   const BacktrackingParser<PA> parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto maybe(PA parser) { | 
 |   return MaybeParser<PA>{parser}; | 
 | } | 
 |  | 
 | // If x is a parser, then defaulted(x) returns a parser that always | 
 | // succeeds.  When x succeeds, its result is that of x; otherwise, its | 
 | // result is a default-constructed value of x's result type. | 
 | template <typename PA> class DefaultedParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr DefaultedParser(const DefaultedParser &) = default; | 
 |   constexpr DefaultedParser(PA p) : parser_{p} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     std::optional<std::optional<resultType>> ax{maybe(parser_).Parse(state)}; | 
 |     if (ax.value()) { // maybe() always succeeds | 
 |       return std::move(*ax); | 
 |     } | 
 |     return resultType{}; | 
 |   } | 
 |  | 
 | private: | 
 |   const BacktrackingParser<PA> parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto defaulted(PA p) { | 
 |   return DefaultedParser<PA>(p); | 
 | } | 
 |  | 
 | // If a is a parser, and f is a function mapping an rvalue of a's result type | 
 | // to some other type T, then applyFunction(f, a) returns a parser that succeeds | 
 | // iff a does, and whose result value ax has been passed through the function; | 
 | // the final result is that returned by the call f(std::move(ax)). | 
 | // | 
 | // Function application is generalized to functions with more than one | 
 | // argument with applyFunction(f, a, b, ...) succeeding if all of the parsers | 
 | // a, b, &c. do so, and the result is the value of applying f to their | 
 | // results. | 
 | // | 
 | // applyLambda(f, ...) is the same concept extended to std::function<> functors. | 
 | // It is not constexpr. | 
 | // | 
 | // Member function application is supported by applyMem(f, a).  If the | 
 | // parser a succeeds and returns some value ax, the result is that returned | 
 | // by ax.f().  Additional parser arguments can be specified to supply their | 
 | // results to the member function call, so applyMem(f, a, b) succeeds if | 
 | // both a and b do so and returns the result of calling ax.f(std::move(bx)). | 
 |  | 
 | // Runs a sequence of parsers until one fails or all have succeeded. | 
 | // Collects their results in a std::tuple<std::optional<>...>. | 
 | template <typename... PARSER> | 
 | using ApplyArgs = std::tuple<std::optional<typename PARSER::resultType>...>; | 
 |  | 
 | template <typename... PARSER, std::size_t... J> | 
 | inline bool ApplyHelperArgs(const std::tuple<PARSER...> &parsers, | 
 |     ApplyArgs<PARSER...> &args, ParseState &state, std::index_sequence<J...>) { | 
 |   return (... && | 
 |       (std::get<J>(args) = std::get<J>(parsers).Parse(state), | 
 |           std::get<J>(args).has_value())); | 
 | } | 
 |  | 
 | // Applies a function to the arguments collected by ApplyHelperArgs. | 
 | template <typename RESULT, typename... PARSER> | 
 | using ApplicableFunctionPointer = RESULT (*)(typename PARSER::resultType &&...); | 
 | template <typename RESULT, typename... PARSER> | 
 | using ApplicableFunctionObject = | 
 |     const std::function<RESULT(typename PARSER::resultType &&...)> &; | 
 |  | 
 | template <template <typename...> class FUNCTION, typename RESULT, | 
 |     typename... PARSER, std::size_t... J> | 
 | inline RESULT ApplyHelperFunction(FUNCTION<RESULT, PARSER...> f, | 
 |     ApplyArgs<PARSER...> &&args, std::index_sequence<J...>) { | 
 |   return f(std::move(*std::get<J>(args))...); | 
 | } | 
 |  | 
 | template <template <typename...> class FUNCTION, typename RESULT, | 
 |     typename... PARSER> | 
 | class ApplyFunction { | 
 |   using funcType = FUNCTION<RESULT, PARSER...>; | 
 |  | 
 | public: | 
 |   using resultType = RESULT; | 
 |   constexpr ApplyFunction(const ApplyFunction &) = default; | 
 |   constexpr ApplyFunction(funcType f, PARSER... p) | 
 |       : function_{f}, parsers_{p...} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     ApplyArgs<PARSER...> results; | 
 |     using Sequence = std::index_sequence_for<PARSER...>; | 
 |     if (ApplyHelperArgs(parsers_, results, state, Sequence{})) { | 
 |       return ApplyHelperFunction<FUNCTION, RESULT, PARSER...>( | 
 |           function_, std::move(results), Sequence{}); | 
 |     } else { | 
 |       return std::nullopt; | 
 |     } | 
 |   } | 
 |  | 
 | private: | 
 |   const funcType function_; | 
 |   const std::tuple<PARSER...> parsers_; | 
 | }; | 
 |  | 
 | template <typename RESULT, typename... PARSER> | 
 | inline constexpr auto applyFunction( | 
 |     ApplicableFunctionPointer<RESULT, PARSER...> f, const PARSER &...parser) { | 
 |   return ApplyFunction<ApplicableFunctionPointer, RESULT, PARSER...>{ | 
 |       f, parser...}; | 
 | } | 
 |  | 
 | template <typename RESULT, typename... PARSER> | 
 | inline /* not constexpr */ auto applyLambda( | 
 |     ApplicableFunctionObject<RESULT, PARSER...> f, const PARSER &...parser) { | 
 |   return ApplyFunction<ApplicableFunctionObject, RESULT, PARSER...>{ | 
 |       f, parser...}; | 
 | } | 
 |  | 
 | // Member function application | 
 | template <typename OBJPARSER, typename... PARSER> class AMFPHelper { | 
 |   using resultType = typename OBJPARSER::resultType; | 
 |  | 
 | public: | 
 |   using type = void (resultType::*)(typename PARSER::resultType &&...); | 
 | }; | 
 | template <typename OBJPARSER, typename... PARSER> | 
 | using ApplicableMemberFunctionPointer = | 
 |     typename AMFPHelper<OBJPARSER, PARSER...>::type; | 
 |  | 
 | template <typename OBJPARSER, typename... PARSER, std::size_t... J> | 
 | inline auto ApplyHelperMember( | 
 |     ApplicableMemberFunctionPointer<OBJPARSER, PARSER...> mfp, | 
 |     ApplyArgs<OBJPARSER, PARSER...> &&args, std::index_sequence<J...>) -> | 
 |     typename OBJPARSER::resultType { | 
 |   ((*std::get<0>(args)).*mfp)(std::move(*std::get<J + 1>(args))...); | 
 |   return std::get<0>(std::move(args)); | 
 | } | 
 |  | 
 | template <typename OBJPARSER, typename... PARSER> class ApplyMemberFunction { | 
 |   using funcType = ApplicableMemberFunctionPointer<OBJPARSER, PARSER...>; | 
 |  | 
 | public: | 
 |   using resultType = typename OBJPARSER::resultType; | 
 |   constexpr ApplyMemberFunction(const ApplyMemberFunction &) = default; | 
 |   constexpr ApplyMemberFunction(funcType f, OBJPARSER o, PARSER... p) | 
 |       : function_{f}, parsers_{o, p...} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     ApplyArgs<OBJPARSER, PARSER...> results; | 
 |     using Sequence1 = std::index_sequence_for<OBJPARSER, PARSER...>; | 
 |     using Sequence2 = std::index_sequence_for<PARSER...>; | 
 |     if (ApplyHelperArgs(parsers_, results, state, Sequence1{})) { | 
 |       return ApplyHelperMember<OBJPARSER, PARSER...>( | 
 |           function_, std::move(results), Sequence2{}); | 
 |     } else { | 
 |       return std::nullopt; | 
 |     } | 
 |   } | 
 |  | 
 | private: | 
 |   const funcType function_; | 
 |   const std::tuple<OBJPARSER, PARSER...> parsers_; | 
 | }; | 
 |  | 
 | template <typename OBJPARSER, typename... PARSER> | 
 | inline constexpr auto applyMem( | 
 |     ApplicableMemberFunctionPointer<OBJPARSER, PARSER...> mfp, | 
 |     const OBJPARSER &objParser, PARSER... parser) { | 
 |   return ApplyMemberFunction<OBJPARSER, PARSER...>{mfp, objParser, parser...}; | 
 | } | 
 |  | 
 | // As is done with function application via applyFunction() above, class | 
 | // instance construction can also be based upon the results of successful | 
 | // parses.  For some type T and zero or more parsers a, b, &c., the call | 
 | // construct<T>(a, b, ...) returns a parser that succeeds if all of | 
 | // its argument parsers do so in succession, and whose result is an | 
 | // instance of T constructed upon the values they returned. | 
 | // With a single argument that is a parser with no usable value, | 
 | // construct<T>(p) invokes T's default nullary constructor (T(){}). | 
 | // (This means that "construct<T>(Foo >> Bar >> ok)" is functionally | 
 | // equivalent to "Foo >> Bar >> construct<T>()", but I'd like to hold open | 
 | // the opportunity to make construct<> capture source provenance all of the | 
 | // time, and the first form will then lead to better error positioning.) | 
 |  | 
 | template <typename RESULT, typename... PARSER, std::size_t... J> | 
 | inline RESULT ApplyHelperConstructor( | 
 |     ApplyArgs<PARSER...> &&args, std::index_sequence<J...>) { | 
 |   return RESULT{std::move(*std::get<J>(args))...}; | 
 | } | 
 |  | 
 | template <typename RESULT, typename... PARSER> class ApplyConstructor { | 
 | public: | 
 |   using resultType = RESULT; | 
 |   constexpr ApplyConstructor(const ApplyConstructor &) = default; | 
 |   constexpr explicit ApplyConstructor(PARSER... p) : parsers_{p...} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if constexpr (sizeof...(PARSER) == 0) { | 
 |       return RESULT{}; | 
 |     } else { | 
 |       if constexpr (sizeof...(PARSER) == 1) { | 
 |         if constexpr (std::is_same_v<Success, typename PARSER::resultType...>) { | 
 |           if (std::get<0>(parsers_).Parse(state)) { | 
 |             return RESULT{}; | 
 |           } | 
 |         } else if (auto arg{std::get<0>(parsers_).Parse(state)}) { | 
 |           return RESULT{std::move(*arg)}; | 
 |         } | 
 |       } else { | 
 |         ApplyArgs<PARSER...> results; | 
 |         using Sequence = std::index_sequence_for<PARSER...>; | 
 |         if (ApplyHelperArgs(parsers_, results, state, Sequence{})) { | 
 |           return ApplyHelperConstructor<RESULT, PARSER...>( | 
 |               std::move(results), Sequence{}); | 
 |         } | 
 |       } | 
 |       return std::nullopt; | 
 |     } | 
 |   } | 
 |  | 
 | private: | 
 |   const std::tuple<PARSER...> parsers_; | 
 | }; | 
 |  | 
 | template <typename RESULT, typename... PARSER> | 
 | inline constexpr auto construct(PARSER... p) { | 
 |   return ApplyConstructor<RESULT, PARSER...>{p...}; | 
 | } | 
 |  | 
 | // For a parser p, indirect(p) returns a parser that builds an indirect | 
 | // reference to p's return type. | 
 | template <typename PA> inline constexpr auto indirect(PA p) { | 
 |   return construct<common::Indirection<typename PA::resultType>>(p); | 
 | } | 
 |  | 
 | // If a and b are parsers, then nonemptySeparated(a, b) returns a parser | 
 | // that succeeds if a does.  If a succeeds, it then applies many(b >> a). | 
 | // The result is the list of the values returned from all of the applications | 
 | // of a. | 
 | template <typename T> | 
 | common::IfNoLvalue<std::list<T>, T> prepend(T &&head, std::list<T> &&rest) { | 
 |   rest.push_front(std::move(head)); | 
 |   return std::move(rest); | 
 | } | 
 |  | 
 | template <typename PA, typename PB> class NonemptySeparated { | 
 | private: | 
 |   using paType = typename PA::resultType; | 
 |  | 
 | public: | 
 |   using resultType = std::list<paType>; | 
 |   constexpr NonemptySeparated(const NonemptySeparated &) = default; | 
 |   constexpr NonemptySeparated(PA p, PB sep) : parser_{p}, separator_{sep} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     return applyFunction(prepend<paType>, parser_, many(separator_ >> parser_)) | 
 |         .Parse(state); | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 |   const PB separator_; | 
 | }; | 
 |  | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto nonemptySeparated(PA p, PB sep) { | 
 |   return NonemptySeparated<PA, PB>{p, sep}; | 
 | } | 
 |  | 
 | // ok is a parser that always succeeds.  It is useful when a parser | 
 | // must discard its result in order to be compatible in type with other | 
 | // parsers in an alternative, e.g. "x >> ok || y >> ok" is type-safe even | 
 | // when x and y have distinct result types. | 
 | constexpr struct OkParser { | 
 |   using resultType = Success; | 
 |   constexpr OkParser() {} | 
 |   static constexpr std::optional<Success> Parse(ParseState &) { | 
 |     return Success{}; | 
 |   } | 
 | } ok; | 
 |  | 
 | // A variant of recovery() above for convenience. | 
 | template <typename PA, typename PB> | 
 | inline constexpr auto localRecovery(MessageFixedText msg, PA pa, PB pb) { | 
 |   return recovery(withMessage(msg, pa), pb >> pure<typename PA::resultType>()); | 
 | } | 
 |  | 
 | // nextCh is a parser that succeeds if the parsing state is not | 
 | // at the end of its input, returning the next character location and | 
 | // advancing the parse when it does so. | 
 | struct NextCh { | 
 |   using resultType = const char *; | 
 |   constexpr NextCh() {} | 
 |   std::optional<const char *> Parse(ParseState &state) const { | 
 |     if (std::optional<const char *> result{state.GetNextChar()}) { | 
 |       return result; | 
 |     } | 
 |     state.Say("end of file"_err_en_US); | 
 |     return std::nullopt; | 
 |   } | 
 | }; | 
 |  | 
 | constexpr NextCh nextCh; | 
 |  | 
 | // If a is a parser for some nonstandard language feature LF, extension<LF>(a) | 
 | // is a parser that optionally enabled, sets a strict conformance violation | 
 | // flag, and may emit a warning message, if those are enabled. | 
 | template <LanguageFeature LF, typename PA> class NonstandardParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr NonstandardParser(const NonstandardParser &) = default; | 
 |   constexpr NonstandardParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if (UserState * ustate{state.userState()}) { | 
 |       if (!ustate->features().IsEnabled(LF)) { | 
 |         return std::nullopt; | 
 |       } | 
 |     } | 
 |     auto at{state.GetLocation()}; | 
 |     auto result{parser_.Parse(state)}; | 
 |     if (result) { | 
 |       state.Nonstandard( | 
 |           CharBlock{at, state.GetLocation()}, LF, "nonstandard usage"_en_US); | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <LanguageFeature LF, typename PA> | 
 | inline constexpr auto extension(PA parser) { | 
 |   return NonstandardParser<LF, PA>(parser); | 
 | } | 
 |  | 
 | // If a is a parser for some deprecated or deleted language feature LF, | 
 | // deprecated<LF>(a) is a parser that is optionally enabled, sets a strict | 
 | // conformance violation flag, and may emit a warning message, if enabled. | 
 | template <LanguageFeature LF, typename PA> class DeprecatedParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr DeprecatedParser(const DeprecatedParser &) = default; | 
 |   constexpr DeprecatedParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     if (UserState * ustate{state.userState()}) { | 
 |       if (!ustate->features().IsEnabled(LF)) { | 
 |         return std::nullopt; | 
 |       } | 
 |     } | 
 |     auto at{state.GetLocation()}; | 
 |     auto result{parser_.Parse(state)}; | 
 |     if (result) { | 
 |       state.Nonstandard( | 
 |           CharBlock{at, state.GetLocation()}, LF, "deprecated usage"_en_US); | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <LanguageFeature LF, typename PA> | 
 | inline constexpr auto deprecated(PA parser) { | 
 |   return DeprecatedParser<LF, PA>(parser); | 
 | } | 
 |  | 
 | // Parsing objects with "source" members. | 
 | template <typename PA> class SourcedParser { | 
 | public: | 
 |   using resultType = typename PA::resultType; | 
 |   constexpr SourcedParser(const SourcedParser &) = default; | 
 |   constexpr SourcedParser(PA parser) : parser_{parser} {} | 
 |   std::optional<resultType> Parse(ParseState &state) const { | 
 |     const char *start{state.GetLocation()}; | 
 |     auto result{parser_.Parse(state)}; | 
 |     if (result) { | 
 |       const char *end{state.GetLocation()}; | 
 |       for (; start < end && start[0] == ' '; ++start) { | 
 |       } | 
 |       for (; start < end && end[-1] == ' '; --end) { | 
 |       } | 
 |       result->source = CharBlock{start, end}; | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 | private: | 
 |   const PA parser_; | 
 | }; | 
 |  | 
 | template <typename PA> inline constexpr auto sourced(PA parser) { | 
 |   return SourcedParser<PA>{parser}; | 
 | } | 
 | } // namespace Fortran::parser | 
 | #endif // FORTRAN_PARSER_BASIC_PARSERS_H_ |