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