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