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