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