#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 { namespace parser { // 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 parser } // namespace Fortran #endif // FORTRAN_BASIC_PARSERS_H_