brintos

brintos / llvm-project-archived public Read only

0
0
Text · 31.0 KiB · 46d5168 Raw
939 lines · c
1//===-- lib/Parser/basic-parsers.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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef FORTRAN_PARSER_BASIC_PARSERS_H_10#define FORTRAN_PARSER_BASIC_PARSERS_H_11 12// Let a "parser" be an instance of any class that supports this13// type definition and member (or static) function:14//15//   using resultType = ...;16//   std::optional<resultType> Parse(ParseState &) const;17//18// which either returns a value to signify a successful recognition or else19// returns {} to signify failure.  On failure, the state cannot be assumed20// to still be valid, in general -- see below for exceptions.21//22// This header defines the fundamental parser class templates and helper23// template functions.  See parser-combinators.txt for documentation.24 25#include "flang/Common/idioms.h"26#include "flang/Common/indirection.h"27#include "flang/Parser/char-block.h"28#include "flang/Parser/message.h"29#include "flang/Parser/parse-state.h"30#include "flang/Parser/provenance.h"31#include "flang/Parser/user-state.h"32#include "flang/Support/Fortran-features.h"33#include <cstring>34#include <functional>35#include <list>36#include <memory>37#include <optional>38#include <string>39#include <tuple>40#include <type_traits>41#include <utility>42 43namespace Fortran::parser {44 45// fail<A>("..."_err_en_US) returns a parser that never succeeds.  It reports an46// error message at the current position.  The result type is unused,47// but might have to be specified at the point of call to satisfy48// the type checker.  The state remains valid.49template <typename A> class FailParser {50public:51  using resultType = A;52  constexpr FailParser(const FailParser &) = default;53  constexpr explicit FailParser(MessageFixedText t) : text_{t} {}54  std::optional<A> Parse(ParseState &state) const {55    state.Say(text_);56    return std::nullopt;57  }58 59private:60  const MessageFixedText text_;61};62 63template <typename A = Success> inline constexpr auto fail(MessageFixedText t) {64  return FailParser<A>{t};65}66 67// pure(x) returns a parser that always succeeds, does not advance the68// parse, and returns a captured value x whose type must be copy-constructible.69//70// pure<A>() is essentially pure(A{}); it returns a default-constructed A{},71// and works even when A is not copy-constructible.72template <typename A> class PureParser {73public:74  using resultType = A;75  constexpr PureParser(const PureParser &) = default;76  constexpr explicit PureParser(A &&x) : value_(std::move(x)) {}77  std::optional<A> Parse(ParseState &) const { return value_; }78 79private:80  const A value_;81};82 83template <typename A> inline constexpr auto pure(A x) {84  return PureParser<A>(std::move(x));85}86 87template <typename A> class PureDefaultParser {88public:89  using resultType = A;90  constexpr PureDefaultParser(const PureDefaultParser &) = default;91  constexpr PureDefaultParser() {}92  std::optional<A> Parse(ParseState &) const { return std::make_optional<A>(); }93};94 95template <typename A> inline constexpr auto pure() {96  return PureDefaultParser<A>();97}98 99// If a is a parser, attempt(a) is the same parser, but on failure100// the ParseState is guaranteed to have been restored to its initial value.101template <typename A> class BacktrackingParser {102public:103  using resultType = typename A::resultType;104  constexpr BacktrackingParser(const BacktrackingParser &) = default;105  constexpr BacktrackingParser(const A &parser) : parser_{parser} {}106  std::optional<resultType> Parse(ParseState &state) const {107    Messages messages{std::move(state.messages())};108    ParseState backtrack{state};109    std::optional<resultType> result{parser_.Parse(state)};110    if (result) {111      state.messages().Annex(std::move(messages));112    } else {113      state = std::move(backtrack);114      state.messages() = std::move(messages);115    }116    return result;117  }118 119private:120  const A parser_;121};122 123template <typename A> inline constexpr auto attempt(const A &parser) {124  return BacktrackingParser<A>{parser};125}126 127// For any parser x, the parser returned by !x is one that succeeds when128// x fails, returning a useless (but present) result.  !x fails when x succeeds.129template <typename PA> class NegatedParser {130public:131  using resultType = Success;132  constexpr NegatedParser(const NegatedParser &) = default;133  constexpr NegatedParser(PA p) : parser_{p} {}134  std::optional<Success> Parse(ParseState &state) const {135    ParseState forked{state};136    forked.set_deferMessages(true);137    if (parser_.Parse(forked)) {138      return std::nullopt;139    }140    return Success{};141  }142 143private:144  const PA parser_;145};146 147template <typename PA, typename = typename PA::resultType>148constexpr auto operator!(PA p) {149  return NegatedParser<PA>(p);150}151 152// For any parser x, the parser returned by lookAhead(x) is one that succeeds153// or fails if x does, but the state is not modified.154template <typename PA> class LookAheadParser {155public:156  using resultType = Success;157  constexpr LookAheadParser(const LookAheadParser &) = default;158  constexpr LookAheadParser(PA p) : parser_{p} {}159  std::optional<Success> Parse(ParseState &state) const {160    ParseState forked{state};161    forked.set_deferMessages(true);162    if (parser_.Parse(forked)) {163      return Success{};164    }165    return std::nullopt;166  }167 168private:169  const PA parser_;170};171 172template <typename PA> inline constexpr auto lookAhead(PA p) {173  return LookAheadParser<PA>{p};174}175 176// If a is a parser, inContext("..."_en_US, a) runs it in a nested message177// context.178template <typename PA> class MessageContextParser {179public:180  using resultType = typename PA::resultType;181  constexpr MessageContextParser(const MessageContextParser &) = default;182  constexpr MessageContextParser(MessageFixedText t, PA p)183      : text_{t}, parser_{p} {}184  std::optional<resultType> Parse(ParseState &state) const {185    state.PushContext(text_);186    std::optional<resultType> result{parser_.Parse(state)};187    state.PopContext();188    return result;189  }190 191private:192  const MessageFixedText text_;193  const PA parser_;194};195 196template <typename PA>197inline constexpr auto inContext(MessageFixedText context, PA parser) {198  return MessageContextParser{context, parser};199}200 201// If a is a parser, withMessage("..."_en_US, a) runs it unchanged if it202// succeeds, and overrides its messages with a specific one if it fails and203// has matched no tokens.204template <typename PA> class WithMessageParser {205public:206  using resultType = typename PA::resultType;207  constexpr WithMessageParser(const WithMessageParser &) = default;208  constexpr WithMessageParser(MessageFixedText t, PA p)209      : text_{t}, parser_{p} {}210  std::optional<resultType> Parse(ParseState &state) const {211    if (state.deferMessages()) { // fast path212      std::optional<resultType> result{parser_.Parse(state)};213      if (!result) {214        state.set_anyDeferredMessages();215      }216      return result;217    }218    Messages messages{std::move(state.messages())};219    bool hadAnyTokenMatched{state.anyTokenMatched()};220    state.set_anyTokenMatched(false);221    std::optional<resultType> result{parser_.Parse(state)};222    bool emitMessage{false};223    if (result) {224      messages.Annex(std::move(state.messages()));225      if (hadAnyTokenMatched) {226        state.set_anyTokenMatched();227      }228    } else if (state.anyTokenMatched()) {229      emitMessage = state.messages().empty();230      messages.Annex(std::move(state.messages()));231    } else {232      emitMessage = true;233      if (hadAnyTokenMatched) {234        state.set_anyTokenMatched();235      }236    }237    state.messages() = std::move(messages);238    if (emitMessage) {239      state.Say(text_);240    }241    return result;242  }243 244private:245  const MessageFixedText text_;246  const PA parser_;247};248 249template <typename PA>250inline constexpr auto withMessage(MessageFixedText msg, PA parser) {251  return WithMessageParser{msg, parser};252}253 254// If a and b are parsers, then a >> b returns a parser that succeeds when255// b succeeds after a does so, but fails when either a or b does.  The256// result is taken from b.  Similarly, a / b also succeeds if both a and b257// do so, but the result is that returned by a.258template <typename PA, typename PB> class SequenceParser {259public:260  using resultType = typename PB::resultType;261  constexpr SequenceParser(const SequenceParser &) = default;262  constexpr SequenceParser(PA pa, PB pb) : pa_{pa}, pb2_{pb} {}263  std::optional<resultType> Parse(ParseState &state) const {264    if (pa_.Parse(state)) {265      return pb2_.Parse(state);266    } else {267      return std::nullopt;268    }269  }270 271private:272  const PA pa_;273  const PB pb2_;274};275 276template <typename PA, typename PB>277inline constexpr auto operator>>(PA pa, PB pb) {278  return SequenceParser<PA, PB>{pa, pb};279}280 281template <typename PA, typename PB> class FollowParser {282public:283  using resultType = typename PA::resultType;284  constexpr FollowParser(const FollowParser &) = default;285  constexpr FollowParser(PA pa, PB pb) : pa_{pa}, pb_{pb} {}286  std::optional<resultType> Parse(ParseState &state) const {287    if (std::optional<resultType> ax{pa_.Parse(state)}) {288      if (pb_.Parse(state)) {289        return ax;290      }291    }292    return std::nullopt;293  }294 295private:296  const PA pa_;297  const PB pb_;298};299 300template <typename PA, typename PB>301inline constexpr auto operator/(PA pa, PB pb) {302  return FollowParser<PA, PB>{pa, pb};303}304 305template <typename PA, typename... Ps> class AlternativesParser {306public:307  using resultType = typename PA::resultType;308  constexpr AlternativesParser(PA pa, Ps... ps) : ps_{pa, ps...} {}309  constexpr AlternativesParser(const AlternativesParser &) = default;310  std::optional<resultType> Parse(ParseState &state) const {311    Messages messages{std::move(state.messages())};312    ParseState backtrack{state};313    std::optional<resultType> result{std::get<0>(ps_).Parse(state)};314    if constexpr (sizeof...(Ps) > 0) {315      if (!result) {316        ParseRest<1>(result, state, backtrack);317      }318    }319    state.messages().Annex(std::move(messages));320    return result;321  }322 323private:324  template <int J>325  void ParseRest(std::optional<resultType> &result, ParseState &state,326      ParseState &backtrack) const {327    ParseState prevState{std::move(state)};328    state = backtrack;329    result = std::get<J>(ps_).Parse(state);330    if (!result) {331      state.CombineFailedParses(std::move(prevState));332      if constexpr (J < sizeof...(Ps)) {333        ParseRest<J + 1>(result, state, backtrack);334      }335    }336  }337 338  const std::tuple<PA, Ps...> ps_;339};340 341template <typename... Ps> inline constexpr auto first(Ps... ps) {342  return AlternativesParser<Ps...>{ps...};343}344 345template <typename PA, typename PB>346inline constexpr auto operator||(PA pa, PB pb) {347  return AlternativesParser<PA, PB>{pa, pb};348}349 350// If a and b are parsers, then recovery(a,b) returns a parser that succeeds if351// a does so, or if a fails and b succeeds.  If a succeeds, b is not attempted.352// All messages from the first parse are retained.353// The two parsers must return values of the same type.354template <typename PA, typename PB> class RecoveryParser {355public:356  using resultType = typename PA::resultType;357  static_assert(std::is_same_v<resultType, typename PB::resultType>);358  constexpr RecoveryParser(const RecoveryParser &) = default;359  constexpr RecoveryParser(PA pa, PB pb) : pa_{pa}, pb_{pb} {}360  std::optional<resultType> Parse(ParseState &state) const {361    bool originallyDeferred{state.deferMessages()};362    ParseState backtrack{state};363    if (!originallyDeferred && state.messages().empty() &&364        !state.anyErrorRecovery()) {365      // Fast path.  There are no messages or recovered errors in the incoming366      // state.  Attempt to parse with messages deferred, expecting that the367      // parse will succeed silently.368      state.set_deferMessages(true);369      if (std::optional<resultType> ax{pa_.Parse(state)}) {370        if (!state.anyDeferredMessages() && !state.anyErrorRecovery()) {371          state.set_deferMessages(false);372          return ax;373        }374      }375      state = backtrack;376    }377    Messages messages{std::move(state.messages())};378    if (std::optional<resultType> ax{pa_.Parse(state)}) {379      state.messages().Annex(std::move(messages));380      return ax;381    }382    messages.Annex(std::move(state.messages()));383    bool hadDeferredMessages{state.anyDeferredMessages()};384    bool anyTokenMatched{state.anyTokenMatched()};385    state = std::move(backtrack);386    state.set_deferMessages(true);387    std::optional<resultType> bx{pb_.Parse(state)};388    state.messages() = std::move(messages);389    state.set_deferMessages(originallyDeferred);390    if (anyTokenMatched) {391      state.set_anyTokenMatched();392    }393    if (hadDeferredMessages) {394      state.set_anyDeferredMessages();395    }396    if (bx) {397      // Error recovery situations must also produce messages.398      CHECK(state.anyDeferredMessages() || state.messages().AnyFatalError());399      state.set_anyErrorRecovery();400    }401    return bx;402  }403 404private:405  const PA pa_;406  const PB pb_;407};408 409template <typename PA, typename PB>410inline constexpr auto recovery(PA pa, PB pb) {411  return RecoveryParser<PA, PB>{pa, pb};412}413 414// If x is a parser, then many(x) returns a parser that always succeeds415// and whose value is a list, possibly empty, of the values returned from416// repeated application of x until it fails or does not advance the parse.417template <typename PA> class ManyParser {418  using paType = typename PA::resultType;419 420public:421  using resultType = std::list<paType>;422  constexpr ManyParser(const ManyParser &) = default;423  constexpr ManyParser(PA parser) : parser_{parser} {}424  std::optional<resultType> Parse(ParseState &state) const {425    resultType result;426    auto at{state.GetLocation()};427    while (std::optional<paType> x{parser_.Parse(state)}) {428      result.emplace_back(std::move(*x));429      if (state.GetLocation() <= at) {430        break; // no forward progress, don't loop431      }432      at = state.GetLocation();433    }434    return {std::move(result)};435  }436 437private:438  const BacktrackingParser<PA> parser_;439};440 441template <typename PA> inline constexpr auto many(PA parser) {442  return ManyParser<PA>{parser};443}444 445// If x is a parser, then some(x) returns a parser that succeeds if x does446// and whose value is a nonempty list of the values returned from repeated447// application of x until it fails or does not advance the parse.  In other448// words, some(x) is a variant of many(x) that has to succeed at least once.449template <typename PA> class SomeParser {450  using paType = typename PA::resultType;451 452public:453  using resultType = std::list<paType>;454  constexpr SomeParser(const SomeParser &) = default;455  constexpr SomeParser(PA parser) : parser_{parser} {}456  std::optional<resultType> Parse(ParseState &state) const {457    auto start{state.GetLocation()};458    if (std::optional<paType> first{parser_.Parse(state)}) {459      resultType result;460      result.emplace_back(std::move(*first));461      if (state.GetLocation() > start) {462        result.splice(result.end(), many(parser_).Parse(state).value());463      }464      return {std::move(result)};465    }466    return std::nullopt;467  }468 469private:470  const PA parser_;471};472 473template <typename PA> inline constexpr auto some(PA parser) {474  return SomeParser<PA>{parser};475}476 477// If x is a parser, skipMany(x) is equivalent to many(x) but with no result.478template <typename PA> class SkipManyParser {479public:480  using resultType = Success;481  constexpr SkipManyParser(const SkipManyParser &) = default;482  constexpr SkipManyParser(PA parser) : parser_{parser} {}483  std::optional<Success> Parse(ParseState &state) const {484    for (auto at{state.GetLocation()};485         parser_.Parse(state) && state.GetLocation() > at;486         at = state.GetLocation()) {487    }488    return Success{};489  }490 491private:492  const BacktrackingParser<PA> parser_;493};494 495template <typename PA> inline constexpr auto skipMany(PA parser) {496  return SkipManyParser<PA>{parser};497}498 499// If x is a parser, skipManyFast(x) is equivalent to skipMany(x).500// The parser x must always advance on success and never invalidate the501// state on failure.502template <typename PA> class SkipManyFastParser {503public:504  using resultType = Success;505  constexpr SkipManyFastParser(const SkipManyFastParser &) = default;506  constexpr SkipManyFastParser(PA parser) : parser_{parser} {}507  std::optional<Success> Parse(ParseState &state) const {508    while (parser_.Parse(state)) {509    }510    return Success{};511  }512 513private:514  const PA parser_;515};516 517template <typename PA> inline constexpr auto skipManyFast(PA parser) {518  return SkipManyFastParser<PA>{parser};519}520 521// If x is a parser returning some type A, then maybe(x) returns a522// parser that returns std::optional<A>, always succeeding.523template <typename PA> class MaybeParser {524  using paType = typename PA::resultType;525 526public:527  using resultType = std::optional<paType>;528  constexpr MaybeParser(const MaybeParser &) = default;529  constexpr MaybeParser(PA parser) : parser_{parser} {}530  std::optional<resultType> Parse(ParseState &state) const {531    if (resultType result{parser_.Parse(state)}) {532      // permit optional<optional<...>>533      return {std::move(result)};534    }535    return resultType{};536  }537 538private:539  const BacktrackingParser<PA> parser_;540};541 542template <typename PA> inline constexpr auto maybe(PA parser) {543  return MaybeParser<PA>{parser};544}545 546// If x is a parser, then defaulted(x) returns a parser that always547// succeeds.  When x succeeds, its result is that of x; otherwise, its548// result is a default-constructed value of x's result type.549template <typename PA> class DefaultedParser {550public:551  using resultType = typename PA::resultType;552  constexpr DefaultedParser(const DefaultedParser &) = default;553  constexpr DefaultedParser(PA p) : parser_{p} {}554  std::optional<resultType> Parse(ParseState &state) const {555    std::optional<std::optional<resultType>> ax{maybe(parser_).Parse(state)};556    if (ax.value()) { // maybe() always succeeds557      return std::move(*ax);558    }559    return resultType{};560  }561 562private:563  const BacktrackingParser<PA> parser_;564};565 566template <typename PA> inline constexpr auto defaulted(PA p) {567  return DefaultedParser<PA>(p);568}569 570// If a is a parser, and f is a function mapping an rvalue of a's result type571// to some other type T, then applyFunction(f, a) returns a parser that succeeds572// iff a does, and whose result value ax has been passed through the function;573// the final result is that returned by the call f(std::move(ax)).574//575// Function application is generalized to functions with more than one576// argument with applyFunction(f, a, b, ...) succeeding if all of the parsers577// a, b, &c. do so, and the result is the value of applying f to their578// results.579//580// applyLambda(f, ...) is the same concept extended to std::function<> functors.581// It is not constexpr.582//583// Member function application is supported by applyMem(&C::f, a).  If the584// parser a succeeds and returns some value ax of type C, the result is that585// returned by ax.f().  Additional parser arguments can be specified to supply586// their results to the member function call, so applyMem(&C::f, a, b) succeeds587// if both a and b do so and returns the result of calling ax.f(std::move(bx)).588 589// Runs a sequence of parsers until one fails or all have succeeded.590// Collects their results in a std::tuple<std::optional<>...>.591template <typename... PARSER>592using ApplyArgs = std::tuple<std::optional<typename PARSER::resultType>...>;593 594template <typename... PARSER, std::size_t... J>595inline bool ApplyHelperArgs(const std::tuple<PARSER...> &parsers,596    ApplyArgs<PARSER...> &args, ParseState &state, std::index_sequence<J...>) {597  return (... &&598      (std::get<J>(args) = std::get<J>(parsers).Parse(state),599          std::get<J>(args).has_value()));600}601 602// Applies a function to the arguments collected by ApplyHelperArgs.603template <typename RESULT, typename... PARSER>604using ApplicableFunctionPointer = RESULT (*)(typename PARSER::resultType &&...);605template <typename RESULT, typename... PARSER>606using ApplicableFunctionObject =607    const std::function<RESULT(typename PARSER::resultType &&...)> &;608 609template <template <typename...> class FUNCTION, typename RESULT,610    typename... PARSER, std::size_t... J>611inline RESULT ApplyHelperFunction(FUNCTION<RESULT, PARSER...> f,612    ApplyArgs<PARSER...> &&args, std::index_sequence<J...>) {613  return f(std::move(*std::get<J>(args))...);614}615 616template <template <typename...> class FUNCTION, typename RESULT,617    typename... PARSER>618class ApplyFunction {619  using funcType = FUNCTION<RESULT, PARSER...>;620 621public:622  using resultType = RESULT;623  constexpr ApplyFunction(const ApplyFunction &) = default;624  constexpr ApplyFunction(funcType f, PARSER... p)625      : function_{f}, parsers_{p...} {}626  std::optional<resultType> Parse(ParseState &state) const {627    ApplyArgs<PARSER...> results;628    using Sequence = std::index_sequence_for<PARSER...>;629    if (ApplyHelperArgs(parsers_, results, state, Sequence{})) {630      return ApplyHelperFunction<FUNCTION, RESULT, PARSER...>(631          function_, std::move(results), Sequence{});632    } else {633      return std::nullopt;634    }635  }636 637private:638  const funcType function_;639  const std::tuple<PARSER...> parsers_;640};641 642template <typename RESULT, typename... PARSER>643inline constexpr auto applyFunction(644    ApplicableFunctionPointer<RESULT, PARSER...> f, const PARSER &...parser) {645  return ApplyFunction<ApplicableFunctionPointer, RESULT, PARSER...>{646      f, parser...};647}648 649template <typename RESULT, typename... PARSER>650inline /* not constexpr */ auto applyLambda(651    ApplicableFunctionObject<RESULT, PARSER...> f, const PARSER &...parser) {652  return ApplyFunction<ApplicableFunctionObject, RESULT, PARSER...>{653      f, parser...};654}655 656// Member function application657template <typename MEMFUNC, typename OBJPARSER, typename... PARSER,658    std::size_t... J>659inline auto ApplyHelperMember(MEMFUNC mfp,660    ApplyArgs<OBJPARSER, PARSER...> &&args, std::index_sequence<J...>) {661  return ((*std::get<0>(args)).*mfp)(std::move(*std::get<J + 1>(args))...);662}663 664template <typename MEMFUNC, typename OBJPARSER, typename... PARSER>665class ApplyMemberFunction {666  static_assert(std::is_member_function_pointer_v<MEMFUNC>);667  using funcType = MEMFUNC;668 669public:670  using resultType =671      std::invoke_result_t<MEMFUNC, typename OBJPARSER::resultType, PARSER...>;672 673  constexpr ApplyMemberFunction(const ApplyMemberFunction &) = default;674  constexpr ApplyMemberFunction(MEMFUNC f, OBJPARSER o, PARSER... p)675      : function_{f}, parsers_{o, p...} {}676  std::optional<resultType> Parse(ParseState &state) const {677    ApplyArgs<OBJPARSER, PARSER...> results;678    using Sequence1 = std::index_sequence_for<OBJPARSER, PARSER...>;679    using Sequence2 = std::index_sequence_for<PARSER...>;680    if (ApplyHelperArgs(parsers_, results, state, Sequence1{})) {681      return ApplyHelperMember<MEMFUNC, OBJPARSER, PARSER...>(682          function_, std::move(results), Sequence2{});683    } else {684      return std::nullopt;685    }686  }687 688private:689  const funcType function_;690  const std::tuple<OBJPARSER, PARSER...> parsers_;691};692 693template <typename MEMFUNC, typename OBJPARSER, typename... PARSER>694inline constexpr auto applyMem(695    MEMFUNC memfn, const OBJPARSER &objParser, PARSER... parser) {696  return ApplyMemberFunction<MEMFUNC, OBJPARSER, PARSER...>{697      memfn, objParser, parser...};698}699 700// As is done with function application via applyFunction() above, class701// instance construction can also be based upon the results of successful702// parses.  For some type T and zero or more parsers a, b, &c., the call703// construct<T>(a, b, ...) returns a parser that succeeds if all of704// its argument parsers do so in succession, and whose result is an705// instance of T constructed upon the values they returned.706// With a single argument that is a parser with no usable value,707// construct<T>(p) invokes T's default nullary constructor (T(){}).708// (This means that "construct<T>(Foo >> Bar >> ok)" is functionally709// equivalent to "Foo >> Bar >> construct<T>()", but I'd like to hold open710// the opportunity to make construct<> capture source provenance all of the711// time, and the first form will then lead to better error positioning.)712 713template <typename RESULT, typename... PARSER, std::size_t... J>714inline RESULT ApplyHelperConstructor(715    ApplyArgs<PARSER...> &&args, std::index_sequence<J...>) {716  return RESULT{std::move(*std::get<J>(args))...};717}718 719template <typename RESULT, typename... PARSER> class ApplyConstructor {720public:721  using resultType = RESULT;722  constexpr ApplyConstructor(const ApplyConstructor &) = default;723  constexpr explicit ApplyConstructor(PARSER... p) : parsers_{p...} {}724  std::optional<resultType> Parse(ParseState &state) const {725    if constexpr (sizeof...(PARSER) == 0) {726      return RESULT{};727    } else {728      if constexpr (sizeof...(PARSER) == 1) {729        return ParseOne(state);730      } else {731        ApplyArgs<PARSER...> results;732        using Sequence = std::index_sequence_for<PARSER...>;733        if (ApplyHelperArgs(parsers_, results, state, Sequence{})) {734          return ApplyHelperConstructor<RESULT, PARSER...>(735              std::move(results), Sequence{});736        }737      }738      return std::nullopt;739    }740  }741 742private:743  std::optional<resultType> ParseOne(ParseState &state) const {744    if constexpr (std::is_same_v<Success, typename PARSER::resultType...>) {745      if (std::get<0>(parsers_).Parse(state)) {746        return RESULT{};747      }748    } else if (auto arg{std::get<0>(parsers_).Parse(state)}) {749      return RESULT{std::move(*arg)};750    }751    return std::nullopt;752  }753 754  const std::tuple<PARSER...> parsers_;755};756 757template <typename RESULT, typename... PARSER>758inline constexpr auto construct(PARSER... p) {759  return ApplyConstructor<RESULT, PARSER...>{p...};760}761 762// For a parser p, indirect(p) returns a parser that builds an indirect763// reference to p's return type.764template <typename PA> inline constexpr auto indirect(PA p) {765  return construct<common::Indirection<typename PA::resultType>>(p);766}767 768// If a and b are parsers, then nonemptySeparated(a, b) returns a parser769// that succeeds if a does.  If a succeeds, it then applies many(b >> a).770// The result is the list of the values returned from all of the applications771// of a.772template <typename T>773common::IfNoLvalue<std::list<T>, T> prepend(T &&head, std::list<T> &&rest) {774  rest.push_front(std::move(head));775  return std::move(rest);776}777 778template <typename PA, typename PB> class NonemptySeparated {779private:780  using paType = typename PA::resultType;781 782public:783  using resultType = std::list<paType>;784  constexpr NonemptySeparated(const NonemptySeparated &) = default;785  constexpr NonemptySeparated(PA p, PB sep) : parser_{p}, separator_{sep} {}786  std::optional<resultType> Parse(ParseState &state) const {787    return applyFunction<std::list<paType>>(788        prepend<paType>, parser_, many(separator_ >> parser_))789        .Parse(state);790  }791 792private:793  const PA parser_;794  const PB separator_;795};796 797template <typename PA, typename PB>798inline constexpr auto nonemptySeparated(PA p, PB sep) {799  return NonemptySeparated<PA, PB>{p, sep};800}801 802// ok is a parser that always succeeds.  It is useful when a parser803// must discard its result in order to be compatible in type with other804// parsers in an alternative, e.g. "x >> ok || y >> ok" is type-safe even805// when x and y have distinct result types.806struct OkParser {807  using resultType = Success;808  constexpr OkParser() {}809  static constexpr std::optional<Success> Parse(ParseState &) {810    return Success{};811  }812};813constexpr OkParser ok;814 815// A variant of recovery() above for convenience.816template <typename PA, typename PB>817inline constexpr auto localRecovery(MessageFixedText msg, PA pa, PB pb) {818  return recovery(withMessage(msg, pa), pb >> pure<typename PA::resultType>());819}820 821// nextCh is a parser that succeeds if the parsing state is not822// at the end of its input, returning the next character location and823// advancing the parse when it does so.824struct NextCh {825  using resultType = const char *;826  constexpr NextCh() {}827  std::optional<const char *> Parse(ParseState &state) const {828    if (std::optional<const char *> result{state.GetNextChar()}) {829      return result;830    }831    state.Say(MessageFixedText::endOfFileMessage);832    return std::nullopt;833  }834};835 836constexpr NextCh nextCh;837 838// If a is a parser for some nonstandard language feature LF, extension<LF>(a)839// is a parser that optionally enabled, sets a strict conformance violation840// flag, and may emit a warning message, if those are enabled.841template <LanguageFeature LF, typename PA> class NonstandardParser {842public:843  using resultType = typename PA::resultType;844  constexpr NonstandardParser(const NonstandardParser &) = default;845  constexpr NonstandardParser(PA parser, MessageFixedText msg)846      : parser_{parser}, message_{msg} {}847  constexpr NonstandardParser(PA parser) : parser_{parser} {}848  std::optional<resultType> Parse(ParseState &state) const {849    if (UserState * ustate{state.userState()}) {850      if (!ustate->features().IsEnabled(LF)) {851        return std::nullopt;852      }853    }854    auto at{state.GetLocation()};855    auto result{parser_.Parse(state)};856    if (result && !message_.empty()) {857      state.Nonstandard(858          CharBlock{at, std::max(state.GetLocation(), at + 1)}, LF, message_);859    }860    return result;861  }862 863private:864  const PA parser_;865  const MessageFixedText message_;866};867 868template <LanguageFeature LF, typename PA>869inline constexpr auto extension(MessageFixedText feature, PA parser) {870  return NonstandardParser<LF, PA>(parser, feature);871}872 873template <LanguageFeature LF, typename PA>874inline constexpr auto extension(PA parser) {875  return NonstandardParser<LF, PA>(parser);876}877 878// If a is a parser for some deprecated or deleted language feature LF,879// deprecated<LF>(a) is a parser that is optionally enabled, sets a strict880// conformance violation flag, and may emit a warning message, if enabled.881template <LanguageFeature LF, typename PA> class DeprecatedParser {882public:883  using resultType = typename PA::resultType;884  constexpr DeprecatedParser(const DeprecatedParser &) = default;885  constexpr DeprecatedParser(PA parser) : parser_{parser} {}886  std::optional<resultType> Parse(ParseState &state) const {887    if (UserState * ustate{state.userState()}) {888      if (!ustate->features().IsEnabled(LF)) {889        return std::nullopt;890      }891    }892    auto at{state.GetLocation()};893    auto result{parser_.Parse(state)};894    if (result) {895      state.Nonstandard(CharBlock{at, state.GetLocation()}, LF,896          "deprecated usage"_port_en_US);897    }898    return result;899  }900 901private:902  const PA parser_;903};904 905template <LanguageFeature LF, typename PA>906inline constexpr auto deprecated(PA parser) {907  return DeprecatedParser<LF, PA>(parser);908}909 910// Parsing objects with "source" members.911template <typename PA> class SourcedParser {912public:913  using resultType = typename PA::resultType;914  constexpr SourcedParser(const SourcedParser &) = default;915  constexpr SourcedParser(PA parser) : parser_{parser} {}916  std::optional<resultType> Parse(ParseState &state) const {917    const char *start{state.GetLocation()};918    auto result{parser_.Parse(state)};919    if (result) {920      const char *end{state.GetLocation()};921      for (; start < end && start[0] == ' '; ++start) {922      }923      for (; start < end && end[-1] == ' '; --end) {924      }925      result->source = CharBlock{start, end};926    }927    return result;928  }929 930private:931  const PA parser_;932};933 934template <typename PA> inline constexpr auto sourced(PA parser) {935  return SourcedParser<PA>{parser};936}937} // namespace Fortran::parser938#endif // FORTRAN_PARSER_BASIC_PARSERS_H_939