diff --git a/flang/basic-parsers.h b/flang/basic-parsers.h new file mode 100644 index 000000000000..7cc099f1b2b2 --- /dev/null +++ b/flang/basic-parsers.h @@ -0,0 +1,1330 @@ +#ifndef FORTRAN_BASIC_PARSERS_H_ +#define FORTRAN_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 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 template classes and helper +// template functions. See parser-combinators.txt for documentation. + +#include "idioms.h" +#include "message.h" +#include "parse-state.h" +#include "position.h" +#include +#include +#include +#include +#include +#include + +namespace Fortran { + +// fail("...") 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 for satisfy +// the type checker. The state remains valid. +template +class FailParser { + public: + using resultType = A; + constexpr FailParser(const FailParser &) = default; + constexpr explicit FailParser(const char *str) : str_{str} {} + std::optional Parse(ParseState *state) const { + state->messages()->Add(Message{state->position(), str_, state->context()}); + return {}; + } + private: + const char *const str_; +}; + +class Success {}; // for when one must return something that's present + +template +inline constexpr auto fail(const char *message) { + return FailParser{message}; +} + +// pure(x) returns a parsers that always succeeds, does not advance the +// parse, and returns a captured value whose type must be copy-constructible. +template +class PureParser { + public: + using resultType = A; + constexpr PureParser(const PureParser &) = default; + constexpr explicit PureParser(A &&x) : value_(std::move(x)) {} + std::optional Parse(ParseState *) const { return {value_}; } + private: + const A value_; +}; + +template +inline constexpr auto pure(A x) { + return PureParser(std::move(x)); +} + +// 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 +class BacktrackingParser { + public: + using resultType = typename A::resultType; + constexpr BacktrackingParser(const BacktrackingParser &) = default; + constexpr BacktrackingParser(const A &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + Messages messages{std::move(*state->messages())}; + MessageContext context{state->context()}; + ParseState backtrack{*state}; + std::optional result{parser_.Parse(state)}; + if (result) { + // preserve any new messages + messages.Annex(state->messages()); + state->messages()->swap(messages); + } else { + state->swap(backtrack); + state->messages()->swap(messages); + state->set_context(context); + } + return result; + } + private: + const A parser_; +}; + +template +inline constexpr auto attempt(const A &parser) { + return BacktrackingParser{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 +class NegatedParser { + public: + using resultType = Success; + constexpr NegatedParser(const NegatedParser &) = default; + constexpr NegatedParser(const PA &p) : parser_{p} {} + std::optional Parse(ParseState *state) const { + Messages messages{std::move(*state->messages())}; + ParseState forked{*state}; + state->messages()->swap(messages); + if (parser_.Parse(&forked)) { + return {}; + } + return {Success{}}; + } + private: + const PA parser_; +}; + +template +inline constexpr auto operator!(const PA &p) { + return NegatedParser(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 +class LookAheadParser { + public: + using resultType = Success; + constexpr LookAheadParser(const LookAheadParser &) = default; + constexpr LookAheadParser(const PA &p) : parser_{p} {} + std::optional Parse(ParseState *state) const { + Messages messages{std::move(*state->messages())}; + ParseState forked{*state}; + state->messages()->swap(messages); + return parser_.Parse(&forked); + } + private: + const PA parser_; +}; + +template +inline constexpr auto lookAhead(const PA &p) { + return LookAheadParser{p}; +} + +// If a is a parser, inContext("...", a) runs it in a nested message context. +template +class MessageContextParser { + public: + using resultType = typename PA::resultType; + constexpr MessageContextParser(const MessageContextParser &) = default; + constexpr MessageContextParser(const char *str, const PA &p) + : str_{str}, parser_{p} {} + std::optional Parse(ParseState *state) const { + state->PushContext(std::string{str_}); + std::optional result{parser_.Parse(state)}; + state->PopContext(); + return result; + } + private: + const char *str_; + const PA parser_; +}; + +template +inline constexpr auto inContext(const char *context, const PA &parser) { + return MessageContextParser{context, 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 +class SequenceParser { + public: + using resultType = typename PB::resultType; + constexpr SequenceParser(const SequenceParser &) = default; + constexpr SequenceParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (pa_.Parse(state)) { + return pb_.Parse(state); + } + return {}; + } + private: + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto operator>>(const PA &pa, const PB &pb) { + return SequenceParser{pa, pb}; +} + +template +class InvertedSequenceParser { + public: + using resultType = typename PA::resultType; + constexpr InvertedSequenceParser(const InvertedSequenceParser &) = default; + constexpr InvertedSequenceParser(const PA &pa, const PB &pb) + : pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + if (pb_.Parse(state)) { + return std::move(ax); + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto operator/(const PA &pa, const PB &pb) { + return InvertedSequenceParser{pa, pb}; +} + +// If a and b are parsers, then a || b returns a parser that succeeds if +// a does so, or if a fails and b succeeds. The result types of the parsers +// must be the same type. If a succeeds, b is not attempted. +template +class AlternativeParser { + public: + using resultType = typename PA::resultType; + constexpr AlternativeParser(const AlternativeParser &) = default; + constexpr AlternativeParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + Messages messages{std::move(*state->messages())}; + MessageContext context{state->context()}; + ParseState backtrack{*state}; + if (std::optional ax{pa_.Parse(state)}) { + // preserve any new messages + messages.Annex(state->messages()); + state->messages()->swap(messages); + return ax; + } + ParseState paState{std::move(*state)}; + state->swap(backtrack); + state->set_context(context); + if (std::optional bx{pb_.Parse(state)}) { + // preserve any new messages + messages.Annex(state->messages()); + state->messages()->swap(messages); + return bx; + } + // Both alternatives failed. Retain the state (and messages) from the + // alternative parse that went the furthest. + if (state->position() <= paState.position()) { + messages.Annex(paState.messages()); + state->swap(paState); + } else { + messages.Annex(state->messages()); + } + state->messages()->swap(messages); + return {}; + } + private: + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto operator||(const PA &pa, const PB &pb) { + return AlternativeParser{pa, pb}; +} + +#if 0 +// Should have been a big speed-up, but instead produced a slow-down. +// TODO: Further investigate rebinding alternatives to the right. +template +inline constexpr auto operator||(const AlternativeParser &papb, + const PC &pc) { + return papb.pa_ || (papb.pb_ || pc); // bind to the right for performance +} +#endif + +// 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. +template +class RecoveryParser { + public: + using resultType = typename PA::resultType; + constexpr RecoveryParser(const RecoveryParser &) = default; + constexpr RecoveryParser(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + Messages messages{std::move(*state->messages())}; + MessageContext context{state->context()}; + ParseState backtrack{*state}; + std::optional ax{pa_.Parse(state)}; + messages.Annex(state->messages()); + if (ax.has_value()) { + state->messages()->swap(messages); + return ax; + } + state->swap(backtrack); + state->set_context(context); + std::optional bx{pb_.Parse(state)}; + state->messages()->swap(messages); + if (bx.has_value()) { + state->set_anyErrorRecovery(); + } + return bx; + } + private: + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto recovery(const PA &pa, const PB &pb) { + return RecoveryParser{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 +class ManyParser { + using paType = typename PA::resultType; + public: + using resultType = std::list; + constexpr ManyParser(const ManyParser &) = default; + constexpr ManyParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + resultType result; + Position at{state->position()}; + while (std::optional x{parser_.Parse(state)}) { + result.emplace_back(std::move(*x)); + if (state->position() <= at) { + break; // no forward progress, don't loop + } + at = state->position(); + } + return {std::move(result)}; + } + private: + const BacktrackingParser parser_; +}; + +template +inline constexpr auto many(const PA &parser) { + return ManyParser{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 +class SomeParser { + using paType = typename PA::resultType; + public: + using resultType = std::list; + constexpr SomeParser(const SomeParser &) = default; + constexpr SomeParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + Position start{state->position()}; + if (std::optional first{parser_.Parse(state)}) { + resultType result; + result.emplace_back(std::move(*first)); + if ((state->position() > start)) { + result.splice(result.end(), *many(parser_).Parse(state)); + } + return {std::move(result)}; + } + return {}; + } + private: + const PA parser_; +}; + +template +inline constexpr auto some(const PA &parser) { + return SomeParser{parser}; +} + +// If x is a parser, skipMany(x) is equivalent to many(x) but with no result. +template +class SkipManyParser { + public: + using resultType = Success; + constexpr SkipManyParser(const SkipManyParser &) = default; + constexpr SkipManyParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + for (Position at{state->position()}; + parser_.Parse(state) && state->position() > at; + at = state->position()) { + } + return {Success{}}; + } + private: + const BacktrackingParser parser_; +}; + +template +inline constexpr auto skipMany(const PA &parser) { + return SkipManyParser{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 +class SkipManyFastParser { + public: + using resultType = Success; + constexpr SkipManyFastParser(const SkipManyFastParser &) = default; + constexpr SkipManyFastParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + while (parser_.Parse(state)) { + } + return {Success{}}; + } + private: + const PA parser_; +}; + +template +inline constexpr auto skipManyFast(const PA &parser) { + return SkipManyFastParser{parser}; +} + +// If x is a parser returning some type A, then maybe(x) returns a +// parser that returns std::optional, always succeeding. +template +class MaybeParser { + using paType = typename PA::resultType; + public: + using resultType = std::optional; + constexpr MaybeParser(const MaybeParser &) = default; + constexpr MaybeParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (resultType result{parser_.Parse(state)}) { + return {std::move(result)}; + } + return {resultType{}}; + } + private: + const BacktrackingParser parser_; +}; + +template +inline constexpr auto maybe(const PA &parser) { + return MaybeParser{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 +class DefaultedParser { + public: + using resultType = typename PA::resultType; + constexpr DefaultedParser(const DefaultedParser &) = default; + constexpr DefaultedParser(const PA &p) : parser_{p} {} + std::optional Parse(ParseState *state) const { + std::optional> ax{maybe(parser_).Parse(state)}; + CHECK(ax.has_value()); // maybe() always succeeds + if (ax.value().has_value()) { + return std::move(*ax); + } + return {resultType{}}; + } + private: + const BacktrackingParser parser_; +}; + +template +inline constexpr auto defaulted(const PA &p) { + return DefaultedParser(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)). +template +class Apply1 { + using paType = typename PA::resultType; + using funcType = T (*)(paType &&); + public: + using resultType = T; + constexpr Apply1(const Apply1 &) = default; + constexpr Apply1(funcType function, const PA &parser) + : function_{function}, parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{parser_.Parse(state)}) { + return {function_(std::move(*ax))}; + } + return {}; + } + private: + const funcType function_; + const PA parser_; +}; + +template +inline constexpr auto +applyFunction(T (*f)(typename PA::resultType &&), const PA &pa) { + return Apply1{f, pa}; +} + +template +class Apply1Functor { + using paType = typename PA::resultType; + using funcType = std::function; + public: + using resultType = T; + Apply1Functor(const Apply1Functor &) = default; + Apply1Functor(const funcType &functor, const PA &parser) + : functor_{functor}, parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{parser_.Parse(state)}) { + return {functor_(std::move(*ax))}; + } + return {}; + } + private: + const funcType &functor_; + const PA parser_; +}; + +template +inline auto +applyLambda(const std::function &f, + const PA &pa) { + return Apply1Functor{f, pa}; +} + +template +class Apply1Mem { + public: + using resultType = typename PA::resultType; + using funcType = void (resultType::*)(); + constexpr Apply1Mem(const Apply1Mem &) = default; + constexpr Apply1Mem(funcType function, const PA &pa) + : function_{function}, pa_{pa} {} + std::optional Parse(ParseState *state) const { + std::optional result{pa_.Parse(state)}; + if (result) { + ((*result).*function_)(); + } + return result; + } + private: + const funcType function_; + const PA pa_; +}; + +template +inline constexpr auto +applyMem(typename Apply1Mem::funcType f, const PA &pa) { + return Apply1Mem{f, pa}; +} + +template +class Apply2 { + using paType = typename PA::resultType; + using pbType = typename PB::resultType; + using funcType = T (*)(paType &&, pbType &&); + public: + using resultType = T; + constexpr Apply2(const Apply2 &) = default; + constexpr Apply2(funcType function, const PA &pa, const PB &pb) + : function_{function}, pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + return {function_(std::move(*ax), std::move(*bx))}; + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto +applyFunction(T (*f)(typename PA::resultType &&, typename PB::resultType &&), + const PA &pa, const PB &pb) { + return Apply2{f, pa, pb}; +} + +template +class Apply2Functor { + using paType = typename PA::resultType; + using pbType = typename PB::resultType; + using funcType = std::function; + public: + using resultType = T; + Apply2Functor(const Apply2Functor &) = default; + Apply2Functor(const funcType &function, const PA &pa, const PB &pb) + : function_{function}, pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + return {function_(std::move(*ax), std::move(*bx))}; + } + } + return {}; + } + private: + const funcType &function_; + const PA pa_; + const PB pb_; +}; + +template +inline auto +applyLambda(const std::function &f, + const PA &pa, const PB &pb) { + return Apply2Functor{f, pa, pb}; +} + +template +class Apply2Mem { + using pbType = typename PB::resultType; + public: + using resultType = typename PA::resultType; + using funcType = void (resultType::*)(pbType &&); + constexpr Apply2Mem(const Apply2Mem &) = default; + constexpr Apply2Mem(funcType function, const PA &pa, const PB &pb) + : function_{function}, pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (std::optional result{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + ((*result).*function_)(std::move(*bx)); + return result; + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; +}; + +template +inline constexpr auto +applyMem(typename Apply2Mem::funcType f, const PA &pa, const PB &pb) { + return Apply2Mem{f, pa, pb}; +} + +template +class Apply3 { + using paType = typename PA::resultType; + using pbType = typename PB::resultType; + using pcType = typename PC::resultType; + using funcType = T (*) (paType &&, pbType &&, pcType &&); + public: + using resultType = T; + constexpr Apply3(const Apply3 &) = default; + constexpr Apply3(funcType function, const PA &pa, const PB &pb, const PC &pc) + : function_{function}, pa_{pa}, pb_{pb}, pc_{pc} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + if (std::optional cx{pc_.Parse(state)}) { + return {function_(std::move(*ax), std::move(*bx), std::move(*cx))}; + } + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; + const PC pc_; +}; + +template +inline constexpr auto +applyFunction(T (*f)(typename PA::resultType &&, typename PB::resultType &&, + typename PC::resultType &&), + const PA &pa, const PB &pb, const PC &pc) { + return Apply3{f, pa, pb, pc}; +} + +template +class Apply3Mem { + using pbType = typename PB::resultType; + using pcType = typename PC::resultType; + public: + using resultType = typename PA::resultType; + using funcType = void (resultType::*)(pbType &&, pcType &&); + constexpr Apply3Mem(const Apply3Mem &) = default; + constexpr Apply3Mem(funcType function, const PA &pa, const PB &pb, + const PC &pc) + : function_{function}, pa_{pa}, pb_{pb}, pc_{pc} {} + std::optional Parse(ParseState *state) const { + if (std::optional result{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + if (std::optional cx{pc_.Parse(state)}) { + ((*result).*function_)(std::move(*bx), std::move(*cx)); + return result; + } + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; + const PC pc_; +}; + +template +inline constexpr auto +applyMem(typename Apply3Mem::funcType f, + const PA &pa, const PB &pb, const PC &pc) { + return Apply3Mem{f, pa, pb, pc}; +} + +template +class Apply4 { + using paType = typename PA::resultType; + using pbType = typename PB::resultType; + using pcType = typename PC::resultType; + using pdType = typename PD::resultType; + using funcType = T (*) (paType &&, pbType &&, pcType &&, pdType &&); + public: + using resultType = T; + constexpr Apply4(const Apply4 &) = default; + constexpr Apply4(funcType function, const PA &pa, const PB &pb, const PC &pc, + const PD &pd) + : function_{function}, pa_{pa}, pb_{pb}, pc_{pc}, pd_{pd} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + if (std::optional cx{pc_.Parse(state)}) { + if (std::optional dx{pd_.Parse(state)}) { + return {function_(std::move(*ax), std::move(*bx), + std::move(*cx), std::move(*dx))}; + } + } + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; + const PC pc_; + const PD pd_; +}; + +template +inline constexpr auto +applyFunction(T (*f)(typename PA::resultType &&, typename PB::resultType &&, + typename PC::resultType &&, typename PD::resultType &&), + const PA &pa, const PB &pb, const PC &pc, const PD &pd) { + return Apply4{f, pa, pb, pc, pd}; +} + +template +class Apply4Mem { + using pbType = typename PB::resultType; + using pcType = typename PC::resultType; + using pdType = typename PD::resultType; + public: + using resultType = typename PA::resultType; + using funcType = void (resultType::*) (pbType &&, pcType &&, pdType &&); + constexpr Apply4Mem(const Apply4Mem &) = default; + constexpr Apply4Mem(funcType function, const PA &pa, const PB &pb, + const PC &pc, const PD &pd) + : function_{function}, pa_{pa}, pb_{pb}, pc_{pc}, pd_{pd} {} + std::optional Parse(ParseState *state) const { + if (std::optional result{pa_.Parse(state)}) { + if (std::optional bx{pb_.Parse(state)}) { + if (std::optional cx{pc_.Parse(state)}) { + if (std::optional dx{pd_.Parse(state)}) { + ((*result).*function_)(std::move(*bx), std::move(*cx), + std::move(*dx)); + return result; + } + } + } + } + return {}; + } + private: + const funcType function_; + const PA pa_; + const PB pb_; + const PC pc_; + const PD pd_; +}; + +template +inline constexpr auto +applyMem(typename Apply4Mem::funcType f, + const PA &pa, const PB &pb, const PC &pc, const PD &pd) { + return Apply4Mem{f, pa, pb, pc, pd}; +} + +// 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{}(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. +template +struct construct { + + using resultType = T; + constexpr construct(const construct &) = default; + std::optional Parse(ParseState *state) const { return {T{}}; } + + constexpr construct operator()() const { + return *this; + } + + template + class Construct1 { + public: + using resultType = T; + constexpr Construct1(const Construct1 &) = default; + constexpr explicit Construct1(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (auto ax = parser_.Parse(state)) { + return {T(std::move(*ax))}; + } + return {}; + } + private: + const PA parser_; + }; + + template + constexpr Construct1 operator()(const PA &pa) const { + return Construct1{pa}; + } + + template + class Construct2 { + public: + using resultType = T; + constexpr Construct2(const Construct2 &) = default; + constexpr Construct2(const PA &pa, const PB &pb) : pa_{pa}, pb_{pb} {} + std::optional Parse(ParseState *state) const { + if (auto ax = pa_.Parse(state)) { + if (auto bx = pb_.Parse(state)) { + return {T{std::move(*ax), std::move(*bx)}}; + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; + }; + + template + constexpr Construct2 operator()(const PA &pa, const PB &pb) const { + return Construct2{pa, pb}; + } + + template + class Construct3 { + public: + using resultType = T; + constexpr Construct3(const Construct3 &) = default; + constexpr Construct3(const PA &pa, const PB &pb, const PC &pc) + : pa_{pa}, pb_{pb}, pc_{pc} {} + std::optional Parse(ParseState *state) const { + if (auto ax = pa_.Parse(state)) { + if (auto bx = pb_.Parse(state)) { + if (auto cx = pc_.Parse(state)) { + return {T{std::move(*ax), std::move(*bx), std::move(*cx)}}; + } + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; + const PC pc_; + }; + + template + constexpr Construct3 + operator()(const PA &pa, const PB &pb, const PC &pc) const { + return Construct3{pa, pb, pc}; + } + + template + class Construct4 { + public: + using resultType = T; + constexpr Construct4(const Construct4 &) = default; + constexpr Construct4(const PA &pa, const PB &pb, + const PC &pc, const PD &pd) + : pa_{pa}, pb_{pb}, pc_{pc}, pd_{pd} {} + std::optional Parse(ParseState *state) const { + if (auto ax = pa_.Parse(state)) { + if (auto bx = pb_.Parse(state)) { + if (auto cx = pc_.Parse(state)) { + if (auto dx = pd_.Parse(state)) { + return {T{std::move(*ax), std::move(*bx), std::move(*cx), + std::move(*dx)}}; + } + } + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; + const PC pc_; + const PD pd_; + }; + + template + constexpr Construct4 + operator()(const PA &pa, const PB &pb, const PC &pc, const PD &pd) const { + return Construct4{pa, pb, pc, pd}; + } + + template + class Construct5 { + public: + using resultType = T; + constexpr Construct5(const Construct5 &) = default; + constexpr Construct5(const PA &pa, const PB &pb, + const PC &pc, const PD &pd, + const PE &pe) + : pa_{pa}, pb_{pb}, pc_{pc}, pd_{pd}, pe_{pe} {} + std::optional Parse(ParseState *state) const { + if (auto ax = pa_.Parse(state)) { + if (auto bx = pb_.Parse(state)) { + if (auto cx = pc_.Parse(state)) { + if (auto dx = pd_.Parse(state)) { + if (auto ex = pe_.Parse(state)) { + return {T{std::move(*ax), std::move(*bx), std::move(*cx), + std::move(*dx), std::move(*ex)}}; + } + } + } + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; + const PC pc_; + const PD pd_; + const PE pe_; + }; + + template + constexpr Construct5 + operator()(const PA &pa, const PB &pb, const PC &pc, const PD &pd, + const PE &pe) const { + return Construct5{pa, pb, pc, pd, pe}; + } + + template + class Construct6 { + public: + using resultType = T; + constexpr Construct6(const Construct6 &) = default; + constexpr Construct6(const PA &pa, const PB &pb, + const PC &pc, const PD &pd, + const PE &pe, const PF &pf) + : pa_{pa}, pb_{pb}, pc_{pc}, pd_{pd}, pe_{pe}, pf_{pf} {} + std::optional Parse(ParseState *state) const { + if (auto ax = pa_.Parse(state)) { + if (auto bx = pb_.Parse(state)) { + if (auto cx = pc_.Parse(state)) { + if (auto dx = pd_.Parse(state)) { + if (auto ex = pe_.Parse(state)) { + if (auto fx = pf_.Parse(state)) { + return {T{std::move(*ax), std::move(*bx), std::move(*cx), + std::move(*dx), std::move(*ex), std::move(*fx)}}; + } + } + } + } + } + } + return {}; + } + private: + const PA pa_; + const PB pb_; + const PC pc_; + const PD pd_; + const PE pe_; + const PF pf_; + }; + + template + constexpr Construct6 + operator()(const PA &pa, const PB &pb, const PC &pc, const PD &pd, + const PE &pe, const PF &pf) const { + return Construct6{pa, pb, pc, pd, pe, pf}; + } +}; + +// If f is a function of type bool (*f)(const ParseState &), then +// StatePredicateGuardParser{f} is a parser that succeeds when f() is true +// and fails otherwise. The state is preserved. +class StatePredicateGuardParser { + public: + using resultType = Success; + constexpr StatePredicateGuardParser(const StatePredicateGuardParser &) + = default; + constexpr explicit + StatePredicateGuardParser(bool (*predicate)(const ParseState &)) + : predicate_{predicate} {} + std::optional Parse(ParseState *state) const { + if (predicate_(*state)) { + return {Success{}}; + } + return {}; + } + private: + bool (*const predicate_)(const ParseState &); +}; + +// 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 +std::list prepend(T &&head, std::list &&rest) { + rest.push_front(std::move(head)); + return std::move(rest); +} + +template +class NonemptySeparated { + private: + using paType = typename PA::resultType; + public: + using resultType = std::list; + constexpr NonemptySeparated(const NonemptySeparated &) = default; + constexpr NonemptySeparated(const PA &p, const PB &sep) + : parser_{p}, separator_{sep} {} + std::optional Parse(ParseState *state) const { + return applyFunction(prepend, + parser_, + many(separator_ >> parser_)).Parse(state); + } + private: + const PA parser_; + const PB separator_; +}; + +template +inline constexpr auto +nonemptySeparated(const PA &p, const PB &sep) { + return NonemptySeparated{p, sep}; +} + +// If f is a function of type void (*f)(ParseState *), then +// StateUpdateParser{f} is a parser that always succeeds, possibly with +// side effects on the parsing state. +class StateUpdateParser { + public: + using resultType = Success; + constexpr StateUpdateParser(const StateUpdateParser &) = default; + constexpr StateUpdateParser(void (*function)(ParseState *)) + : function_{function} {} + std::optional Parse(ParseState *state) const { + function_(state); + return {Success{}}; + } + private: + void (*const function_)(ParseState *); +}; + +// If a is a parser with some result type A, and f is a function of A&& that +// returns another parser, then a >>= f returns a parser that succeeds +// when a does so and then f(ax) also does so; the final result is that of +// applying the parser that was returned by f(ax). +template +class BoundMoveParser { + using paType = typename PA::resultType; + using funcType = T (*)(paType &&); + public: + using resultType = T; + constexpr BoundMoveParser(const BoundMoveParser &) = default; + constexpr BoundMoveParser(const PA &pa, funcType f) : pa_{pa}, f_{f} {} + std::optional Parse(ParseState *state) const { + if (std::optional ax{pa_.Parse(state)}) { + return f_(std::move(*ax)).Parse(state); + } + return {}; + } + private: + const PA pa_; + const funcType f_; +}; + +template +inline constexpr auto +operator>>=(const PA &pa, T (*f)(typename PA::resultType &&)) { + return BoundMoveParser(pa, f); +} + +// 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. +// +// cut is a parser that always fails. It is useful when a parser must +// have its type implicitly set; one use is the idiom "defaulted(cut >> x)", +// which is essentially what "pure(T{})" would be able to do for x's +// result type T, but without requiring that T have a default constructor +// or a non-trivial destructor. The state is preserved. +template +struct FixedParser { + using resultType = Success; + constexpr FixedParser() {} + static constexpr std::optional Parse(ParseState *) { + if (pass) { + return {Success{}}; + } + return {}; + } +}; + +constexpr FixedParser ok; +constexpr FixedParser cut; + +// guard(bool) returns a parser that succeeds iff its dynamic argument +// value is true. The state is preserved. +class GuardParser { + public: + using resultType = Success; + constexpr GuardParser(const GuardParser &) = default; + constexpr GuardParser(bool ok) : ok_{ok} {} + constexpr std::optional Parse(ParseState *) const { + if (ok_) { + return {Success{}}; + } + return {}; + } + private: + const bool ok_; +}; + +inline constexpr auto guard(bool truth) { + return GuardParser(truth); +} + +// rawNextChar is a parser that succeeds if the parsing state is not +// at the end of its input, returning the next character and +// advancing the parse when it does so. +constexpr struct RawNextCharParser { + using resultType = char; + constexpr RawNextCharParser() {} + std::optional Parse(ParseState *state) const { + if (std::optional ch{state->GetNextRawChar()}) { + state->Advance(); + return ch; + } + state->messages()->Add(Message{state->position(), "end of file", + state->context()}); + return {}; + } +} rawNextChar; + +// If a is a parser, then withinCharLiteral(a) succeeds if a does so, with the +// parsing state temporarily modified during the recognition of a to +// signify that the parse is within quotes or Hollerith. +template +class WithinCharLiteral { + public: + using resultType = typename PA::resultType; + constexpr WithinCharLiteral(const WithinCharLiteral &) = default; + constexpr WithinCharLiteral(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + bool was = state->set_inCharLiteral(true); + std::optional result{parser_.Parse(state)}; + state->set_inCharLiteral(was); + return result; + } + private: + const PA parser_; +}; + +template +inline constexpr auto withinCharLiteral(const PA &parser) { + return WithinCharLiteral(parser); +} + +// If a is a parser for nonstandard usage, extension(a) is a parser that +// is disabled if strict standard compliance is enforced, and enabled with +// a warning if such a warning is enabled. +template +class NonstandardParser { + public: + using resultType = typename PA::resultType; + constexpr NonstandardParser(const NonstandardParser &) = default; + constexpr NonstandardParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (state->strictConformance()) { + return {}; + } + Position at{state->position()}; + auto result = parser_.Parse(state); + if (result) { + if (state->warnOnNonstandardUsage()) { + state->messages()->Add(Message{at, "nonstandard usage", + state->context()}); + } + } + return result; + } + private: + const PA parser_; +}; + +template +inline constexpr auto extension(const PA &parser) { + return NonstandardParser(parser); +} + +// If a is a parser for deprecated usage, deprecated(a) is a parser that +// is disabled if strict standard compliance is enforced, and enabled with +// a warning if such a warning is enabled. +template +class DeprecatedParser { + public: + using resultType = typename PA::resultType; + constexpr DeprecatedParser(const DeprecatedParser &) = default; + constexpr DeprecatedParser(const PA &parser) : parser_{parser} {} + std::optional Parse(ParseState *state) const { + if (state->strictConformance()) { + return {}; + } + Position at{state->position()}; + auto result = parser_.Parse(state); + if (result) { + if (state->warnOnDeprecatedUsage()) { + state->messages()->Add(Message{at, "deprecated usage", + state->context()}); + } + } + return result; + } + private: + const PA parser_; +}; + +template +inline constexpr auto deprecated(const PA &parser) { + return DeprecatedParser(parser); +} + + +constexpr struct GetUserState { + using resultType = UserState *; + constexpr GetUserState() {} + static std::optional Parse(ParseState *state) { + return {state->userState()}; + } +} getUserState; + +constexpr struct InFixedForm { + using resultType = Success; + constexpr InFixedForm() {} + static std::optional Parse(ParseState *state) { + if (state->inFixedForm()) { + return {Success{}}; + } + return {}; + } +} inFixedForm; + +constexpr struct GetColumn { + using resultType = int; + constexpr GetColumn() {} + static std::optional Parse(ParseState *state) { + return {state->position().column()}; + } +} getColumn; + +constexpr struct GetPosition { + using resultType = Position; + constexpr GetPosition() {} + static std::optional Parse(ParseState *state) { + return {state->position()}; + } +} getPosition; + +} // namespace Fortran +#endif // FORTRAN_BASIC_PARSERS_H_