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