1 | //===-- lib/Parser/stmt-parser.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_STMT_PARSER_H_ |
10 | #define FORTRAN_PARSER_STMT_PARSER_H_ |
11 | |
12 | // Basic parsing of statements. |
13 | |
14 | #include "basic-parsers.h" |
15 | #include "token-parsers.h" |
16 | |
17 | namespace Fortran::parser { |
18 | |
19 | // statement(p) parses Statement<P> for some statement type P that is the |
20 | // result type of the argument parser p, while also handling labels and |
21 | // end-of-statement markers. |
22 | |
23 | // R611 label -> digit [digit]... |
24 | constexpr auto label{space >> digitString64 / spaceCheck}; |
25 | |
26 | template <typename PA> |
27 | inline constexpr auto unterminatedStatement(const PA &p) { |
28 | return skipStuffBeforeStatement >> |
29 | sourced(construct<Statement<typename PA::resultType>>( |
30 | maybe(label), space >> p)); |
31 | } |
32 | |
33 | constexpr auto endOfLine{ |
34 | "\n"_ch >> ok || fail("expected end of line"_err_en_US )}; |
35 | |
36 | constexpr auto semicolons{";"_ch >> skipMany(";"_tok ) / space / maybe("\n"_ch )}; |
37 | constexpr auto endOfStmt{ |
38 | space >> withMessage("expected end of statement"_err_en_US , |
39 | semicolons || endOfLine)}; |
40 | constexpr auto forceEndOfStmt{recovery(endOfStmt, SkipPast<'\n'>{})}; |
41 | |
42 | template <typename PA> inline constexpr auto statement(const PA &p) { |
43 | return unterminatedStatement(p) / endOfStmt; |
44 | } |
45 | |
46 | // unlabeledStatement() is basically statement() for those few situations |
47 | // in Fortran where a statement cannot have a label. |
48 | template <typename PA> inline constexpr auto unlabeledStatement(const PA &p) { |
49 | return space >> |
50 | sourced(construct<UnlabeledStatement<typename PA::resultType>>(p)); |
51 | } |
52 | |
53 | // This unambiguousStatement() variant of statement() provides better error |
54 | // recovery for contexts containing statements that might have trailing |
55 | // garbage, but it must be used only when no instance of the statement in |
56 | // question could also be a legal prefix of some other statement that might |
57 | // be valid at that point. It only makes sense to use this within "some()" |
58 | // or "many()" so as to not end the list of statements. |
59 | template <typename PA> inline constexpr auto unambiguousStatement(const PA &p) { |
60 | return unterminatedStatement(p) / forceEndOfStmt; |
61 | } |
62 | |
63 | constexpr auto ignoredStatementPrefix{ |
64 | skipStuffBeforeStatement >> maybe(label) >> maybe(name / ":" ) >> space}; |
65 | |
66 | // Error recovery within a statement() call: skip *to* the end of the line, |
67 | // unless at an END or CONTAINS statement. |
68 | constexpr auto inStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> |
69 | SkipTo<'\n'>{} >> construct<ErrorRecovery>()}; |
70 | |
71 | // Error recovery within statement sequences: skip *past* the end of the line, |
72 | // but not over an END or CONTAINS statement. |
73 | constexpr auto skipStmtErrorRecovery{!"END"_tok >> !"CONTAINS"_tok >> |
74 | SkipPast<'\n'>{} >> construct<ErrorRecovery>()}; |
75 | |
76 | // Error recovery across statements: skip the line, unless it looks |
77 | // like it might end the containing construct. |
78 | constexpr auto stmtErrorRecoveryStart{ignoredStatementPrefix}; |
79 | constexpr auto skipBadLine{SkipPast<'\n'>{} >> construct<ErrorRecovery>()}; |
80 | constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >> |
81 | !"END"_tok >> !"CONTAINS"_tok >> !"ELSE"_tok >> !"CASE"_tok >> |
82 | !"TYPE IS"_tok >> !"CLASS"_tok >> !"RANK"_tok >> |
83 | !("!$ACC "_sptok >> "END"_tok ) >> |
84 | !("!$OMP "_sptok >> ("END"_tok || "SECTION"_id )) >> skipBadLine}; |
85 | |
86 | // END statement error recovery |
87 | constexpr auto missingOptionalName{pure<std::optional<Name>>()}; |
88 | constexpr auto noNameEnd{"END" >> missingOptionalName}; |
89 | constexpr auto atEndOfStmt{space >> |
90 | withMessage("expected end of statement"_err_en_US , lookAhead(";\n"_ch ))}; |
91 | constexpr auto bareEnd{noNameEnd / recovery(atEndOfStmt, SkipTo<'\n'>{})}; |
92 | |
93 | // For unrecognizable construct END statements. Be sure to not consume |
94 | // a program unit's END statement. |
95 | constexpr auto progUnitEndStmt{ |
96 | "END" >> (lookAhead("\n"_ch ) || "SUBROUTINE"_tok || "FUNCTION"_tok || |
97 | "PROCEDURE"_tok || "MODULE"_tok || "SUBMODULE"_tok || |
98 | "PROGRAM"_tok || "BLOCK DATA"_tok )}; |
99 | constexpr auto constructEndStmtErrorRecovery{ |
100 | !progUnitEndStmt >> ("END"_tok >> SkipTo<'\n'>{} || ok)}; |
101 | constexpr auto namedConstructEndStmtErrorRecovery{ |
102 | constructEndStmtErrorRecovery >> missingOptionalName}; |
103 | |
104 | constexpr auto progUnitEndStmtErrorRecovery{ |
105 | (many(!"END"_tok >> SkipPast<'\n'>{}) >> |
106 | ("END"_tok >> SkipTo<'\n'>{} || consumedAllInput)) >> |
107 | missingOptionalName}; |
108 | |
109 | constexpr auto beginDirective{skipStuffBeforeStatement >> "!"_ch }; |
110 | constexpr auto endDirective{space >> endOfLine}; |
111 | |
112 | } // namespace Fortran::parser |
113 | #endif // FORTRAN_PARSER_STMT_PARSER_H_ |
114 | |