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